zoukankan      html  css  js  c++  java
  • 11-STM32 高级定时器TIM1/8

    高级定时器

    高级控制定时器(TIM1 和 TIM8)和通用定时器在基本定时器的基础上引入了外部引脚,可以实现输入捕获输出比较功能。
    高级控制定时器比通用定时器增加了可编程死区互补输出、重复计数器、带刹车(断路)功能,这些功能都是针对工业电机控制方面。
    高级控制定时器时基单元包含:
    ①16 位自动重装载寄存器ARR,
    ②16 位的计数器CNT,可向上/下计数
    ③16位可编程预分频器 PSC,预分频器时钟源有多种可选,有内部的时钟、外部时钟

    ④还有一个 8 位的重复计数器 RCR,这样最高可实现 40 位的可编程定时(仅高级定时器独有)

    功能框图:

     

    高级定时器的定时器的时钟来源(有四个时钟来源):

    内部时钟源 CK_INT

    外部时钟模式 1:外部输入引脚 TIx(x=1,2,3,4)

    外部时钟模式 2:外部触发输入 ETR

    内部触发输入(ITRx)

    高级定时器时钟挂载在APB2上

     1)内部时钟源CK_INT    内部时钟 CK_INT来自于芯片内部,等于72M(一般情况下,我们都是使用内部时钟

    对应于寄存器配置位

    当从模式控制寄存器 TIMx_SMCR 的 SMS 位等于 000 时,则使用内部时钟。

    2)外部时钟模式 1:外部输入引脚 TIx(x=1,2,3,4)                     

    ①:时钟信号输入引脚

    当使用外部时钟模式 1 的时候,时钟信号来自于定时器的输入通道,总共有 4 个,分别为TI1/2/3/4,即TIMx_CH1/2/3/4。具体使用哪一路信号,由TIM_CCMRx的位CCxS[1:0]配置,其中 CCMR1 控制 TI1/2,CCMR2 控制 TI3/4。

    ②:滤波器

    如果来自外部的时钟信号的频率过高或者混杂有高频干扰信号的话,我们就需要使用滤波器对信号重新采样,来达到降频或者去除高频干扰的目的,具体的由 TIMx_CCMRx的位 ICxF[3:0]配置。

    ③:边沿检测

    边沿检测的信号来自于滤波器的输出,在成为触发信号之前,需要进行边沿检测,决定是上升沿有效还是下降沿有效,具体的由 TIMx_CCER的位 CCxP 和 CCxNP 配置。

    ④:触发选择

    当使用外部时钟模式 1时,触发源有两个,一个是滤波后的定时器输入 1(TI1FP1)和滤波后的定时器输入 2(TI2FP2),具体的由TIMxSMCR 的位 TS[2:0]配置。

    ⑤:从模式选择

    选定了触发源信号后,最后我们需把信号连接到 TRGI 引脚,让触发信号成为外部时钟模式1的输入,最终等于CK_PSC,然后驱动计数器CNT计数。具体的配置TIMx_SMCR的位 SMS[2:0]为 111 即可选择外部时钟模式 1。

    ⑥:使能计数器

    经过上面的 5 个步骤之后,最后我们只需使能计数器开始计数,外部时钟模式 1 的配置就算完成。使能计数器由 TIMx_CR1 的位 CEN 配置。

    3)外部时钟模式 2:外部触发输入 ETR

     

    ①:时钟信号输入引脚

     当使用外部时钟模式 2 的时候,时钟信号来自于定时器的特定输入通道 TIMx_ETR,只有 1 个。

    ②:外部触发极性

    来自 ETR 引脚输入的信号可以选择为上升沿或者下降沿有效,具体的由 TIMx_SMCR的位 ETP 配置。

    ③:外部触发预分频器

    由于ETRP 的信号的频率不能超过 TIMx_CLK(72M)的 1/4,当触发信号的频率很高的情况下,就必须使用分频器来降频,具体的由 TIMx_SMCR 的位 ETPS[1:0]配置。

     ④:滤波器

    如果 ETRP 的信号的频率过高或者混杂有高频干扰信号的话,我们就需要使用滤波器对 ETRP 信号重新采样,来达到降频或者去除高频干扰的目的。具体的由 TIMx_SMCR 的位 ETF[3:0]配置,其中的 fDTS 是由内部时钟 CK_INT 分频得到,具体的由 TIMx_CR1的位CKD[1:0]配置。

    ⑤:从模式选择

    经过滤波器滤波的信号连接到ETRF引脚后,触发信号成为外部时钟模式2的输入,最终等于CK_PSC,然后驱动计数器 CNT 计数。具体的配置TIMx_SMCR 的位 ECE 为 1 即可选择外部时钟模式 2。

    ⑥:使能计数器

    经过上面的 5 个步骤之后,最后我们只需使能计数器开始计数,外部时钟模式 2 的配置就算完成。使能计数器由 TIMx_CR1 的位 CEN 配置。

    4)内部触发输入

    内部触发输入是使用一个定时器作为另一个定时器的预分频器。硬件上高级控制定时器和通用定时器在内部连接在一起,可以实现定时器同步或级联。主模式的定时器可以对从模式定时器执行复位、启动、停止或提供时钟。

    控制器:

    高级控制定时器控制器部分包括触发控制器、从模式控制器以及编码器接口。触发控制器用来针对片内外设输出触发信号,比如为其它定时器提供时钟和触发 DAC/ADC 转换。 编码器接口专门针对编码器计数而设计。从模式控制器可以控制计数器复位、启动、递增/递减、计数。

     

    时基单元:

     

    高级控制定时器时基单元功能包括四个寄存器,分别是计数器寄存器(CNT)、预分频器寄存器(PSC)、自动重载寄存器(ARR)和重复计数器寄存器(RCR)

    预分频器 PSC 

    预分频器 PSC,有一个输入时钟 CK_PSC 和一个输出时钟 CK_CNT。输入时钟CK_PSC 就是上面时钟源的输出,输出 CK_CNT 则用来驱动计数器 CNT 计数。通过设置预分频器 PSC 的值可以得到不同的 CK_CNT,实际计算为:f CK_CNT 等于 f CK_PSC /(PSC[15:0]+1),可以实现 1 至 65536 分频。

    计数器 CNT 

    高级控制定时器的计数器有三种计数模式,分别为递增计数模式、递减计数模式和递增/递减(中心对齐)计数模式。

    (1) 递增计数模式下,计数器从 0 开始计数,每来一个 CK_CNT 脉冲计数器就增加 1,直到计数器的值与自动重载寄存器 ARR 值相等,然后计数器又从 0 开始计数并生成计数器上溢事件,计数器总是如此循环计数。如果禁用重复计数器,在计数器生成上溢事件就马上生成更新事件(UEV);如果使能重复计数器,每生成一次上溢事件重复计数器内容就减 1,直到重复计数器内容为 0 时才会生成更新事件。 

    (2) 递减计数模式下,计数器从自动重载寄存器 ARR 值开始计数,每来一个 CK_CNT 脉冲计数器就减 1,直到计数器值为 0,然后计数器又从自动重载寄存器 ARR 值开始递减计数并生成计数器下溢事件,计数器总是如此循环计数。如果禁用重复计数器,计数器生成下溢事件就马上生成更新事件;如果使能重复计数器,每生成一次下溢事件重复计数器内容就减 1,直到重复计数器内容为 0 时才会生成更新事件。 

    (3) 中心对齐模式下,计数器从 0 开始递增计数,直到计数值等于(ARR-1)值生成计数器上溢事件,然后从 ARR 值开始递减计数直到 1 生成计数器下溢事件。然后又从 0 开始计数,如此循环。每次发生计数器上溢和下溢事件都会生成更新事件。 

     

    自动重载寄存器 ARR  

    自动重载寄存器 ARR 用来存放与计数器 CNT 比较的值,如果两个值相等就递减重复计数器。可以通过 TIMx_CR1寄存器的 ARPE位控制自动重载影子寄存器功能

    如果 ARPE位置 1,自动重载影子寄存器有效,只有在事件更新时才把 TIMx_ARR 值赋给影子寄存器。

    如果 ARPE 位为 0,则修改 TIMx_ARR 值马上有效。 

      

    重复计数器 RCR 

    在基本/通用定时器发生上/下溢事件时直接就生成更新事件,但对于高级控制定时器却不是这样,高级控制定时器在硬件结构上多出了重复计数器,在定时器发生上溢或下溢事件是递减重复计数器的值,只有当重复计数器为 0 时才会生成更新事件。在发生 N+1 个上溢或下溢事件(N 为 RCR 的值)时产生更新事件。

     

    输入捕获功能:

    可以对输入的信号的上升沿,下降沿或者双边沿进行捕获。

    1)测量输入信号的脉宽

    2)测量PWM输入信号的频率和占空比 

    输入捕获的大概的原理:

    当捕获到信号的跳变沿的时候,把计数器 CNT 的值锁存到捕获寄存器 CCR 中,把前后两次捕获到的 CCR 寄存器中的值相减,就可以算出脉宽或者频率。(如果捕获的脉宽的时间长度>你的捕获定时器的周期,就会发生溢出,这个需要做额外的处理)

             

    ①输入通道(脉冲信号输入)    

    需要被测量的信号从定时器的外部引脚 TIMx_CH1/2/3/4 进入,通常叫 TI1/2/3/4   

    ②输入滤波器和边沿检测器 

    当输入的信号存在高频干扰的时候,我们需要对输入信号进行滤波,即进行重新采样,根据采样定律,采样的频率必须大于等于两倍的输入信号。比如输入的信号为 1M,又存在高频的信号干扰,那么此时就很有必要进行滤波,我们可以设置采样频率为 2M,这样可以在保证采样到有效信号的基础上把高于 2M 的高频干扰信号过滤掉。 滤波器的配置由 CR1 寄存器的位 CKD[1:0]和 CCMR1/2 的位 ICxF[3:0]控制。从 ICxF位的描述可知,采样频率 f SAMPLE 可以由 f CK_INT 和 f DTS 分频后的时钟提供,其中是 f CK_INT 内部时钟,f DTS 是 f CK_INT 经过分频后得到的频率,分频因子由 CKD[1:0]决定,可以是不分频,2 分频或者是 4 分频。

          

          

           边沿检测器用来设置信号在捕获的时候是什么边沿有效,可以是上升沿,下降沿,或者是双边沿,具体的由 CCER 寄存器的位 CCxP 和 CCxNP 决定。 

          

    ③捕获通道 

    捕获通道就是图中的 IC1/2/3/4,每个捕获通道都有相对应的捕获寄存器 CCR1/2/3/4,当发生捕获的时候,计数器 CNT 的值就会被锁存到捕获寄存器中。 

    输入通道和捕获通道的区别:输入通道是用来输入信号的,捕获通道是用来捕获输入信号的通道,一个输入通道的信号可以同时输入给两个捕获通道。比如输入通道 TI1 的信号经过滤波边沿检测器之后的 TI1FP1 和 TI1FP2 可以进入到捕获通道 IC1和 IC2,其实这就是我们后面要讲的 PWM 输入捕获,只有一路输入信号(TI1)却占用了两个捕获通道(IC1 和 IC2)。当只需要测量输入信号的脉宽时候,用一个捕获通道即可。输入通道和捕获通道的映射关系具体由寄存器 CCMRx 的位 CCxS[1:0]配置。 

          

         

            ④预分频器 

            ICx 的输出信号会经过一个预分频器,用于决定发生多少个事件时进行一次捕获。具体的由寄存器 CCMRx 的位 ICxPSC 配置,如果希望捕获信号的每一个边沿,则不分频。 

          

    ⑤捕获寄存器 

    经过预分频器的信号 ICxPS 是最终被捕获的信号,当发生捕获时(第一次),计数器CNT 的值会被锁存到捕获寄存器 CCR 中,还会产生 CCxI 中断,相应的中断位 CCxIF(在SR 寄存器中)会被置位,通过软件或者读取 CCR 中的值可以将 CCxIF清 0。如果发生第二次捕获(即重复捕获:CCR 寄存器中已捕获到计数器值且 CCxIF 标志已置 1),则捕获溢出标志位 CCxOF(在 SR 寄存器中)会被置位,CCxOF 只能通过软件清零。

                 

    输出比较功能:      

       

    输出比较就是通过定时器的外部引脚对外输出控制信号,有冻结、将通道 X(x=1,2,3,4)设置为匹配时输出有效电平、无效电平、翻转、强制变为无效电平、强制变为有效电平、PWM1 和 PWM2 这八种模式,具体使用哪种模式由寄存器 CCMRx 的位 OCxM[2:0]配置。其中 PWM 模式是输出比较中的特例,使用的也最多。

      

    ①比较寄存器    

    计数器 CNT 的值跟比较寄存器 CCR 的值相等的时候,输出参考信号 OCxREF 的信号的极性就会改变,其中 OCxREF=1(高电平)称之为有效电平,OCxREF=0(低电平)称之为无效电平,并且会产生比较中断 CCxI,相应的标志位 CCxIF(SR 寄存器中)会置位。然后 OCxREF 再经过一系列的控制之后就成为真正的输出信号 OCx/OCxN。        

    ②死区发生器 

    在生成的参考波形 OCxREF 的基础上,可以插入死区时间,用于生成两路互补的输出信号 OCx 和 OCxN,死区时间的大小具体由 BDTR 寄存器的位 DTG[7:0]配置。死区时间的大小必须根据与输出信号相连接的器件及其特性来调整。

    MOS开关和关闭需要时间-->(由 MOS 管的工艺决定)

     

    在这个半桥驱动电路中,如果想让 Q1 截止 Q2 导通,要先让Q1 截止一段时间之后,再等一段时间才让 Q2 导通,那么这段等待的时间就称为死区时间,如果 Q1 关闭之后,马上打开 Q2,那么此时一段时间内相当于 Q1 和 Q2 都导通了,这样电路会短路。

    针对上面的半桥驱动电路而画的带死区插入的 PWM 信号,图中的死区时间要根据 MOS 管的工艺来调节:

     

    ③输出控制 

     

    在输出比较的输出控制中,参考信号OCxREF在经过死区发生器之后会产生两路带死区的互补信号 OCx_DT 和 OCxN_DT(通道 1~3 才有互补信号,通道4没有,其余跟通道1~3 一样),这两路带死区的互补信号然后就进入输出控制电路,如果没有加入死区控制,那么进入输出控制电路的信号就直接是OCxREF。 

    进入输出控制电路的信号会被分成两路,一路是原始信号,一路是被反向的信号,具体的由寄存器 CCER 的位 CCxP 和 CCxNP 控制。经过极性选择的信号是否由 OCx 引脚输出到外部引脚 CHx/CHxN 则由寄存器 CCER 的位 CxE/CxNE 配置。 如果加入了断路(刹车)功能,则断路和死区寄存器 BDTR 的 MOE、OSSI和 OSSR 这三个位会共同影响输出的信号。 

    ④输出引脚 

    输出比较的输出信号最终是通过定时器的外部 IO 来输出的,分别为 CH1/2/3/4,其中前面三个通道还有互补的输出通道 CH1/2/3N

     

     

    断路功能: 就是电机控制的刹车功能。

    使能断路功能时,根据相关控制位状态修改输出信号电平。在任何情况下,OCx 和 OCxN 输出都不能同时为有效电平,这关系到电机控制常用的 H 桥电路结构原因。 

     

    断路源可以是时钟故障事件,由内部复位时钟控制器中的时钟安全系统(CSS)生成,也可以是外部断路输入 IO,两者是或运算关系。 系统复位启动都默认关闭断路功能,将断路和死区寄存器(TIMx_BDTR)的 BKE 为置 1,使能断路功能。可通过 TIMx_BDTR 寄存器的 BKP 位设置设置断路输入引脚的有效电平,设置为 1 时输入 BRK 为高电平有效,否则低电平有效。 

    发送断路时,将产生以下效果:

    ①TIMx_BDTR寄存器中主输出模式使能(MOE)位被清零,输出处于无效、空闲或复位状态; 

    ②根据相关控制位状态控制输出通道引脚电平;当使能通道互补输出时,会根据情况自动控制输出通道电平; 

    ③将TIMx_SR寄存器中的BIF位置 1,并可产生中断和DMA传输请求。 

    ④如果TIMx_BDTR寄存器中的自动输出使能(AOE)位置1,则MOE位会在发生下一个UEV事件时自动再次置 1。

    结构体:

    时基结构体

    1 1 typedef struct
    2 2 {
    3 3   uint16_t TIM_Prescaler;          //16位   预分频值                                
    4 4   uint16_t TIM_CounterMode;   //计数模式(向上、向下...)    基本定时器只能向上,故不用设置                              
    5 5   uint16_t TIM_Period;              //16位  定时器周期        ARR自动重装值        
    6 6   uint16_t TIM_ClockDivision;       //时钟分频 设置定时器时钟 CK_INT 频率与数字滤波器采样时钟频率分频比,基本定时器没有此功能,不用设置                 
    7 7   uint8_t TIM_RepetitionCounter; //重复计数器,只有TIM1和TIM8才有  利用它可以非常容易控制输出 PWM 的个数
    8 8                                        
    9 9 } TIM_TimeBaseInitTypeDef; 

    输出比较结构体

     1 typedef struct
     2 {
     3   uint16_t TIM_OCMode;        //比较输出模式选择,总共有八种,常用的为 PWM1/PWM2。它设定CCMRx 寄存器 OCxM[2:0]位的值                               
     4   uint16_t TIM_OutputState;  //比较输出使能,决定最终的输出比较信号 OCx 是否通过外部引脚输出
     5   uint16_t TIM_OutputNState;  //比较互补输出使能,决定 OCx 的互补信号 OCxN 是否通过外部引脚输出
     6   uint16_t TIM_Pulse;       //比较输出脉冲宽度,实际设定比较寄存器 CCR 的值,决定脉冲宽度。可设置范围为 0 至 65535
     7   uint16_t TIM_OCPolarity;    //比较输出极性,可选 OCx 为高电平有效或低电平有效。它决定着定时器通道有效电平
     8   uint16_t TIM_OCNPolarity; // 比较互补输出极性,可选 OCxN 为高电平有效或低电平有效
     9   uint16_t TIM_OCIdleState;   //空闲状态时通道输出电平设置,可选输出 1 或输出 0
    10   uint16_t TIM_OCNIdleState;  //空闲状态时互补通道输出电平设置,可选输出 1 或输出 0
    11 } TIM_OCInitTypeDef;    

    带死区和刹车功能的互补输出实验:

     1 void PWM_OC_IN(void)
     2 {
     3   GPIO_InitTypeDef          GPIO_InitStructure;
     4     TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;
     5     TIM_OCInitTypeDef         TIM_OCInitStructure;
     6     TIM_BDTRInitTypeDef       TIM_BDTRInitStructure;
     7     
     8     
     9     //时钟配置
    10     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);// 默认复用
    11     
    12     
    13     //复用管脚配置--输出比较通道
    14     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; 
    15     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出模式
    16     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  //输出速度频率 
    17     GPIO_Init(GPIOA, &GPIO_InitStructure);   //GPIOA
    18     
    19     //输出比较通道互补通道初始化
    20     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; 
    21     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出模式
    22     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  //输出速度频率 
    23     GPIO_Init(GPIOB, &GPIO_InitStructure);   //GPIOB
    24     
    25     //输出比较通道刹车通道
    26     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; 
    27     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出模式
    28     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  //输出速度频率 
    29     GPIO_Init(GPIOB, &GPIO_InitStructure);   //GPIOB
    30     GPIO_ResetBits(GPIOB,GPIO_Pin_12);//默认输出低电平
    31     
    32     
    33      //时基配置
    34     TIM_TimeBaseStructure.TIM_Prescaler = 0;   //预分频 --72MHZ来驱动
    35     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
    36     TIM_TimeBaseStructure.TIM_Period = 7199;     //TimerPeriod;    //ARR (占空比CCR/AAR)10kHz
    37     TIM_TimeBaseStructure.TIM_ClockDivision = 0;   //定时器滤波,通常为0,这里死区时间用到
    38     TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;//配置寄存器TIM_RCR(重复次数寄存器) 
    39     TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
    40     
    41     
    42     
    43      //输出比较功能配置
    44     TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;    //pwm1模式
    45     TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//比较输出使能
    46     TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;//比较输出互补输出使能
    47     TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//!!!!!!高电平有效!!!!!
    48     TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;//!!!!!!高电平有效!!!!!
    49     TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;//经死区后输出高电平
    50     TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;//经死区后输出低电平
    51     TIM_OCInitStructure.TIM_Pulse = 1500;   //Channel1Pulse(CCR);
    52     TIM_OC1Init(TIM1, &TIM_OCInitStructure); //通道1
    53     
    54     //使能TIM的ARR和CRR,以及使能TIM定时器,开启pwm输出
    55     TIM_ARRPreloadConfig(TIM1, ENABLE);                 //使能TIM1的寄存器ARR的预装载功能,disable时将会使改变ARR值时立即生效
    56     TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);  //使能TIM1通道1的CCR的预装载功能,disable时将会使改变CRR值时立即生效
    57     
    58      
    59      //刹车和死区结构体初始化
    60   TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;//运行状态下关闭状态选择
    61   TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;//空闲状态下关闭状态选择
    62   TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;//锁定配置级别
    63   TIM_BDTRInitStructure.TIM_DeadTime = 11;  //输出比较信号死区时间配置,具体如何计算可参考BDTR:UTG[7:0]的描述
    64                                              //这里配置的死区时间为152ns
    65   TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;//断路控制使能
    66   //当BKIN引脚--PB12检测到高电平时,输出比较信号被禁止,就好像是刹车一样
    67   TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;//断路输入极性-高电平
    68   TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;//自动输出使能
    69   TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);
    70     
    71     
    72   TIM_Cmd(TIM1, ENABLE);//计数使能
    73   TIM_CtrlPWMOutputs(TIM1, ENABLE);//主输出使能,当使用的是通用定时器时,这句话不要
    74 
    75 }

    输出捕获实验:

      1 /*******************************************************************
      2   *@使用TIM5的输入捕获功能进行按键按下的时间---高电平的时间(按键下拉)
      3   *@输入捕获引脚--PA0  5   *@注意:这里的溢出中断和捕获中断属于不同的两个中断
      8 *******************************************************************/
      9 
     10 
     11 //定时器输入捕获用户自定义变量结构体声明
     12 typedef struct 
     13 {
     14    u8  Capture_FinishFlag;  //捕获结束标志位
     15    u8  Capture_StartFlag;  //捕获开始标志位
     16    u16 Capture_CcrValue; //捕获寄存器的值
     17    u16 Capture_Period;   //自动重装载寄存器更新标志
     18 }TIM_ICUserValueTypeDef;
     20 TIM_ICUserValueTypeDef  TIM_ICUserValueStructure;//结构体初始化
     21 
     22 void GET_PluseWidth(void)
     23 {
     24   GPIO_InitTypeDef          GPIO_InitStructure;
     25   TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;
     26   TIM_ICInitTypeDef         TIM_ICInitStructure;
     27   NVIC_InitTypeDef          NVIC_InitStructure;
     28     
     29     //RCC configuration
     30     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
     31     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);
     32     
     33     //GPIO configuration
     34     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; 
     35     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入模式
     36     GPIO_Init(GPIOA, &GPIO_InitStructure);   //GPIOA
     37     
     38     
     39      //值得注意的是input capture period(1us*(65535+1)=65.536ms) > 捕获脉宽的时间,当小于时会溢出,需额外处理
     40     TIM_TimeBaseStructure.TIM_Prescaler = 72-1;   //预分频 --1MHZ来驱动
     41     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
     42     TIM_TimeBaseStructure.TIM_Period =0xFFFF;     //TimerPeriod;    //ARR 
     43     TIM_TimeBaseStructure.TIM_ClockDivision = 0;   //定时器滤波,通常为0
     44     TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;//配置寄存器TIM_RCR(重复次数寄存器) 
     45     TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
     46     
     47     //中断优先级配置
     48     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
     49     NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
     50     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0;
     51     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //响应优先级
     52     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
     53     NVIC_Init(&NVIC_InitStructure);
     54     
     55     
     56   TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;//输入捕获的通道,由具体的GPIO来配置
     57   TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;//捕获信号极性配置
     58   TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//输入通道与捕获通道的映射关系,有直连和非直连
     59   TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//输入的需要被捕获的信号的分频系数
     60   TIM_ICInitStructure.TIM_ICFilter = 0x0;//输入的需要被捕获的信号的滤波系数
     61   TIM_ICInit(TIM5, &TIM_ICInitStructure);
     62     
     63   TIM_ClearFlag(TIM5, TIM_FLAG_Update|TIM_FLAG_CC1);//清除TIM5的更新标志位和捕获标志位
     64   TIM_ITConfig(TIM5, TIM_IT_Update|TIM_IT_CC1, ENABLE);//开启更新中断和捕获中断
     65     
     66   TIM_Cmd(TIM5, ENABLE);
     67 }
     68 
     69 //中断服务函数
     70 void TIM5_IRQHandler(void)
     71 {
     72      //被捕获的信号周期大于定时器的最长定时时,定时器就会溢出,产生更新中断
     73      //特殊处理;把这个最长的定时周期加到捕获信号的时间里面去
     74    if(TIM_GetITStatus(TIM5,TIM_IT_Updata) != RESET)//产生中断
     75      {
     76        TIM_ICUserValueStructure.Capture_Period ++;
     77      TIM_ClearITPendingBit(TIM5,TIM_FLAG_Update);        //清中断标志位 
     78      }
     79      
     80      //第一次捕获中断
     81      if(TIM_GetITStatus(TIM5,TIM_IT_CC1)!=RESET)//产生捕获中断
     82      {
     83         if(TIM_ICUserValueStructure.Capture_StartFlag ==0)
     84             {
     85               TIM_SetCounter(TIM5,0);//计数器清0
     86                 TIM_ICUserValueStructure.Capture_Period =0;//自动重装载寄存器更新标志清零
     87                 TIM_ICUserValueStructure.Capture_CcrValue =0;//捕获比较寄存器的值的变量清0
     88                 TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling);//当第一次捕获到上升沿时,就把捕获边沿配置为下降沿
     89                 TIM_ICUserValueStructure.Capture_StartFlag =1; //开始捕获标志位置1
     90             }
     91             else//第二次捕获
     92             {
     93                 //获取捕获比较寄存器的值,这个值就是捕获到的高电平的时间的值
     94               TIM_ICUserValueStructure.Capture_CcrValue =TIM_GetCapture1(TIM5);
     95                 TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising);//当第二次捕获到下降沿时,就把捕获边沿配置为上升沿,进行新一轮捕获
     96               TIM_ICUserValueStructure.Capture_StartFlag =0;//开始捕获标志位置0
     97                 TIM_ICUserValueStructure.Capture_FinishFlag =1;//捕获完成标志位置1
     98             }
     99               TIM_ClearITPendingBit(TIM5,TIM_IT_CC1);        //清中断标志位 
    100      }
    101 }

    main:

     1 int main(void)
     2 {
     3     u32 time;
     4     u32 TIM_Psclk =72000000/72;
     5     Usart_init();//初始化串口
     6     GET_PluseWidth();//初始化定时器5
     7     
     8     while(1)
     9     {
    10       if(TIM_ICUserValueStructure.Capture_FinishFlag ==1)
    11         {
    12           time = TIM_ICUserValueStructure.Capture_Period *(0xFFFF+1) + (TIM_ICUserValueStructure.Capture_CcrValue +1);//计算高电平的计数器值
    13           printf("测得按下的时间:%d.%d
    ",time/TIM_Psclk,time%Psclk);//打印高电平脉宽时间
    14             
    15             TIM_ICUserValueStructure.Capture_FinishFlag =0;
    16         }
    17     }
    19 }
  • 相关阅读:
    数据库事务的四个隔离级别
    synchronized与Lock的区别
    线程池的注意事项
    守护线程与非守护线程
    wait与sleep的区别
    String,StringBuffer,StringBuilder
    2019牛客暑期多校训练营 第二场
    2019牛客暑期多校训练营 第一场
    Codeforces Round #568 (div. 2)
    Codeforces Round #570 (Div. 3)
  • 原文地址:https://www.cnblogs.com/darren-pty/p/13992224.html
Copyright © 2011-2022 走看看