完全照搬正点原子的实验:http://openedv.com/posts/list/11885.htm
我使用的库函数
下面我们介绍输入捕获的配置步骤:
1)开启TIM5时钟,配置PA0为下拉输入。
要使用TIM5,我们必须先开启TIM5的时钟(通过APB1ENR设置)。这里我们还要配置PA0为下拉输入,因为我们要捕获TIM5_CH1上面的高电平脉宽,而TIM5_CH1是连接在PA0上面的。
2)设置TIM5的ARR和PSC。
在开启了TIM5的时钟之后,我们要设置ARR和PSC两个寄存器的值来设置输入捕获的自动重装载值和计数频率。
3)设置TIM5的CCMR1
TIM5_CCMR1寄存器控制着输入捕获1和2的模式,包括映射关系,滤波和分频等。这里我们需要设置通道1为输入模式,且IC1映射到TI1(通道1)上面,并且不使用滤波(提高响应速度)器。
4)设置TIM5的CCER,开启输入捕获,并设置为上升沿捕获。
TIM5_CCER寄存器是定时器的开关,并且可以设置输入捕获的边沿。只有TIM5_CCER寄存器使能了输入捕获,我们的外部信号,才能被TIM5捕获到,否则一切白搭。同时要设置好捕获边沿,才能得到正确的结果。
5)设置TIM5的DIER,使能捕获和更新中断,并编写中断服务函数
因为我们要捕获的是高电平信号的脉宽,所以,第一次捕获是上升沿,第二次捕获时下降沿,必须在捕获上升沿之后,设置捕获边沿为下降沿,同时,如果脉宽比较长,那么定时器就会溢出,对溢出必须做处理,否则结果就不准了。这两件事,我们都在中断里面做,所以必须开启捕获中断和更新中断。
设置了中断必须编写中断函数,否则可能导致死机。我们需要在中断函数里面完成数据处理和捕获设置等关键操作,从而实现高电平脉宽统计。
6)设置TIM5的CR1,使能定时器
最后,必须打开定时器的计数器开关,通过设置TIM5_CR1的最低位为1,启动TIM5的计数器,开始输入捕获。
通过以上6步设置,定时器5的通道1就可以开始输入捕获了,同时因为还用到了串口输出结果,所以还需要配置一下串口。
TIM5_IRQHandler是TIM5的中断服务函数,该函数用到了两个全局变量,用于辅助实现高电平捕获。其中TIM5CH1_CAPTURE_STA,是用来记录捕获状态,该变量类似我们在usart.c里面自行定义的USART_RX_STA寄存器。TIM5CH1_CAPTURE_STA各位描述如表15.3.1所示:
TIM5CH1_CAPTURE_STA |
||
bit7 |
bit6 |
bit5~0 |
捕获完成标志 |
捕获到高电平标志 |
捕获高电平后定时器溢出的次数 |
表15.3.1 TIM5CH1_CAPTURE_STA各位描述
另外一个变量TIM5CH1_CAPTURE_VAL,则用来记录捕获到下降沿的时候,TIM5_CNT的值。
现在我们来介绍一下,捕获高电平脉宽的思路:首先,设置TIM5_CH1捕获上升沿,这在TIM5_Cap_Init函数执行的时候就设置好了,然后等待上升沿中断到来,当捕获到上升沿中断,此时如果TIM5CH1_CAPTURE_STA的第6位为0,则表示还没有捕获到新的上升沿,就先把
TIM5CH1_CAPTURE_STA、TIM5CH1_CAPTURE_VAL和TIM5->CNT等清零,然后再设置TIM5CH1_CAPTURE_STA的第6位为1,标记捕获到高电平,最后设置为下降沿捕获,等待下降沿到来。如果等待下降沿到来期间,定时器发生了溢出,就在TIM5CH1_CAPTURE_STA里面对溢出次数进行计数,当最大溢出次数来到的时候,就强制标记捕获完成(虽然此时还没有捕获到下降沿)。当下降沿到来的时候,先设置TIM5CH1_CAPTURE_STA的第7位为1,标记成功捕获一次高电平,然后读取此时的定时器值到TIM5CH1_CAPTURE_VAL里面,最后设置为上升沿捕获,回到初始状态。
这样,我们就完成一次高电平捕获了,只要TIM5CH1_CAPTURE_STA的第7位一直为1,那么就不会进行第二次捕获,我们在main函数处理完捕获数据后,将TIM5CH1_CAPTURE_STA置零,就可以开启第二次捕获
下面看下main函数:
1 extern u8 TIM5CH1_CAPTURE_STA; //输入捕获状态 2 extern u16 TIM5CH1_CAPTURE_VAL; //输入捕获值 3 /** 4 * @brief Main program. 5 * @param None 6 * @retval None 7 */ 8 int main(void) 9 { 10 u32 temp=0; 11 //省略不少其他硬件配置代码 12 TIM5_Cap_Init(0XFFFF,72-1); //以1Mhz的频率计数 13 while(1) 14 { 15 if(TIM5CH1_CAPTURE_STA&0X80)//成功捕获到了一次上升沿 16 { 17 temp=TIM5CH1_CAPTURE_STA&0X3F; 18 temp*=65536;//溢出时间总和 19 temp+=TIM5CH1_CAPTURE_VAL;//得到总的高电平时间 20 printf("HIGH:%d us\r\n",temp);//打印总的高点平时间 21 TIM5CH1_CAPTURE_STA=0;//开启下一次捕获 22 } 23 24 25 } 26 }
实验OK
修改一下,在TIM5中断函数中直接输出捕获值,将main函数中代码屏蔽
1 u8 TIM5CH1_CAPTURE_STA=0; //输入捕获状态 2 u16 TIM5CH1_CAPTURE_VAL; //输入捕获值 3 void TIM5_IRQHandler(void) 4 { u32 temp=0; 5 if((TIM5CH1_CAPTURE_STA&0X80)==0)//还未成功捕获 6 { 7 if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET) 8 9 { 10 if(TIM5CH1_CAPTURE_STA&0X40)//已经捕获到高电平了 11 { 12 if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了 13 { 14 TIM5CH1_CAPTURE_STA|=0X80;//标记成功捕获了一次 15 TIM5CH1_CAPTURE_VAL=0XFFFF; 16 17 temp=TIM5CH1_CAPTURE_STA&0X3F; 18 temp*=65536;//溢出时间总和 19 temp+=TIM5CH1_CAPTURE_VAL;//得到总的高电平时间 20 printf("HIGH:%d us\r\n",temp);//打印总的高点平时间 21 TIM5CH1_CAPTURE_STA=0;//开启下一次捕获 22 }else TIM5CH1_CAPTURE_STA++; 23 } 24 } 25 if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET)//捕获1发生捕获事件 26 { 27 if(TIM5CH1_CAPTURE_STA&0X40) //捕获到一个下降沿 28 { 29 TIM5CH1_CAPTURE_STA|=0X80; //标记成功捕获到一次上升沿,finish 30 TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5); 31 TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //CC1P=0 设置为上升沿捕获 32 33 temp=TIM5CH1_CAPTURE_STA&0X3F; 34 temp*=65536;//溢出时间总和 35 temp+=TIM5CH1_CAPTURE_VAL;//得到总的高电平时间 36 printf("HIGH:%d us\r\n",temp);//打印总的高点平时间 37 TIM5CH1_CAPTURE_STA=0;//开启下一次捕获 38 }else //还未开始,第一次捕获上升沿 ,CNT,VAL开始 count 39 { 40 TIM5CH1_CAPTURE_STA=0; //清空 41 TIM5CH1_CAPTURE_VAL=0; 42 TIM_SetCounter(TIM5,0); 43 TIM5CH1_CAPTURE_STA|=0X40; //标记捕获到了上升沿 44 TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); //CC1P=1 设置为下降沿捕获 45 } 46 } 47 } 48 49 TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位 50 51 }