赞
踩
通过arduinoapi实现封装,实现底层分离,支持arduino生态,
通过固件库模块化外设,由ArduinoAPI调用
参考FastShift的封装方式,由于F403A固件库升级,底层需要重新封装
由图可以看出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); }
对于外部脉冲(方波)计数,通用的方法为捕获比较方式,由于项目对于脉冲的精度要求比较高,在快速搭建代码测试过后,发现该方法并不能满足需求,进而寻求计数更为精确的方法----ETR计数。
定时器实际就是一个计数器
可选内部、外部、内部触发输入用作计数时钟
即使用外部触发ETR作为计数器触发源
参考https://blog.csdn.net/u010650845/article/details/81781670
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 ); }
/** * @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 0 adc_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)); #endif return adc_ordinary_conversion_data_get(ADCx); }
通道注册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++; #endif return 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);
#else
dma_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; #endif return ADC_DMA_ConvertedValue[index]; }
设置正确才能正确识别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(); }
bootloader
app
保持一致
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。