任务:输入捕获 脉冲测距。
STM32 的定时器,除了 TIM6 和 TIM7,其他定时器都有输入捕获功能。
STM32定时器检测是否有信号,若有信号(上升沿),则定时器开始计时,直至检测到下降沿计时结束。这期间的脉宽长度*定时器的检测频率(定时器初始化时配置好的)即为实际的时长。 实际的时长*声速=距离
TIM_TimeBaseStructure.TIM_Period=65536-1; 定时器计数达到65535后溢出
TIM_TimeBaseStructure.TIM_Prescaler=7200-1; 预分频值,实际检测频率为72000 000/7200=10 000Hz,周期为100us。 每100us+1。
定时器触发一次的时间为:(7200/72000 000)*65536
定时器中断函数:
void TIM2_IRQHandler(void)
{
if((TIM2CH1_CAPTURE_STA&0X80)==0)//未捕获 1000 0000
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update) != RESET)
{
if(TIM2CH1_CAPTURE_STA&0X40)//已经捕获到高电平 0100 0000
{
if((TIM2CH1_CAPTURE_STA&0X3F)==0X3F)//溢出处理 0011 1111
{
TIM2CH1_CAPTURE_STA|=0X80;//标记成功捕获一次 1000 0000
TIM2CH1_CAPTURE_VAL=0XFFFF;
}else TIM2CH1_CAPTURE_STA++;
}
}
if(TIM_GetITStatus(TIM2,TIM_IT_CC1) !=RESET) //捕获到上升沿中断
{
if(TIM2CH1_CAPTURE_STA & 0x40) //捕获到一个下降沿 0100 0000
{
TIM2CH1_CAPTURE_STA|=0X80; //标记成功捕获到一次上升沿 1000 0000
TIM2CH1_CAPTURE_VAL = TIM_GetCounter(TIM2);
TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Rising); //CC1P=0 设置上升沿捕获
}
else
{ //还没有捕获到新的上升沿
TIM2CH1_CAPTURE_STA=0; //清空
TIM2CH1_CAPTURE_VAL=0;
TIM_SetCounter(TIM2,0);
TIM2CH1_CAPTURE_STA|=0X40; //标记捕获到了上升沿 0100 0000
TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Falling); //CC1P=1 设置为下降沿捕获
}
}
}
TIM_ClearITPendingBit(TIM2,TIM_IT_CC1|TIM_IT_Update); /*清除中断标志位*/
}
捕获基本思路:
首先设置两个变量Capture_State和Capture_Value。 其中 Capture_State,是用来记录捕获状态,该变量类似一个寄存器(其实就是个变量,只是我们把它当成一个寄存器那样来使用)。 另外一个变量 Capture_Value,则用来记录捕获到下降沿的时候,TIM2_CNT的值。现在我们来介绍一下,捕获高电平脉宽的思路:首先,设置 TIM2_CH1 捕获上升沿(这在TIM2的初始化函数执行的时候就设置好了),然后等待上升沿中捕获断到来,当捕获到上升沿中断,此时如果 Capture_State的第 6 位为 0,则表示还没有捕获到新的上升沿,就先把 Capture_State、Capture_Value和 TIM2->CNT 等清零,然后再设置 Capture_State的第 6 位为 1,标记捕获到高电平,最后设置为下降沿捕获,等待下降沿到来。如果等待下降沿到来期间,定时器发生了溢出,就在Capture_State里面对溢出次数进行计数,当最大溢出次数来到的时候,就强制标记 捕获完成 (虽然此时还没有捕获到下降沿 )。 当下降沿到来的时候,先设置Capture_State的第 7 位为 1,标记成功捕获一次高电平,然后读取此时的定时器的捕获值到 Capture_Value里面,最后设置为上升沿捕获,回到初始状态。 这样,我们就完成一次高电平捕获了,只要 Capture_State的第 7 位一直为 1,那么就不会进行第二次捕获,我们在main函数处理完捕获数据后,将Capture_State置零,就可以开启第二次捕获。
主函数:
主要的宗旨就是: TIM2 的计数频率(根据TIM_Prescaler计算得来 每一次计数的时长)*高电平脉宽(计数个数)= 准确高电平持续时间。
while(1)
{
if(TIM2CH1_CAPTURE_STA&0X80)//成功捕获一次上升沿
{
temp=TIM2CH1_CAPTURE_STA&0X3F;
temp*=65536;/溢出时间总和 //对应和TIM_Period一致 TIM是16位的 最大即为65536
temp+=TIM2CH1_CAPTURE_VAL;//总计数总和
if(temp>1000) //省去一些干扰信号
{
printf("电平持续时间:%d us ",temp*100);//us
printf("%d ms ",temp/10);//ms
printf("%d s ",temp/10000);//s
printf("\r\n距离: 1500 m/s * %d ms= %dm\r\n",temp/10,temp*15/100);//s
printf("\r\n");//空行
}
TIM2CH1_CAPTURE_STA=0;/开启下一次捕获
}
}
(错误思路:通过TIM_Period和TIM_Prescaler把TIM时间算出来,乘以统计的数据temp)和代码中temp*=65536重复。
另外注意TIM2_IRQn对应的PA0引脚,工作模式为下拉输入。
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;