第四节:STM32定时器(3.输入捕获:HC | 您所在的位置:网站首页 › 超声波测距精度最高多少 › 第四节:STM32定时器(3.输入捕获:HC |
关联:STM32超全笔记【秋招自用】【含PID小车、飞控等项目】
【引言】
首先,同样是在理论前,我们需要对定时器输入捕获和他的应用做一个简单的了解。 输入捕获,在我们前面定时器学习的基础上,就是由我们设定psc和arr两个数,检测定时器通道输入的信号。 这个信号可以是传感器发出的,比如这节的例程就是使用超声波模块测量距离。 【问】超声波模块测量距离的原理是什么? 超声波模块向前发送超声波,遇到障碍然后返回,这样一次来回的时间,就是超声波模块引脚高电平持续的时间。 所以:我们只需要通过定时器的输入捕获,捕获这个引脚的高电平并且计算出持续时间,就可以计算出距离。 公式:距离 = 高电平时间 * 声速 / 2 声速:0.0343 厘米/微秒 其他不同的传感器也是相似的原理,都用到了输入捕获,所以学好这一节是至关重要的。 【输入捕获】接下来就是比较枯燥的理论知识了。 来看看在通用定时器框图中的输入捕获原理吧: 就是左下角的部分: 接下来就是代码了: 【例程7】输入捕获:超声波测距实验超声波模块的原理已经在前面讲过了,我们要做的,就是配置定时器的输入捕获模式。 在中断处理函数中,计算出高电平的持续时间。 这里有一个要注意的点:在捕获过程中,定时器可能会发生溢出,而溢出会导致计数器的值从 0 开始重新计数。因此,捕获的持续时间不仅包括了捕获值之后的计数时间,还要加上捕获值之前溢出的计数时间。 这也会导致编程的难度加倍,这段代码的逻辑可能比较复杂,实现思想和串口那块相似。 【输入捕获结构体初始化】首先硬件连接: 传感器的Echo引脚 ----- PA1 ---- TIM2_CH2 【问】为什么echo引脚(PA2)设置上拉输入? 超声波模块没有连接到外部设备时,Echo引脚会保持在逻辑高电平状态,这有助于避免电磁干扰或其他因素导致的误操作。 TIM_TimeBaseStructure输入捕获结构体: 1.因为用到TIM2_CH2,所以设置为TIM_Channel_22.上升沿捕获3.CH2对应TI24.不分频、不滤波 【中断服务函数】(难点) u8 TIM2CH1_CAPTURE_STA=0; // 输入捕获状态 u16 TIM2CH1_CAPTURE_VAL; // 输入捕获值 void TIM2_IRQHandler(void) { if((TIM2CH1_CAPTURE_STA&0X80)==0)//还未成功捕获 { if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) { if(TIM2CH1_CAPTURE_STA&0X40)//已经捕获到高电平了 { if((TIM2CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了 { TIM2CH1_CAPTURE_STA|=0X80;//标记成功捕获了一次 TIM2CH1_CAPTURE_VAL=0XFFFF; }else TIM2CH1_CAPTURE_STA++; } } if (TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)//捕获1发生捕获事件 { if(TIM2CH1_CAPTURE_STA&0X40) //捕获到一个下降沿 { TIM2CH1_CAPTURE_STA|=0X80; //标记成功捕获 TIM2CH1_CAPTURE_VAL=TIM_GetCapture2(TIM2); TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Rising); //CC1P=0 设置为上升沿捕获 }else //还未开始,第一次捕获上升沿 { TIM2CH1_CAPTURE_STA=0; //清空 TIM2CH1_CAPTURE_VAL=0; TIM_SetCounter(TIM2,0); TIM2CH1_CAPTURE_STA|=0X40; //标记捕获到了上升沿 TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Falling); //CC1P=1 设置为下降沿捕获 } } } TIM_ClearITPendingBit(TIM2, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位 }TIM2CH1_CAPTURE_STA 这个8位无符号整型变量,用于跟踪输入捕获状态: 最高位(7):标记捕获是否成功,如果置1,表示已成功捕获到一次输入信号的上升沿或下降沿。 第七位(6):标记是否捕获到高电平(置1) 前六位用于计数(高电平到来前的时间)TIM2CH1_CAPTURE_VAL 首先我们明确一下前提: 每一个周期时间到了,就会进一次这个中断服务函数。捕获到高电平,也会进一次这个中断服务函数。然后我们的需求:是求出Echo引脚高电平持续的时间。 难点在于:在捕获过程中,定时器可能会发生溢出,而溢出会导致计数器的值从 0 开始重新计数。因此,捕获的持续时间不仅包括了捕获值之后的计数时间,还要加上捕获值之前溢出的计数时间。 所以每次进入中断服务函数之前, 判断一下:有没有捕获成功?(成功了会置1) 尚未成功捕获到信号边沿,继续等待捕获。 继续判断:是定时器更新事件,还是捕获事件? (定时器的计数器溢出并重新开始计数时,会触发更新事件)(定时器捕获到外部信号的边沿(上升沿或下降沿)时,会触发捕获事件)如果是更新事件:表示定时器溢出 如果成功捕获到高电平: 如果高电平持续时间和定时周期一样:标记成功捕获了一次,将捕获值设置为最大值 如果高电平持续时间小于定时周期:那就让捕获值持续计数 如果是捕获事件, 如果第一次捕获上升沿 类似初始化: 1.两个变量置0 2.定时器计数值为0 3.标记捕获到上升沿 4.【问】为什么设置下次捕获为下降沿? 我要测高电平的时间,第一次是上升沿下一次下降沿到来,就是计时结束的时间。 如果捕获到下降沿: 首先标记捕获成功,然后获取捕获值(因为相当于第二次捕获到下降沿),此时CCR寄存器的值就是高电平的时间(我们需要!),读出来即可,赋值给TIM2CH1_CAPTURE_VAL。然后标记下次捕获为上升沿(相当于重新开始计时)。 【距离计算函数】 int SR04_Distance(void) { SR04 = 1; delay_us(13); SR04 = 0; if(TIM2CH1_CAPTURE_STA&0X80)//成功捕获到了一次上升沿 { time=TIM2CH1_CAPTURE_STA&0X3F; time*=65536;//溢出时间总和 time+=TIM2CH1_CAPTURE_VAL;//得到总的高电平时间 Distance = time*0.033/2; TIM2CH1_CAPTURE_STA=0;//开启下一次捕获 } return Distance; }如果捕获成功,读取sta此时的值,然后再加上val计算的时间得到总的高电平时间。 然后进行换算得到距离。同时把sta清0。 代码中,当捕获到上升沿时,会记录捕获值并设置下一次捕获为下降沿; 当捕获到下降沿时,会记录捕获值并设置下一次捕获为上升沿。 |
CopyRight 2018-2019 实验室设备网 版权所有 |