转载于 http://blog.csdn.net/u010661782/article/details/50301729,大侠的原创几篇的STM32转载过来集*后来者学习。
实验目的:
在串口调试助手上打印出按键按下的时间
实验步骤:
实验程序:
[cpp] view plain copy- /*******************************timer.c********************************/
- #include "sys.h"
- #include "stm32f4xx.h"
- extern u8 TIM5CHA1_CAPTURE_STA;
- extern u16 TIM5CHA1_CAPTURE_VAL;
- /*
- 本示例的作用就是,
- 当按键按下时,每次输入捕获的时间差,
- 然后从串口调试助手中打印出其时间差;
- */
- /*
- 关于输入捕获的操作可参考寄存器版的步骤
- */
- /*
- 定时器输入捕获的初始化函数:
- 主要是关于寄存器的相关配置
- */
- /*初始化定时器5为输入捕获*/
- void TIM5_Init(void){
- /*************************
- 定时器输入捕获的设置:
- *************************/
- /*将按键KEY_UP复用*/
- /*1.使能GPIO端口时钟*/
- RCC->AHB1ENR |= 1;
- /*这里还需要将其配置成下拉,
- 因为在输入捕获中,将通过上升沿来触发;
- */
- GPIOA->PUPDR |= 0X2;
- /*2.使能复用外设时钟*/
- RCC->APB1ENR |= 1<<3;
- /*3.端口模式配置为复用功能*/
- GPIOA->MODER |= 0X2;
- /*4.配置GPIOx_AFRL或者GPIOx_AFRH寄存器,
- 将IO连接到所需的复用外设*/
- GPIOA->AFR[0] |= 0X2;
- /*设置定时器5的输入捕获*/
- //设置TIM5的分频和自动重装
- TIM5->PSC = 84-1;
- TIM5->ARR = 0XFFFF-1; //芯片手册上写着是16位,
- //设置滤波/映射/分频
- TIM5->CCMR1 |= 0X1;
- //设置上升沿触发并使能捕获
- TIM5->CCER |= 0X1;
- //使能更新中断和使能捕获中断
- TIM5->DIER |= 0X3;
- //使能计数器
- TIM5->CR1 |= 1;
- //设置中断优先级
- SCB->AIRCR |= 0x5 << 8; //设置分组
- NVIC->IP[50] |= 0; //设置优先级,具体可分析MY_NVIC_Init()函数;
- //只要涉及中断,最后一定记得使能中断;
- //若不使能,则中断不会发生
- NVIC->ISER[1] |= 1<<18; //使能中断;
- }
- /*每次在按键按下时,输入捕获按键,
- 然后每产生两次中断,就在在中断里边
- 算出两次捕获之间的时间差;
- */
- void TIM5_IRQHandler(void){
- /*
- 中断处理函数:
- */
- if((TIM5CHA1_CAPTURE_STA & 0x80) != 0x80){ //说明一次完整的输入捕获还没有结束;
- if((TIM5->SR & 0X1) == 0X1){ //说明是溢出标志发生
- if((TIM5CHA1_CAPTURE_STA & 0x40) == 0x40){ //只有捕获到高电平之后,
- //我们才累计计数计数器的值
- if((TIM5CHA1_CAPTURE_STA & 0x3f)==0x3f){ //说明能累计的计数器已满;
- //在这里,高电平持续的时间最多为4s
- TIM5CHA1_CAPTURE_STA |= 0x80;
- TIM5CHA1_CAPTURE_VAL = 0xffff;
- }else{
- TIM5CHA1_CAPTURE_STA++;
- }
- }
- }
- if((TIM5->SR & 0X2) == 0X2){ //说明上升沿或下降沿已捕获
- if((TIM5CHA1_CAPTURE_STA & 0x40) == 0x40){ //说明下降沿已触发
- TIM5CHA1_CAPTURE_STA |= 0x80 ; //说明上升沿和下降沿一个周期的捕获已完成 ;
- TIM5CHA1_CAPTURE_VAL = TIM5->CCR1;//保存发生下降沿触发时计数器的值;
- //设置上升沿触发并使能捕获
- TIM5->CCER &= ~(1<<1);
- }else{ //说明上升沿已捕获
- //禁止定时器5的计数器
- TIM5->CR1 &= ~(1);
- //让计数器的值为0,以便计算从0到下一次下降沿捕获的值之间的计算;
- TIM5->CNT = 0;
- //设置输入捕获为下降沿触发
- TIM5->CCER &= ~(0XF);
- TIM5->CCER |= 0X3;
- //初始化要计数的值;
- TIM5CHA1_CAPTURE_STA = 0;
- TIM5CHA1_CAPTURE_STA |= 0X40;
- TIM5CHA1_CAPTURE_VAL = 0;
- //使能计数器
- TIM5->CR1 |= 1;
- }
- }
- }
- /*
- 在中断里边最后记得清中断标志:
- */
- TIM5->SR &= ~(0x3);
- }
[cpp] view plain copy
- /*******************************timer.h*********************************/
- #ifndef _EXTI_H
- #define _EXTI_H
- void TIM5_Init(void);
- #endif
[cpp] view plain copy
- /*******************************test.c***********************************/
- #include "sys.h"
- #include "delay.h"
- #include "beep.h"
- #include "exti.h"
- #include "led.h"
- #include "uart.h"
- #include "usart.h"
- u8 TIM5CHA1_CAPTURE_STA;
- u32 TIM5CHA1_CAPTURE_VAL;
- int main(void){
- u8 i = 0;
- long long temp = 0; //这里的值比较大,所以选择long long
- Stm32_Clock_Init(336,8,2,7);//设置时钟,168Mhz
- delay_init(168); //初始化延时函数
- LED_Init();
- Beep_Init();
- TIM5_Init();
- UART_Init();
- while(1){
- PFout(9) = 0;
- delay_ms(500);
- PFout(9) = 1;
- delay_ms(500);
- if((TIM5CHA1_CAPTURE_STA & 0x80) == 0x80){ //若一个完整的捕获周期(上升沿和下降沿)
- i = TIM5CHA1_CAPTURE_STA & 0x3f;
- printf("TIM5:%d\r\n",i);
- //计算累计的时间(高电平到低电平的之间的时间差)
- temp = (TIM5CHA1_CAPTURE_STA & 0x3f)*0xffff;
- temp += TIM5CHA1_CAPTURE_VAL;
- printf("temp:%lld us\r\n",temp); //思考printf()函数是如何做的;
- //重新初始化
- TIM5CHA1_CAPTURE_STA = 0;
- TIM5CHA1_CAPTURE_VAL = 0;
- }
- }
- }
实验分析:
1.定时器的框图及输入捕获框图的放大版
注:通过检测TIMx_CHx上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,
将当前定时器的值(TIMx_CNT)存放到对应的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。
2.输入捕获的工作流程分析:
<1>
<2>
<3>
<4>
<5>
3.中断处理函数部分的提示
注意事项:
1.只要涉及到中断,在最后一定都要记得使能中断
2.按键那块,处理不是很好,有时会一连打出好几串数字;
更准确的说是按键有时会有些抖动,就相当于按了好几下,但没有滤掉波段较小的那一部分;