正点原子的输入捕获程序是利用TIM5的单通道实现的,通过先捕获上升沿,清除计数器值,再更改捕获极性为下降沿,第二次进中断时读出高电平脉宽。一次捕获过程完成,下面解释程序中的问题和疑惑。
extern u8 TIM5CH1_CAPTURE_STA; //输入捕获状态
extern u16 TIM5CH1_CAPTURE_VAL; //输入捕获值
int main(void)
{
u32 temp=0;
delay_init(); //延时函数初始化
NVIC_Configuration(); //中断优先级配置
uart_init(9600); //波特率为9600
LED_Init(); //LED初始化
TIM3_PWM_Init(899,0); //PWM频率=72000/(899+1)=80Khz
TIM5_Cap_Init(0XFFFF,72-1); //以1Mhz频率计数
while(1)
{
delay_ms(10);
TIM_SetCompare2(TIM3,TIM_GetCapture2(TIM3)+1);//设置占空比,300是900的1/3,高电平最大持续时间是4.16us
if(TIM_GetCapture2(TIM3)==300)
{
TIM_SetCompare2(TIM3,0);
}
if(TIM5CH1_CAPTURE_STA&0X80)//成功捕获了一次上升沿
{
temp=TIM5CH1_CAPTURE_STA&0X3F;//统计溢出次数
temp*=65536;//溢出时间总和
temp+=TIM5CH1_CAPTURE_VAL;//得到总的高电平时间
printf("HIGH:%d us\r\n",temp);//打印高电平时间
TIM5CH1_CAPTURE_STA=0;//开启下一次捕获
}
}
程序中省略了相关定时器的配置,相关配置参考正点原子的输入捕获程序。下面重点对信号进行捕获的定时器5的中断服务程序进行解读
u8 TIM5CH1_CAPTURE_STA=0; //输入捕获状态
u16 TIM5CH1_CAPTURE_VAL; //输入捕获值
- 捕获状态TIM5CH1_CAPTURE_STA这个寄存器是作者自己定义的一个,stm32中无硬件对应,无相应硬件置位复位。这个寄存器大家可以把它当做两个标志位flag1+flag2+一个存次数的数length。
flag1(or2)=1有一次成功捕获过程完成或已经捕获到高电平。
flag1(or2)=0未有一次成功捕获过程完成或未捕获到高电平。 - 捕获状态TIM5CH1_CAPTURE_STA各位功能
//[7]: 0,没有成功捕获,1,已经成功捕获一次
//[6]: 0,还没有捕获到高电平,1,已经捕获到高电平了
//[5:0]: 捕获高电平后溢出的次数
//定时器5的中断服务程序
void TIM5_IRQHandler(void)
{
//1.程序进更新中断的原因是,TIM5只有65536/1M=0.06s的时长,按占空比50%计算,不溢出能计算1/0.12=8.33Hz以上的频率脉宽,8hz以下的要有更新中断。
//2.程序初始化后,第一次进中断是进捕获中断,而且是进入else语句,将极性改为下降沿且STA=0x40;计数溢出后才会进更新中断,执行if((TIM5CH1_CAPTURE_STA&0X80)==0)语句,最后进入if(TIM5CH1_CAPTURE_STA&0X40)语句里。
//3.在if(TIM5CH1_CAPTURE_STA&0X40)语句里,如果溢出次数未达到3F,STA++继续,达到3F,高电平时间太长超出计数范围,默认捕获一次高电平,VAL=0xffff计数输出。
//4.退出更新中断进主函数中,与下面步骤3相同。
//
if((TIM5CH1_CAPTURE_STA&0X80)==0)//还未成功捕获
{
if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)
{
if(TIM5CH1_CAPTURE_STA&0X40)//已经捕获到高电平了
{
if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了
{
TIM5CH1_CAPTURE_STA|=0X80;//标记成功捕获了一次
TIM5CH1_CAPTURE_VAL=0XFFFF;
}else
{
TIM5CH1_CAPTURE_STA++;
}
}
}
//1.初始化后,程序第一次上升沿进捕获中断,第一次进中断,进else语句,将STA和VAL清零,清零CNT,标记捕获到了高电平(也就是上升沿,因为初始化是上升沿被捕获嘛),将极性改为下降沿捕获,退出中断后,在主函数中由于if(TIM5CH1_CAPTURE_STA&0x80)语句不成立,所以不进if中,STA状态保持。
//2.下降沿到来时,进中断里的if(TIM5CH1_CAPTURE_STA&0x40)语句,是高电平再进if语句里,STA=1,成功捕获一次高电平信号,将数据给VAL,将极性改为上升沿捕获。
//3.退出中断进主函数后,如果一次捕获成功,有溢出就计算溢出次数再加上VAL的值就是高电平时间,打印输出。并将STA清零,保证在下一个上升沿进捕获中断后,程序又进入else语句,不进入if(TIM5CH1_CAPTURE_STA&0x40)语句中,因为STA在主函数中被清零了。然后循环上述步骤,一个周期产生一次捕获,得到高电平时间。
if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET)//捕获1发生捕获事件
{
if(TIM5CH1_CAPTURE_STA&0X40) //捕获到一个下降沿
{
TIM5CH1_CAPTURE_STA|=0X80; //标记成功捕获到一次上升沿
TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //CC1P=0 设置为上升沿捕获
}else //还未开始,第一次捕获上升沿
{
TIM5CH1_CAPTURE_STA=0; //清空
TIM5CH1_CAPTURE_VAL=0;
TIM_SetCounter(TIM5,0);
TIM5CH1_CAPTURE_STA|=0X40; //标记捕获到了上升沿
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); //CC1P=1 设置为下降沿捕获
}
}
}
TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位
整个程序就是这样,一个通道完成后,可以开始写四路通道同时捕获高电平的程序了,用一个定时器就可以完成,还是比较简单的。