高级计时器TIM1:输入捕获功能功能实现信号周期与占空比测量
信号周期测量
输入捕获功能
-
输入捕获的定义
上一章介绍的两种计数方法只能对外部信号进行边沿识别与计数,如果需要测量信号波形的幅值、周期、频率和占空比,就需要用到TIM1的输入捕获功能(TIM2/3也有此功能,因为TIM1功能最全且三者配置方法都类似,因此只介绍TIM1)
顾名思义,输入捕获功能就是把通过TIM1_CHx通道输入的信号捕获,经过处理之后交给CPU进行操作
-
输入捕获功能流程
-
信号从输入捕获通道TIM1_CHx(也即前文提到的PC1-4引脚)进入,产生TIx信号
-
经过滤波器和边沿检测器,产生两路相同的信号TIxFP1和TIxFP2
-
TIxFP1送入IC1单元(输入捕获1)用于测量信号周期
TIxFP2送入IC2可以用于配合测量信号占空比
-
检测到ICx单元的相应边沿后,TIM1的计数值器寄存器CNTRH和CNTRL中的值会被锁存到相应的捕获/比较寄存器CCRx中
-
发生捕获事件后状态寄存器SR1的标志位CCxIF会被置1,表示计数值已经拷贝到了CCRx寄存器,如果又发生了一层捕获事件,那么CCxOF将会被置1,这两个位可以用软件来置0清除
-
-
输入捕获实现周期测量
前文的计数功能中,已经知道怎样检测所需的信号极性
而对于一个信号,当识别到某一边沿后,隔一段时间再检测到了下一相同边沿,那么就可以判断这个信号经过了一个周期,这两个边沿相隔的时间就是一个周期的时长
要实现这一过程,关键在于:
- 通过TIM1的状态寄存器TIM1_SR1/2相应位来判断是否检测到了边沿
- 通过TIM1的捕获比较寄存器TIM1_CCRx中的计数值来判断检测到捕获时的时间
由上可得到周期的计算公式:
f外部信号=(预分频因子*计时器时钟频率)/(二次捕获值-一次捕获值)
输入捕获功能配置简述
-
选择并启用输入通道
配置TIM1_CCMRx寄存器的CCxS[1:0]位(位1:0),将通道配置为输入模式
例如:选择TIM1_CH1为信号输入通道,就将TIM1_CCMR1中的CC1S位配置为01,使CC1通道被配置为输入,IC1映射到TI1FP1上
-
设置信号采样率以及滤波器
配置TIM1_CCMRx的ICxF[3:0]位(位7:4)
-
设置信号沿极性
配置TIM1_CCERx的CC1P位(位1),0为高电平或上升沿有效,1则相反
-
配置输入捕获通道预分频器
配置TIM1_CCMRx的ICxPSC[1:0]位(位3:2)
-
使能捕获功能
使用TIM1_CH1,则配置TIM1_CCER1寄存器的CC1E位(位1)为1
-
使能捕获中断
如果需要,还可以启用捕获中断
配置中断使能寄存器TIM1_IER中的CCxIE位(x的值取决于使用的通道)为1
-
使能TIM1计数器
配置TIM1_CR1_CEN=1
输入捕获相关寄存器
-
这些寄存器有些在上一章中已有介绍,此处仅介绍与输入捕获相关的功能,其它不再赘述
-
捕获/比较模式寄存器TIM1_CCMRx
有用于配置信号采样率与预分频器的ICxF位与ICxPSC位,以及配置通道功能的CCxS位
注意各个通道有对应的CCMR寄存器,CH1对应CCMR1,另有CCMR2/3/4,各个寄存器中控制位的位置相同,但是控制的通道不同,可见使用TIM1计数功能章节的CCMR1,不再赘述
-
捕获/比较使能寄存器TIM1_CCER1/2
用于配置信号极性的CCxP位与使能捕获功能的CCxE位
一共有两个CCER寄存器,比如:在配置信号极性时,如果使用CH1或CH2,则设定TI1F或TI2F,配置TIM1_CCER1的CC1P或CC2P,如果要使用TIM1_CH3/4就需要配置TIM1_CCER2的CC3P(位1)或CC4P(位5)
-
状态寄存器TIM1_SR1/2
用于反映计时器状态,类似TIM4_SR,不过因为TIM1的功能更多、要控制四个通道,因此要反映的状态也更多,需要用到两个寄存器
在TIM1_SR1中的配置位有CCxIF位,用于反映捕获到了设置的边沿
这个寄存器是实现周期测量的关键:周期测量的原理是识别到某一边沿后,到下一相同边沿的时间就是该信号的周期时间,通过查询TIM1_SR1状态寄存器的捕获标志位CCxIF实现这一过程:在输入模式下,当检测到与所选极性相同的边沿信号时,CCxIF就会被置1
在TIM1_SR2中的配置位是CCxOF位,用于反映重复发生的捕获,这是之后实现占空比测量的关键
-
捕获/比较寄存器TIM1_CCRx
用于储存检测到ICx单元的相应边沿后,TIM1的计数值器寄存器CNTRH和CNTRL中的值
因为有4个独立比较/捕获通道,所以ICx单元有4个;而又因为16位的计数值需要分高低两个寄存器来储存,所以CCRx寄存器总共有8个
-
启用中断的中断使能寄存器TIM1_IER和启动计时器的控制寄存器TIM1_CRx与之前都是一样的,不再赘述
代码实现
-
CH1通道测量信号周期
识别到某一边沿后,到下一相同边沿的时间就是该信号的周期时间,这通过查询TIM1_SR1状态寄存器的捕获标志位CC1IF实现这一过程:当CC1IF为1,则在IC1单元上检测到了与TIM1_CCER1_CC1P位所配置相同的极性
而标志位变化时,计数器值已经被复制到了捕获/比较寄存器TIM1_CCR1H/L中,通过公式:f外部信号=(预分频因子*计时器时钟频率)/(二次捕获值-一次捕获值)计算得到真实周期
//得到第一次捕获值后和第二次捕获值后,禁用捕获功能 //用第二次捕获值减去第一次捕获值,得到信号周期的计数值 //若有预分频处理则计数值还需进一步处理得到真实时间 TIM1_CCER1H = 0x00; TIM1_CCER1L = 0x00;//清除捕获/比较寄存器 TIM1_CCER1 |= 0x01;//捕获功能使能 //此处演示查询方式: while((TIM1_SR1&0x02)==0);//等待捕获比较标志位1CC1IF变为1 A = (u16)TIM1_CCR1H<<8;//取回捕获/比较寄存器高八位 A |= TIM1_CCR1L;//取回捕获/比较寄存器低八位 while((TIM1_SR1&0x02)==0);//等待捕获比较标志位1CC1IF变为1 B = (u16)TIM1_CCR1H<<8;//取回捕获/比较寄存器高八位 B |= TIM1_CCR1L;//取回捕获/比较寄存器低八位 TIM1_CCER1&=OxFE;//捕获功能禁止 sys_num = B-A;//得到信号周期计数值,由于工作频率不同,这个值还不反映真实的周期 F_num = 8*SYS_CLOCK/SYS_num;//计算频率值,假设为8分频 //SYS_CLOCK是系统当前的f_master频率值,以宏定义方式写在程序开头
信号占空比测量
复位触发模式
-
复位触发模式的定义
- TIM1支持4种触发输入:ETR、TI1、TI2、和来自TIM5/6的TRGO信号
- 而TIM1使用三种模式与外部的触发信号同步:标准触发模式、复位触发模式、门控触发模式
- 所谓复位触发,指的是触发事件到来时会对计数器和预分频器进行初始化(如果CR1的URS位为0,那么还将产生一个更新事件UEV,然后所有预装载寄存器都被更新)
- 简而言之:计时器依据内部时钟正常计数,直到输入信号TIx出现一个上升沿,此时计数器会被清零,然后重新计数;与此同时,状态寄存器TIM1_SR1的TIF位(触发标志)会被置1(如果使能了中断则会产生一个中断请求)
-
复位触发实现占空比测量
- 所谓占空比,就是指一个周期内,信号处于高电平的时间占整个周期的百分比。例如,一个方波的占空比是50%,因此可知只要测量高电平脉冲的宽度,再测得信号周期,两个值相比便是占空比
问题关键在于如何测量高电平脉冲宽度,这一点可以借助TIM1输入捕获的边沿检测实现,具体流程如下:
- 在检测到第一个上升沿后,开始计数,再到第一个下降沿时取出计数值,这个值便是高电平脉宽;
- 然后继续计数,直到检测到第二个上升沿,此时的计数值便是整个周期
- 这个过程中较为稳妥的处理方式是:在上升沿到来时,将当前计数器值取出存放,然后自动清零计数器,紧接着开始下一次启动,也就是复位触发模式
复位触发模式配置简述
-
配置捕获/比较通道TIM1_CHx
按需配置TIM1_CCMRx的预分频器、滤波器、输入捕获源,这些同上文输入捕获功能的配置
重点在于配置检测极性,为了检测高电平脉宽,要设为上升沿
-
设定复位触发模式
以CH1通道为例,配置从模式控制寄存器TIM1_SMCR中的SMS[2:0]位为100(启用复位触发模式)
然后配置TS[2:0]位为101(因为使用CH1,所以选择TI1FP1作为输入源)
-
启动计时器
配置控制寄存器TIM1_CR1_CEN位为1
代码实现
-
CH1通道测量信号占空比
因为占空比的计算需要高电平脉宽和周期两个数据,恰好利用上输入时TIx产生的两路相同信号TIxFP1和TIxFP2,对于CH1而言就是TI1FP1与TI1FP2这两路信号
//首先设置具体的输入通道,此处选择捕获/比较1通道,对应PC1/TIM1_CH1 TIM1_CCMR1 |= 0x01; //CC1S[1:0]设置为01,TI1FP1连接到IC1 TIM1_CCER1 &= 0xFD; //CC1P位置0,捕捉TI1FP1的高电平或上升沿 TIM1_CCMR2 |= 0x02; //CC2S[1:0]配置为10,TI1FP2连接到IC2 TIM1_CCER1 |= 0x20; //CC2P位置1,捕捉TI1FP2的低电平或下降沿 //现在就完成了两路信号的触发输入与触发边沿,接下来选定具体的复位触发信号 TIM1_SMCR |= 0x50; //TS[2:0]=101,配置触发输入信号为TI1FP1 TIM1_SMCR |= 0x04; //SMS[2:0]=100,配置复位触发模式 //接下来使能两路信号的捕获功能与计数器功能 TIM1_CCER1 |= 0x11; //置1使能CC1E与CC2E捕获功能 TIM1_CR1 |= 0x01;//使能计数器 //之后就可以进行具体测量了,获得两个值:IC1捕获高电平脉宽,IC2捕获信号周期 TIM1_SR1 &= 0xF9; //清除CC1IF和CC2IF标志位 TIM1_SR2 &= 0xFD; //清除CC1OF标志位 TIM1_CCER1 |= 0x11; //开启捕获功能 while((TIM1_SR1&0x02)==0); //等待捕获比较标志位CC1IF变为1 while((TIM1_SR1&0x04)==0); //等待捕获比较标志位CC2IF变为1 A_num = (u16)TIM1_CCR2H<<8; //取高电平脉宽的高8位 A_num |= TIM1_CCR2L; //取高电平脉宽的低8位 while((TIM1_SR2&0x02)==0); //等待重复捕获比较标志位CC1OF变为1 B_num = (u16)TIM1_CCR1H<<8; //取周期的高8位 B_num |= TIM1_CCR1L; //取周期的低8位 TIM1_CCER1 &= 0xEE; //或者置0把禁止捕获功能 F_num = SYS_CLOCK/B_num; //计算实际的频率值 Duty = (A_num*10000/B_num); //计算占空比,乘10000是为了保留小数 //需要注意,随着输入频率的增大,占空比参数的测量误差总体上增大
本文来自博客园,作者:无术师,转载请注明原文链接:https://www.cnblogs.com/untit1ed/p/18576105
本文使用知识共享4.0协议许可 CC BY-NC-SA 4.0
请注意: 特别说明版权归属的文章以及不归属于本人的转载内容(如引用的文章与图片)除外
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了