单片机
返回首页

STM32F103_通用定时器“输入捕获”测量输入脉冲宽度

2019-08-22 来源:eefocus

一、硬件设计

        选用通用定时器TIM5的CH1,其输入管脚为PA0,在开发板上PA0连接按键,当按键按下输入高电平,按键松开输入低电平,实验测量高电平的脉冲宽度。


二、软件设计

    1. 配置中断向量表的优先级


        因只使用一个中断 TIM5_IRQn,抢占优先级与子优先级可随意配置。


        代码如下:


static void  General_NVIC_Config(void)

{

    NVIC_InitTypeDef NVIC_InitStructure;

    

    NVIC_PriorityGroupConfig (NVIC_PriorityGroup_0);

    

    NVIC_InitStructure.NVIC_IRQChannel = GENERAL_TIM_IRQn;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;

    

    NVIC_Init(&NVIC_InitStructure);

}

    2. GPIO配置


        PA0配置为浮空输入模式。


static void General_GPIO_Gonfig(void)

{

    GPIO_InitTypeDef GPIO_InitStructure;

    

    RCC_APB2PeriphClockCmd(GENERAL_TIM_CH1_GPIO_CLK , ENABLE);

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

    GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH1_PIN;

    

    GPIO_Init(GENERAL_TIM_CH1_PORT, &GPIO_InitStructure);    

}

    3. 定时器模式配置,其中包含时基结构体、输入捕获结构体的初始化以及中断的开启。

static void GeneralTim_Config(void)

{

  // 开启定时器时钟,即内部时钟CK_INT=72M

    GENERAL_TIM_APBxClock_FUN(GENERAL_TIM_CLK,ENABLE);

 

/*--------------------时基结构体初始化-------------------------*/    

  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

    // 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断

    TIM_TimeBaseStructure.TIM_Period=GENERAL_TIM_PERIOD;    

    // 驱动CNT计数器的时钟 = Fck_int/(psc+1)

    TIM_TimeBaseStructure.TIM_Prescaler= GENERAL_TIM_PSC;    

    // 时钟分频因子 ,配置死区时间时需要用到

    TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;        

    // 计数器计数模式,设置为向上计数

    TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;        

    // 重复计数器的值,没用到不用管

    TIM_TimeBaseStructure.TIM_RepetitionCounter=0;    

    // 初始化定时器

    TIM_TimeBaseInit(GENERAL_TIM, &TIM_TimeBaseStructure);

 

    /*--------------------输入捕获结构体初始化-------------------*/    

    TIM_ICInitTypeDef TIM_ICInitStructure;

    // 配置输入捕获的通道,需要根据具体的GPIO来配置

    TIM_ICInitStructure.TIM_Channel = GENERAL_TIM_CHANNEL_x;

    // 输入捕获信号的极性配置

    TIM_ICInitStructure.TIM_ICPolarity = GENERAL_TIM_STRAT_ICPolarity;

    // 输入通道和捕获通道的映射关系,有直连和非直连两种

    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;

    // 输入的需要被捕获的信号的分频系数

    TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;

    // 输入的需要被捕获的信号的滤波系数

    TIM_ICInitStructure.TIM_ICFilter = 0;

    // 定时器输入捕获初始化

    TIM_ICInit(GENERAL_TIM, &TIM_ICInitStructure);

    

    // 清除更新和捕获中断标志位

  TIM_ClearFlag(GENERAL_TIM, TIM_FLAG_Update|GENERAL_TIM_IT_CCx);    

  // 开启更新和捕获中断  

    TIM_ITConfig (GENERAL_TIM, TIM_IT_Update | GENERAL_TIM_IT_CCx, ENABLE );

    

    // 使能计数器

    TIM_Cmd(GENERAL_TIM, ENABLE);

}

    4. 输入捕获初始化函数

void GeneralTim_Init(void)

{

    General_NVIC_Config();

    

    General_GPIO_Gonfig();

        

    GeneralTim_Config();

}

    5. 中断函数

        首先判断定时器是否溢出定时周期,并做处理。然后上升沿捕获时将计数器寄存器的值清零,中断改为下降沿触发。下降沿捕获中断时,读取计数值,改为上升沿触发,开始捕获标识清零,结束捕获置1,。。。。。。。。


void GENERAL_TIM_INT_FUN(void)

{

    // 当要被捕获的信号的周期大于定时器的最长定时时,定时器就会溢出,产生更新中断

    // 这个时候我们需要把这个最长的定时周期加到捕获信号的时间里面去

    if ( TIM_GetITStatus ( GENERAL_TIM, TIM_IT_Update) != RESET )               

    {    

        TIM_ICUserValueStructure.Capture_Period ++;        

        TIM_ClearITPendingBit ( GENERAL_TIM, TIM_FLAG_Update );         

    }

 

    // 上升沿捕获中断

    if ( TIM_GetITStatus (GENERAL_TIM, GENERAL_TIM_IT_CCx ) != RESET)

    {

        // 第一次捕获

        if ( TIM_ICUserValueStructure.Capture_StartFlag == 0 )

        {

            // 计数器清0

            TIM_SetCounter ( GENERAL_TIM, 0 );

            // 自动重装载寄存器更新标志清0

            TIM_ICUserValueStructure.Capture_Period = 0;

      // 存捕获比较寄存器的值的变量的值清0            

            TIM_ICUserValueStructure.Capture_CcrValue = 0;

 

            // 当第一次捕获到上升沿之后,就把捕获边沿配置为下降沿

            GENERAL_TIM_OCxPolarityConfig_FUN(GENERAL_TIM, TIM_ICPolarity_Falling);

      // 开始捕获标准置1            

            TIM_ICUserValueStructure.Capture_StartFlag = 1;            

        }

        // 下降沿捕获中断

        else // 第二次捕获

        {

            // 获取捕获比较寄存器的值,这个值就是捕获到的高电平的时间的值

            TIM_ICUserValueStructure.Capture_CcrValue = 

            GENERAL_TIM_GetCapturex_FUN (GENERAL_TIM);

 

            // 当第二次捕获到下降沿之后,就把捕获边沿配置为上升沿,好开启新的一轮捕获

            GENERAL_TIM_OCxPolarityConfig_FUN(GENERAL_TIM, TIM_ICPolarity_Rising);

      // 开始捕获标志清0        

            TIM_ICUserValueStructure.Capture_StartFlag = 0;

      // 捕获完成标志置1            

            TIM_ICUserValueStructure.Capture_FinishFlag = 1;        

        }

 

        TIM_ClearITPendingBit (GENERAL_TIM,GENERAL_TIM_IT_CCx);        

    }        

}

     6. 主函数,计算脉冲宽度利用串口输出

         int main()

{

        uint32_t time;

    

    // TIM 计数器的驱动时钟

    float TIM_PscCLK = 72000000.0 / (GENERAL_TIM_PSC+1);

    

    USART_Config();

    GeneralTim_Init();

        

    printf('rn ----输入捕获测量脉宽实验----rn');

    while(1)

    {

        if(TIM_ICUserValueStructure.Capture_FinishFlag == 1)

        {

            time = (TIM_ICUserValueStructure.Capture_Period * (GENERAL_TIM_PERIOD + 1)

            + TIM_ICUserValueStructure.Capture_CcrValue + 1);

            

            printf('t=%fn',time/TIM_PscCLK);

            TIM_ICUserValueStructure.Capture_FinishFlag = 0;

            

        }

        

    }

}

 

   

  7. 相关宏定义      

#define            GENERAL_TIM                   TIM5

#define            GENERAL_TIM_APBxClock_FUN     RCC_APB1PeriphClockCmd

#define            GENERAL_TIM_CLK               RCC_APB1Periph_TIM5

#define            GENERAL_TIM_PERIOD            0XFFFF

#define            GENERAL_TIM_PSC              (72-1)

 

// TIM 输入捕获通道GPIO相关宏定义

#define            GENERAL_TIM_CH1_GPIO_CLK      RCC_APB2Periph_GPIOA

#define            GENERAL_TIM_CH1_PORT          GPIOA

#define            GENERAL_TIM_CH1_PIN           GPIO_Pin_0

#define            GENERAL_TIM_CHANNEL_x         TIM_Channel_1

 

// 中断相关宏定义

#define            GENERAL_TIM_IT_CCx            TIM_IT_CC1

#define            GENERAL_TIM_IRQ               TIM5_IRQn

#define            GENERAL_TIM_INT_FUN           TIM5_IRQHandler

 

// 获取捕获寄存器值函数宏定义

#define            GENERAL_TIM_GetCapturex_FUN                 TIM_GetCapture1

// 捕获信号极性函数宏定义

#define            GENERAL_TIM_OCxPolarityConfig_FUN           TIM_OC1PolarityConfig

 

// 测量的起始边沿

#define            GENERAL_TIM_STRAT_ICPolarity                TIM_ICPolarity_Rising

// 测量的结束边沿

#define            GENERAL_TIM_END_ICPolarity                  TIM_ICPolarity_Falling

 

 

// 定时器输入捕获用户自定义变量结构体声明

typedef struct

{   

    uint8_t   Capture_FinishFlag;   // 捕获结束标志位

    uint8_t   Capture_StartFlag;    // 捕获开始标志位

    uint16_t  Capture_CcrValue;     // 捕获寄存器的值

    uint16_t  Capture_Period;       // 自动重装载寄存器更新标志 

}TIM_ICUserValueTypeDef;

 

extern TIM_ICUserValueTypeDef TIM_ICUserValueStructure ; / /在c文件中已经定义

 

/**************************函数声明********************************/

void GENERAL_TIM_Init(void);


参考资料:野火《stm32库卡发实战指南》

进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • PIC单片机控制的遥控防盗报警器电路

  • 使用ESP8266从NTP服务器获取时间并在OLED显示器上显示

  • 用NE555制作定时器

  • 如何构建一个触摸传感器电路

  • 基于ICL296的大电流开关稳压器电源电路

  • 基于TDA2003的简单低功耗汽车立体声放大器电路

    相关电子头条文章