[] STM32 universal input capture timers (Example: input capture)

"STM32 Chinese Reference Manual V10" - Chapter 14 General Purpose Timer

 

Universal timer input capture Overview

Input capture works

In general block diagram of the timer, mainly related to a portion of the topmost ( the count of the selected clock ), an intermediate portion ( time base unit ), the lower left portion ( input capture ) the three sections. Here mainly explain the lower left portion (input capture), two other portions may refer to the article: [] STM32 basic principles of general-purpose timers (example: timer interrupt) .

Input capture mode may be used to measure the pulse width or the measurement frequency. STM32 timer, in addition to TIM6, TIM7, the other has a timer input capture function. Below an example of a simple pulse input, simply we talk about capture the input for pulse width measurement principle:

First set input capture detect rising edges, the rising edge of the recording TIMx_CNT value occurs. Then configure the capture edge capture signal, the time when the falling edge of capture occurs, and the recorded value at that time TIMx_CNT. Thus, the difference between the values ​​before and after the two TIMx_CNT pulse width is high. At the same time according to the count frequency TIM, we can know the exact time high pulse width.

Channel input capture overview

Each capture / compare channels are surrounded by a capture / compare registers (shadow registers comprising a), an input section comprising capturing (digital filtering, multiplexing and prescaler), and an output section (output of the comparator and control ).

Capture / compare module consists of a preload register and a shadow register. Only during read and write operations preload register.

  • In capture mode, capture occurs in the shadow registers, and then copied to the preload register. 
  • In the comparison mode, the contents of the preload register is copied into the shadow registers, then the contents of the shadow register is compared to the counter.

TIx corresponding to the input portion of the input signal samples, and generates a signal after a TIxF filtered. Then, with a selected edge polarity detector generates a signal (TIxFPx), it can serve as a trigger input from the mode controller or as capture control. The signal enters the prescaler capture register (ICxPS).

Stating working process: by detecting the edge signal TIMx_CHx channel transition occurs (for example, rising / falling) edge signal in time, the current value of the timer (as TIMx_CNT) stored in the corresponding capture / compare register ( TIMx_CCRx) inside, to complete a capture. At the same time, also whether to trigger an interrupt / DMA, etc. When configuring capture.

 

Enter the working process of capture

FIG captured input channel is decomposed, broken down into four parts, four of these portions is analyzed to understand the following working process of the input capture:

Setting input capture filters

Input Capture Filter IC1F [3: 0], is used to set the sampling frequency and the digital filter length . Wherein: fCK_INT the timer is the input frequency, fDTS according TIMx_CR1 of CKD: determined in [10] is provided.

The role of the filter here is what does that mean? The digital filter by an event counter, it will produce an output to the recording of the N events hopping. That N consecutive samples, if are high, then this is a valid trigger, will enter the input capture interrupt (if set of words). This will filter out that high level pulse of the pulse signal is less than 8 sample periods, so as to achieve filtering.

Set input capture polarity

Here it is to set the capture event occurred in rising or falling .

Set the input capture mapping relationship

Since we show only one channel of the channel of FIG case if several passages:

In the case of two channels TIMx_CH1 and TIMx_CH2, we can see that in addition to the captured signal TIMx_CH1 can be connected to IC1, TIMx_CH2 captured signal may be connected to the outside of IC2, TIMx_CH1 captured signal may also be connected to the IC2, TIMx_CH2 the captured signals may also be connected to IC1.

In general, we arranged TIMx_CH1 captured signal may be connected to IC1, TIMx_CH2 captured signal may be connected to the IC2.

Set the input capture divider

Here is the set every N events trigger a capture . In other words, we can set, every two rising edge event trigger a capture.

 

Related input capture register

Capture / Compare mode register 1 (TIMx_CCMR1)

Action: in input acquisition mode to determine the digital filter, channel mapping, prescalers .

Capture / Compare Enable Register (TIMx_CCER)

Action: in input acquisition mode to determine the capture and capture enable polarity .

Capture / compare register 1 (TIMx_CCR1)

Action: in the capture mode input, determines the transmission input capture event last count value.

 

Input capture configuration library functions

  • An initialization function input
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
  
  

Action: initializing acquisition channels, filters, capturing a polar, mapping relationship, the division ratio parameters.

Note: Since the output initialization function to separate the function of all four channels each defining a function, input initialization function did not. Therefore, the input initialization function, you need to specify the capture channel.

  • A parameter acquisition function

  
  
  1. uint16_t TIM_GetCapture1(TIM_TypeDef* TIMx);
  2. uint16_t TIM_GetCapture2(TIM_TypeDef* TIMx);
  3. uint16_t TIM_GetCapture3(TIM_TypeDef* TIMx);
  4. uint16_t TIM_GetCapture4(TIM_TypeDef* TIMx);

Action: select one of the four channels, determines the last transmission input capture event count value .

  • A parameter setting function

  
  
  1. void TIM_OC1PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
  2. void TIM_OC2PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
  3. void TIM_OC3PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
  4. void TIM_OC4PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);

作用:在四个通道中选择一个,设置通道极性。通常在初始化函数中已经设置了通道极性,此函数用于除初始化之外的修改。

 

输入捕获的一般步骤

实例要求:使用TIM5的通道1(PA0)来作为输入捕获,捕获PA0上高电平的脉宽(用WK_UP按键输入高电平),通过串口打印高电平脉冲时间。

  • 初始化定时器和通道对应IO的时钟;
  • 初始化IO口,模式为输入。调用函数:GPIO_Init();
  • 初始化定时器ARR,PSC。调用函数:TIM_TimeBaseInit();
  • 初始化输入捕获通道。调用函数:TIM_ICInit();
  • 如果要开启捕获中断。调用函数:TIM_ITConfig();NVIC_Init();
  • 使能定时器。调用函数:TIM_Cmd();
  • 编写中断服务函数。调用函数:TIMx_IRQHandler()。

下面按照这个一般步骤来进行一个简单的输入捕获程序:


  
  
  1. //定时器5通道1输入捕获配置
  2. TIM_ICInitTypeDef TIM5_ICInitStructure;
  3. void TIM5_Cap_Init(u16 arr,u16 psc)
  4. {
  5. GPIO_InitTypeDef GPIO_InitStructure;
  6. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  7. NVIC_InitTypeDef NVIC_InitStructure;
  8. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); //使能TIM5时钟
  9. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA时钟
  10. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PA0 清除之前设置
  11. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0 输入
  12. GPIO_Init(GPIOA, &GPIO_InitStructure);
  13. GPIO_ResetBits(GPIOA,GPIO_Pin_0); //PA0 下拉
  14. //初始化定时器5 TIM5
  15. TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值
  16. TIM_TimeBaseStructure.TIM_Prescaler =psc; //预分频器
  17. TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
  18. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
  19. TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
  20. //初始化TIM5输入捕获参数
  21. TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 选择输入端 IC1映射到TI1上
  22. TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
  23. TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
  24. TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
  25. TIM5_ICInitStructure.TIM_ICFilter = 0x00; //IC1F=0000 配置输入滤波器 不滤波
  26. TIM_ICInit(TIM5, &TIM5_ICInitStructure);
  27. //中断分组初始化
  28. NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; //TIM3中断
  29. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级2级
  30. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从优先级0级
  31. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
  32. NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
  33. TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE); //允许更新中断 ,允许CC1IE捕获中断
  34. TIM_Cmd(TIM5,ENABLE ); //使能定时器5
  35. }
  36. u8 TIM5CH1_CAPTURE_STA= 0; //输入捕获状态
  37. u16 TIM5CH1_CAPTURE_VAL; //输入捕获值
  38. //定时器5中断服务程序
  39. void TIM5_IRQHandler( void)
  40. {
  41. if((TIM5CH1_CAPTURE_STA& 0X80)== 0) //还未成功捕获
  42. {
  43. if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)
  44. {
  45. if(TIM5CH1_CAPTURE_STA& 0X40) //已经捕获到高电平了
  46. {
  47. if((TIM5CH1_CAPTURE_STA& 0X3F)== 0X3F) //高电平太长了
  48. {
  49. TIM5CH1_CAPTURE_STA|= 0X80; //标记成功捕获了一次
  50. TIM5CH1_CAPTURE_VAL= 0XFFFF;
  51. } else TIM5CH1_CAPTURE_STA++;
  52. }
  53. }
  54. if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET) //捕获1发生捕获事件
  55. {
  56. if(TIM5CH1_CAPTURE_STA& 0X40) //捕获到一个下降沿
  57. {
  58. TIM5CH1_CAPTURE_STA|= 0X80; //标记成功捕获到一次高电平脉宽
  59. TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);
  60. TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //CC1P=0 设置为上升沿捕获
  61. } else //还未开始,第一次捕获上升沿
  62. {
  63. TIM5CH1_CAPTURE_STA= 0; //清空
  64. TIM5CH1_CAPTURE_VAL= 0;
  65. TIM_SetCounter(TIM5, 0);
  66. TIM5CH1_CAPTURE_STA|= 0X40; //标记捕获到了上升沿
  67. TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); //CC1P=1 设置为下降沿捕获
  68. }
  69. }
  70. }
  71. TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位
  72. }

  
  
  1. extern u8 TIM5CH1_CAPTURE_STA; //输入捕获状态
  2. extern u16 TIM5CH1_CAPTURE_VAL; //输入捕获值
  3. int main( void)
  4. {
  5. u32 temp= 0;
  6. delay_init(); //延时函数初始化
  7. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
  8. uart_init( 115200); //串口初始化为115200
  9. TIM5_Cap_Init( 0XFFFF, 72 -1); //以1Mhz的频率计数
  10. while( 1)
  11. {
  12. delay_ms( 10);
  13. if(TIM5CH1_CAPTURE_STA& 0X80) //成功捕获到了一次上升沿
  14. {
  15. temp=TIM5CH1_CAPTURE_STA& 0X3F;
  16. temp*= 65536; //溢出时间总和
  17. temp+=TIM5CH1_CAPTURE_VAL; //得到总的高电平时间
  18. printf( "HIGH:%d us\r\n",temp); //打印总的高点平时间
  19. TIM5CH1_CAPTURE_STA= 0; //开启下一次捕获
  20. }
  21. }
  22. }

代码逻辑

这里关于输入捕获的初始化部分比较简单,对照着一般步骤来就行了。但是在中断处理函数TIM5_IRQHandler()部分就有所难度了,为什么会比较复杂呢?

由于我们进行输入捕获,一旦捕捉到了上升沿,就设置计数器当前值为0,让它从0开始重新计数:

	 		TIM_SetCounter(TIM5,0);
  
  

但是如果脉冲的长度过于宽了,也就是说,从0开始计数到自动重加载值一个循环结束了,脉冲还是没有结束。这个情况下,显而易见不能只记录一下最后的计数器当前值。

解决这个问题的办法:

设置一个变量TIM5CH1_CAPTURE_STA,bit5-0为捕捉高电平后定时器溢出的次数,bit6为捕捉到高电平标志,bit7为捕获完场标志。

同时设置两个中断(更新中断和捕获中断)

	TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新中断 ,允许CC1IE捕获中断	
  
  

在中断处理函数中,先判断是否捕获成功,如果捕获成功了,说明是在脉冲低电平的阶段,什么都不需要做;如果捕获没有成功,说明是在脉冲高电平的阶段,就需要继续判断中断类型,然后再分别进行处理。在更新中断中,表示此时脉冲长度过长,TIM5CH1_CAPTURE_STA加1。在捕获中断中,判断捕捉到的是否为上升沿,如果是,计数器当前值清零,TIM5CH1_CAPTURE_STA清零,同时标记标志,设置极性下降沿捕捉;如果不是,标记捕获完成,保存当前计数器的值,设置极性上升沿捕获。

extern关键字

C语言中,extern可以置于变量或者函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇到此类变量和函数时在其他模块中寻找其定义。

注意:对于extern申明变量可以多次,但是定义只有一次。

Guess you like

Origin blog.csdn.net/wu694128/article/details/90316010