高级计时器TIM1:输入捕获功能功能实现信号周期与占空比测量

信号周期测量

输入捕获功能

  • 输入捕获的定义

    上一章介绍的两种计数方法只能对外部信号进行边沿识别与计数,如果需要测量信号波形的幅值、周期、频率和占空比,就需要用到TIM1的输入捕获功能(TIM2/3也有此功能,因为TIM1功能最全且三者配置方法都类似,因此只介绍TIM1)

    顾名思义,输入捕获功能就是把通过TIM1_CHx通道输入的信号捕获,经过处理之后交给CPU进行操作

  • 输入捕获功能流程
    1. 信号从输入捕获通道TIM1_CHx(也即前文提到的PC1-4引脚)进入,产生TIx信号

    2. 经过滤波器和边沿检测器,产生两路相同的信号TIxFP1和TIxFP2

    3. TIxFP1送入IC1单元(输入捕获1)用于测量信号周期

      TIxFP2送入IC2可以用于配合测量信号占空比

    4. 检测到ICx单元的相应边沿后,TIM1的计数值器寄存器CNTRH和CNTRL中的值会被锁存到相应的捕获/比较寄存器CCRx中

    5. 发生捕获事件后状态寄存器SR1的标志位CCxIF会被置1,表示计数值已经拷贝到了CCRx寄存器,如果又发生了一层捕获事件,那么CCxOF将会被置1,这两个位可以用软件来置0清除

  • 输入捕获实现周期测量

    前文的计数功能中,已经知道怎样检测所需的信号极性

    而对于一个信号,当识别到某一边沿后,隔一段时间再检测到了下一相同边沿,那么就可以判断这个信号经过了一个周期,这两个边沿相隔的时间就是一个周期的时长

    要实现这一过程,关键在于:

    1. 通过TIM1的状态寄存器TIM1_SR1/2相应位来判断是否检测到了边沿
    2. 通过TIM1的捕获比较寄存器TIM1_CCRx中的计数值来判断检测到捕获时的时间

    由上可得到周期的计算公式:

    f外部信号=(预分频因子*计时器时钟频率)/(二次捕获值-一次捕获值)

输入捕获功能配置简述

  1. 选择并启用输入通道

    配置TIM1_CCMRx寄存器的CCxS[1:0]位(位1:0),将通道配置为输入模式

    例如:选择TIM1_CH1为信号输入通道,就将TIM1_CCMR1中的CC1S位配置为01,使CC1通道被配置为输入,IC1映射到TI1FP1上

  2. 设置信号采样率以及滤波器

    配置TIM1_CCMRx的ICxF[3:0]位(位7:4)

  3. 设置信号沿极性

    配置TIM1_CCERx的CC1P位(位1),0为高电平或上升沿有效,1则相反

  4. 配置输入捕获通道预分频器

    配置TIM1_CCMRx的ICxPSC[1:0]位(位3:2)

  5. 使能捕获功能

    使用TIM1_CH1,则配置TIM1_CCER1寄存器的CC1E位(位1)为1

  6. 使能捕获中断

    如果需要,还可以启用捕获中断

    配置中断使能寄存器TIM1_IER中的CCxIE位(x的值取决于使用的通道)为1

  7. 使能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位,用于反映捕获到了设置的边沿

    image

    这个寄存器是实现周期测量的关键:周期测量的原理是识别到某一边沿后,到下一相同边沿的时间就是该信号的周期时间,通过查询TIM1_SR1状态寄存器的捕获标志位CCxIF实现这一过程:在输入模式下,当检测到与所选极性相同的边沿信号时,CCxIF就会被置1

    在TIM1_SR2中的配置位是CCxOF位,用于反映重复发生的捕获,这是之后实现占空比测量的关键

    image

  • 捕获/比较寄存器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输入捕获的边沿检测实现,具体流程如下:

    1. 在检测到第一个上升沿后,开始计数,再到第一个下降沿时取出计数值,这个值便是高电平脉宽;
    2. 然后继续计数,直到检测到第二个上升沿,此时的计数值便是整个周期
    • 这个过程中较为稳妥的处理方式是:在上升沿到来时,将当前计数器值取出存放,然后自动清零计数器,紧接着开始下一次启动,也就是复位触发模式

复位触发模式配置简述

  1. 配置捕获/比较通道TIM1_CHx

    按需配置TIM1_CCMRx的预分频器、滤波器、输入捕获源,这些同上文输入捕获功能的配置

    重点在于配置检测极性,为了检测高电平脉宽,要设为上升沿

  2. 设定复位触发模式

    以CH1通道为例,配置从模式控制寄存器TIM1_SMCR中的SMS[2:0]位为100(启用复位触发模式)

    然后配置TS[2:0]位为101(因为使用CH1,所以选择TI1FP1作为输入源)

  3. 启动计时器

    配置控制寄存器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是为了保留小数
    //需要注意,随着输入频率的增大,占空比参数的测量误差总体上增大
    

posted on   无术师  阅读(125)  评论(2编辑  收藏  举报

相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了

统计

点击右上角即可分享
微信分享提示