单片机学习小组
直播中

恐龙之家

8年用户 839经验值
私信 关注

如何对通用定时器的输入捕获进行测试呢

输入捕获模式有何作用?
通用定时器的输入捕获过程是怎样的?
如何对通用定时器的输入捕获进行测试呢?

回帖(1)

何元

2022-2-24 11:12:41
通用定时器的输入捕获实验



1、作用


  输入捕获模式可以用来测量脉冲宽度或者测量频率。

2、过程


  STM32的输入捕获,简单的说就是通过检测TIMx_CHx(定时器X的通道X)上的边沿信号,在边沿信号发生跳变(上升沿/下降沿)的时候,将定时器的值(TIMx_CNT)存放到对应通道的捕获/比较寄存器(TIMX_CCRx)里面,完成一次捕获,同时可以配置捕获时是否触发中断/DMA。

3、图解


  以CH1为例,定时器通过TIMx_CH1脚产生TI1,TI1经过滤波器后,将信号传输给边沿检测器,边沿检测器检测到准确的边沿信号之后,产生TI1FP1和TI1FP2信号(这两个信号其实是一样的,只是输出的路径不一样),TI1FP1信号提供给IC1,IC1经过预分频器之后,产生捕获信号,这时定时器计数器的当前值被锁存到捕获/比较寄存器中,而且TIMx_SR状态寄存器的CC1IF标志位置1,如果使能了通道1输入捕获的中断功能,就会产生中断。


4、测试方法


1、本次测试实验选择TIM2的CH1,也就是引脚PA0,需要外部输入一个PWM波给PA0,可以采用以下几种方法:



  • 通过函数信号发生器输入。
  • 通过STM32的其他定时器生成一个PWM波。
  • 通过延时函数和GPIO生成一个PWM波。
  • 通过PC串口助手和USB转TTL模块发送一个0x55给引脚。


2、配置流程



  • 打开定时器和通道GPIO的时钟,将通道配置为复用输入。
  • 设置定时器的计数频率,当产生捕获时,用于计时,需要注意定时器溢出的问题,当定时器溢出后,会清除定时器计数器的值(TIMx_CNT),在计算捕获时间的时候,如果有溢出,需要加上溢出的时间。
  • 配置捕获/比较模式寄存器(TIMx_CCMRx)的通道模式为输入,映射关系选择ICx的输入源,配置滤波器和预分频器(一般选择不滤波不分频)。
  • 配置捕获/比较使能寄存器(TIMx_CCER)捕获的边沿信号(上升沿/下降沿触发),在使用输入捕获功能时需要先使能。
  • 配置DMA/中断使能寄存器(TIMx_DIER)打开对应通道的中断或者DMA。
  • 配置控制寄存器(TIMx_CR1)使能定时器,开启计数。


3、本次测试的方案是通过捕获上升沿来获取计数器的值,再根据计数频率得出两个上升沿之间的时间。

4、需要注意的是,如果采用串口助手发送,需要从低位开始读上升沿。

5、代码


#include "stm32f10x.h"

uint16_t flag, val;      

void TIM2_CH1_GPIO_Init(void)
{
    RCC->APB2ENR|=1<<2;                         //使能GPIOA时钟

    GPIOA->CRL&=0xFFFFFFF0;                     //清除A0
    GPIOA->CRL|=0x00000004;                     //模拟输入
}

void MY_NVIC_PriorityGroupConfig(u8 NVIC_Group)         
{
        u32 temp,temp1;         

        temp1=(~NVIC_Group)&0x07;                   //取后三位
        temp1<<=8;
        temp=SCB->AIRCR;                            //读取先前的设置
        temp&=0X0000F8FF;                           //清空先前分组
        temp|=0X05FA0000;                           //写入钥匙
        temp|=temp1;         
        SCB->AIRCR=temp;                            //设置分组                                                        
}

void MY_NVIC_Init(u8 NVIC_PreemptionPriority,u8 NVIC_SubPriority,u8 NVIC_Channel,u8 NVIC_Group)         
{
        u32 temp;      

        MY_NVIC_PriorityGroupConfig(NVIC_Group);                //设置分组
        temp=NVIC_PreemptionPriority<<(4-NVIC_Group);         
        temp|=NVIC_SubPriority&(0x0f>>NVIC_Group);
        temp&=0xf;                                                                                //取低四位  
        NVIC->ISER[NVIC_Channel/32]|=(1<
        NVIC->IP[NVIC_Channel]|=temp<<4;                                //设置响应优先级和抢断优先级                                                           
}

void TIM2_Init(uint16_t arr, uint16_t psc)
{
    RCC->APB1ENR|=1<<0;                         //使能定时器2时钟
      
    //初始化TIM2
    TIM2->ARR = arr;                            //ARR 自动重装载值
    TIM2->PSC = psc;                            //PSC 预分频系数
    TIM2->CR1&=~(1<<4);                         //DIR 向上计数
    TIM2->CR1&=~(3<<8);                         //CKD[1:0] 时钟分频因子 tDTS=tCK_INT

    //初始化TIM1输入捕获参数
    TIM2->CCMR1|=1<<0;                          //CC1S[1:0] CC1通道被配置为输入,IC1映射在TI1上
    TIM2->CCMR1&=~(3<<2);                       //IC1PSC[1:0] 输入/捕获预分频 不分频
    TIM2->CCMR1&=~(0xF<<4);                     //IC1F[3:0] 不滤波
   
        TIM2->CCER|=1<<0;                           //输入捕获1使能
    TIM2->CCER&=~(1<<1);                        //CC1P 捕获发生在IC1的上升沿,不反向  
    TIM2->SMCR|=5<<4;                           //TS[2:0] 触发选择 滤波后的定时器输入1(TI1FP1)
   
    //开启中断
    TIM2->DIER|=1<<1;                           //CC1IE 允许捕获比较1中断
    TIM2->DIER|=1<<0;                           //UIE 允许更新中断

    //使能定时器
    TIM2->CR1|=1<<0;                            //CEN 使能定时器
}
                                          
void testcase()
{  
    TIM2_CH1_GPIO_Init();                                                //使能TIM2 CH1的引脚PA0 模拟输入
    TIM2_Init(1000-1, 72-1);                         //计数频率1MHz  定时1ms
    MY_NVIC_Init(1,3,TIM2_IRQn,2);              //抢占1,子优先级3,组2 输入捕获中断
      
    while(1)
    {                 
                if(flag&0X80)                                                        //捕获到第二个上升沿
                {
                        flag = 0;
                        printf("time = %dus", val);
                }
    }
}

void TIM2_IRQHandler(void)
{
    uint16_t tsr;
        static uint16_t i, count;
      
        tsr=TIM2->SR;
        if((flag&0X80)==0)                                                        //还未成功捕获第二次上升沿      
        {
                if((tsr&0X01)&&(flag&0x40))                                //溢出并且捕获到第一个上升沿
                {                           
                        count++;
                }
                if(tsr&0x02)                                                        //发生捕获事件
                {      
                        i++;
                        if(i==1)                                                        //第一次捕获到上升沿
                        {
                                flag|=0x40;                                                //标记成功捕获到第一次上升沿
                                TIM2->CNT = 0;                                        //计数器清零
                        }
                        if(i == 2)                                                        //第二次捕获到上升沿
                        {
                                i = 0;
                                flag|=0X80;                                                //标记成功捕获到第二次上升沿
                                val=count*1000 + TIM2->CCR1;        //获取当前的捕获值
                        }
                }                                                                                   
        }
        TIM2->SR=0;//清除中断标志位            
}
举报

更多回帖

×
20
完善资料,
赚取积分