zoukankan      html  css  js  c++  java
  • STM32学习笔记11(通用定时器作为输入捕获2)

    通用定时器作为输入捕获的使用。我们将用 TIM5 的通道 1 (PA0)来做输入捕获,捕获 PA0 上高电平的脉宽(用 WK_UP 按键输入高电平),通过串口打印高电平脉宽时间

    输入捕获简介

    输入捕获模式可以用来测量脉冲宽度或者测量频率。 STM32 的定时器,除了 TIM6 和 TIM7,其他定时器都有输入捕获功能。STM32 的输入捕获,简单的说就是通过检测 TIMx_CHx 上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。同时还可以配置捕获时是否触发中断/DMA 等。

    我们用到 TIM5_CH1 来捕获高电平脉宽,也就是要先设置输入捕获为上升沿检测,记录发生上升沿的时候 TIM5_CNT 的值。然后配置捕获信号为下降沿捕获,当下降沿到来时,发生捕获,并记录此时的 TIM5_CNT 值。这样,前后两次 TIM5_CNT 之差,就是高电平的脉宽,同时 TIM5 的计数频率我们是知道的,从而可以计算出高电平脉宽的准确时间。

    输入捕获的配置步骤:

    1)开启 TIM5 时钟和 GPIOA 时钟,配置 P A0 为下拉输入。

    要使用 TIM5,我们必须先开启 TIM5 的时钟。这里我们还要配置 P A0 为下拉输入,因为我们要捕获 TIM5_CH1 上面的高电平脉宽,而 TIM5_CH1 是连接在 PA0 上面的。

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);  //使能 TIM5 时钟

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);   //使能 GPIOA 时钟

    2)初始化 TIM5,设置 TIM5 的 ARR 和 PSC。

    在开启了 TIM5 的时钟之后,我们要设置 ARR 和 PSC 两个寄存器的值来设置输入捕获的自动重装载值和计数频率。 这在库函数中是通过 TIM_TimeBaseInit 函数实现的

    点击(此处)折叠或打开

    1.    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    2.    TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值 
    3.    TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置预分频值 
    4.    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // TDTS = Tck_tim
    5.    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM 向上计数模式
    6.    TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);

    3)设置 TIM5 的输入比较参数,开启输入捕获

    输入比较参数的设置包括映射关系,滤波,分频以及捕获方式等。这里我们需要设置通道 1为输入模式,且 IC1 映射到 TI1(通道 1)上面,并且不使用滤波(提高响应速度)器,上升沿捕获。库函数是通过 TIM_ICInit 函数来初始化输入比较参数的:

    void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);

    同样,我们来看看参数设置结构体 TIM_ICInitTypeDef 的定义:

    点击(此处)折叠或打开

    1.    typedef struct
    2.    {
    3.        uint16_t TIM_Channel; //设置通道
    4.        uint16_t TIM_ICPolarity; //设 置 输 入 信 号 的 有效 捕获 极性 
    5.        uint16_t TIM_ICSelection; //设置映射关系
    6.        uint16_t TIM_ICPrescaler; //设置 输入捕获分频系数
    7.        uint16_t TIM_ICFilter; //设置滤波器长度
    8.    } TIM_ICInitTypeDef;

    配置代码是:

    点击(此处)折叠或打开

    1.    TIM_ICInitTypeDef TIM5_ICInitStructure; 
    2.    TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //选择输入端 IC1 映射到 TI1 上
    3.    TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
    4.    TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到 TI1 上
    5.    TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频 
    6.    TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波
    7.    TIM_ICInit(TIM5, &TIM5_ICInitStructure);

    4)使能捕获和更新中断(设置 TIM5 的 DIER 寄存器)

    因为我们要捕获的是高电平信号的脉宽,所以,第一次捕获是上升沿,第二次捕获时下降沿,必须在捕获上升沿之后,设置捕获边沿为下降沿,同时,如果脉宽比较长,那么定时器就会溢出,对溢出必须做处理,否则结果就不准了。这两件事,我们都在中断里面做,所以必须开启捕获中断和更新中断。 

    这里我们使用定时器的开中断函数 TIM_ITConfig 即可使能捕获和更新中断:

    TIM_ITConfig( TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新中断和捕获中断

    5)设置中断分组,编写中断服务函数

    设置中断分组主要是通过函数 NVIC_Init()来完成。分组完成后,我们还需要在中断函数里面完成数据处理和捕获设置等关键操作,从而实现高电平脉宽统计。在中断服务函数里面,跟以前的外部中断和定时器中断实验中一样,我们在中断开始的时候要进行中断类型判断,在中断结束的时候要清除中断标志位。使用到的函数分别为 TIM_GetITStatus()函数和 TIM_ClearITPendingBit()函数。

    if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET){}//判断是否为更新中断

    if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET){}//判断是否发生捕获事件

    TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update);//清除中断和捕获标志位

    6)使能定时器(设置 TIM5 的 CR1 寄存器) 

    最后,必须打开定时器的计数器开关,  启动 TIM5 的计数器,开始输入捕获。 

    TIM_Cmd(TIM5,ENABLE );    //使能定时器 5

    例程:

    点击(此处)折叠或打开

    1. #include "timer.h"
    2. #include "led.h"
    3. #include "usart.h"
    4. /**
    5.  * 定时器5通道1输入捕获配置
    6.  */
    7.  void TIM5_Cap_Init(u16 arr,u16 psc)
    8. {
    9.     GPIO_InitTypeDef GPIO_InitStructure;
    10.     TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    11.     TIM_ICInitTypeDef TIM5_ICInitStructure;
    12.     NVIC_InitTypeDef NVIC_InitStructure;
    13.     
    14.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);    /*使能TIM5时钟*/
    15.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); /*使能GPIOA时钟*/
    16.     
    17.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; /**/
    18.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; /*PA0 输入*/
    19.     GPIO_Init(GPIOA,&GPIO_InitStructure);
    20.     GPIO_ResetBits(GPIOA,GPIO_Pin_0); /*PA0 下拉*/
    21.     
    22.     /*初始化定时器5 TIM5*/
    23.     TIM_TimeBaseStructure.TIM_Period = arr; /*设定计数器自动重装值 */
    24.     TIM_TimeBaseStructure.TIM_Prescaler = psc; /*预分频器 */
    25.     TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; /*设置时钟分割:TDTS = Tck_tim*/
    26.     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; /*TIM向上计数模式*/
    27.     TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure); /*根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位*/
    28.             
    29.     /* 初始化TIM5输入捕获参数 */
    30.     TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; /*CC1S=01     选择输入端 IC1映射到TI1上*/    
    31.     TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; /*上升沿捕获*/
    32.     TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; /*映射到TI1上*/
    33.     TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; /*配置输入分频,不分频*/
    34.     TIM5_ICInitStructure.TIM_ICFilter = 0; /*IC1F=0000 配置输入滤波器 不滤波*/
    35.     TIM_ICInit(TIM5,&TIM5_ICInitStructure); 
    36.     
    37.     /*中断分组初始化*/
    38.     NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;    /*TIM5中断*/
    39.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; /*先占优先级2级*/
    40.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; /*从优先级0级*/
    41.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; /*IRQ通道被使能*/
    42.     NVIC_Init(&NVIC_InitStructure);
    43.     
    44.     TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);/*允许更新中断 ,允许CC1IE捕获中断*/
    45.     TIM_Cmd(TIM5,ENABLE); /*使能定时器5*/    
    46. }
    47. u8 TIM5CH1_CAPTURE_STA=0;    //输入捕获状态                         
    48. u16    TIM5CH1_CAPTURE_VAL;    //输入捕获值
    49. /**
    50.  * 定时器5中断服务程序     
    51.  */
    52. void TIM5_IRQHandler(void)
    53.     if((TIM5CH1_CAPTURE_STA&0X80)==0)//还未成功捕获    
    54.     {
    55.         if(TIM_GetITStatus(TIM5,TIM_IT_Update) != RESET)
    56.         {
    57.             if(TIM5CH1_CAPTURE_STA&0X40)//已经捕获到高电平了
    58.             {
    59.                 if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了
    60.                 {
    61.                     TIM5CH1_CAPTURE_STA|=0X80;//标记成功捕获了一次
    62.                     TIM5CH1_CAPTURE_VAL=0XFFFF;
    63.                 }else TIM5CH1_CAPTURE_STA++;
    64.             }
    65.         }
    66.         
    67.         if(TIM_GetITStatus(TIM5,TIM_IT_CC1) !=RESET)
    68.         {
    69.             if(TIM5CH1_CAPTURE_STA & 0x40)
    70.             {
    71.                 TIM5CH1_CAPTURE_STA|=0X80;        //标记成功捕获到一次上升沿
    72.                 TIM5CH1_CAPTURE_VAL = TIM_GetCounter(TIM5);
    73.                 TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //CC1P=0 设置为上升沿捕获
    74.             }
    75.             else
    76.             {
    77.                 TIM5CH1_CAPTURE_STA=0;            //清空
    78.                 TIM5CH1_CAPTURE_VAL=0;
    79.                 
    80.                 TIM_SetCounter(TIM5,0);
    81.                 TIM5CH1_CAPTURE_STA|=0X40;        //标记捕获到了上升沿
    82.                 TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling);        //CC1P=1 设置为下降沿捕获
    83.             }
    84.         }
    85.         
    86.     }
    87.     TIM_ClearITPendingBit(TIM5,TIM_IT_CC1|TIM_IT_Update); /*清除中断标志位*/
    88. }

    点击(此处)折叠或打开

    1. extern u8 TIM5CH1_CAPTURE_STA;        //输入捕获状态                         
    2. extern u16    TIM5CH1_CAPTURE_VAL;    //输入捕获值    
    3.  int main(void)
    4.  {        
    5.      u32 temp=0; 
    6.     delay_init();          //延时函数初始化     
    7.     NVIC_Configuration();      //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    8.     uart_init(9600);     //串口初始化为9600
    9.      LED_Init();             //LED端口初始化
    10.  
    11.      TIM5_Cap_Init(0XFFFF,72-1);    //以1Mhz的频率计数 
    12.        while(1)
    13.     {
    14.          delay_ms(10);
    15.                   
    16.          if(TIM5CH1_CAPTURE_STA&0X80)//成功捕获到了一次上升沿
    17.         {
    18.             temp=TIM5CH1_CAPTURE_STA&0X3F;
    19.             temp*=65536;//溢出时间总和
    20.             temp+=TIM5CH1_CAPTURE_VAL;//得到总的高电平时间
    21.             printf("HIGH:%d us ",temp);//打印总的高点平时间
    22.             TIM5CH1_CAPTURE_STA=0;//开启下一次捕获
    23.         }
    24.     }
    25.  }
  • 相关阅读:
    METHODS OF AND APPARATUS FOR USING TEXTURES IN GRAPHICS PROCESSING SYSTEMS
    Display controller
    Graphics processing architecture employing a unified shader
    Graphics-Processing Architecture Based on Approximate Rendering
    Architectures for concurrent graphics processing operations
    Procedural graphics architectures and techniques
    DYNAMIC CONTEXT SWITCHING BETWEEN ARCHITECTURALLY DISTINCT GRAPHICS PROCESSORS
    Thermal zone monitoring in an electronic device
    System and method for dynamically adjusting to CPU performance changes
    Framework for Graphics Animation and Compositing Operations
  • 原文地址:https://www.cnblogs.com/dustinzhu/p/4152374.html
Copyright © 2011-2022 走看看