STM32学习笔记之定时器输入捕获实验

时间:2022-06-19 02:54:44

转载于 http://blog.csdn.net/u010661782/article/details/50301729,大侠的原创几篇的STM32转载过来集*后来者学习。


实验目的:

在串口调试助手上打印出按键按下的时间


实验步骤:

STM32学习笔记之定时器输入捕获实验

STM32学习笔记之定时器输入捕获实验



实验程序:

[cpp] view plain copy
  1. /*******************************timer.c********************************/  
  2. #include "sys.h"  
  3. #include "stm32f4xx.h"  
  4.   
  5.   
  6. extern u8 TIM5CHA1_CAPTURE_STA;  
  7. extern u16  TIM5CHA1_CAPTURE_VAL;  
  8.   
  9.   
  10. /* 
  11. 本示例的作用就是, 
  12. 当按键按下时,每次输入捕获的时间差, 
  13. 然后从串口调试助手中打印出其时间差; 
  14. */  
  15.   
  16.   
  17. /* 
  18. 关于输入捕获的操作可参考寄存器版的步骤 
  19. */  
  20.   
  21.   
  22. /* 
  23. 定时器输入捕获的初始化函数: 
  24. 主要是关于寄存器的相关配置 
  25. */  
  26.   
  27.   
  28. /*初始化定时器5为输入捕获*/  
  29. void TIM5_Init(void){  
  30.       
  31.     /************************* 
  32.     定时器输入捕获的设置:  
  33.     *************************/  
  34.       
  35.     /*将按键KEY_UP复用*/  
  36.     /*1.使能GPIO端口时钟*/  
  37.     RCC->AHB1ENR |= 1;  
  38.     /*这里还需要将其配置成下拉, 
  39.     因为在输入捕获中,将通过上升沿来触发; 
  40.     */  
  41.     GPIOA->PUPDR |= 0X2;  
  42.       
  43.     /*2.使能复用外设时钟*/  
  44.     RCC->APB1ENR |= 1<<3;  
  45.       
  46.     /*3.端口模式配置为复用功能*/  
  47.     GPIOA->MODER |= 0X2;  
  48.       
  49.     /*4.配置GPIOx_AFRL或者GPIOx_AFRH寄存器, 
  50.     将IO连接到所需的复用外设*/  
  51.     GPIOA->AFR[0] |= 0X2;  
  52.       
  53.       
  54.       
  55.     /*设置定时器5的输入捕获*/  
  56.       
  57.     //设置TIM5的分频和自动重装  
  58.     TIM5->PSC = 84-1;  
  59.     TIM5->ARR = 0XFFFF-1;   //芯片手册上写着是16位,  
  60.                               
  61.     //设置滤波/映射/分频  
  62.     TIM5->CCMR1 |= 0X1;  
  63.       
  64.       
  65.     //设置上升沿触发并使能捕获  
  66.     TIM5->CCER |= 0X1;  
  67.       
  68.     //使能更新中断和使能捕获中断  
  69.     TIM5->DIER |= 0X3;  
  70.       
  71.     //使能计数器  
  72.     TIM5->CR1 |= 1;  
  73.       
  74.       
  75.     //设置中断优先级  
  76.     SCB->AIRCR |= 0x5 << 8; //设置分组  
  77.     NVIC->IP[50] |= 0; //设置优先级,具体可分析MY_NVIC_Init()函数;  
  78.       
  79.     //只要涉及中断,最后一定记得使能中断;  
  80.     //若不使能,则中断不会发生  
  81.     NVIC->ISER[1] |= 1<<18;  //使能中断;  
  82.       
  83. }  
  84.   
  85.   
  86.   
  87. /*每次在按键按下时,输入捕获按键, 
  88. 然后每产生两次中断,就在在中断里边 
  89. 算出两次捕获之间的时间差; 
  90. */  
  91. void TIM5_IRQHandler(void){  
  92.       
  93.     /* 
  94.     中断处理函数: 
  95.     */  
  96.       
  97.       
  98.     if((TIM5CHA1_CAPTURE_STA & 0x80) != 0x80){  //说明一次完整的输入捕获还没有结束;  
  99.           
  100.           
  101.           
  102.         if((TIM5->SR & 0X1) == 0X1){  //说明是溢出标志发生  
  103.               
  104.               
  105.             if((TIM5CHA1_CAPTURE_STA & 0x40) == 0x40){  //只有捕获到高电平之后,  
  106.                                                         //我们才累计计数计数器的值  
  107.                 if((TIM5CHA1_CAPTURE_STA & 0x3f)==0x3f){  //说明能累计的计数器已满;  
  108.                                                         //在这里,高电平持续的时间最多为4s  
  109.                     TIM5CHA1_CAPTURE_STA |= 0x80;  
  110.                     TIM5CHA1_CAPTURE_VAL = 0xffff;  
  111.                       
  112.                       
  113.                 }else{  
  114.                   
  115.                     TIM5CHA1_CAPTURE_STA++;  
  116.                 }  
  117.                   
  118.                   
  119.             }  
  120.               
  121.         }  
  122.         if((TIM5->SR & 0X2) == 0X2){  //说明上升沿或下降沿已捕获  
  123.               
  124.               
  125.             if((TIM5CHA1_CAPTURE_STA & 0x40) == 0x40){   //说明下降沿已触发  
  126.                   
  127.                 TIM5CHA1_CAPTURE_STA |= 0x80 ; //说明上升沿和下降沿一个周期的捕获已完成 ;  
  128.                 TIM5CHA1_CAPTURE_VAL = TIM5->CCR1;//保存发生下降沿触发时计数器的值;  
  129.           
  130.                 //设置上升沿触发并使能捕获  
  131.                 TIM5->CCER &= ~(1<<1);  
  132.                   
  133.             }else{     //说明上升沿已捕获  
  134.                   
  135.                 //禁止定时器5的计数器  
  136.                 TIM5->CR1 &= ~(1);  
  137.                   
  138.                 //让计数器的值为0,以便计算从0到下一次下降沿捕获的值之间的计算;  
  139.                 TIM5->CNT = 0;  
  140.                   
  141.                 //设置输入捕获为下降沿触发  
  142.                 TIM5->CCER &= ~(0XF);  
  143.                 TIM5->CCER |= 0X3;  
  144.                   
  145.                 //初始化要计数的值;  
  146.                 TIM5CHA1_CAPTURE_STA = 0;  
  147.                 TIM5CHA1_CAPTURE_STA |= 0X40;  
  148.                 TIM5CHA1_CAPTURE_VAL = 0;  
  149.                   
  150.                 //使能计数器  
  151.                 TIM5->CR1 |= 1;  
  152.               
  153.             }  
  154.               
  155.         }  
  156.           
  157.     }  
  158.       
  159.     /* 
  160.     在中断里边最后记得清中断标志: 
  161.     */  
  162.     TIM5->SR &= ~(0x3);  
  163. }   


[cpp] view plain copy
  1. /*******************************timer.h*********************************/  
  2. #ifndef _EXTI_H  
  3. #define _EXTI_H  
  4.   
  5.   
  6. void TIM5_Init(void);  
  7.   
  8.   
  9. #endif  


[cpp] view plain copy
  1. /*******************************test.c***********************************/  
  2. #include "sys.h"  
  3. #include "delay.h"  
  4. #include "beep.h"  
  5. #include "exti.h"  
  6. #include "led.h"  
  7. #include "uart.h"  
  8. #include "usart.h"  
  9.   
  10.   
  11.   
  12. u8 TIM5CHA1_CAPTURE_STA;  
  13. u32  TIM5CHA1_CAPTURE_VAL;  
  14.   
  15.   
  16. int main(void){  
  17.       
  18.     u8 i = 0;  
  19.     long long  temp = 0;  //这里的值比较大,所以选择long long  
  20.       
  21.     Stm32_Clock_Init(336,8,2,7);//设置时钟,168Mhz    
  22.     delay_init(168);        //初始化延时函数  
  23.     LED_Init();  
  24.     Beep_Init();  
  25.     TIM5_Init();  
  26.     UART_Init();  
  27.       
  28.       
  29.     while(1){  
  30.           
  31.         PFout(9) = 0;  
  32.         delay_ms(500);  
  33.         PFout(9) = 1;  
  34.         delay_ms(500);  
  35.           
  36.         if((TIM5CHA1_CAPTURE_STA & 0x80) == 0x80){  //若一个完整的捕获周期(上升沿和下降沿)  
  37.   
  38.   
  39.             i = TIM5CHA1_CAPTURE_STA & 0x3f;  
  40.             printf("TIM5:%d\r\n",i);  
  41.             //计算累计的时间(高电平到低电平的之间的时间差)    
  42.             temp = (TIM5CHA1_CAPTURE_STA & 0x3f)*0xffff;  
  43.             temp += TIM5CHA1_CAPTURE_VAL;  
  44.   
  45.               
  46.             printf("temp:%lld us\r\n",temp);  //思考printf()函数是如何做的;  
  47.                   
  48.                 //重新初始化  
  49.                 TIM5CHA1_CAPTURE_STA = 0;  
  50.                 TIM5CHA1_CAPTURE_VAL = 0;  
  51.   
  52.         }  
  53.               
  54.     }  
  55. }  



实验分析:

1.定时器的框图及输入捕获框图的放大版

STM32学习笔记之定时器输入捕获实验

STM32学习笔记之定时器输入捕获实验

注:通过检测TIMx_CHx上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,

将当前定时器的值(TIMx_CNT)存放到对应的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。


2.输入捕获的工作流程分析:

<1>

STM32学习笔记之定时器输入捕获实验

<2>

STM32学习笔记之定时器输入捕获实验

<3>

STM32学习笔记之定时器输入捕获实验

<4>

STM32学习笔记之定时器输入捕获实验

<5>

STM32学习笔记之定时器输入捕获实验


3.中断处理函数部分的提示

STM32学习笔记之定时器输入捕获实验


注意事项:

1.只要涉及到中断,在最后一定都要记得使能中断

2.按键那块,处理不是很好,有时会一连打出好几串数字;

更准确的说是按键有时会有些抖动,就相当于按了好几下,但没有滤掉波段较小的那一部分;