我是靠谱客的博主 合适洋葱,这篇文章主要介绍输入捕获笔记一、输入捕获介绍二、输入捕获配置步骤三、代码举例,现在分享给大家,希望可以做个参考。

一、输入捕获介绍

 在定时器中断实验章节中我们介绍了通用定时器具有多种功能,输入捕获就是其中一种。STM32F1 除了基本定时器 TIM6 和 TIM7,其他定时器都具有输入捕获功能。输入捕获可以对输入的信号的上升沿,下降沿或者双边沿进行捕获,通常用于测量输入信号的脉宽、测量 PWM 输入信号的频率及占空比。

  输入捕获的工作原理比较简单,在输入捕获模式下,当相应的 ICx 信号检测到跳变沿后,将使用捕获/比较寄存器(TIMx_CCRx)来锁存计数器的值。简单的说就是通过检测 TIMx_CHx 上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存(TIMx_CCRx)里面,完成一次捕获。同时还可以配置捕获时是否触发中断/DMA 等。下面我们以输入捕获测量脉宽为例,通过一个简图来介绍输入捕获的工作原理,如图 所示:

  从上图可以看出,t1-t2 时间就是我们需要测量的高电平时间,假如定时器工作在向上计数模式,测量方法是:首先设置定时器通道 x 为上升沿捕获,这样在 t1 时刻,就会捕获到当前的 CNT 值,然后立即清零 CNT,并设置通道 x 为下降沿捕获,这样到 t2 时刻,又会发生捕获事件,得到此时的 CNT 值,记为 CCRx2。根据定时器的计数频率,我们就可以算出 t1-t2 的时间,从而得到高电平脉宽。在 t1-t2 时间内可能会出现 N 次定时器溢出,因此我们还需要对定时器溢出进行处理,防止因高电平时间过长发生溢出导致测量数据不准。CNT计数的次数等于:N*ARR+CCRx2,有了这个计数次数,再乘以 CNT 的计数周期,即可得到 t2-t1 的时间长度,即高电平持续时间。

二、输入捕获配置步骤

(1)使能定时器及端口时钟,并设置引脚复用器映射和引脚模式等

   RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

   GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD;

(2)初始化定时器参数,包含自动重装值,分频系数,计数方式等

  TIM_TimeBaseInit(TIM_TypeDef*TIMx,TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

(3)设置通用定时器的输入捕获参数,开启输入捕获功能

  TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);

(4)开启捕获和定时器溢出(更新)中断

  TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState)

(5)设置定时器中断优先级,使能定时器中断通道 NVIC初始化库函数是

  NVIC_Init()

(6)使能定时器

  TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);

(7)编写定时器中断服务函数

  void TIM5_IRQHandle()

三、代码举例

所要实现的功能是:按键不按下的时候是低电平(GPIO中配置了下拉输入模式)使用TIM2的CH1检测按键按下的高电平时间, 将检测的高电平脉宽时间通过OLED显示屏显示出来。(使用最小系统stm32f103开发板)

(下面是正点原子的思路,熟悉寄存器操作的话很好看懂,毕竟我学过51单片机,但是我没用这种寄存器的思路去编写)

(原子开发板资料)

bit7位置1时表示成功捕获完一次高电平(按键按下直到抬起整个过程结束);代码58、66、79

bit6位置1时表示获得高电平的标志位,(表示按键已经按下)代码62、77、87

bit0~5位表示高电平时间是定时器溢出的次数(即在按键按下时定时器溢出几次)

如果溢出次数超过了6位所能表示的范围时怎么办?

  代码64—68解决办法

就是在TIM5_CH1_CAPTURE_STA==0x3f 时将 TIM5_CH1_CAPTURE_STA变量强制bit7置1(即强制捕获完成去执行主函数代码27以后的代码段,然后重新进行下一次的捕获)   TIM5_CH1_CAPTURE_STA|=0x80;

(下面是我自己写的代码)

 1.定时器2的输入捕获通道1配置

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
void Timer2_Capture1_Init(void){     GPIO_InitTypeDef GPIO_InitStructure;     TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;     TIM_ICInitTypeDef TIM_ICInitStructure;     NVIC_InitTypeDef NVIC_InitStructure;          RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);     TIM_InternalClockConfig(TIM2);          GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD;     GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;     GPIO_Init(GPIOA,&GPIO_InitStructure);     GPIO_ResetBits(GPIOA,GPIO_Pin_0);          TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;     TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;     TIM_TimeBaseInitStructure.TIM_Period=65535;     TIM_TimeBaseInitStructure.TIM_Prescaler=7200-1;     TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;     TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);          TIM_ICInitStructure.TIM_Channel=TIM_Channel_1;     TIM_ICInitStructure.TIM_ICFilter=0;     TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;     TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;     TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;     TIM_ICInit(TIM2,&TIM_ICInitStructure);          NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);     NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;     NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;     NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;     NVIC_Init(&NVIC_InitStructure);          TIM_ITConfig(TIM2,TIM_IT_Update|TIM_IT_CC1,ENABLE);          TIM_Cmd(TIM2,ENABLE); }

2.OLED用的是江科大的模板,OLED的SCL---GPIOB8,SDA---GPIOB9,这里不展示了

3.中断函数,能够解决尽管按键按下的时间很长也能计算高电平持续的时间

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void TIM2_IRQHandler(void){     //如果捕获到了一个上升沿,清除标志位,清空CNT,准备捕获下降沿     if(TIM_GetITStatus(TIM2,TIM_IT_CC1)==SET&&Falling_Flag==0){             Capture1_Count=0;                 TIM_ClearITPendingBit(TIM2,TIM_IT_CC1);         TIM_SetCounter(TIM2,0);         Falling_Flag=1;         TIM_OC1PolarityConfig(TIM2,TIM_OCPolarity_Low);     }     //如果已经捕获了一次上升沿,还没捕获过下降沿的期间出现了定时器溢出的情况时     if(TIM_GetITStatus(TIM2,TIM_IT_CC1)==RESET&&Falling_Flag==1){         if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET){             Spill_Count++;                 }     }     //如果捕获到了一个下降沿,清空标志位,保存计数值并进行计算(包含定时器溢出的情况),清空CNT,准备捕获上升沿     if(TIM_GetITStatus(TIM2,TIM_IT_CC1)==SET&&Falling_Flag==1){             Capture1_Count=(TIM_GetCapture1(TIM2)+Spill_Count*65535)/10;//得到最终的计数值(原本记一个数是0.1ms,现在把单位转换为1ms)         Spill_Count=0;         TIM_SetCounter(TIM2,0);         Falling_Flag=0;             TIM_OC1PolarityConfig(TIM2,TIM_OCPolarity_High);                 }         OLED_ShowNum(4,12,Spill_Count,2);     OLED_ShowNum(3,1,Capture1_Count/1000,4);     OLED_ShowNum(3,6,Capture1_Count%100,2);     TIM_ClearITPendingBit(TIM2,TIM_IT_Update|TIM_IT_CC1); }

4.定时器这个模板函数的变量声明和文件包含

复制代码
1
2
3
4
5
#include "stm32f10x.h"                  // Device header #include "OLED.h" static uint8_t Falling_Flag;//0表示这次捕获是上升沿,1表示这次捕获是下降沿 static uint8_t Spill_Count;//定时器溢出的次数 static uint32_t Capture1_Count;//两个边沿之间的计数值

5.主函数

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "stm32f10x.h"                  // Device header #include "OLED.h" #include "Timer.h" //默认OLED的SCL---GPIOB的GPIO_Pin_8,SDA---GPIOB的GPIO_Pin_9 int main(){     Timer2_Capture1_Init();     OLED_Init();     OLED_ShowString(1,1,"Timer_Capture!");     OLED_ShowString(2,1,"KeyPressTime:");     OLED_ShowString(3,1,"    .  s");     OLED_ShowString(4,1,"SpillCount:  ");     while(1){     } }

最后

以上就是合适洋葱最近收集整理的关于输入捕获笔记一、输入捕获介绍二、输入捕获配置步骤三、代码举例的全部内容,更多相关输入捕获笔记一、输入捕获介绍二、输入捕获配置步骤三、代码举例内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(54)

评论列表共有 0 条评论

立即
投稿
返回
顶部