STM32学习笔记——单定时器四通道输入捕获

以下笔记始发于观海听涛,原创人Apache,转载请说明
输入捕获作为定时器的一个功能,在工业测速上有很大的应用。STM32的一些定时器具有四个外部通道,可利用一个定时器采集外部四路脉冲频率,节约硬件资源和软件代码
如需要测量一个或多个外部方波脉冲频率,频率低于单片机运行频率,可如下操作:(以TIM4为例)
初始化:(省略GPIO配置,将TIM4的四个通道引脚配置为上拉或浮空输入,省略定时器RCC配置,省略中断NVIC配置)

  1. void TIM_Configuration(void)
  2. {
  3.     
  4. TIM_ICInitTypeDef  
  5. TIM_ICInitStructure;
  6. TIM_TimeBaseInitTypeDef  
  7. TIM_TimeBaseStructure; // TIM4 时基 
  8.     
  9. TIM_DeInit(TIM4); 
  10.     TIM_TimeBaseStructure.TIM_Period = 
  11. 0xffff;                                  
  12. //自动重装值 
  13.     TIM_TimeBaseStructure.TIM_Prescaler = 
  14. 719;                                   
  15. //预分频值, 使TIMx_CLK=1MHz 
  16.     
  17. TIM_TimeBaseStructure.TIM_ClockDivision = 
  18. TIM_CKD_DIV1;                     
  19. //输入时钟不分频 
  20.     TIM_TimeBaseStructure.TIM_CounterMode = 
  21. TIM_CounterMode_Up;                 
  22. //向上计数 
  23.     TIM_TimeBaseInit(TIM4, 
  24. &TIM_TimeBaseStructure);
  25.                              
  26. //TIM4_TimeBase 
  27. //  TIM_ICInitStructure.TIM_ICMode = 
  28. TIM_ICMode_ICAP;                             
  29. //输入捕捉方式
  30.   TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;//| 
  31. TIM_Channel_2;        //输入通道
  32.   
  33. TIM_ICInitStructure.TIM_ICPolarity = 
  34. TIM_ICPolarity_Rising;     //捕捉上升沿
  35.   
  36. TIM_ICInitStructure.TIM_ICSelection = 
  37. TIM_ICSelection_DirectTI;    //捕捉中断
  38.   
  39. TIM_ICInitStructure.TIM_ICPrescaler = 
  40. TIM_ICPSC_DIV1;       //捕捉不分频
  41.   
  42. TIM_ICInitStructure.TIM_ICFilter = 
  43. 0x0;          //捕捉输入不滤波
  44.   TIM_ICInit(TIM4, &TIM_ICInitStructure);
  45.   TIM_ICInitStructure.TIM_Channel = TIM_Channel_2 ;//| 
  46. TIM_Channel_2;        //输入通道
  47.   
  48. TIM_ICInitStructure.TIM_ICPolarity = 
  49. TIM_ICPolarity_Rising;     //捕捉上升沿
  50.   
  51. TIM_ICInitStructure.TIM_ICSelection = 
  52. TIM_ICSelection_DirectTI;    //捕捉中断
  53.   
  54. TIM_ICInitStructure.TIM_ICPrescaler = 
  55. TIM_ICPSC_DIV1;       //捕捉不分频
  56.   
  57. TIM_ICInitStructure.TIM_ICFilter = 
  58. 0x0;          //捕捉输入不滤波
  59.   TIM_ICInit(TIM4, &TIM_ICInitStructure);
  60.   TIM_ICInitStructure.TIM_Channel = TIM_Channel_3 ;//| 
  61. TIM_Channel_2;        //输入通道
  62.   
  63. TIM_ICInitStructure.TIM_ICPolarity = 
  64. TIM_ICPolarity_Rising;     //捕捉上升沿
  65.   
  66. TIM_ICInitStructure.TIM_ICSelection = 
  67. TIM_ICSelection_DirectTI;    //捕捉中断
  68.   
  69. TIM_ICInitStructure.TIM_ICPrescaler = 
  70. TIM_ICPSC_DIV1;       //捕捉不分频
  71.   
  72. TIM_ICInitStructure.TIM_ICFilter = 
  73. 0x0;          //捕捉输入不滤波
  74.   TIM_ICInit(TIM4, &TIM_ICInitStructure);
  75.   TIM_ICInitStructure.TIM_Channel = TIM_Channel_4 ;//| 
  76. TIM_Channel_2;        //输入通道
  77.   
  78. TIM_ICInitStructure.TIM_ICPolarity = 
  79. TIM_ICPolarity_Rising;     //捕捉上升沿
  80.   
  81. TIM_ICInitStructure.TIM_ICSelection = 
  82. TIM_ICSelection_DirectTI;    //捕捉中断
  83.   
  84. TIM_ICInitStructure.TIM_ICPrescaler = 
  85. TIM_ICPSC_DIV1;       //捕捉不分频
  86.   
  87. TIM_ICInitStructure.TIM_ICFilter = 
  88. 0x0;          //捕捉输入不滤波
  89.   TIM_ICInit(TIM4, &TIM_ICInitStructure);
  90.   /* TIM enable counter */
  91.   TIM_Cmd(TIM4, ENABLE);
  92.   /* Enable the CC2 Interrupt Request */
  93.   TIM_ITConfig(TIM4, 
  94. TIM_IT_CC1, ENABLE);
  95.   TIM_ITConfig(TIM4, TIM_IT_CC2, ENABLE);
  96.   
  97. TIM_ITConfig(TIM4, TIM_IT_CC3, ENABLE);
  98.   TIM_ITConfig(TIM4, TIM_IT_CC4, 
  99. ENABLE);
  100. }
复制代码


其中:
TIM_TimeBaseStructure.TIM_Period = 0xffff;为自动重装值,与普通单片机一样
TIM_TimeBaseStructure.TIM_Prescaler = 719; 预分频值, 使TIMx_CLK=100KHz ,系统时钟运行于72M时720分频,定时器运行于100KHZ,即10us每分度
TIM_ICInitStructure.TIM_ICMode = TIM_ICMode_ICAP; 此句选择定时器为输入捕获模式,但在我的库函数下未定义,所以注释掉,未影响程序执行
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;配置通道1
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;上升沿捕获
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;捕获中断
TIM_ICInitStructure.TIM_ICFilter = 0x0;不滤波
TIM_ICInit(TIM4, &TIM_ICInitStructure);将配置应用
以上每个通道都需要将整个配置再写一遍,使用与'|'是无效的。
TIM_Cmd(TIM4, ENABLE);使能定时器4
  TIM_ITConfig(TIM4, TIM_IT_CC1, ENABLE);
  TIM_ITConfig(TIM4, TIM_IT_CC2, ENABLE);
  TIM_ITConfig(TIM4, TIM_IT_CC3, ENABLE);
  TIM_ITConfig(TIM4, TIM_IT_CC4, ENABLE);打开四个通道的捕获中断
以上将TIM配置完成,下面是中断内代码:

  1. void 
  2. TIM4_IRQHandler(void)
  3. {
  4.                                              
  5. //频率缓冲区计数 
  6. static u16 this_time_CH1 = 0; 
  7. static u16 
  8. last_time_CH1 = 0; 
  9. static u8 capture_number_CH1 = 0;
  10. vu16 
  11. tmp16_CH1;
  12. static u16 this_time_CH2 = 0; 
  13. static u16 last_time_CH2 = 0; 
  14. static u8 capture_number_CH2 = 0;
  15. vu16 tmp16_CH2;
  16. static u16 this_time_CH3 = 0; 
  17. static u16 last_time_CH3 = 0; 
  18. static u8 capture_number_CH3 = 0;
  19. vu16 tmp16_CH3;
  20. static u16 this_time_CH4 = 0; 
  21. static u16 last_time_CH4 = 0; 
  22. static u8 capture_number_CH4 = 0;
  23. vu16 tmp16_CH4;
  24.   if(TIM_GetITStatus(TIM4, TIM_IT_CC1) == SET) 
  25.     { 
  26.         
  27. TIM_ClearITPendingBit(TIM4, TIM_IT_CC1); 
  28.         if(capture_number_CH1 == 0) 
  29.         { 
  30.             
  31. capture_number_CH1 = 1; 
  32.             
  33. last_time_CH1 = TIM_GetCapture1(TIM4); 
  34.         } 
  35.         else if(capture_number_CH1 == 1) 
  36.         { 
  37.             
  38. capture_number_CH1 = 0; 
  39.             
  40. this_time_CH1 = TIM_GetCapture1(TIM4); 
  41.             
  42. if(this_time_CH1 > last_time_CH1) 
  43.             { 
  44.                 
  45. tmp16_CH1 = (this_time_CH1 - last_time_CH1); 
  46.             } 
  47.             else 
  48.             { 
  49.                 
  50. tmp16_CH1 = ((0xFFFF - last_time_CH1) + this_time_CH1); 
  51.             } 
  52.             //TIM2 
  53. counter clock = 1MHz 
  54. //            
  55. FreqBuf[cnt] = (1000000L * 100) / 
  56. tmp16;                  
  57. //*100为扩大显示量程 
  58.    Freq_Value[0]=tmp16_CH1; 
  59.         } 
  60.   }
  61.     if(TIM_GetITStatus(TIM4, TIM_IT_CC2) == SET) 
  62.     { 
  63.         
  64. TIM_ClearITPendingBit(TIM4, TIM_IT_CC2); 
  65.         if(capture_number_CH2 == 0) 
  66.         { 
  67.             
  68. capture_number_CH2 = 1; 
  69.             
  70. last_time_CH2 = TIM_GetCapture2(TIM4); 
  71.         } 
  72.         else if(capture_number_CH2 == 1) 
  73.         { 
  74.             
  75. capture_number_CH2 = 0; 
  76.             
  77. this_time_CH2 = TIM_GetCapture2(TIM4); 
  78.             
  79. if(this_time_CH2 > last_time_CH2) 
  80.             { 
  81.                 
  82. tmp16_CH2 = (this_time_CH2 - last_time_CH2); 
  83.             } 
  84.             else 
  85.             { 
  86.                 
  87. tmp16_CH2 = ((0xFFFF - last_time_CH2) + this_time_CH2); 
  88.             } 
  89.             //TIM2 
  90. counter clock = 1MHz 
  91. //            
  92. FreqBuf[cnt] = (1000000L * 100) / 
  93. tmp16;                  
  94. //*100为扩大显示量程 
  95.    Freq_Value[1]=tmp16_CH2; 
  96.         
  97. }
  98. }
  99. if(TIM_GetITStatus(TIM4, TIM_IT_CC3) == SET) 
  100.     { 
  101.         
  102. TIM_ClearITPendingBit(TIM4, TIM_IT_CC3); 
  103.         if(capture_number_CH3 == 0) 
  104.         { 
  105.             
  106. capture_number_CH3 = 1; 
  107.             
  108. last_time_CH3 = TIM_GetCapture3(TIM4); 
  109.         } 
  110.         else if(capture_number_CH3 == 1) 
  111.         { 
  112.             
  113. capture_number_CH3 = 0; 
  114.             
  115. this_time_CH3 = TIM_GetCapture3(TIM4); 
  116.             
  117. if(this_time_CH3 > last_time_CH3) 
  118.             { 
  119.                 
  120. tmp16_CH3 = (this_time_CH3 - last_time_CH3); 
  121.             } 
  122.             else 
  123.             { 
  124.                 
  125. tmp16_CH3 = ((0xFFFF - last_time_CH3) + this_time_CH3); 
  126.             } 
  127.             //TIM2 
  128. counter clock = 1MHz 
  129. //            
  130. FreqBuf[cnt] = (1000000L * 100) / 
  131. tmp16;                  
  132. //*100为扩大显示量程 
  133.    Freq_Value[2]=tmp16_CH3; 
  134.         }
  135. if(TIM_GetITStatus(TIM4, TIM_IT_CC4) == SET) 
  136.     { 
  137.         
  138. TIM_ClearITPendingBit(TIM4, TIM_IT_CC4); 
  139.         if(capture_number_CH4 == 0) 
  140.         { 
  141.             
  142. capture_number_CH4 = 1; 
  143.             
  144. last_time_CH4 = TIM_GetCapture4(TIM4); 
  145.         } 
  146.         else if(capture_number_CH4 == 1) 
  147.         { 
  148.             
  149. capture_number_CH4 = 0; 
  150.             
  151. this_time_CH4 = TIM_GetCapture4(TIM4); 
  152.             
  153. if(this_time_CH4 > last_time_CH4) 
  154.             { 
  155.                 
  156. tmp16_CH4 = (this_time_CH4 - last_time_CH4); 
  157.             } 
  158.             else 
  159.             { 
  160.                 
  161. tmp16_CH4 = ((0xFFFF - last_time_CH4) + this_time_CH4); 
  162.             } 
  163.             //TIM2 
  164. counter clock = 1MHz 
  165. //            
  166. FreqBuf[cnt] = (1000000L * 100) / 
  167. tmp16;                  
  168. //*100为扩大显示量程 
  169.    Freq_Value[3]=tmp16_CH4; 
  170.         }
  171. //  
  172. GPIO_WriteBit(GPIOC, GPIO_Pin_13, 
  173. (BitAction)((1-GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13))));
  174. }
复制代码


中断内四部分代码完全一样,只分析其中一段
输入捕获的原理是,定时器正常计数运行,当外部脉冲到来时,将定时器计数值存起来,当下次脉冲到来时,求出这两次计数值差值,即为这两段脉冲的周期。
例如,定时器计数到10,外部脉冲到来,使用last_time_CH1存储10,下次脉冲到来,此时定时器计数值运行到110,使用this_time_CH1存储110,之后做差,tmp16_CH1存储差值100,由于定时器运行于100KHZ,10us计数值增加一次,所以脉冲周期为100*10=1000us=1ms,即为1KHZ。
当然,定时器会溢出重装,此时需要将差值补偿运算,tmp16_CH1 = ((0xFFFF - last_time_CH1) + this_time_CH1);
可测量的范围取决于定时器运行的频率,如果外部频率慢到当定时器整个计数一周后也没有触发两次,会发生溢出,此时计数值已不准确。所以定时器时钟配置取决于外部脉冲频率,应配置得当使得脉冲频率范围不致溢出。
由于每次外部脉冲都会触发中断,尤其是四通道时,所以使用中断方式会略微占用CPU资源,使用DMA可以解决这一问题。
得到脉冲周期后,即可通过运算获得外部频率,进而测速。
哈工大电子设计联盟 观海听涛 HRT车队

posted @ 2017-04-05 14:52  -Robot-  阅读(1764)  评论(0)    收藏  举报