AT32固件库外设使用,ArduinoAPI接口移植,模块化

2023-10-31 18:15

本文主要是介绍AT32固件库外设使用,ArduinoAPI接口移植,模块化,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 一、ArduinoAPI移植
  • 一、通用定时器使用
    • 1.计时
    • 1.
    • 2.ETR外部时钟计数
    • 4.ArduinoAPI - timer
  • 三、ADC
    • 1.ADC初始化(非DMA)
    • 2.ADC_DMA 规则通道扫描
  • 六、USB HID IAP
    • 1.准备好Bootloader和app
    • 2.配置好时钟,一定要打开USB
    • 3.将生成的时钟配置复制到bootloader和app对应位置
    • 4 设置bootloader和app的起始位置
    • 5 使用IAP Programmer下载,地址要设置为app地址

一、ArduinoAPI移植

通过arduinoapi实现封装,实现底层分离,支持arduino生态,
通过固件库模块化外设,由ArduinoAPI调用
参考FastShift的封装方式,由于F403A固件库升级,底层需要重新封装

一、通用定时器使用

1.计时

在这里插入图片描述

在这里插入图片描述
由图可以看出AHB时钟为240M
定时器时钟为240M

时间计算
Tout= ((arr+1)(psc+1))/Tclk;
Tclk:TIM3的输入时钟频率(单位为MHz)。
Tout:TIM3溢出时间(单位为us)。
例:计时1ms,输入时钟频率为240MHz。
  arr = 239,psc = 999。
  Tout = ((arr+1)
(psc+1))/Tclk = ((239+1) *(240+1))/240=1000(us)=1(ms)

void trm3_int_init(u16 arr, u16 psc)
{/* enable tmr1 clock */crm_periph_clock_enable(CRM_TMR3_PERIPH_CLOCK, TRUE);tmr_base_init(TMR3, arr, psc);tmr_cnt_dir_set(TMR3, TMR_COUNT_UP);tmr_interrupt_enable(TMR3, TMR_OVF_INT, TRUE);/* tmr1 overflow interrupt nvic init */nvic_priority_group_config(NVIC_PRIORITY_GROUP_0);nvic_irq_enable(TMR3_GLOBAL_IRQn, 1, 0);/* enable tmr3 */tmr_counter_enable(TMR3, TRUE);  
}void TMR3_GLOBAL_IRQHandler(void)
{ 		  TMR3->ists = 0;;lv_tick_inc(1);	     
}

1.

2.ETR外部时钟计数

对于外部脉冲(方波)计数,通用的方法为捕获比较方式,由于项目对于脉冲的精度要求比较高,在快速搭建代码测试过后,发现该方法并不能满足需求,进而寻求计数更为精确的方法----ETR计数。

定时器实际就是一个计数器
可选内部、外部、内部触发输入用作计数时钟
即使用外部触发ETR作为计数器触发源

参考https://blog.csdn.net/u010650845/article/details/81781670

4.ArduinoAPI - timer


void Timer_SetInterrupt(TIM_TypeDef* TIMx, uint32_t Time, Timer_CallbackFunction_t Function)
{uint16_t period = 0;uint16_t prescaler = 0;uint32_t clock = TIMER_GET_CLOCK_MAX(TIMx);if(!IS_TMR_ALL_PERIPH(TIMx) || Time == 0){return;}/*将定时中断时间转换为重装值和时钟分频值*/Timer_TimeFactorization(Time,clock,&period,&prescaler);/*定时中断配置*/Timer_SetInterruptBase(TIMx,period,prescaler,Function,TIMER_PREEMPTIONPRIORITY_DEFAULT,TIMER_SUBPRIORITY_DEFAULT);
}

三、ADC

1.ADC初始化(非DMA)


/*** @brief  ADC 配置* @param  ADCx: ADC地址* @retval 无*/
void ADCx_Init(adc_type* ADCx)
{adc_base_config_type adc_base_struct;if(ADCx == ADC1){crm_periph_clock_enable(CRM_ADC1_PERIPH_CLOCK, TRUE);}else if(ADCx == ADC2){crm_periph_clock_enable(CRM_ADC2_PERIPH_CLOCK, TRUE);}else if(ADCx == ADC3){crm_periph_clock_enable(CRM_ADC3_PERIPH_CLOCK, TRUE);}else{return;}/* select combine mode */adc_combine_mode_select(ADC_INDEPENDENT_MODE);adc_base_default_para_init(&adc_base_struct);adc_base_struct.sequence_mode = FALSE;adc_base_struct.repeat_mode = FALSE;adc_base_struct.data_align = ADC_RIGHT_ALIGNMENT;adc_base_struct.ordinary_channel_length = 1;adc_base_config(ADCx, &adc_base_struct);adc_resolution_set(ADCx, ADC_RESOLUTION_12B);adc_ordinary_conversion_trigger_set(ADCx, ADC_ORDINARY_TRIG_TMR1CH1, ADC_ORDINARY_TRIG_EDGE_NONE);adc_dma_mode_enable(ADCx, FALSE);adc_dma_request_repeat_enable(ADCx, FALSE);adc_interrupt_enable(ADCx, ADC_OCCO_INT, FALSE);adc_enable(ADCx, TRUE);while(adc_flag_get(ADCx, ADC_RDY_FLAG) == RESET);/* adc calibration */adc_calibration_init(ADCx);while(adc_calibration_init_status_get(ADCx));adc_calibration_start(ADCx);while(adc_calibration_status_get(ADCx));}
/*** @brief  获取 ADC 值* @param  ADCx: ADC地址* @param  ADC_Channel: ADC通道* @retval 无*/
uint16_t ADCx_GetValue(adc_type* ADCx, uint16_t ADC_Channel)
{
#if 0adc_ordinary_channel_set(ADCx, (adc_channel_select_type)ADC_Channel, 1, ADC_SAMPLETIME_47_5);adc_ordinary_software_trigger_enable(ADCx, TRUE);while(!adc_flag_get(ADCx, ADC_OCCE_FLAG));
#endifreturn adc_ordinary_conversion_data_get(ADCx);}

2.ADC_DMA 规则通道扫描

通道注册API

	pinMode(PWR_FWD_L_Pin, INPUT_ANALOG_DMA);pinMode(PWR_FWD_M_Pin, INPUT_ANALOG_DMA);pinMode(PWR_RET_L_Pin, INPUT_ANALOG_DMA);pinMode(PWR_RET_M_Pin, INPUT_ANALOG_DMA);

pinMode会调用ADC_DMA_Register

/*** @brief  注册需要DMA搬运的ADC通道* @param  ADC_Channel:ADC通道号* @retval 见ADC_DMA_Res_Type*/
ADC_DMA_Res_Type ADC_DMA_Register(uint8_t ADC_Channel)
{
#if 1/*初始化ADC通道列表*/static bool isInit = false;if(!isInit){uint8_t i;for(i = 0; i < ADC_DMA_REGMAX; i++){ADC_DMA_RegChannelList[i] = 0xFF;}isInit = true;}/*是否是合法ADC通道*/if(!IS_ADC_CHANNEL(ADC_Channel))return ADC_DMA_RES_NOT_ADC_CHANNEL;/*是否已在引脚列表重复注册*/if(ADC_DMA_SearchChannel(ADC_Channel) != -1)return ADC_DMA_RES_DUPLICATE_REGISTRATION;/*是否超出最大注册个数*/if(ADC_DMA_RegCnt >= ADC_DMA_REGMAX)return ADC_DMA_RES_MAX_NUM_OF_REGISTRATIONS_EXCEEDED;/*写入注册列表*/ADC_DMA_RegChannelList[ADC_DMA_RegCnt] = ADC_Channel;/*注册个数+1*/ADC_DMA_RegCnt++;
#endifreturn ADC_DMA_RES_OK;
}

ADC_DMA_Init函数必须放到所有ADC_DMA引脚注册完之后

/**
* @brief  ADC DMA 配置  配置ADC和对应DMA,固定ADC1 如果不需要DMA则使用ADCx_Init函数*       需要放到初始化最后,或者所有ADC_DMA引脚注册完之后* @param  无* @retval 无*/
void ADC_DMA_Init(void)
{uint8_t index;dma_init_type dma_init_structure;adc_base_config_type adc_base_struct;/*CLOCK CONFIG*/crm_periph_clock_enable(CRM_ADC1_PERIPH_CLOCK, TRUE);crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);/*INTERUPT COFIG*/nvic_irq_enable(DMA1_Channel1_IRQn, 0, 0);/*DMA CONFIG*/dma_reset(DMA1_CHANNEL1);dma_default_para_init(&dma_init_structure);dma_init_structure.buffer_size = ADC_DMA_RegCnt;dma_init_structure.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;dma_init_structure.memory_base_addr = (uint32_t)ADC_DMA_ConvertedValue;dma_init_structure.memory_data_width = DMA_MEMORY_DATA_WIDTH_HALFWORD;dma_init_structure.memory_inc_enable = TRUE;dma_init_structure.peripheral_base_addr = (uint32_t) (&(ADC1->odt));dma_init_structure.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_HALFWORD;dma_init_structure.peripheral_inc_enable = FALSE;dma_init_structure.priority = DMA_PRIORITY_HIGH;dma_init_structure.loop_mode_enable = TRUE;dma_init(DMA1_CHANNEL1, &dma_init_structure);dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, TRUE);dma_channel_enable(DMA1_CHANNEL1, TRUE);/*ADC CONFIG*/adc_combine_mode_select(ADC_INDEPENDENT_MODE);adc_base_default_para_init(&adc_base_struct);adc_base_struct.sequence_mode = TRUE;adc_base_struct.repeat_mode = TRUE;adc_base_struct.data_align = ADC_RIGHT_ALIGNMENT;adc_base_struct.ordinary_channel_length = ADC_DMA_RegCnt;adc_base_config(ADC1, &adc_base_struct);for(index = 0; index < ADC_DMA_RegCnt; index++){adc_ordinary_channel_set(ADC1,(adc_channel_select_type)ADC_DMA_RegChannelList[index],index + 1,ADC_SAMPLETIME_41_5);}adc_ordinary_conversion_trigger_set(ADC1, ADC12_ORDINARY_TRIG_SOFTWARE, TRUE);adc_dma_mode_enable(ADC1, TRUE);adc_enable(ADC1, TRUE);adc_calibration_init(ADC1);while(adc_calibration_init_status_get(ADC1));adc_calibration_start(ADC1);while(adc_calibration_status_get(ADC1));}

两种方式 :1 DMA完成中断中再次软件触发,实现循环采样,中断频率较高
2 ADC_DMA_GetValue中软件触发,需要获取数据时才开启采集
通过CONFIG_ADC_CIRCLE_ENABLE 进行切换

void DMA1_Channel1_IRQHandler(void)
{if(dma_flag_get(DMA1_FDT1_FLAG) != RESET){dma_flag_clear(DMA1_FDT1_FLAG);#if (CONFIG_ADC_CIRCLE_ENABLE == 1)adc_ordinary_software_trigger_enable(ADC1, TRUE);
#elsedma_trans_complete_flag = 1;
#endif}
}

/*** @brief  获取DMA搬运的ADC值* @param  ADC_Channel:ADC通道号* @retval ADC值*/
uint16_t ADC_DMA_GetValue(uint8_t ADC_Channel)
{int16_t index;if(!IS_ADC_CHANNEL(ADC_Channel))return 0;index = ADC_DMA_SearchChannel(ADC_Channel);if(index == -1)return 0;#if (CONFIG_ADC_CIRCLE_ENABLE == 0) adc_ordinary_software_trigger_enable(ADC1, TRUE);while(dma_trans_complete_flag == 0);dma_trans_complete_flag = 0;
#endifreturn ADC_DMA_ConvertedValue[index];
}

六、USB HID IAP

1.准备好Bootloader和app

在这里插入图片描述

2.配置好时钟,一定要打开USB

在这里插入图片描述

3.将生成的时钟配置复制到bootloader和app对应位置

设置正确才能正确识别HID设备,并且免驱,否则无法识别usb

void system_clock_config(void)
{/* reset crm */crm_reset();/* enable hext */crm_clock_source_enable(CRM_CLOCK_SOURCE_HEXT, TRUE);/* wait till hext is ready */while(crm_hext_stable_wait() == ERROR){}/* config pll clock resource */crm_pll_config(CRM_PLL_SOURCE_HEXT, CRM_PLL_MULT_15, CRM_PLL_OUTPUT_RANGE_GT72MHZ);/* enable pll */crm_clock_source_enable(CRM_CLOCK_SOURCE_PLL, TRUE);/* wait till pll is ready */while(crm_flag_get(CRM_PLL_STABLE_FLAG) != SET){}/* config ahbclk */crm_ahb_div_set(CRM_AHB_DIV_1);/* config apb2clk */crm_apb2_div_set(CRM_APB2_DIV_2);/* config apb1clk */crm_apb1_div_set(CRM_APB1_DIV_2);/* enable auto step mode */crm_auto_step_mode_enable(TRUE);/* select pll as system clock source */crm_sysclk_switch(CRM_SCLK_PLL);/* wait till pll is used as system clock source */while(crm_sysclk_switch_status_get() != CRM_SCLK_PLL){}/* disable auto step mode */crm_auto_step_mode_enable(FALSE);/* update system_core_clock global variable */system_core_clock_update();
}

4 设置bootloader和app的起始位置

bootloader
在这里插入图片描述

app
在这里插入图片描述
在这里插入图片描述
保持一致

5 使用IAP Programmer下载,地址要设置为app地址

在这里插入图片描述

这篇关于AT32固件库外设使用,ArduinoAPI接口移植,模块化的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/317201

相关文章

Java使用ANTLR4对Lua脚本语法校验详解

《Java使用ANTLR4对Lua脚本语法校验详解》ANTLR是一个强大的解析器生成器,用于读取、处理、执行或翻译结构化文本或二进制文件,下面就跟随小编一起看看Java如何使用ANTLR4对Lua脚本... 目录什么是ANTLR?第一个例子ANTLR4 的工作流程Lua脚本语法校验准备一个Lua Gramm

Java Optional的使用技巧与最佳实践

《JavaOptional的使用技巧与最佳实践》在Java中,Optional是用于优雅处理null的容器类,其核心目标是显式提醒开发者处理空值场景,避免NullPointerExce... 目录一、Optional 的核心用途二、使用技巧与最佳实践三、常见误区与反模式四、替代方案与扩展五、总结在 Java

使用Java将DOCX文档解析为Markdown文档的代码实现

《使用Java将DOCX文档解析为Markdown文档的代码实现》在现代文档处理中,Markdown(MD)因其简洁的语法和良好的可读性,逐渐成为开发者、技术写作者和内容创作者的首选格式,然而,许多文... 目录引言1. 工具和库介绍2. 安装依赖库3. 使用Apache POI解析DOCX文档4. 将解析

Qt中QUndoView控件的具体使用

《Qt中QUndoView控件的具体使用》QUndoView是Qt框架中用于可视化显示QUndoStack内容的控件,本文主要介绍了Qt中QUndoView控件的具体使用,具有一定的参考价值,感兴趣的... 目录引言一、QUndoView 的用途二、工作原理三、 如何与 QUnDOStack 配合使用四、自

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

使用Python构建一个Hexo博客发布工具

《使用Python构建一个Hexo博客发布工具》虽然Hexo的命令行工具非常强大,但对于日常的博客撰写和发布过程,我总觉得缺少一个直观的图形界面来简化操作,下面我们就来看看如何使用Python构建一个... 目录引言Hexo博客系统简介设计需求技术选择代码实现主框架界面设计核心功能实现1. 发布文章2. 加

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

使用Python开发一个带EPUB转换功能的Markdown编辑器

《使用Python开发一个带EPUB转换功能的Markdown编辑器》Markdown因其简单易用和强大的格式支持,成为了写作者、开发者及内容创作者的首选格式,本文将通过Python开发一个Markd... 目录应用概览代码结构与核心组件1. 初始化与布局 (__init__)2. 工具栏 (setup_t

Python虚拟环境终极(含PyCharm的使用教程)

《Python虚拟环境终极(含PyCharm的使用教程)》:本文主要介绍Python虚拟环境终极(含PyCharm的使用教程),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录一、为什么需要虚拟环境?二、虚拟环境创建方式对比三、命令行创建虚拟环境(venv)3.1 基础命令3

Python Transformer 库安装配置及使用方法

《PythonTransformer库安装配置及使用方法》HuggingFaceTransformers是自然语言处理(NLP)领域最流行的开源库之一,支持基于Transformer架构的预训练模... 目录python 中的 Transformer 库及使用方法一、库的概述二、安装与配置三、基础使用:Pi