小工具知识网

当前位置: 首页 > 行业知识 > 嵌入式学习笔记——PWM与输入捕获(下)

行业知识

嵌入式学习笔记——PWM与输入捕获(下)

2026-10-31 21:43:14 来源:互联网转载

输入捕获

  • 前言
    • 输入捕获的概述
    • 框图
      • 输入通道部分
      • 比较捕获寄存器与事件生成
      • 寄存器
      • 编程思路
      • 实际需求
        • 配置流程
          • 打开对应的时钟
          • 配置GPIO为复用模式
          • 定时器的时基部分配置
          • 定时器输入通道部分配置
          • 定时器中断配置
          • 代码:
          • 运行效果:
          • 需求2
            • 测试时序图
            • 选择GPIO
            • 实现效果:
            • 总结
            • M4���列目录

              前言

              上一篇介绍了通用定时器的输出比较部分,这一篇再来介绍一下输入捕获的相关内容。

              输入捕获的概述

              输入捕获,见名知意,就用来对输入信号进行捕获的,说到捕获输入信号,之前介绍过一个叫做外部中断的片上外设,它的作用也是捕获输入;它们的不同在于,外部中断捕获的只是边沿,而定时器的输入捕获,捕获的是信号的时间信息,可以用来测试脉冲宽度、高电平时间、低电平时间等,还可以利用这个输入捕获的功能来获取一些模块采集的数据,典型代表就是HC-SR04超声波模块。

              老规矩还是看看AI对于输入捕获的简介:

              上面提到的四个部分都是在配置过程中需要进行编程来实现的,

              输入捕获:捕获输入到芯片中的脉冲宽度,捕获的是单个脉冲的宽度

              捕获的原理:通过边沿触发捕获

              可以通过计算得到:上升沿和下降之间的时间

              输出比较:调整脉冲宽度

              输入捕获:计算脉冲宽度 捕获一个脉冲的有效时间

              框图

              对输入捕获有了一个大致的概念后,来看看框图,简易版的框图再上上篇中提到过,那个还看不出具体的配置流程,所以这里再将详细的框图做个分析,和输出比较一样,输入捕获部分的详细框图也很复杂,具体的如下图所示:

              这里还是将框图拆分开了看。

              输入通道部分

              首先来看框图的前半段,输入信号进来后,第一个需要经过的就是数字滤波器,如下图红框中的位置。

              该滤波器是通过TIMx_CCMR1的ICF[3:0]位控制的,功能是“每N个事件视为一个有效边沿”,举个栗子来说就是,假设编程了这个N为4,而我们检测的高电平有效,那么就需要四个高电平才会生成一次有效边沿。

              具体的控制寄存器描述如下:

              需要注意的是,这里的频率分为了两部分,一部分是fck_INT也就是初始化的时钟,另一部分是fDTS,这里的f都是频率的意思,是对应的周期分之一;这里的fdts与fck_int的关系取决于TIMx 控制寄存器 1 (TIMx_CR1)的第八第九位的配置,这里配置的是周期的关系。t=1/f.

              经过数字滤波器后,信号需要经过一个边沿计测器,检测对应的上升沿还是下降沿,注意上方或门以及后面的一个向上的箭头都是到从模式控制器的,与输入捕获无关,所以可以忽略。

              进一步简化后如下图所示,通道1的输入信号经过边沿检测器后,会有一个数据选择器,这个选择器的控制寄存器是CC1P/CC1NP。

              对应的是TIMx_CCER寄存器的第一位与第三位,这里需要特别注意,虽然也是两位进行配合,来控制此处的是上升沿有效、下降沿有效还是双边沿都有效,但是是间隔开的两位,位2是不做配置的,在编写代码的时候需要特别小心。

              然后就是后面橙色框内的大的数据选择器,这个选择器是用来选输入信号的,一共三个输入,根据上上篇的简略框图,我们知道这三个输入分别是来自通道一的输入信号、来自通道二的输入信号,以及从模式控制器来的信号;此时配置的是输入捕获,而且为了避免交叉使用通道导致配置出错,后两个输入信号在此处是不考虑的,可以直接不看。也就是说,在配置过程中,需要将TIMx_CCMR1的CC1s的两位配置为“01”——选择通道一作为输入。

              最后就是蓝色框内的分频器了,这个分频器的作用于前面的数字滤波器的效果类似,假设配置为2分频,则需要有两个对应事件产生才会生成一个有效边沿。一般都配置为了不分频,检测到一个边沿就进行捕获。他的控制寄存器对应的是TIMx_CCMR1的IC1PSC的两位:

              最后还有一个控制器,TIMx_CCER的CC1E控制位,这个想必大家也都猜到了,是使能位的意思,细心的同学可能发现了,上一篇的PWM输出,在输出通道最后也是这个CC1E位做的使能,其实他们使用一个寄存器,只是在不同模式中有着不同的含义。

              比较捕获寄存器与事件生成

              在输入捕获中,除了上面的通道配置以外还有两个需要配置的,如下图,第一个框内CCR1比较捕获寄存器需要写入对应的比较值,这与PWM模式下的CCR1的写法其实一样。

              还有一个是CC1G,这个对应的是TIMx 事件生成寄存器 (TIMx_EGR)的第1位,这里后面是个或门,由于CC1E和IC1PS已经配置了,上面的那个输入是真,所以这一位其实不配置也可以。

              至于时基部分,与之前的一样,所以在此就不做赘述了,接下来总结一下具体使用到的寄存器有哪些。

              寄存器

              1.TIMx 控制寄存器 1 (TIMx_CR1):

              写法:TIMx->CR1

              位 9:8 CKD:时钟分频 (Clock pision)

              和滤波器的采样频率有关

              2.TIMx 从模式控制寄存器 (TIMx_SMCR)

              写法:TIMx->SMCR

              时钟源选择

              3.TIMx DMA/中断使能寄存器 (TIMx_DIER)

              写法:TIMx->DIER

              配置更新中断

              配置捕获中断

              4.TIMx 事件生成寄存器 (TIMx_EGR)

              写法:TIMx->EGR

              人为生成更新事件

              5.TIMx 捕获/比较模式寄存器 1 (TIMx_CCMR1)

              写法:TIMx->CCMR1

              位 1:0 CC1S:捕获/比较 1 选择 (Capture/Compare 1 selection)

              选择输入还是输出

              选择输入中的第一个信号源

              位 3:2 IC1PSC:输入捕获 1 预分频器 (Input capture 1 prescaler)

              配置无预分频

              位 7:4 IC1F:输入捕获 1 滤波器 (Input capture 1 filter)

              选择对应采样频率 1111

              6.TIMx 捕获/比较使能寄存器 (TIMx_CCER)

              写法:TIMx->CCER

              位 0 CC1E:捕获/比较 1 输出使能 (Capture/Compare 1 output enable)。

              使能位

              位 1 CC1P:捕获/比较 1 输出极性 (Capture/Compare 1 output Polarity)。

              位 3 CC1NP:捕获/比较 1 输出极性 (Capture/Compare 1 output Polarity)。

              可读可写

              00:上升沿触发

              01:下降沿触发

              11:双边触发 ----- 通过进入中断的次数来判断

              编程思路

              根据上面的框图解析以及寄存器介绍,我们可以大致总结出配置为输入捕获是时的代码思路,

              伪代码:

              输入捕获初始化函数{  //打开时钟  GPIO  TIM5    GPIO控制器配置  //GPIO模式  复用功能寄存器  定时器的时基单元  //更新禁止  //更新请求源  //关闭单脉冲  //方向  //重装载值得影子寄存器  //分频    4分频  //选择时钟源  //预分频器配置  //重装载值配置  //产生更新事件    定时器得输入部分  //选择输入模式  TI1  //输入捕获分频器 无分频器  //采样频率配置   1111  //边沿触发  //使能捕获  中断配置  //更新中断使能  //捕获中断使能  //NVIC控制器  //计数器使能}

              而对应的功能则需要到对应的中断服务函数去进行,中断服务函数的思路如下:

              中断服务函数{    判断位更新中断    {        N++;//记录产生更新事件的次数,依次来计算时间    }    判断为捕获中断    {       判断为上升沿捕获          {          N=0;          或者这时刻得CCR得值          切换下降沿捕获  //flag=1       }       判断为下降沿捕获        {          直接计算整个时间          切换回上升沿捕获 下一次进来还是先捕获上升沿       }    }}

              实际需求

              上面总结了输入捕获的编程流程,这里借助两个小需求,来具体编程实现对应的功能。

              需求1:

              检测开发板上Key_UP的按下时间,并通过串口输出。

              需求分析:

              首先,要检测按键按下的时间,肯定需要使用到上面的输入捕获功能了,具体怎么实现呢,第一步查看原理图找到KEY_UP按下时的输入信号是什么样子的。

              如上图所示,在按键输入的时候使用过这个按键,当时是配置为了下拉,使得空闲状态是低电平,按下按键会产生一个脉冲,我们需要捕获时间长度的就是这个高脉冲的时间。具体的捕获过程应该是:

              1. 捕获按下时的高电平,并记录此时的计数值;
              2. 记录高电平期间产生的更新事件的个数(也就是计数器从0计数到重装载值的循环次数);
              3. 记录松手时的计数器的计数值,
              4. 计算时间:更新事件的次数X重装载值+松手时的计数器值-按下时的计数器值

              举个栗子:假设定时器的分频系数是84分频,每秒会计数84M/84=1 000 000次,重装载数是1000;也就是每1ms计数1000次,每一次计数时间等于1us;

              此时按键按下时对应的计数值是800,从按下按键到松手期间一共产生了6个更新事件,松手时的计数值为400;则此次按键按下的时间为:

              TIME = 6*1000+400-800=5600us=5.6ms

              配置流程

              分析清楚了捕获过程后,我们来看看具体的配置流程,由于定时器是片上外设,捕获按键按下时常需要有GPIO的参与,所以对应的GPIO需要配置为复用模式。前面提到过,通用定时器至少都有两个通道,怎么知道KEY_UP具体的定时器和通道是哪个呢,这就有需要使用到引脚复用表了。通过查询原理图,或者根据经验,KEY_UP的引脚应该是GPIOA0;在引脚复用表中可以看出它对应的是TIM5的CH1。

              打开对应的时钟

              根据以前的配置经验,第一步应该打开对应的片上外设的时钟,GPIOA的对应的时钟线是AHB1;TIM5对应的时钟线是APB1,然后到对应的编程手册找到对应位,写入1即可,具体的配置请看后面的代码。

              配置GPIO为复用模式

              打开时钟后,就需要将GPIOA的0号管脚配置为复用模式,且要对照复用表映射到对应的功能,TIM5的CH1,GPIOA0对应的应该是低位的复用功能寄存器的0-3四位,写入AF2对应的0010即可配置为复用TIM5的通道1。

              定时器的时基部分配置

              紧接着就是定时器的时基部分了,这个也是很熟悉的了,前面配置过多次,需要配置CR1、SMCR、预分频和重装载而且还需要手动操作EGR产生一次更新事件,让数据写入影子寄存器已生效。

              定时器输入通道部分配置

              再这后就是输入通道的配置了,具体的配置流程参考上面的框图流程,主要配置CCMR1、CCER。

              定时器中断配置

              这需要使用到两个中断,一个是更新事件的中断,用来记录脉冲的期间内的更新事件个数,还有一个是捕获中断,利用捕获中断来获取对应边沿的计数器值。

              再就是中断源使能,优先级配置,最后的最后,一定不要忘记使能计数器。

              代码:

              /*******************************函数名:Time5_Interrupt函数功能:Time5_上升沿捕获函数形参:u32 arr   u16 psc预分频系数函数返回值:void备注:预分频系数  重装载值********************************/void Time5_Capture(u16 psc, u32 arr){/*-----------开始时钟使能-----------------------------------------------------------------*/RCC->AHB1ENR |=(1static u32 cnt;static u32 cnt_data;static u32 timer=0;if(TIM5-SR & (1TIM5-SR &=~(1TIM5-SR &=~(1cnt=0;//让更新中断的次数清零cnt_data = TIM5-CCR1;//获取当前值TIM5-CCER |=(1timer =cnt*1000-cnt_data+TIM5-CCR1;if(timer/100030)//将抖动的误触发舍弃{printf("按键按下时间为%d\r\n",timer/1000);//单位是MS}TIM5-CCER &=~(1Time4_Capture(84,1000);//定时器4的输入捕获(用于超声波检测)GPIOD-MODER &=~(3/*-----------开始时钟使能-----------------------------------------------------------------*/RCC-AHB1ENR |=(1static u32 cnt;static u32 cnt_data;static float timer=0;if(TIM4-SR & (1TIM4-SR &=~(1TIM4-SR &=~(1cnt=0;//让更新中断的次数清零cnt_data = TIM4-CCR1;//获取当前值TIM4-CCER |=(1timer =cnt*1000-cnt_data+TIM4-CCR1;printf("物体的距离为:%.2fcm\r\n",timer/58.0f);TIM4-CCER &=~(1

上一篇:约克主机面板报低压故障怎么办

下一篇:服务器固态内存盘怎么安装?