STM32CubeMX学习笔记7 - 输入捕获
输入捕获模式可以用来测量脉冲宽度或者测量频率,下图以测量脉宽为例来说明输入捕获的原理假定定时器工作在向上计数模式,图中t1-t2的时间就是我们需要测量的低电平时间。测量方法为:首先设置定时器通道x为下降沿捕获,在t1时刻就会捕获到当前的CNT值,然后立即清零CNT,并设置通道x为上升沿捕获,到t2时刻又会发送捕获事件,得到此时的CNT值(记为CCRx2)。在t1-t2之间可能产生N次定时器溢出,因
1. 输入捕获简介
输入捕获模式可以用来测量脉冲宽度或者测量频率,下图以测量脉宽为例来说明输入捕获的原理
假定定时器工作在向上计数模式,图中t1-t2的时间就是我们需要测量的低电平时间。测量方法为:首先设置定时器通道x为下降沿捕获,在t1时刻就会捕获到当前的CNT值,然后立即清零CNT,并设置通道x为上升沿捕获,到t2时刻又会发送捕获事件,得到此时的CNT值(记为CCRx2)。在t1-t2之间可能产生N次定时器溢出,因此需要对定时器溢出做处理,防止低电平太长导致数据不准确。 t1-t2之间计数的次数为:N * ARR + CCRx2,再乘以CNT计数周期即可得到低电平持续时间
2. 硬件设计
本实验通过TIM5的通道1输入捕获功能捕获S1按键的高电平持续时间,并通过printf函数打印捕获到的高电平时间,用LED灯提示系统正常运行
3、 STM32CubeMX设置
- RCC设置外接HSE,时钟设置为72M
- PE5设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平
- USART1选择为异步通讯方式,波特率设置为115200Bits/s,传输数据长度为8Bit,无奇偶校验,1位停止位
- 选择TIM5,定时器时钟源已经默认为内部时钟源、设置通道1为输入捕获模式(PA0自动被选中),预分频系数设置为72-1,向上计数,自动重装载值设为0x65535(最大值),则计时器时钟频率为1MHz,计时器周期为1us,定时器溢出周期为 65535 * 1 = 65535us。CH1选择上升沿触发,默认不分频,滤波8位。
NVIC设置中激活定时器中断。
在GPIO设置里将PA0下拉,保证没有信号输入的时候电平稳定。
输入工程名,选择工程路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码
4、程序编译
由于定时器最大的重装载值是65535,溢出一次约65ms,考虑到按下按键的时间过长,因此添加定时器溢出中断,用来计算计数器溢出的次数。
/* TIM5CH1_CAP_STA 各数据位说明
** bit7 捕获完成标志
** bit6 捕获到高电平标志
** bit5~0 捕获高电平后定时器溢出的次数*/
uint8_t TIM5CH1_CAP_STA = 0;
uint16_t TIM5CH1_CAP_VAL;
//定时器溢出回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
if((TIM5CH1_CAP_STA & 0X80) == 0){ //还未成功捕获
if(TIM5CH1_CAP_STA & 0X40){ //已经捕获到高电平
if((TIM5CH1_CAP_STA & 0X3F) == 0X3F)
{ //高电平时间太长了
TIM5CH1_CAP_STA |= 0X80; //标记为完成一次捕获
TIM5CH1_CAP_VAL = 0XFFFF; //计数器值
}
else
TIM5CH1_CAP_STA++; //溢出次数加1
}
}
}
添加输入捕获中断回调函数
//输入捕获中断回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){
if((TIM5CH1_CAP_STA & 0X80) == 0){ //还未成功捕获
if(TIM5CH1_CAP_STA & 0X40){ //捕获到上升沿后条件为真
TIM5CH1_CAP_STA |= 0X80; //标记为完成一次高电平捕获
TIM5CH1_CAP_VAL = HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_1); //获取当前的计数器值
TIM_RESET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1); //清除原来的设置
TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING); //设置上升沿捕获
}
else{
TIM5CH1_CAP_STA = 0;
TIM5CH1_CAP_VAL = 0;
TIM5CH1_CAP_STA |= 0X40; //标记捕获到上升沿
__HAL_TIM_DISABLE(&htim5); //关闭定时器
__HAL_TIM_SET_COUNTER(&htim5,0); //计数器值清零
TIM_RESET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1); //清除原来的设置
TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING); //设置下降沿捕获
__HAL_TIM_ENABLE(&htim5); //使能定时器
}
}
}
程序流程:
初始化时设置为上升沿触发,当按下按键时触发输入捕获中断,程序进入输入捕获中断回调函数,将TIM5CH1_CAP_STA设置为0X40,定时器计数器清零并重新计数,同时将触发模式改成下降沿触发,然后等待按键松开。
在等待按键松开的过程中,按键长按超过65ms,计数器溢出触发定时器中断,在定时器中断中将TIM5CH1_CAP_STA的值加1,标志一次溢出。如果时间过长导致(TIM5CH1_CAP_STA & 0X3F)>= 0X3F,这时强制完成输入捕获,
按键松开时,触发下降沿输入捕获中断,进入回调函数将TIM5CH1_CAP_STA的最高位设置为1,标志完成一次输入捕获,并将此时的计数器的值给到TIM5CH1_CAP_VAL,同时将触发模式重新改回上升沿触发。
当完成输入捕获时,在main函数中计算TIM5CH1_CAP_STA的溢出次数*65535 再加上结束时的计数器值,即可计算出输入捕获高电平的总时间。
//注意:在更改触发模式前要先清除原来的设置!!!
extern uint8_t TIM5CH1_CAP_STA ;
extern uint16_t TIM5CH1_CAP_VAL;
int main(void)
{
//***省略***//
long long temp = 0;
HAL_TIM_IC_Start_IT(&htim5,TIM_CHANNEL_1); //一定要开启TIM5通道1的捕获中断
__HAL_TIM_ENABLE_IT(&htim5,TIM_IT_UPDATE); //一定要开启TIM5的更新中断
while (1)
{
HAL_Delay(50);
if(TIM5CH1_CAP_STA & 0X80){ //完成一次高电平捕获
temp = TIM5CH1_CAP_STA & 0X3F;
temp *= 65536; //溢出总时间
temp += TIM5CH1_CAP_VAL; //总的高电平时间
printf1("High level duration:%lld us\r\n",temp);
TIM5CH1_CAP_STA = 0; //准备下一次捕获
}
HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_5);
}
}
5、下载验证
将程序编译无误后下载到板子上,打开串口助手,按下按键,即可看到按下按键的时间了。
6、参考文献
【STM32】HAL库 STM32CubeMX教程八---定时器输入捕获_hal_tim_readcapturedvalue-CSDN博客
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)