STM32定时器详细教程

STM32定时器

1. 引言

STM32微控制器以其丰富的外设和强大的性能,在嵌入式领域得到了广泛应用。其中,定时器作为其核心外设之一,在实现精确时间控制、波形生成、事件测量等方面发挥着不可替代的作用。本教程将深入探讨STM32定时器的分类、工作原理、主要寄存器配置以及常见应用,旨在帮助读者全面理解并熟练运用STM32定时器。

2. STM32定时器分类

STM32系列微控制器通常包含以下三类定时器:

  • 基本定时器 (Basic Timers):如TIM6、TIM7。功能相对简单,主要用于产生时基,触发中断或DAC转换。它们不具备输入捕获、输出比较、PWM生成等高级功能。
  • 通用定时器 (General-Purpose Timers):如TIM2、TIM3、TIM4、TIM5等。功能较为全面,除了基本定时器的功能外,还支持输入捕获、输出比较、PWM生成、单脉冲模式等,适用于各种通用定时需求。
  • 高级控制定时器 (Advanced-Control Timers):如TIM1、TIM8。功能最为强大,在通用定时器的基础上,增加了重复计数器、死区生成、互补输出、刹车输入等高级特性,特别适用于电机控制、电源管理等需要高精度和复杂波形输出的应用。

3. 定时器工作原理与核心寄存器

STM32定时器的核心是一个可编程的计数器,通过对时钟信号进行计数来实现定时功能。其基本工作原理和主要寄存器如下:

3.1. 时基单元

所有STM32定时器都包含一个时基单元,这是实现定时功能的基础。时基单元主要由以下几个核心寄存器组成:

  • 计数器寄存器 (TIMx_CNT):这是一个16位或32位的计数器,它会根据定时器时钟(CK_CNT)进行计数。计数模式可以是向上计数、向下计数或向上/向下计数。
  • 预分频器寄存器 (TIMx_PSC):这是一个16位的寄存器,用于对定时器时钟源(CK_INT)进行分频。实际分频系数为 PSC + 1。通过调整PSC的值,可以改变计数器的计数速度,从而控制定时周期。
  • 自动重载寄存器 (TIMx_ARR):这是一个16位或32位的寄存器,用于设置计数器的上限值。当计数器(TIMx_CNT)的值达到ARR中设定的值时,会触发一个更新事件(Update Event, UEV),计数器可以清零或重新加载,从而完成一个定时周期。
  • 重复计数器寄存器 (TIMx_RCR):仅存在于高级控制定时器中。它用于控制更新事件的生成频率。当计数器溢出时,并不会立即产生更新事件,而是先使RCR减1,直到RCR减到0时才产生更新事件。这在PWM输出中非常有用,可以控制PWM的周期数。

3.2. 影子寄存器

STM32定时器中的一些重要寄存器(如ARR、PSC)具有“影子寄存器”机制。这意味着我们对这些寄存器进行写入操作时,实际上是写入到其“预装载寄存器”(Preload Register,也称为本体寄存器),而不是直接写入到实际工作的“影子寄存器”。只有在特定事件(如更新事件UEV)发生时,预装载寄存器中的值才会被传输到影子寄存器中,从而生效。

这种机制的目的是为了防止在定时器运行过程中,由于修改寄存器值而导致的不确定性或毛刺。例如,在PWM输出过程中,如果直接修改ARR或PSC,可能会导致PWM波形出现异常。通过影子寄存器,可以确保在当前周期结束后,新的配置才会在下一个周期开始时生效,从而保证波形的平滑过渡。

3.3. 定时周期计算

定时器的中断周期(或溢出时间)可以通过以下公式计算:

中断周期 = (ARR + 1) * (PSC + 1) / 定时器时钟频率

其中:

  • 定时器时钟频率:通常是APB1或APB2总线时钟经过倍频后的频率。
  • PSC:预分频器寄存器的值。
  • ARR:自动重载寄存器(周期)的值。

例如,如果定时器时钟频率为72MHz,PSC设置为7199,ARR设置为4999,则中断周期为:

(4999 + 1) * (7199 + 1) / 72,000,000 = 5000 * 7200 / 72,000,000 = 36,000,000 / 72,000,000 = 0.5 秒

这意味着每0.5秒会产生一次定时器中断。

3.4. 其他重要寄存器

  • 控制寄存器1 (TIMx_CR1):用于配置定时器的工作模式,如计数器使能、计数方向、时钟分频等。
  • 事件生成寄存器 (TIMx_EGR):通过写入特定位,可以软件触发更新事件(UEV),强制将预装载寄存器中的值传输到影子寄存器。
  • DMA/中断使能寄存器 (TIMx_DIER):用于使能或禁用定时器的各种中断和DMA请求,如更新中断、捕获/比较中断等。

4. 基本定时器配置示例 (HAL库)

以STM32 HAL库为例,配置一个基本定时器(如TIM6)实现定时中断的步骤如下:

  1. 开启定时器时钟
    __HAL_RCC_TIM6_CLK_ENABLE();
    
  2. 配置时基单元
    TIM_HandleTypeDef htim6;
    htim6.Instance = TIM6;
    htim6.Init.Prescaler = 7199; // 预分频器,例如,如果时钟为72MHz,分频后为10KHz
    htim6.Init.Period = 4999;    // 自动重载值,例如,配合预分频器实现0.5秒中断
    htim6.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数模式
    htim6.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 时钟不分频
    HAL_TIM_Base_Init(&htim6);
    
  3. 配置NVIC中断
    HAL_NVIC_SetPriority(TIM6_DAC_IRQn, 0, 0); // 设置中断优先级
    HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn);         // 使能中断
    
  4. 启动定时器并使能中断
    HAL_TIM_Base_Start_IT(&htim6);
    
  5. 编写中断回调函数
    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    {
        if(htim->Instance == TIM6)
        {
            // 在这里编写定时器中断服务代码,例如翻转LED
        }
    }
    

5. 通用定时器与高级定时器功能概述

在基本定时器的基础上,通用定时器和高级定时器提供了更丰富的功能:

5.1. 输入捕获 (Input Capture)

输入捕获功能用于测量外部信号的脉冲宽度、频率或周期。当外部信号的边沿(上升沿、下降沿或双边沿)发生时,定时器会将当前计数器的值锁存到捕获/比较寄存器(TIMx_CCR)中,并触发中断。通过两次捕获事件之间计数器值的差值,可以计算出信号的周期或脉宽。

5.2. 输出比较 (Output Compare)

输出比较功能用于在特定时间点产生输出事件,可以控制GPIO引脚电平翻转,或生成单脉冲。通过将计数器的值与捕获/比较寄存器(TIMx_CCR)中的预设值进行比较,当两者相等时,会触发输出事件。

5.3. PWM波形生成 (PWM Generation)

PWM(Pulse Width Modulation,脉冲宽度调制)是利用定时器的输出比较功能实现的。通过周期性地改变输出方波的占空比,可以模拟模拟信号的输出。广泛应用于电机调速、LED亮度控制、D/A转换等。通用定时器和高级定时器都可以生成PWM波形。

HAL库PWM生成示例:

以下是一个使用STM32 HAL库配置通用定时器(如TIM3)生成PWM波的示例:

  1. GPIO和定时器时钟使能
    __HAL_RCC_GPIOC_CLK_ENABLE(); // 假设PWM输出引脚为PC6 (TIM3_CH1)
    __HAL_RCC_TIM3_CLK_ENABLE();
    
  2. 配置GPIO为复用推挽输出
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_6; // PC6
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 复用推挽输出
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF2_TIM3; // PC6复用为TIM3_CH1
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
    
  3. 配置定时器时基单元
    TIM_HandleTypeDef htim3;
    htim3.Instance = TIM3;
    htim3.Init.Prescaler = 71;   // 预分频器,例如,如果时钟为72MHz,分频后为1MHz
    htim3.Init.Period = 999;     // 自动重载值,例如,周期为1ms (1MHz / (999+1) = 1KHz)
    htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    HAL_TIM_Base_Init(&htim3);
    
  4. 配置PWM输出通道
    TIM_OC_InitTypeDef sConfigOC = {0};
    sConfigOC.OCMode = TIM_OCMODE_PWM1; // PWM模式1
    sConfigOC.Pulse = 499;             // 占空比,例如,50%占空比 (499+1)/(999+1) = 0.5
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; // 输出极性高
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1);
    
  5. 启动PWM输出
    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
    

通过修改 sConfigOC.Pulse 的值,可以动态调整PWM的占空比,从而实现调光、调速等功能。

5.4. 编码器接口 (Encoder Interface)

高级定时器通常支持编码器接口模式,可以直接解码正交编码器信号。通过监测编码器A、B相信号的相位差和脉冲数,定时器可以自动更新计数器的值,从而精确测量旋转位置和速度。

5.5. 死区生成与互补输出 (Dead-Time Generation & Complementary Outputs)

这是高级控制定时器特有的功能,主要用于电机控制。在驱动半桥或全桥电路时,为了避免上下桥臂同时导通造成短路(直通),需要在开关管关断和导通之间插入一个短暂的延时,即死区时间。高级定时器可以自动生成带有死区时间的互补PWM输出,简化了电机驱动的设计。

5.6. 刹车输入 (Break Input)

高级控制定时器还支持刹车输入功能。当外部刹车信号有效时,定时器可以立即停止PWM输出,并将所有输出引脚置于预设的安全状态,用于紧急停机或故障保护。

你可能感兴趣的:(c语言,stm32,嵌入式硬件,单片机)