TIM定时器的一些总结

前言

        TIM定时器是一个比较常用的外设,涉及到需要在指定的时间做某个动作需要用到,同时TIM定时器也能用来输出PWM波形来驱动电机。由于定时器的基本结构是非常通用的,很多模块都可以使用到,所以在STM32上扩展了许多功能,不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能 根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型。

        可以看到TIM定时器有如此多的功能,恰恰也说明TIM定时器的学习路程比较漫长,路漫漫其修远兮,吾将上下而求索,所以在TIM定时器上花费大量时间是有必要的。

1.TIM(TIMER)定时器

        首先需要知道TIM定时器有三种类型,这三种类型又分别适应不同的情况,下图是对TIM定时器的分类:

        可以看到TIM定时器分为:高级定时器、通用定时器以及基本定时器。三者之间属于包含关系,通用定时器包含基本定时器(拥有基本定时器的全部功能),同时高级定时器包含通用定时器。

        还能注意到,高级定时器外设所在的总线属于APB2(而APB2总线上的时钟频率为72MHzAPB1上的时钟频率为36MHz)APB1总线上挂载着通用定时器和基本定时器。这是因为APB2性能要优于APB1,即高级定时器挂载在APB2上,这样能够更好的发挥高级定时器的作用。

        接下,我会对通用定时器进行展开描述,实际上大多情况会用到通用定时器,高级定时器只是在通用定时器的基础上扩展了一些功能,而基本定时器所拥有的功能少,且被通用定时器包括在内,所以接下来围绕通用定时器进行展开。

        可能有一个疑问,既然高级定时器拥有所有功能,为什么不把其他定时器都换成高级定时器呢?

        首先,高级定时器成本自然高,而且如果都换成高级定时器,容易造成资源过剩,本来只需要用到通用定时器其中一个扩展功能,导致会多出空闲资源;还有一点是APB2总线上不一定有这么多个接口供其他高级定时器使用。从定时器的数量上看,通用定时器数量多,也就说明通用定时器相比其他两种定时器所运用的场景更多,能够充分利用资源,当需要使用到高级定时器特有的扩展功能再去使用高级定时器。

        需要注意的是,STM32F103C8T6定时器资源:TIM1、TIM2、TIM3、TIM4,没有基本定时器。

2.TIMx(x=2~5)(TIMER)通用定时器的结构

        我们知道,通用定时器包含基本定时器,所以基本定时器的结构也是被通用定时器的结构包含,接下来先对基本定时器的结构进行介绍: 

        因为基本定时器和通用定时器都属于APB1总线上的外设,系统时钟为36MHz,然而定时器接收到的时钟是72MHz(“CK_INT"),实际上时钟树单独对APB1上的输入定时器的时钟进行×2操作。

        如果对上面还是存在疑惑,推荐我自己写的时钟树介绍时钟树的一些总结-CSDN博客

        回到上述结构,时钟输入触发控制器,有两个输出,一个是TRGO,另一个是通过控制器接到下面的电路(也即时基单元)。

2.1TRGO的解析

        首先,对TRGO进行一个解析,TRGO就是触发输入源,可以看到TRGO的输出可以接通到DAC模数转换,TRGO是通过下面的时基单元产生的事件更新触发的。

        下图是固件库函数来实现TRGO的事件触发:

        第二个参数选择TIM_TRGOSource_Update,可以通过可选的参数来道明TRGO的所有情况同时可以看到是对定时器的CR2寄存器进行操作的,接下来看到CR2寄存器:

        可以知道函数TIM_SelectOutputTrigger,是通过配置CR2寄存器的位6:4来配置模式的:

MMS[2:0]对应的功能
000复位(与实际复位存在延迟)
001使能(选择计数器使能信号CNT_EN作为触发输出TRGO)
010更新(选择更新事件触发TRGO)
011比较脉冲(输入捕获或输出比较成功后置CC1IF标志,触发输出送出一个正脉冲TRGO
100比较OC1REF信号用作触发输出(TRGO)
101比较OC2REF信号用作触发输出(TRGO)
110比较OC3REF信号用作触发输出(TRGO)
111比较OC4REF信号用作触发输出(TRGO)

        首先,MMS[2:0]这三位配置的叫做主从模式选择(Master Mode Selection),作用是选择在主模式下输送定时器的触发信号TRGO(同步信息)。

        包含功能较多,其中位设置010就是先前所述的事件更新TRGO,其他模式可以在看完下述功能回过头来理解,同时在后续介绍主从模式的时候回涉及到TRGO。

2.2时基单元的分析

        上图位时基单元的基本结构,CK_PSC为输入预分频器的时钟也就是输入定时器的时钟(默认72MHz),进入PSC预分频器,进行预分频操作,实际预分频的值=PSC+1。例如此时72MHz时钟进入PSC=1的预分频器中,输出的CK_CNT也就是(72/(1+1))=36MHz。

        计数器计数频率:CK_CNT = CK_PSC / (PSC + 1)

        时钟输入到CNT计数器中,CNT计数器就开始自增或者是自减操作,一般来说是向上计数模式,对应CNT自增,自增到ARR自动重装仔寄存器存储的目标值,就产生一个事件更新和一个中断更新。

        上述用到的寄存器有:计数器寄存器(TIMx_CNT)、预分频器寄存器 (TIMx_PSC)、自动装载寄存器 (TIMx_ARR)。

        计数器溢出频率:CK_CNT_OV = CK_CNT / (ARR + 1)= CK_PSC / (PSC + 1) / (ARR + 1)

                                   CK_CNT_OV = CK_CNT / (ARR + 1)= CK_PSC / ((PSC + 1) *(ARR + 1))

        这里需要注意的是,ARR、PSC、CNT的范围都在0~65536,因为寄存器是16位的,2的16次方也就是65536。

        接下来对时序进行分析:

  1. CK_PSC也就是系统输入的时钟,
  2. CNT_EN为时钟使能(高电平使能),
  3. 然后是定时器时钟CK_CNT也就是CNT进行自增(上升沿触发)的时钟,
  4. 对应计数器寄存器在定时器时钟脉冲的上升沿时自增+1,
  5. 当计数器寄存器的值为ARR目标值(FC)时产生事件更新。

        对PSC预分频器的控制是对预分频控制寄存器对应的位进行设置来写入控制的,预分频缓冲寄存器(别名影子寄存器)起到缓冲作用。当CNT在自增至ARR途中改变PSC的值,并不会在预分频器计数器立刻改变,由于预分频缓冲寄存器的作用,当CNT在本次周期自增至ARR结束后的下一周期,写入PSC预分频值才起作用。

        如图中所示,预分频控制寄存器在途中改变PSC,预分频计数器并没有立即变为2(PSC+1)分频,而是在下一周期才进行2分频。

        同时对比以下有无预装ARR的情况:

        可以看到,在写入ARR自动重装寄存器时,立刻就生效了。

        接下来看到有预装的ARR,再次改变ARR的值会发生什么:

            可以看到,虽然在ARR=F5的周期下改变位ARR=36,但是本次周期依旧是以ARR=F5结束的,而在下一周期才以ARR=36进行。

        同样的,由于自动加载影子寄存器的存在,会产生缓冲作用。只需要将ARPE的值置1,即可激活影子寄存器 。             

         自动装载寄存器是预先装载的,写或读自动重装载寄存器将访问预装载寄存器。根据在
TIMx_CR1寄存器中的自动装载预装载使能位(ARPE)的设置,预装载寄存器的内容被立即或在
每次的更新事件UEV时传送到影子寄存器。
        

        可以看到,CR1控制寄存器中APRE位(位7)就是用来决定ARR寄存器是否使用缓冲寄存器(影子寄存器)。

2.3通用定时器的时钟输入

        先前介绍的是属于基本定时器的结构,通用、高级定时器都包含其结构,接下来就对通用定时器的结构进行展开:

        上图结构看起来较为复杂,因为为了满足通用定时器的扩展功能而实现的。

        同样的,先从时钟输入进行介绍:

        内部时钟IN_CNT,也就是系统时钟,之前介绍过了。

        然后是TIMx_ETR引脚,也就是外部触发输入(ETR) ,对应的属于外部时钟源模式2 。

2.3.1外部时钟源模式2

        选定此模式的方法为:令TIMx_SMCR寄存器中的ECE=1
        计数器能够在外部触发ETR的每一个上升沿或下降沿计数。
        下图是外部触发输入的框图:

        从图中看到,ETR接收的信号先进入由TIMx_SMCR寄存器控制的数据选择器,下图是该寄存器对ETP控制位的说明:

        这里可以控制外部ETR输入是否需要反向,以及极性选择。

        接着进入分频器,同样也是TIMx_SMCR寄存器,可以说从模式控制寄存器SMCR专门用来配置外部时钟源模式2 。  

        ETPS[1:0]就是用来配置外部时钟源的预分频系数的,可配置的系数有:0、2、4、8;

        然后进入滤波器向下计数器,同样是SMCR寄存器中的位(ETF[3:0]):

        因为外部输入ETR时钟信号难免会出现一些毛刺,所以需要通滤波来获取更加稳定的时钟信号。

        这里是以固定频率为f来采样N个点,如果这N个点都相同,代表输入信号稳定,才会有效输出;如果这N个点不全相同,则说明输入信号带有抖动,则会保持上一次的输出或是直接输出低电平。这样就能实现滤波的目的,采样频率越低、采样个数越多,滤波效果就越好。

        下面看到配置外部时钟源模式2的函数:

        外部时钟ETR(External Clock Mode2),第一个TIMx就是选择需要配置的定时器;

        第二个是TIM_ExtTRGPrescaler,也就是选择ETR外部输入时钟的预分频系数,对应前面的TIMx_SMCR寄存器的ETPS位,可以配置0、0、2、4、8分频。

        第三个是TIM_ExtTRGPolarity,极性选择,上升沿(高电平)有效或者是下降沿(低电平)有效,对应第一个数据选择器,反向还是不反向,计数器能够在外部触发ETR的每一个上升沿或下降沿计数,对应TIMx_SMCR寄存器的ETP位进行控制

        最后一个是滤波ExtTRGFilter,在TIMx_SMCR寄存器的ETF[3:0]位共四位,对应的参数配置为:0000~1111,对应16进制为0x00~0x0F。

        之后输入到另一个数据选择器,同样是处于SMCR寄存器中的控制位:

        位ECE和SMS[2:0]共同控制该数据选择器,ECE位控制外部时钟源模式2的使能和失能。

        下面有3点注意:

        1.设置ECE位与选择外部时钟模式1并将TRGI连到ETRF(SMS=111TS=111)具有相同功

效,对应下图ETR输入对应的两种输出:

        上面的线路属于外部时钟源模式2,也就是ECE使能路线。

        下面红线路线属于外部时钟源模式1,ETR外部时钟可以输入到下面的数据选择器中,然后触发输出TRGI,作为外部时钟源模式1输入。这条路线实际上是将TRGI和ETRF相连接,输出到后面的出发控制器的外部时钟源模式1输入端。

        同时需要将SMS和TS分别置111,查看对应的功能,不难理解,如下图:

       对应选择位外部触发输入(ETRF)以及外部时钟模式1 ,在查看该数据选择器:

        对于数据选择器,需要明确下图的概念,下面分别由TS[2:0]和SMS[2:0]对应的数据选择器:

        同样,可以在SMCR寄存器对应位的描述中可以理解。

        相信通过以上的过程,应该能够很好的理解ETR引脚外部输入下的外部时钟源模式2,外部时钟源模式1这两种模式。

       2.下述从模式可以与外部时钟模式2同时使用:复位模式、门控模式和触发模式;但是,这

TRGI不能连到ETRF(TS位不能是’111’)

        也就是,在外部时钟模式2的情况下,可以配合使用复位模式、门控模式和触发模式这三种从模式。这三种模式在后续进行介绍,要使用这三种模式需要对SMS[2:0]位进行配置:

        同时TS位不能为111,也就是TS[1:0]的数据选择器的输入TRGI不会直接输出到ETRF外部触发输入,而会直接输出到SMS[1:0]的数据选择器,当然也不会入到外部时钟模式1中,而是会输入到上图的红框框中所用到的模式。

        3.外部时钟模式1和外部时钟模式2同时被使能时,外部时钟的输入是ETRF

        这里阐述的是当外部时钟模式1、2同时被使能的情况,对应的位ECE置1以及SMS[2:0]置111。而上述的配置如下图:

         因为ECE和SMS[2:0]同时控制该数据选择器的输入,理论上外部时钟模式1和外部时钟模式2会的输入通道会同时打开,结果时钟会进入到ETRF中,这里个人认为是由于外部时钟模式1的输入源较多,防止妨碍对部时钟模式1对其他输入源的处理,自动默认ETRF外部触发输入。(这里对后续的理解没有关联,只需要单纯的知道这么一个结果)

2.3.2外部时钟源模式1  

        如上图,有这么多个时钟源输入(图中没画用ETR外部触发时钟),接下来看到TS[2:0]数据选择器:

        TS[2:0]里面的参数,便是所有外部时钟源模式1 的所有输来源的可能。

        首先看到,000~011分别是TIM1~TIM4的输入,也称之为定时器之间的级联,两个TIM定时器进行级联就能够将原本的0~65536s范围进行指数爆炸的扩展,具体方式如下图:

        具体如何连接的参照下图。

        对应下面的函数,需要的自行了解。

        如果对定时器的级联功能有需要的可以自行参照手册。

        接下来是TI1的边沿检测器,是用来检测TMx_CH1的输入,当检测到上升沿或者是下降沿时就会产生对应的触发输入。值得一提的是,输入捕获路线的输入滤波器和边沿检测器和ETR外部时钟输入内部中的器件只存在一个。(就是共用一套滤波器)

        最后TI1FP1和TI2FP2分别对应的是TIMx_CH1和TIMx_CH2的输入时钟,对应的下图的函数,同样需要的自行理解。

2.3.3 时钟小结

        在实际应用中更多的会用到CK_INT内部时钟72MHz,其次外部输入更多的是ETR直接输入(通过ETRF)到触发控制器中。

        外部时钟源模式1更多的是在某些特殊的情况下,比如定时器的级联。

        以上就是对输入时钟的所有内容了,接下来对下半部分,输出捕获Output Capture和输入比较Intput Compare进行介绍。

2.4和输出比较Output Compare

        上图是OC(Output Compare)输出比较、IC(Intput Capture)输入捕获的电路,可以看到输入捕获OC和输出比较OC共用一个寄存器,当需要使用输入捕获功能时,就使用该寄存器的输入捕获控制位,因此,该寄存器被称为捕获/比较模式寄存器 x(TIMx_CCMRx)(Capture Compare Mode Register) (x=1~2),其中x=1的寄存器对应OC1和OC2通道,x=2对应OC3和OC4通道的配置。

        同时,不仅四个通道的捕获和比较公用同一个寄存器,而每一个寄存器都共用一个CNT计数器。

2.4.1输出比较(Output Compare)

        输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形,每个高级定时器和通用定时器都拥有4个输出比较通道,高级定时器的前3个通道额外拥有死区生成和互补输出的功能。

        上图位输出比较的部分电路,首先是输出模式控制器由寄存器TIMx_CCMR1控制,用来配置OC1通道:

        可以看到位分布,IC1、IC2输入以及OC1、OC2由该寄存器空,接下来只对OC1进行介绍,后续的在输入捕获的章节对IC1、IC2进行介绍。

        OC1CE:输出比较10使能 (Output compare 1 clear enable) 。

        由于输出的信号是OC1REF,如果没有OC1REF输出,也就没有输出,即失能输出比较。

        这一切是通过是否需要ETRF位的控制,该位写入0,不受影响;写入1,同时还需要当ETRF为高电平时,OC1REF才会为0,从而实现失能输出比较。

        OC1M[2:0]:输出比较1模式 (Output compare 1 enable)

        输出比较模式

        可以由上图简略描述,本质上输出比较是CNT和CCR之间的比较,CNT是一个自增或是自减的计数器(取决于计数模式,在时基单元中进行配置),而CRR是输出比较的一个目标值,和ARR自动重装值类似。

        冻结,类似暂停输出比较;

        匹配时值有效电平(也即高电平),当CNT=CCR的时候就REF输出高电平;

        匹配时值无效电平(也即低电平),当CNT=CCR的时候就REF输出低电平;

        需要注意,以上两种情况只能执行一次,也就是一次性的,不能用来输出连续且变化的PWM波形,一般用的比较少。

        匹配时电平翻转,也就是当CNT=CCR的时候,如果匹配之前REF为低电平,则翻转为高电平,然后当下一个周期再次匹配,REF就反转为低电平,如此往复。

       强制为无效电平,只要使用了该模式,REF输出固定为低电平。

       强制为有效电平,只要使用了该模式,REF输出固定为高电平。

        

        最后这两种模式,可以支持输出连续变换可调的PWM波,以此来驱动不会立即突变的外设,例如LED,当电平跳变由高到低,LED灯不会立即熄灭,如果在LED没有熄灭之前,又进入下一个周期的跳变,LED灯就会一直亮,唯一变化的是LED灯的亮度会呈现类似呼吸灯的样式。

        PWM模式1和2其实本质上是类似的,相当于给PWM1去反得到PWM2,而且在REF输出到失能电路途中,还需要控制一下是否需要反向,同时一般默认向上计数,向下计数也是对向上计数进行取反操作,这样我们只需要了解PWM模式1的向上计数即可。

        同时上面的注意事项1一旦LOCK级别设为3(TIMx_BDTR寄存器中的LOCK)并且CC1S=’00’(该通道配置成输出)则该位不能被修改。

        首先看到刹车和死区寄存器(TIMx_BDTR),属于高级定时器,这相当于在高级定时器中将该寄存器中的LCK值11(也就是级别3),并且CC1S=’00’(该通道配置成输出),就可以对REF的输出模式进行锁定。

       注意事项2:在PWM模式1PWM模式2中,只有当比较结果改变了或在输出比较模式中从冻结模式切换到PWM模式时,OC1REF电平才改变。

        OC1REF输出只会在PWM模式1或2中CNT和CCR的值动态变化(也即CNT>CCR、CNT=CCR、CNT<CCR这三种状态),或者是从冻结模式变换到PWM模式1或2的时候,也即从暂停状态又切换为运行状态,OC1REF输出才会改变。
OC1PE 输出比较 1 预装载使能 (Output compare 1 preload enable)          

        简单来说,就是对影子寄存器的使能和失能,值1对预装载寄存器的写入CCR值更新需要等到事件更新的到来才会进行写入更新CCR的值。

        注1和前面的注1类似,而注2是载单脉冲模式下,下面介绍单脉冲模式:

        单脉冲模式
        单脉冲模式(OPM) 是前述众多模式的一个特例。这种模式允许计数器响应一个激励,并在一个程序可控的延时之后,产生一个脉宽可程序控制的脉冲。
       可以通过从模式控制器启动计数器,在输出比较模式或者PWM模式下产生波形。设置
TIMx_CR1寄存器中的OPM位将选择单脉冲模式,这样可以让计数器自动地在产生下一个更新
事件UEV时停止。
        

         顾名思义,也就是一次性的脉冲,产生一次事件更新就停止。     

        仅当比较值与计数器的初始值不同时,才能产生一个脉冲。启动之前( 当定时器正在等待触发),必须如下配置:       
                                向上计数方式:CNT < CCRx ≤ ARR (特别地,0 < CCRx)
                                向下计数方式:CNT > CCRx。
        当CNT计数到ARR的时候,也就是一个周期,计数器就会溢出,溢出就会执行下一周期的计数,而CCR属于CNT和ARR之间的值,当动态的CNT和设定的CCR会分别处于三种状态(CNT>CCR、CNT=CCR、CNT<CCR),对应的,根据不同的模式会产生不同的脉冲信号:

        这样再来理解上面单脉冲的配置,通过下面一个简单的例子:

        如阶梯一般的是不断自增的CNT计数器的值,输入一个TI2单脉冲信号(下边沿触发),启动CNT计数器自增(向上计数),当CNT=CCR1,OC1REF就输出低电平,然后再输出OC1之前进行反向,就得到一个单脉冲。

        在TIMx_CR1寄存器中的CEN位有这么一个描述:

        在单脉冲模式下,当发生更新时间时,CEN位被自动清除,也就对应CNT停止计数。

CNT三种计数法(TIMx_CR1寄存器)

        再这里介绍以下CNT的三种计数法方式

        最常用的是向上计数,如下图

        当CNT计数从0自增到ARR的时候,才会更新中断/事件。

        向下计数:

        当CNT计数从ARR自减到0的时候,才会更新中断/事件。

        中央对齐计数:

        当CNT从0自增到ARR,以及CNT从ARR自减到0都会更新事件/中断。

        对应的配置的寄存器在TIMx_CR1中:

        首先是CMS[1:0]位对中央对齐更新中断的情况进行分类:

        然后是DIR位(direction),对应控制向上和向下计数

        同时在这个寄存器中还需要注意以下三个控制位:

        其中URS是选择更新中断/事件的来源,而UDIS是置1禁止更新中断/事件。

        CEN也就是CNT计数器的使能位。

PWM的参数计算

PWM频率:    Freq = CK_PSC / (PSC + 1) / (ARR + 1)

PWM占空比:    Duty = CCR / (ARR + 1)

PWM分辨率:    Reso = 1 / (ARR + 1)

        PWM的频率也就是计数器CNT从0到ARR(向上计数)的计数器溢出频率,同时也就是PWM的一个周期(ARR+1),分辨率也就是每次变化的精细程度,即变化补偿,一般来说是1%即可,如果需要0.1%甚至更高的分辨率,这样对硬件要求就很高。

        通过以上对输出比较的配置,就能够实现输出一个可调的PWM波形,根据PWM波高电平和低电平的占比,就可以实现LED呼吸灯、直流电机的运转、以及舵机的控制。

PWM脉冲控制舵机SG90

        这里对舵机SG90进行举例:

        舵机是一种根据输入PWM信号占空比来控制输出角度的装置 输入PWM信号要求:周期为20ms,高电平宽度为0.5ms~2.5ms。

        根据不同的高电平时间,来改变占空比,来实现舵机转向的不同角度,如上图所示的,对占空比的调节,根据公式Duty = CCR / (ARR + 1),在ARR固定的情况下,也就是对CCR的值进行改变来实现改变占空比

输出比较的配置

根据下图的顺序进行配置:

        对输出比较的配置也就是对TM_OCInitTypeDef结构变量的配置:

        需要注意的是,在配置参数之前需要用到TIM_OCStructInit函数:

        该函数会将结构的所有参数值都配置为缺省值(也就是默认值),因为对于TM_OCInitTypeDef结构体变量包含高级、通用、基本定时器的所有需要的配置,当我们只使用通用定时器时,我们会对用到的通用定时器进行配置,而结构体中还包含没有被配置的高级定时器的参数,这样就会出现错误,所以需要通过TIM_OCStructInit函数来对所有参数配置一个缺省值,防止出现错误。

	                                                                //避免结构体初值不确定的问题
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;               //输出比较模式,选择PWM模式1
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;       //输出极性,选择为高,若选择极性为低,则输出高低电平取反
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;   //输出使能
	TIM_OCInitStructure.TIM_Pulse = 0;								//初始的CCR值
	TIM_OC2Init(TIM2, &TIM_OCInitStructure);                        //将结构体变量交给TIM_OC2Init,配置TIM2的输出比较通道2

        上述代码为配置TIM2定时器中的输出比较通道2(OC2),每个参数都可以通过跳转定义进行查看含义,实际上还是对对应的寄存器进行的配置,例如PWM模式1是对TIMx_CCMR1的OC1M[2:0]配置为110,具体如下图:

         分别是CCMR1、CCER寄存器,这里就不再展开了,感兴趣的自行查阅手册P292。

        同样的,将上述配置好的结构体用TIM_OC2Init函数进行参数写入寄存器:

        同样,感兴趣的可以跳转到函数定义自行了解。

2.5时钟源的配置

        为什么在这里才对时钟进行配置呢?

        因为配置时钟源会配置参数PSC预分频系数、ARR重装值,这两个值会决定输出比较(OC)的Fre频率、占空比、以及分辨率,所以在结束对输出比较的介绍,接下来介绍对时钟源的配置,这样能够更好的理解这些系数配置意义。

2.5.1内部时钟为时钟源

        首先,一般情况下选择配置内部时钟输入CK_INT,也就是72MHz。

	/*开启时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟
	
	/*配置时钟源*/
	TIM_InternalClockConfig(TIM2);		//选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟
	
	/*时基单元初始化*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;		//时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;	//计数器模式,选择向上计数
	TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;				//计数周期,即ARR的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;				//预分频器,即PSC的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;			//重复计数器,高级定时器才会用到
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);				//将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元	

         对应配置下图中的寄存器:

        然后输入到时基单元,也就是对时基单元的配置:      

        这里对PSC和ARR进行重点展开:

        PSC也就是预分频系数,PSC越大,分频系数越大,相当于分一个蛋糕,系数越大,分成的小蛋糕数量就多,然而我们只能吃一块蛋糕,蛋糕的分量很少,也就对应分出的时钟频率很低。如果分得的小蛋糕数量小,我们吃到的蛋糕就多,也即时钟频率就高。

        而ARR决定了周期T,一个周期是由(默认向上计数)CNT从0到自增到ARR,ARR越大,所需要的事件就越长。这里也进行类比,相当于爬山,ARR越大,山越高,所需要爬行的时间就越多,对应周期就越长;相反ARR越小,山越矮,越容易怕,耗费时间就少,周期就小。

        根据公式CK_CNT = CK_PSC / (PSC + 1)和

                       CK_CNT_OV = CK_CNT / (ARR + 1) = CK_PSC / (PSC + 1) / (ARR + 1)

        根据需求来共同确定。

        例如,CK_PSC为系统时钟72MHz,要求计数器溢出频率为1s,即72MHz / (PSC + 1) / (ARR + 1)=1s,也即(PSC + 1) * (ARR + 1)=72 000 000Hz,ARR和PSC的值是不固定,根据自己的实际需求,如果设置PSC为7200-1,也就是7200预分频,对应ARR为10000-1。

        如果减小PSC,也就获得的蛋糕就越多,也即频率也高,ARR对应的增大,也就是山的高度变高,花费时间更多。通俗的讲,就是用更高的频率计更多的数。

        相应的,增加PSC,减小ARR也就是用更低频率计更少的数,这两种结果都是会使计数器溢出频率为1s。

        相信经过以上的说明,如何来配置PSC和ARR的值应该就有头绪了。

2.5.2外部时钟的配置

	/*开启时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);						//将PA0引脚初始化为上拉输入
	
    /*外部时钟配置*/
	TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x0F);
																//选择外部时钟模式2,时钟从TIM_ETR引脚输入
																//注意TIM2的ETR引脚固定为PA0,无法随意更改
																//最后一个滤波器参数加到最大0x0F,可滤除时钟信号抖动
	
	/*时基单元初始化*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;		//时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;	//计数器模式,选择向上计数
	TIM_TimeBaseInitStructure.TIM_Period = 10 - 1;					//计数周期,即ARR的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;				//预分频器,即PSC的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;			//重复计数器,高级定时器才会用到
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);				//将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元	

        接下来看到两个函数,这两个函数分别配置外部时钟源模式1和外部时钟源模式2:

void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler,         
                             uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);

void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, 
                             uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter)

        可以看到,参数基本上一致,所以接下来只介绍外部时钟源模式2:

        上图为外部时钟源模式2需要经过的路线,也即需要配置的地方。

        首先需要一个外部时钟输入源,接到PA0引脚:

        需要配置对应的GPIO端口。

        然后是对外部时钟源ETR配置的函数

TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted
, 0x0F);
																//选择外部时钟模式2,时钟从TIM_ETR引脚输入

          第一个参数是定时器选择,然后是分频系数选择:

        接着是极性选择,也就是是否需要反向:

        最后是滤波系数,0x00到0x0F,如果对这里疑惑,回到外部时钟源模式2的介绍。

        接下来是对时基单元的配置,根据自己的需求来配置ARR以及PSC,这里是用对射式红外传感器,通过遮挡该传感器,外部时钟ETR就会发送一个脉冲,使得CNT+1,直到CNT加到ARR=10的时候(PSC=1-1),就产生一次更新事件/中断

2.5.3定时器触发的中断函数

	
	/*中断输出配置*/
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);						//清除定时器更新标志位
																//TIM_TimeBaseInit函数末尾,手动产生了更新事件
																//若不清除此标志位,则开启中断后,会立刻进入一次中断
																//如果不介意此问题,则不清除此标志位也可
																
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);					//开启TIM2的更新中断
	
	/*NVIC中断分组*/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				//配置NVIC为分组2
																//即抢占优先级范围:0~3,响应优先级范围:0~3
																//此分组配置在整个工程中仅需调用一次
																//若有多个中断,可以把此代码放在main函数内,while循环之前
																//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
	
	/*NVIC配置*/
	NVIC_InitTypeDef NVIC_InitStructure;						//定义结构体变量
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;				//选择配置NVIC的TIM2线
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;	//指定NVIC线路的抢占优先级为2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//指定NVIC线路的响应优先级为1
	NVIC_Init(&NVIC_InitStructure);								//将结构体变量交给NVIC_Init,配置NVIC外设
	
	/*TIM使能*/
	TIM_Cmd(TIM2, ENABLE);			//使能TIM2,定时器开始运行

        由于定时器触发中断不需要经过EXTI通道(也就是不是从GPIO端口产生的中断),而是TIM定时器更新中断直接内部选择TIM中断通道到NVIC,所以在配置的时候只需要配置TIM到NVIC的通道以及NVIC的配置即可。

        这里解释一下下图的代码:

TIM_ClearFlag(TIM2, TIM_FLAG_Update);                        //清除定时器更新标志位

        对时基单元的配置,也就是TIM_TimeBaseInit函数,在最后有如图一句:

        产生一个更新事件/中断来重装载PSC和重复计数器(只存在高级定时器中)的值,实际上也属于影子寄存器(缓冲寄存器)的功能,内部所执行的过程。

        产生中断即会置中断标志位,这样就会导致,刚初始化完时基单元机会进入一次中断,这样是不可取的,所以需要清除中断函数标志位。

        然后使能TIM2通道的中断,然会对NVIC配置的时候中断通道选择TIM2_IRQn即可,最后在开启一下TIM2定时器。

        最后根据自己的需求来配置中断函数执行的内容。

        需要注意一点:当需要将TIM定时器产生的PWM输出至片外外设,也就是GPIO端口接通的外设,如LED。

        需要配置GPIO端口为复用开漏/推挽输出,因为正常模式(除复用模式)下GPIO端口的输出控制是由输出数据寄存器ODR来控制的,需要在复用模式下,才能够输出片上外设TIM定时器产生的PWM。

2.6时钟的输入捕获Intput Capture

        输入捕获也即左边的电路,输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数。

        每个高级定时器和通用定时器都拥有4个输入捕获通道 可配置为PWMI模式,同时测量频率和占空比,可配合主从触发模式,实现硬件全自动测量。

2.6.1测频法和测周法

        首先需要明确频率f=1/T,也就1s内有多少个重复的周期,频率就为多少,接下来介绍两种常用的测量频率的方法:

        ,对T闸门时间内对重复的上升沿进行计次,类似的如果采样在2s内的周期频率,也就是T=2,就对该频率进行除2即可得到标准1s内的频率。

        测法,在两个连续的上升沿之间以标准频率fc计次N下,即可得到频率,利用了周期的倒数就是频率。

        这两种法方法分别运用于高频和低频之中,计算出中界频率fm,如果频率大于fm则使用测频法,如果低于fm则使用测周法。

        需要注意在输入捕获配置的时候,需要将ARR调整至最大值也就是65536,当标准频率fc=1MHz的时候,所测得最低的频率是1MHz/65536=15Hz,也就是说,如果信号源低于15Hz时,计数器频率就会溢出,所以ARR的值是尽量设置最大。

2.6.2输入捕获的内部结构

        上图为输入捕获通道的结构图。

·        在CCMR1寄存器中,不仅包含输入捕获控制的16位、同样也包含输出比较控制的16位,即使该寄存器只有16位,在两种模式下展现出截然不同的功能,这里需要注意。

       频率的选择参考外部时钟源模式2的ETR输入滤波电路:

        然后是极性选择在CCER寄存器中的CC1P位,选择是上升沿触发还是下降沿触发:

          同时可以发现通道1的TI2FP2和通道2的TI2FP1都输入到数据选择器的CCMR1中的CC1S中:

        同样的,在通道2中的数据选择器中,通道2的TI2FP2和通道1的TI2FP2都输入到其中:

结合起来如下图:

         其中异或门是为三项无刷电机的使用而存在的,这里不进行介绍。       

        下图为CH1引脚输出的TI1FP1、TI1FP2以及CH2引脚输出的TI1FP1、TI1FP2,分别交叉输出值IC1通道和IC2通道,这样输出由两个好处:

        可以灵活切换数据电路的捕获输入,如果一会想以CH1进行输入,一会想以CH2进行输入,就可以通过数据选择器来进行切换数据源的输入。

        第二个,也是最主要的,就是把一个输入映射到两个捕获单元(两个捕获寄存器RCC),第一个捕获通道使用上升沿触发来捕获周期,第二个捕获用到使用下降沿来捕获占空比,两个通道同时对一个引脚进行捕获,这样就可以同时对占空比和频率进行计算(PWMI的经典结构)。

        可以看到数据选择器还有一个TRC进行输入,该选项是为三项无刷电机的使用而存在的,这里不进行介绍。       

        然后分别经过预分频器:

        以及捕获使能位:

        信号从PSC预分频器输出之后就可以触发捕获电路进行捕获操作,每来一个信号,CNT的值就向CCR内转运,也即存储到CCR,同时会产生一个捕获事件/中断,可以在捕获时,用中断发生某些事情。

        例如,配置一个上升沿捕获触发捕获输入,每来一个上升沿,转运CNT至CCR,同时CNT又是由内部的标准时钟驱动的,所以可以来记录两个上升沿的时差,使用测周法,从而得到频率。

        所以就是,上升沿触发输入捕获,CNT用于计时作用,同时每次捕获后,都要将CNT进行清0,可通过主从触发输入模式来自动对CNT进行清0。

        可以通过主从模式来完成一些自动化的操作,例如在捕获后自动对CNT进行清0,接下里就对主从模式进行介绍。

2.6.3主从模式触发

        主从触发模式实际上是主模式、从模式以及触发源选择这三个功能的简称。                

        其中主模式可以将定时器内部的信号,映射到TRGO引脚,用于触发别的外设,所以叫做主模式。

        而从模式就是接收其他外设或者自身外设的一些信号,用于控制自身定时器的运行,也就是被别的信号控制,所以叫做从模式。

        而触发源选择就是选择从模式的触发信号源的,可以认为从模式的一部分,选择指定的一个信号TRGI,然后TRGI去触发从模式,而从模式可以在从模式列表中选择一项操作来自动执行,这样就实现了自动化的操作。

        例如,上面我们想要输入捕获后让CNT清0,如下图TI1FP1输出至从模式。

        使用框图表示就是:

        从模式对应前面SMCR寄存的SMS[2:0]位:

        对应配置从模式函数:

        主模式则对应TIMx_CR2寄存器中的MMS[2:0]位:

        对应配置从模式函数:

        同样的触发源选择对应:

        函数对应:

        这样使用主从触发模式,就能够减少捕获带后频繁进入中断从而消耗的软件资源,以上就是对主从触发模式的介绍了。

2.6.4捕获输入的配置

        在测周法中fc的标准频率就为72MHz/(PSC+1)。

        在上图中:CH1通道在边沿检测后输出两个信号TI1FP1输出到通道一,同时还输出到触发源选择中,这样就能实现主从模式,在设置从模式位Reset这样就能够在输入捕获后自动清除CNT的值,第二个输出TI1FP2输出到通道2。

        接下来根据左上角波形图来了解:

        首先,CNT等于0时刻,上升沿,将CCR1

(通道1的捕获寄存器)的值=CNT=0。

        然后CNT经过一段事件进入到下降沿,此时将CNT的值(高电平持续的事件)赋值给CCR2(通道2的捕获寄存器)。

        CNT再次经过一段时间后,将进入上升沿,将CNT的值赋给CCR1,此时CCR1的值就是一个周期。

        这样只需要CCR2/CCR1就可以得到占空比,同时根据ARR可以计算出频率。

	/*开启时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);							//将PA6引脚初始化为上拉输入

        首先开启对应的时钟,然对应的配置输入捕获的通道,也就是TIM2定时的CH1输入:

        对应端口PA0,所以要初始化PA0端口。

        接着配置TIM2定时器:

	
	/*配置时钟源*/
	TIM_InternalClockConfig(TIM3);		//选择TIM3为内部时钟,若不调用此函数,TIM默认也为内部时钟
	
	/*时基单元初始化*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
	TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;               //计数周期,即ARR的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;               //预分频器,即PSC的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器,高级定时器才会用到
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);             //将结构体变量交给TIM_TimeBaseInit,配置TIM3的时基单元

       这里需要注意ARR和PSC的值,ARR的值设置为最大,是为了让CNT多计一些数,能够减小误差,通防止计数值溢出。同时PSC预分频系数也决定着fc标准频率的大小:

                                                fc=CK_INT/(PSC+1)

        这样就配置好了时基单元,接下来配置输入捕获:
 

	/*输入捕获初始化*/
	TIM_ICInitTypeDef TIM_ICInitStructure;							//定义结构体变量
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;				//选择配置定时器通道1
	TIM_ICInitStructure.TIM_ICFilter = 0x0F;							//输入滤波器参数,可以过滤信号抖动
	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;		//极性,选择为上升沿触发捕获
	TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;			//捕获预分频,选择不分频,每次信号都触发捕获
	TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;	//输入信号交叉,选择直通,不交叉
	TIM_ICInit(TIM3, &TIM_ICInitStructure);							//将结构体变量交给TIM_ICInit,配置TIM3的输入捕获通道
	
	/*选择触发源及从模式*/
	TIM_SelectInputTrigger(TIM2, TIM_TS_TI1FP1);					//触发源选择TI1FP1
	TIM_SelectSlaveMode(TIM2 TIM_SlaveMode_Reset);					//从模式选择复位
																	//即TI1产生上升沿时,会触发CNT归零
	
	/*TIM使能*/
	TIM_Cmd(TIM2, ENABLE);			//使能TIM3,定时器开始运行

              同样是对TIM_ICInitTypeDef结构体变量进行写入参数,选择CH1通道,滤波选择0x0F,极性为上升沿触发,选择不分频,这里对TIM_ICSelection解释一下:

        参数列表如下,实际上是配置数据选择器的。

        选择TIM_ICSelection_IndirectTI,可以令TI1FP1交叉进入IC2,也可以选择TIM_ICSelection_DirectTI,TI1FP1直接进入IC1中经过PSC预分频器触发输入捕获功能。

        另外TRC输入是配合在无刷电机上的,有需要的可以了解。

        最后在配置一下从模式,也就是之前提到的那三个主从模式的函数,最后使能TIM2即可。

        以上就是输入捕获配置的全部介绍了,如果在上述没有找到需要的配置,可以自行查阅手册及固件库。

3.TIM编码器计次

        可以使用中断函数来对编码器进行计次,但是这样会占用CPU大量时间,所以在TIM的定时器中就包含对编码器计次的功能。编码器通常在电机模块比较常见,霍尔编码器就可以用来测速,从而来调节转速。

        上图是编码器的通路情况。

        Encoder Interface 编码器接口,编码器接口可接收增量(正交)编码器的信号,根据编码器旋转产生的正交信号脉冲,自动控制CNT自增或自减,从而指示编码器的位置、旋转方向和旋转速度。

        每个高级定时器和通用定时器都拥有1个编码器接口 两个输入引脚借用了输入捕获的通道1和通道2,在使用编码器测速的时候,需要注意以下资源分配。

        对于编码器都需要分明是正转还是反转,这里对正交编码器(AB两相相差90°的编码器)进行展开说明 :

        有两种说法:A超前B 90°(产生上升沿相位差90°),说明是正转(逆时针);

                              B超前A 90°(产生上升沿相位差90°),说明是反转(顺时针);

        还有一种说法是:当A相上升沿时B相低电平,A相下降沿时B相高电平都为正传,就是上图右边的两个小表格。

        对正交编码器进行测速大概原理是:当编码器进行正转10个脉冲停下来,CNT则会从0自增到10停下来。若先向正传10个脉冲然后立刻左转5个脉冲,则CNT就会从0自增到5,该编码器是会分明方向的,正转++,反转--,可以把转动的脉冲想象成一个动态的ARR重装值。每隔一段时间取出CNT的值,就可以知道编码器的速度。

3.1编码器的三种计数模式

        选择编码器接口模式的方法是:如果计数器只在TI2 的边沿计数,则置TIMx_SMCR寄存器中的SMS=001;如果只在TI1边沿计数,则置SMS=010;如果计数器同时在TI1TI2边沿计数,则
SMS=011
        下图是编码器的工作模式:
        这里对这三种计数模式进行介绍,如TI1FP1信号接入的是A相,而TI1FP2信号接入的是B相:
        首先是仅在TI1上计数:
        
        结果如下
        对应产生脉冲的时序:
        类似的仅在TI2上计数:
        同样的在TI1和TI2上计数:
        
        可以看到在TI1和TI2上计次精度更高,所以一般会选择在TI1和TI2上计数。
        更多的还可以参照手册上给的例子:
        上图对照下图正转反转的两个小表格,即可得到如上图阶梯状的波形。
        毛刺在TI1和TI2计数模式下就会被消除,这样显得波形更加稳定,可靠。

3.2编码器的配置

        由下图的流程来对编码器进行配置:

             需要注意的是输入端CH1和CH2对应的默认服用功能引脚不要搞错了,例如TIM3的:

        对应PA6和PA7引脚。

	/*开启时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);			//开启TIM3的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);							//将PA6和PA7引脚初始化为上拉输入

        然后是时基单元初始化,对于ARR以及PSC也是遵循输入捕获的原则(测周法):

	/*时基单元初始化*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
	TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;               //计数周期,即ARR的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;                //预分频器,即PSC的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器,高级定时器才会用到
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);             //将结构体变量交给TIM_TimeBaseInit,配置TIM3的时基单元
	

        最后是输入捕获

	/*输入捕获初始化*/
	TIM_ICInitTypeDef TIM_ICInitStructure;							//定义结构体变量
	TIM_ICStructInit(&TIM_ICInitStructure);							//结构体初始化,若结构体没有完整赋值
																	//则最好执行此函数,给结构体所有成员都赋一个默认值
																	//避免结构体初值不确定的问题
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;				//选择配置定时器通道1
	TIM_ICInitStructure.TIM_ICFilter = 0xF;							//输入滤波器参数,可以过滤信号抖动
	TIM_ICInit(TIM3, &TIM_ICInitStructure);							//将结构体变量交给TIM_ICInit,配置TIM3的输入捕获通道
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;				//选择配置定时器通道2
	TIM_ICInitStructure.TIM_ICFilter = 0xF;							//输入滤波器参数,可以过滤信号抖动
	TIM_ICInit(TIM3, &TIM_ICInitStructure);							//将结构体变量交给TIM_ICInit,配置TIM3的输入捕获通道
	
	/*编码器接口配置*/
	TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
																	//配置编码器模式以及两个输入通道是否反相
																	//注意此时参数的Rising和Falling已经不代表上升沿和下降沿了,而是代表是否反相
																	//此函数必须在输入捕获初始化之后进行,否则输入捕获的配置会覆盖此函数的部分配置
	
	/*TIM使能*/
	TIM_Cmd(TIM3, ENABLE);			//使能TIM3,定时器开始运行

        上面配置了两个通道分别是CH1和CH2对应A、B相,这样要传入两次结构体参数,同时可以发现并没有配置极性选择在结构体中,因为在下面编码器接口的配置函数中,会配置到极性选择,选择是否需要反转。

        可以看到,后两个参数分别是对两个通道的极性选择极性配置,对应前面的三种编码器输出模式。

        最后使能时钟TIM3即可。

4.总结

        在编写本篇文章时,毫无头绪,虽然先前以及学习过一边TIM定时器的知识,几个礼拜不到,竟然无从下手,一度想要放弃写本章的内容,太过复杂繁琐。在经过了半天是思想斗争,最终还是写下此片文章。历经九九八十一难,总归是写完了。

        这里需要声明,本片文章,代码思路大部分来自于江科大,很厉害的一位up主,最后欢迎各位的讨论和指正。

文章参考:[6-8] 编码器接口测速_哔哩哔哩_bilibili

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值