完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
STM32单定时器四通道捕获功能实现
输入捕获作为定时器的一个功能,在工业测速上有很大的应用。STM32的一些定时器具有四个外部通道,可利用一个定时器采集外部四路脉冲频率,节约硬件资源和软件代码 如需要测量一个或多个外部方波脉冲频率,频率低于单片机运行频率,可如下操作:(以TIM4为例) 初始化:(省略GPIO配置,将TIM4的四个通道引脚配置为上拉或浮空输入,省略定时器RCC配置,省略中断NVIC配置) void TIM_Configuration(void) { TIM_ICInitTypeDef TIM_ICInitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; // TIM4 时基 TIM_DeInit(TIM4); TIM_TimeBaseStructure.TIM_Period = 0xffff; //自动重装值 TIM_TimeBaseStructure.TIM_Prescaler = 719; //预分频值, 使TIMx_CLK=1MHz TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //输入时钟不分频 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数 TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //TIM4_TimeBase // TIM_ICInitStructure.TIM_ICMode = TIM_ICMode_ICAP; //输入捕捉方式 TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;//| TIM_Channel_2; //输入通道 TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //捕捉上升沿 TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //捕捉中断 TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //捕捉不分频 TIM_ICInitStructure.TIM_ICFilter = 0x0; //捕捉输入不滤波 TIM_ICInit(TIM4, &TIM_ICInitStructure); TIM_ICInitStructure.TIM_Channel = TIM_Channel_2 ;//| TIM_Channel_2; //输入通道 TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //捕捉上升沿 TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //捕捉中断 TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //捕捉不分频 TIM_ICInitStructure.TIM_ICFilter = 0x0; //捕捉输入不滤波 TIM_ICInit(TIM4, &TIM_ICInitStructure); TIM_ICInitStructure.TIM_Channel = TIM_Channel_3 ;//| TIM_Channel_2; //输入通道 TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //捕捉上升沿 TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //捕捉中断 TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //捕捉不分频 TIM_ICInitStructure.TIM_ICFilter = 0x0; //捕捉输入不滤波 TIM_ICInit(TIM4, &TIM_ICInitStructure); TIM_ICInitStructure.TIM_Channel = TIM_Channel_4 ;//| TIM_Channel_2; //输入通道 TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //捕捉上升沿 TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //捕捉中断 TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //捕捉不分频 TIM_ICInitStructure.TIM_ICFilter = 0x0; //捕捉输入不滤波 TIM_ICInit(TIM4, &TIM_ICInitStructure); /* TIM enable counter */ TIM_Cmd(TIM4, ENABLE); /* Enable the CC2 Interrupt Request */ TIM_ITConfig(TIM4, TIM_IT_CC1, ENABLE); TIM_ITConfig(TIM4, TIM_IT_CC2, ENABLE); TIM_ITConfig(TIM4, TIM_IT_CC3, ENABLE); TIM_ITConfig(TIM4, TIM_IT_CC4, ENABLE); } [color=rgb(51, 102, 153) !important]复制代码 其中: TIM_TimeBaseStructure.TIM_Period = 0xffff;为自动重装值,与普通单片机一样 TIM_TimeBaseStructure.TIM_Prescaler = 719; 预分频值, 使TIMx_CLK=100KHz ,系统时钟运行于72M时720分频,定时器运行于100KHZ,即10us每分度 TIM_ICInitStructure.TIM_ICMode = TIM_ICMode_ICAP; 此句选择定时器为输入捕获模式,但在我的库函数下未定义,所以注释掉,未影响程序执行 TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;配置通道1 TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;上升沿捕获 TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;捕获中断 TIM_ICInitStructure.TIM_ICFilter = 0x0;不滤波 TIM_ICInit(TIM4, &TIM_ICInitStructure);将配置应用 以上每个通道都需要将整个配置再写一遍,使用与‘|’是无效的。 TIM_Cmd(TIM4, ENABLE);使能定时器4 TIM_ITConfig(TIM4, TIM_IT_CC1, ENABLE); TIM_ITConfig(TIM4, TIM_IT_CC2, ENABLE); TIM_ITConfig(TIM4, TIM_IT_CC3, ENABLE); TIM_ITConfig(TIM4, TIM_IT_CC4, ENABLE);打开四个通道的捕获中断 以上将TIM配置完成,下面是中断内代码: void TIM4_IRQHandler(void) { //频率缓冲区计数 static u16 this_time_CH1 = 0; static u16 last_time_CH1 = 0; static u8 capture_number_CH1 = 0; vu16 tmp16_CH1; static u16 this_time_CH2 = 0; static u16 last_time_CH2 = 0; static u8 capture_number_CH2 = 0; vu16 tmp16_CH2; static u16 this_time_CH3 = 0; static u16 last_time_CH3 = 0; static u8 capture_number_CH3 = 0; vu16 tmp16_CH3; static u16 this_time_CH4 = 0; static u16 last_time_CH4 = 0; static u8 capture_number_CH4 = 0; vu16 tmp16_CH4; if(TIM_GetITStatus(TIM4, TIM_IT_CC1) == SET) { TIM_ClearITPendingBit(TIM4, TIM_IT_CC1); if(capture_number_CH1 == 0) { capture_number_CH1 = 1; last_time_CH1 = TIM_GetCapture1(TIM4); } else if(capture_number_CH1 == 1) { capture_number_CH1 = 0; this_time_CH1 = TIM_GetCapture1(TIM4); if(this_time_CH1 》 last_time_CH1) { tmp16_CH1 = (this_time_CH1 - last_time_CH1); } else { tmp16_CH1 = ((0xFFFF - last_time_CH1) + this_time_CH1); } //TIM2 counter clock = 1MHz // FreqBuf[cnt] = (1000000L * 100) / tmp16; //*100为扩大显示量程 Freq_Value[0]=tmp16_CH1; } } if(TIM_GetITStatus(TIM4, TIM_IT_CC2) == SET) { TIM_ClearITPendingBit(TIM4, TIM_IT_CC2); if(capture_number_CH2 == 0) { capture_number_CH2 = 1; last_time_CH2 = TIM_GetCapture2(TIM4); } else if(capture_number_CH2 == 1) { capture_number_CH2 = 0; this_time_CH2 = TIM_GetCapture2(TIM4); if(this_time_CH2 》 last_time_CH2) { tmp16_CH2 = (this_time_CH2 - last_time_CH2); } else { tmp16_CH2 = ((0xFFFF - last_time_CH2) + this_time_CH2); } //TIM2 counter clock = 1MHz // FreqBuf[cnt] = (1000000L * 100) / tmp16; //*100为扩大显示量程 Freq_Value[1]=tmp16_CH2; } } if(TIM_GetITStatus(TIM4, TIM_IT_CC3) == SET) { TIM_ClearITPendingBit(TIM4, TIM_IT_CC3); if(capture_number_CH3 == 0) { capture_number_CH3 = 1; last_time_CH3 = TIM_GetCapture3(TIM4); } else if(capture_number_CH3 == 1) { capture_number_CH3 = 0; this_time_CH3 = TIM_GetCapture3(TIM4); if(this_time_CH3 》 last_time_CH3) { tmp16_CH3 = (this_time_CH3 - last_time_CH3); } else { tmp16_CH3 = ((0xFFFF - last_time_CH3) + this_time_CH3); } //TIM2 counter clock = 1MHz // FreqBuf[cnt] = (1000000L * 100) / tmp16; //*100为扩大显示量程 Freq_Value[2]=tmp16_CH3; } } if(TIM_GetITStatus(TIM4, TIM_IT_CC4) == SET) { TIM_ClearITPendingBit(TIM4, TIM_IT_CC4); if(capture_number_CH4 == 0) { capture_number_CH4 = 1; last_time_CH4 = TIM_GetCapture4(TIM4); } else if(capture_number_CH4 == 1) { capture_number_CH4 = 0; this_time_CH4 = TIM_GetCapture4(TIM4); if(this_time_CH4 》 last_time_CH4) { tmp16_CH4 = (this_time_CH4 - last_time_CH4); } else { tmp16_CH4 = ((0xFFFF - last_time_CH4) + this_time_CH4); } //TIM2 counter clock = 1MHz // FreqBuf[cnt] = (1000000L * 100) / tmp16; //*100为扩大显示量程 Freq_Value[3]=tmp16_CH4; } } // GPIO_WriteBit(GPIOC, GPIO_Pin_13, (BitAction)((1-GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13)))); } [color=rgb(51, 102, 153) !important]复制代码 中断内四部分代码完全一样,只分析其中一段 输入捕获的原理是,定时器正常计数运行,当外部脉冲到来时,将定时器计数值存起来,当下次脉冲到来时,求出这两次计数值差值,即为这两段脉冲的周期。 例如,定时器计数到10,外部脉冲到来,使用last_time_CH1存储10,下次脉冲到来,此时定时器计数值运行到110,使用this_time_CH1存储110,之后做差,tmp16_CH1存储差值100,由于定时器运行于100KHZ,10us计数值增加一次,所以脉冲周期为100*10=1000us=1ms,即为1KHZ。 当然,定时器会溢出重装,此时需要将差值补偿运算,tmp16_CH1 = ((0xFFFF - last_time_CH1) + this_time_CH1); 可测量的范围取决于定时器运行的频率,如果外部频率慢到当定时器整个计数一周后也没有触发两次,会发生溢出,此时计数值已不准确。所以定时器时钟配置取决于外部脉冲频率,应配置得当使得脉冲频率范围不致溢出。 由于每次外部脉冲都会触发中断,尤其是四通道时,所以使用中断方式会略微占用CPU资源,使用DMA可以解决这一问题。 得到脉冲周期后,即可通过运算获得外部频率,进而测速。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1800 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1629 浏览 1 评论
1096 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
735 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1684 浏览 2 评论
1944浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
744浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
578浏览 3评论
601浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
564浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-27 03:15 , Processed in 0.825496 second(s), Total 78, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (威廉希尔官方网站 图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号