STM32CubeMX学习笔记(23)——通用定时器接口使用(输入捕获测量脉宽)

发布者:Jikai最新更新时间:2025-02-12 来源: jianshu关键字:STM32CubeMX  通用定时器 手机看文章 扫描二维码
随时随地手机看文章

一、定时器简介

STM32F1 系列中,除了互联型的产品,共有 8 个定时器,分为基本定时器,通用定时器和高级定时器。
基本定时器 TIM6 和 TIM7 是一个 16 位的只能向上计数的定时器,只能定时,没有外部 IO。
通用定时器 TIM2/3/4/5 是一个 16 位的可以向上/下计数的定时器,可以定时,可以输出比较,可以输入捕捉,每个定时器有四个外部 IO。
高级定时器 TIM1/8 是一个 16 位的可以向上/下计数的定时器,可以定时,可以输出比较,可以输入捕捉,还可以有三相电机互补输出信号,每个定时器有 8 个外部 IO。


二、输入捕获

输入捕获模式可以用来测量脉冲宽度或者测量频率。STM32 的定时器,除了TIM6、TIM7,其他的定时器都有输入捕获的功能。

2.1 输入捕获的工作原理


①先设置输入捕获为上升沿检测,
②记录发生上升沿时TIMx_CNT(计数器)的值
③配置捕获信号为下降沿捕获,当下降沿到来的时候发生捕获
④记录此时的TIMx_CN(计数器)T的值
⑤前后两次TIMx_CNT(计数器)的值之差就是高电平的脉宽。同时根据TIM的计数频率,我们就能知道高电平脉宽的准确时间。

简单说:
当你设置的捕获开始的时候,cpu会将计数寄存器的值复制到捕获比较寄存器中并开始计数,当再次捕捉到电平变化时,这是计数寄存器中的值减去刚才复制的值就是这段电平的持续时间,你可以设置上升沿捕获、下降沿捕获、或者上升沿下降沿都捕获。

2.2 溢出时间计算

t1时刻检测到高电平,发生中断,在中断里将计数值置0,开始记溢出次数N,

其中每计数0xFFFF次溢出一次,直到t2时刻跳变回低电平,

获取最后一次溢出时到t2时刻的计数值TIM5CH1_CAPTURE_VAL

则  高电平时间 = 溢出次数x65535+TIM5CH1_CAPTURE_VAL     us;根据定时器初始化时的频率即可计算出溢出总次数所占用的时间,即为高电平时间。

如果计数器值为 32 bit   那么最大为0xFFFFFFFF

高电平时间:


三、新建工程

1. 打开 STM32CubeMX 软件,点击“新建工程”


2. 选择 MCU 和封装


3. 配置时钟
RCC 设置,选择 HSE(外部高速时钟) 为 Crystal/Ceramic Resonator(晶振/陶瓷谐振器)
开启 LSE(外部低速时钟) 为 Crystal/Ceramic Resonator(晶振/陶瓷谐振器)


选择 Clock Configuration,配置系统时钟 SYSCLK 为 72MHz
修改 HCLK 的值为 72 后,输入回车,软件会自动修改所有配置


4. 配置调试模式
非常重要的一步,否则会造成第一次烧录程序后续无法识别调试器
SYS 设置,选择 Debug 为 Serial Wire


四、TIM5通用定时器

4.1 参数配置

在 Timers 中选择 TIM5 设置,勾选 Internal Clock 使用内部时钟。
Channel1 通道1选择 Input Capture direct mode 输入捕获模式。

注:TIM5 的通道1对应开发板上 KEY1 的 PA0。

在 Parameter Settings 进行具体参数配置。

Tclk 即内部时钟CK_INT,经过APB1预分频器后分频提供,如果APB1预分频系数等于1,则频率不变,否则频率乘以2,库函数中APB1预分频的系数是2,即PCLK1=36M,如图所以定时器时钟Tclk=36*2=72M。


计时器时钟频率为 1MHz,此时 1us 计数一次。

定时器溢出时间:

Tout = 1 / (Tclk / (psc + 1)) ∗ (arr + 1)

  • 定时器时钟Tclk:72MHz

  • 预分频器psc:71

  • 自动重装载寄存器arr:65535

即 Tout = 1/(72MHz/(71+1))∗(65535+1) = 65535us

  • Prescaler(时钟预分频数):72-1 则驱动计数器的时钟 CK_CNT = CK_INT(即72MHz)/(71+1) = 1MHz

  • Counter Mode(计数模式):Up(向上计数模式)

  • Counter Period(自动重装载值):65535

  • auto-reload-preload(自动重装载):Disable(不使能)

  • TRGO Parameters(触发输出):不使能 在定时器的定时时间到达的时候输出一个信号(如:定时器更新产生TRGO信号来触发ADC的同步转换)

  • Input Capture Channel 1(输入捕获通道1)

    • Polarity Selection:Rising Edge(上升沿捕获)

    • IC Selection:Direct 默认

    • Prescaler Division Ratio:No division 默认

    • Input Filter(4 bits calue)(滤波值):0

4.2 配置NVIC

使能定时器中断

4.3 生成代码

输入项目名和项目路径

选择应用的 IDE 开发环境 MDK-ARM V5

每个外设生成独立的 ’.c/.h’ 文件
不勾:所有初始化代码都生成在 main.c
勾选:初始化代码生成在对应的外设文件。 如 GPIO 初始化代码生成在 gpio.c 中。

点击 GENERATE CODE 生成代码

4.4 修改定时器中断回调函数

打开 stm32f1xx_it.c 中断服务函数文件,找到 TIM5 中断的服务函数 TIM5_IRQHandler()
中断服务函数里面就调用了定时器中断处理函数 HAL_TIM_IRQHandler()

打开 stm32f1xx_hal_tim.c 文件,找到定时器中断处理函数原型 HAL_TIM_IRQHandler(),其主要作用就是判断是哪个定时器产生哪种事件中断,清除中断标识位,然后调用中断回调函数 HAL_TIM_PeriodElapsedCallback()。

/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_TIM_PeriodElapsedCallback could be implemented in the user file
*/
这个函数不应该被改变,如果需要使用回调函数,请重新在用户文件中实现该函数。

HAL_TIM_PeriodElapsedCallback() 按照官方提示我们应该再次定义该函数,__weak 是一个弱化标识,带有这个的函数就是一个弱化函数,就是你可以在其他地方写一个名称和参数都一模一样的函数,编译器就会忽略这一个函数,而去执行你写的那个函数;而 UNUSED(htim) ,这就是一个防报错的定义,当传进来的定时器号没有做任何处理的时候,编译器也不会报出警告。其实我们在开发的时候已经不需要去理会中断服务函数了,只需要找到这个中断回调函数并将其重写即可而这个回调函数还有一点非常便利的地方这里没有体现出来,就是当同时有多个中断使能的时候,STM32CubeMX会自动地将几个中断的服务函数规整到一起并调用一个回调函数,也就是无论几个中断,我们只需要重写一个回调函并判断传进来的定时器号即可。


接下来我们就在 stm32f1xx_it.c 这个文件的最下面添加 HAL_TIM_PeriodElapsedCallback()

/* USER CODE BEGIN 1 */

/* TIM5CH1_CAP_STA 各数据位说明

** bit7   捕获完成标志

** bit6   捕获到高电平标志

** bit5~0 捕获高电平后定时器溢出的次数*/

uint8_t TIM5CH1_CAP_STA = 0;                        // 输入捕获状态

uint16_t TIM5CH1_CAP_VAL;                           // 输入捕获值

// 中断服务函数里面会自动调用这个回调函数,这个是定时器更新中断处理的函数

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

{

    if(htim->Instance == TIM5)                      // 判断定时器5是否发生中断

    {

        if((TIM5CH1_CAP_STA & 0X80) == 0)           // 还未成功捕获

        {

            if(TIM5CH1_CAP_STA & 0X40)              // 已经捕获到高电平

            {       

                if((TIM5CH1_CAP_STA & 0X3F) == 0X3F)// 高电平时间太长了,做溢出处理

                {   

                    TIM5CH1_CAP_STA |= 0X80;        // 标记为完成一次捕获

                    TIM5CH1_CAP_VAL = 0XFFFF;       // 计数器值

                }

                else

                {

                    TIM5CH1_CAP_STA++;              // 若没有溢出,就只让TIM5CH1_CAP_STA自加

                }                

            }   

        }

    }

}

/* USER CODE END 1 */



4.5 修改输入捕获中断回调函数

打开 stm32f1xx_hal_tim.c HAL库定时器接口文件,找到输入捕获中断处理回调函数 HAL_TIM_IC_CaptureCallback()

/* NOTE : This function should not be modified, when the callback is needed,
the HAL_TIM_IC_CaptureCallback could be implemented in the user file
*/
这个函数不应该被改变,如果需要使用回调函数,请重新在用户文件中实现该函数。

接下来我们就在 stm32f1xx_it.c 这个文件的最下面添加 HAL_TIM_IC_CaptureCallback()

// 定时器输入捕获中断处理回调函数,该函数在 HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim) 中会被调用

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)

{

    if((TIM5CH1_CAP_STA & 0X80) == 0)               // 还未成功捕获

    {

        if(TIM5CH1_CAP_STA & 0X40)                  // 捕获到一个下降沿

        {       

            TIM5CH1_CAP_STA |= 0X80;                // 标记成功捕获到一次高电平脉宽

            TIM5CH1_CAP_VAL = HAL_TIM_ReadCapturedValue(&htim5, TIM_CHANNEL_1); // 获取当前的计数器值

            TIM_RESET_CAPTUREPOLARITY(&htim5, TIM_CHANNEL_1);                   // 清除原来的设置      

            TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1, TIM_ICPOLARITY_RISING);// 设置上升沿捕获

        }

        else

        {

            TIM5CH1_CAP_STA = 0;                    // 清空自定义的状态寄存器

            TIM5CH1_CAP_VAL = 0;                    // 清空捕获值

            TIM5CH1_CAP_STA |= 0X40;                // 标记捕获到上升沿

            __HAL_TIM_DISABLE(&htim5);              // 关闭定时器

            __HAL_TIM_SET_COUNTER(&htim5, 0);       // 计数器值清零

            TIM_RESET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1);    // 一定要先清除原来的设置  !!          

            TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);   // 设置下降沿捕获

            __HAL_TIM_ENABLE(&htim5);               // 使能定时器        

        }   

    }

}  


此处的TIM_RESET_CAPTUREPOLARITY() 函数不同版本库可能有一处HAL库函数错误,会导致编译该函数报错,解决办法是找到该函数在 stm32f1xx_hal_tim.h 文件中的定义,删除多余的一个反括号 ‘)’ 最新版HAL库可跳过这一步

stm32f1xx_hal_tim.h

//修改前

#define TIM_RESET_CAPTUREPOLARITY(__HANDLE__, __CHANNEL__)

  (((__CHANNEL__) == TIM_CHANNEL_1) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC1P | TIM_CCER_CC1NP))) :

   ((__CHANNEL__) == TIM_CHANNEL_2) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC2P | TIM_CCER_CC2NP)) :

   ((__CHANNEL__) == TIM_CHANNEL_3) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC3P)) :

   ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC4P)))

//修改后

#define TIM_RESET_CAPTUREPOLARITY(__HANDLE__, __CHANNEL__)

  (((__CHANNEL__) == TIM_CHANNEL_1) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC1P | TIM_CCER_CC1NP)) :

   ((__CHANNEL__) == TIM_CHANNEL_2) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC2P | TIM_CCER_CC2NP)) :

   ((__CHANNEL__) == TIM_CHANNEL_3) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC3P)) :

   ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC4P)))


4.6 修改main函数

在上面 HAL_TIM_PeriodElapsedCallback() 回调函数中用以处理计数次数和时间;
在上面 HAL_TIM_IC_CaptureCallback() 回调函数负责处理捕获到的上升沿和下降沿。

接下来编写高电平持续时间处理代码

首先在 main.c 声明定义在 stm32f1xx_it.c 的外部变量

extern uint8_t TIM5CH1_CAP_STA;

extern uint16_t TIM5CH1_CAP_VAL;


然后修改 main()

/**

  * @brief  The application entry point.

  * @retval int

  */

int main(void)

{

  /* USER CODE BEGIN 1 */

  long long temp = 0;// 定义一个变量用以存储捕获到的时间 long long型是为了防止数据溢出

  /* USER CODE END 1 */


  /* MCU Configuration--------------------------------------------------------*/


  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */

  HAL_Init();


  /* USER CODE BEGIN Init */


  /* USER CODE END Init */


  /* Configure the system clock */

  SystemClock_Config();


  /* USER CODE BEGIN SysInit */


  /* USER CODE END SysInit */


  /* Initialize all configured peripherals */

  MX_USART1_UART_Init();

  MX_TIM5_Init();

  /* USER CODE BEGIN 2 */

  HAL_TIM_IC_Start_IT(&htim5,TIM_CHANNEL_1);  // 一定要开启TIM5通道1的捕获中断

  __HAL_TIM_ENABLE_IT(&htim5,TIM_IT_UPDATE);  // 一定要开启TIM5的更新中断

[1] [2]
关键字:STM32CubeMX  通用定时器 引用地址:STM32CubeMX学习笔记(23)——通用定时器接口使用(输入捕获测量脉宽)

上一篇:STM32CubeMX学习笔记(24)——通用定时器接口使用(电容按键检测)
下一篇:STM32CubeMX学习笔记(22)——CRC接口使用

推荐阅读最新更新时间:2026-03-20 13:05

用 STM32 通用定时器做微秒延时函数(STM32CubeMX版本)
环境: 开发板:STM32F4探索者(正点原子) 1.配置定时器时钟 选择时钟源 这里选择的是内部时钟,来自 RCC 的TIMxCLK,在通用定时器框图中我们可以看到如下: 而我们可以在 STM32F4xx中文参考手册中找到,TIM2 在外设总线1(APB1上),因此其时钟为 84MHz,如下图所示: 2.计数器时钟频率及计数模式 除了配置定时器的时钟,还需要配置计数器时钟频率,我们要实现微秒延时,因此计数器时钟频率应该是1MHz, 而要实现还需要以下3个参数: 预分频系数 根据STM32F4xx中文参考手册中的时钟频率计算,如下图所示: 其中fCK_PSC就是通用定时器框图中的CK_PSC, 即值为8
[单片机]
用 STM32 <font color='red'>通用</font><font color='red'>定时器</font>做微秒延时函数(<font color='red'>STM32CubeMX</font>版本)
STM32CubeMX学习笔记——STM32H743通用定时器
功能简述 主模式TIM2的中断作为从模式TIM3的时钟输入 (级联定时器) 红灯亮6灭5 频率1hz 绿灯亮3灭3 频率0.5hz STM32CubeMX配置 STM32CubeMX版本:4.27.0 配置流程: Pinout界面选择并开启需要的LED控制引脚 Clock Configuration配置时钟树 Configuration界面配置System 生成工程 Pinout配置 LED输出PIN配置,TIM2,TIM3的基本配置 Clock Configuration配置 开启系统时钟,设置TIM2、TIM3时钟(APB1) Configuration 左侧主要系统功能的开启,或中间软件层功能的开
[单片机]
<font color='red'>STM32CubeMX</font>学习笔记——STM32H743<font color='red'>通用</font><font color='red'>定时器</font>
stm32 TIM(通用定时器)
寄存器 描述 CR1 控制寄存器1 CR2 控制寄存器2 SMCR 从模式控制寄存器 DIER DMA/中断使能寄存器 SR 状态寄存器 EGR 事件产生寄存器 CCMR1 捕获/比较模式寄存器1 CCMR2 捕获/比较模式寄存器2 CCER 捕获/比较使能寄存器 CNT 计数器寄存器 PSC 预分频寄存器 APR 自动重装载寄存器 CCR1 捕获/比较寄存器1 CCR2 捕获/比较寄存器2 CCR3 捕获/比较寄存器3 CCR4 捕获/比较寄存器4 DCR DMA控制寄存器 DMAR 连续模式的DMA地址寄存器 #define PWMA TIM8- CCR1 定时器初始化
[单片机]
基于stm32单片机的通用定时器配置
stm32单片机的定时器资源相当丰富,它的定时器分为高级控制定时器、通用定时器和基本定时器,具体这些定时器资源在哪个系列的片子有就得看不同的片子的手册了。他们具体有什么区别,我也是刚接触这个,看他的数据手册介绍也是茫然,主要是刚开始摸,那些功能都没用到,反正用做定时作用的话哪种定时器都行。在这我就把我自己配置通用定时器的方法及心得简短做个总结,以防以后忘记了。我配置的是定时器2(TIM2)。 通用定时器的时钟可来自于外部或内部,选用默认即是采用内部的。通用定时器的时钟来源为APB1总线,所以首先,得将APB1外设时钟打开。 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE)
[单片机]
stm32f103——通用定时器输出PWM
通用定时器 ----输出 1,输出一个PWM 2,检测脉冲宽度 1》PWM---脉冲宽度调制 占空比:高电平占整个周期的百分比 2》PWM作用:调节灯的亮度,声音的大小,速度的快慢----平均电压值 什么是PWM信号? PWM,英文名Pulse Width Modulation,是脉冲宽度调制(记住这个名词)缩写,它是通过对一系列脉冲的宽度进行调制,等效出所需要的波形(包含形状以及幅值),对模拟信号电平进行数字编码,也就是说通过调节占空比的变化来调节信号、能量等的变化,占空比就是指在一个周期内,信号处于高电平的时间占据整个信号周期的百分比,例如方波的占空比就是50%. PWM脉冲宽度
[单片机]
stm32f103——<font color='red'>通用</font><font color='red'>定时器</font>输出PWM
PIC单片机通用定时器使用说明
一般所有单片机的定时器用做普通定时功能,都需要具备以下几点要素: 1. 时基:时基就是定时器的时钟来源,一般都是来源于内部时钟或外部时钟,并且一般都能设置对应的分频系数,因此要弄清楚 时基来源,分频器设置,设置完时钟来源和分频器就知道计时的最小单元。 2.当前计数器: 该寄存器反应的就是当前实时的计数值,这个计数值在每个计时最小单元的时间内加1或者减1。 3.计数匹配器: 一般向上计数的定时器肯定需要1个计数匹配器,当前计数器从0开始加1,一直加到与计数匹配器相等,则认为定时时间到,这个时候将置位对应标志位或者发出对应中断请求。也有向下计时器,从某个值一直减到0则认为定时时间到,这种定时器不需要计数匹配值。 4.
[单片机]
PIC单片机<font color='red'>通用</font><font color='red'>定时器</font>使用说明
通用定时器基本原理讲解
概述: STM32定时器:STM32F10x系列总共最多有8个定时器。 三种STM32定时器区别: 通用定时器功能特点描述: STM3 的通用 TIMx (TIM2、TIM3、TIM4 和 TIM5)定时器功能特点包括: 位于低速的APB1总线上(APB1) 16 位向上、向下、向上/向下(中心对齐)计数模式,自动装载计数器(TIMx_CNT)。 16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数 为 1~65535 之间的任意数值。 4 个独立通道(TIMx_CH1~4),这些通道可以用来作为: 输入捕获 输出比较 PWM 生成(边缘或中间对齐模式) 单脉冲模式输出 可使用外部信号(
[单片机]
<font color='red'>通用</font><font color='red'>定时器</font>基本原理讲解
STM32-一文搞懂通用定时器捕获/比较通道
捕获和比较 捕获 什么是捕获 所谓捕获就是通过检测捕获通道上的边沿信号。在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存器(TIMx_CCR)里面,完成一次捕获。 捕获的应用 STM32支持一下捕获模式: 输入捕获模式 PWM输入模式 输入捕获模式可以用来测量脉冲宽度或者测量频率。下图是输入捕获测量高电平脉宽的原理,假定定时器工作在向上计数模式,图中 t1~t2 时间,就是需要测量的高电平时间。 测量方法如下:首先设置定时器通道 x 为上升沿捕获,这样,t1 时刻,就会捕获到当前的 CNT 值,然后立即清零 CNT,并设置通道 x为下降沿捕获,这样到
[单片机]
STM32-一文搞懂<font color='red'>通用</font><font color='red'>定时器</font><font color='red'>捕获</font>/比较通道
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved