zoukankan      html  css  js  c++  java
  • (stm32f103学习总结)—输入捕获模式

    一、输入捕获介绍

     在定时器中断实验章节中我们介绍了通用定时器具有多种功能,输入捕获就是其中一种。STM32F1 除了基本定时器 TIM6 和 TIM7,其他定时器都具有输入捕获功能。输入捕获可以对输入的信号的上升沿,下降沿或者双边沿进行捕获,通常用于测量输入信号的脉宽、测量 PWM 输入信号的频率及占空比。
      输入捕获的工作原理比较简单,在输入捕获模式下,当相应的 ICx 信号检测到跳变沿后,将使用捕获/比较寄存器(TIMx_CCRx)来锁存计数器的值。简单的说就是通过检测 TIMx_CHx 上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存(TIMx_CCRx)里面,完成一次捕获。同时还可以配置捕获时是否触发中断/DMA 等。下面我们以输入捕获测量脉宽为例,通过一个简图来介绍输入捕获的工作原理,如图 所示:
      从上图可以看出,t1-t2 时间就是我们需要测量的高电平时间,假如定时器工作在向上计数模式,测量方法是:首先设置定时器通道 x 为上升沿捕获,这样在 t1 时刻,就会捕获到当前的 CNT 值,然后立即清零 CNT,并设置通道 x 为下降沿捕获,这样到 t2 时刻,又会发生捕获事件,得到此时的 CNT 值,记为 CCRx2。根据定时器的计数频率,我们就可以算出 t1-t2 的时间,从而得到高电平脉宽。在 t1-t2 时间内可能会出现 N 次定时器溢出,因此我们还需要对定时器溢出进行处理,防止因高电平时间过长发生溢出导致测量数据不准。CNT计数的次数等于:N*ARR+CCRx2,有了这个计数次数,再乘以 CNT 的计数周期,即可得到 t2-t1 的时间长度,即高电平持续时间。

    二、输入捕获配置步骤

    (1)使能定时器及端口时钟,并设置引脚复用器映射和引脚模式等

       RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);

      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

       GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD;

     

    (2)初始化定时器参数,包含自动重装值,分频系数,计数方式等

      TIM_TimeBaseInit(TIM_TypeDef*TIMx,TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

    (3)设置通用定时器的输入捕获参数,开启输入捕获功能

      TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);

    (4)开启捕获和定时器溢出(更新)中断

      TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState)

    (5)设置定时器中断优先级,使能定时器中断通道 NVIC初始化库函数是

      NVIC_Init()

    (6)使能定时器

      TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);

    (7)编写定时器中断服务函数

      void TIM5_IRQHandle()

    三、代码举例

    所要实现的功能是:使用TIM5的CH1检测输入信号高电平脉宽, 将检测的高电平脉宽时间通过printf函数打印出来,同时让D1指示灯不 断闪烁表示系统正常运行。(使用普中stm32f103开发板)

     1 #ifndef _input_H
     2 #define _input_H
     3 
     4 #include "system.h"
     5 
     6 extern u8 TIM5_CH1_CAPTURE_STA; //输入捕获的状态
     7 extern u16 TIM5_CH1_CAPTURE_VAL;//输入捕获值
     8 
     9 
    10 void TIM5_CH1_Input_Init(u16 arr,u16 psc);
    11     
    12 #endif

    (原子开发板资料)

    bit7位置1时表示成功捕获完一次高电平(按键按下直到抬起整个过程结束);代码58、66、79

    bit6位置1时表示获得高电平的标志位,(表示按键已经按下)代码62、77、87

    bit0~5位表示高电平时间是定时器溢出的次数(即在按键按下时定时器溢出几次)

    如果溢出次数超过了6位所能表示的范围时怎么办?

      代码64—68解决办法

    就是在TIM5_CH1_CAPTURE_STA==0x3f 时将 TIM5_CH1_CAPTURE_STA变量强制bit7置1(即强制捕获完成去执行主函数代码27以后的代码段,然后重新进行下一次的捕获)   TIM5_CH1_CAPTURE_STA|=0x80;

     1 #include "input.h"
     2 
     3 u8 TIM5_CH1_CAPTURE_STA; //输入捕获状态 
     4 u16 TIM5_CH1_CAPTURE_VAL;//输入捕获值
     5 
     6 /*******************************************************************************
     7 * 函 数 名         : TIM5_CH1_Input_Init
     8 * 函数功能           : TIM5_CH1输入捕获初始化函数
     9 * 输    入         : arr:自动重装载值
    10                      psc:预分频系数
    11 * 输    出         : 无
    12 *******************************************************************************/
    13 void TIM5_CH1_Input_Init(u16 arr,u16 psc)
    14 {
    15     TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    16     TIM_ICInitTypeDef TIM_ICInitStructure;
    17     NVIC_InitTypeDef NVIC_InitStructure;
    18     GPIO_InitTypeDef GPIO_InitStructure;
    19     
    20     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    21     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);//使能TIM5时钟
    22     
    23     GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;//管脚设置
    24     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD;     //设置下拉输入模式
    25     GPIO_Init(GPIOA,&GPIO_InitStructure);        /* 初始化GPIO */
    26     
    27     TIM_TimeBaseInitStructure.TIM_Period=arr;   //自动装载值
    28     TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //分频系数
    29     TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
    30     TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //设置向上计数模式
    31     TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStructure);    
    32     
    33     TIM_ICInitStructure.TIM_Channel=TIM_Channel_1; //通道1
    34     TIM_ICInitStructure.TIM_ICFilter=0x00;  //滤波
    35     TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//捕获极性
    36     TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1; //分频系数
    37     TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//直接映射到TI1
    38     TIM_ICInit(TIM5,&TIM_ICInitStructure);
    39     TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);
    40     
    41     NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;//中断通道
    42     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
    43     NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;        //子优先级
    44     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ通道使能
    45     NVIC_Init(&NVIC_InitStructure);
    46         
    47     TIM_Cmd(TIM5,ENABLE); //使能定时器
    48 }
    49 
    50 /*******************************************************************************
    51 * 函 数 名         : TIM5_IRQHandler
    52 * 函数功能           : TIM5中断函数
    53 * 输    入         : 无
    54 * 输    出         : 无
    55 *******************************************************************************/
    56 void TIM5_IRQHandler(void)
    57 {
    58     if((TIM5_CH1_CAPTURE_STA&0x80)==0) //还未成功捕获
    59     {
    60         if(TIM_GetITStatus(TIM5,TIM_IT_Update)) //发生更新中断
    61         {
    62             if(TIM5_CH1_CAPTURE_STA&0X40)//捕获到了高电平
    63             {
    64                 if((TIM5_CH1_CAPTURE_STA&0x3f)==0x3f) //高电平时间太长
    65                 {
    66                     TIM5_CH1_CAPTURE_STA|=0x80; //标志一次捕获成功
    67                     TIM5_CH1_CAPTURE_VAL=0xffff;
    68                 }
    69                 else
    70                 {
    71                     TIM5_CH1_CAPTURE_STA++;
    72                 }
    73             }
    74         }
    75         if(TIM_GetITStatus(TIM5,TIM_IT_CC1)) //发生捕获中断
    76         {
    77             if(TIM5_CH1_CAPTURE_STA&0X40)//捕获到了高电平
    78             {
    79                 TIM5_CH1_CAPTURE_STA|=0x80; //成功捕获一次高电平
    80                 TIM5_CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);
    81                 TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //设置上升沿捕获
    82             }
    83             else
    84             {
    85                 TIM5_CH1_CAPTURE_STA=0;
    86                 TIM5_CH1_CAPTURE_VAL=0;
    87                 TIM5_CH1_CAPTURE_STA|=0x40; //捕获到高电平标志
    88                 TIM_Cmd(TIM5,DISABLE);
    89                 TIM_SetCounter(TIM5,0); //定时器初值为0
    90                 TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); //设置下降沿捕获
    91                 TIM_Cmd(TIM5,ENABLE);
    92             }
    93         }
    94     }
    95     TIM_ClearITPendingBit(TIM5,TIM_IT_CC1|TIM_IT_Update);
    96 }
     1 #include "system.h"
     2 #include "SysTick.h"
     3 #include "led.h"
     4 #include "usart.h"
     5 #include "input.h"
     6 
     7 
     8 /*******************************************************************************
     9 * 函 数 名         : main
    10 * 函数功能           : 主函数
    11 * 输    入         : 无
    12 * 输    出         : 无
    13 *******************************************************************************/
    14 int main()
    15 {
    16     u8 i=0;
    17     u32 indata=0;
    18     
    19     SysTick_Init(72);
    20     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //中断优先级分组 分2组
    21     LED_Init();
    22     USART1_Init(9600);
    23     TIM5_CH1_Input_Init(0xffff,71);  //以1M频率计数
    24     
    25     while(1)
    26     {
    27         if(TIM5_CH1_CAPTURE_STA&0x80) //成功捕获
    28         {
    29             indata=TIM5_CH1_CAPTURE_STA&0x3f;
    30             indata*=0xffff; //溢出次数乘以一次的计数次数时间 us
    31             indata+=TIM5_CH1_CAPTURE_VAL;//加上高电平捕获的时间
    32             printf("高电平持续时间:%d us
    ",indata); //总的高电平时间
    33             TIM5_CH1_CAPTURE_STA=0; //开始下一次捕获
    34         }
    35         
    36         i++;
    37         if(i%20==0)
    38         {
    39             led1=!led1;
    40         }
    41         delay_ms(10);
    42     }
    43 }
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     

     

  • 相关阅读:
    刷题向》关于一道比较优秀的递推型DP(openjudge9275)(EASY+)
    刷题向》一道简单的思路题BZOJ1800(EASY+)
    算法描述》关于二分的两三事
    值得一做》关于一道暴搜BZOJ1024(EASY+)
    写一个C语言的链表记录一下
    qt 创建第一个工程
    windows好用的便签
    .pro文件部分命令详解
    QT 子文件的建立(pri)
    QTAction Editor的简单使用(简洁明了)
  • 原文地址:https://www.cnblogs.com/zhj868/p/12673427.html
Copyright © 2011-2022 走看看