一、STM32定时器简介

(一)分类

常规定时器:

  • 基本定时器(TIM6和TIM7):拥有定时中断、主模式触发DAC的功能
  • 通用定时器(TIM2到TIM7,TIM9到TIM14):拥有基本定时器全部功能,并额外具有内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等功能。
  • 高级定时器(TIM1和TIM8):拥有通用定时器全部功能,并额外具有重复计时器、死区生成、互补输出、刹车输入等功能。
定时器种类 位数 计数器模式 产生DMA请求 捕获/比较通道 互补输出 特殊应用场景

高级定时器

(TIM1,TIM8)

16

向上,向下

向上/向下

可以 4 带可编程死区互补输出

通用定时器

(TIM2,TIM5)

32

向上,向下

向上/向下

可以 4 没有

定时计数、PWM输出、

输入捕获、输出比较

通用定时器

(TIM3,TIM4)

16

向上,向下

向上/向下

可以 4 没有

定时计数、PWM输出、

输入捕获、输出比较

通用定时器

(TIM9~TIM14)

16

向上

没有 2 没有

定时计数、PWM输出、

输入捕获、输出比较

基本定时器

(TIM6,TIM7)

16

向上,向下

向上/向下

可以 0 没有 主要应用于驱动DAC

(二 )各种定时器的结构框图

1、基本定时器

2、通用定时器

3、高级定时器

二、定时器定时中断

(一)定时器定时时序

  • 计数器计数频率:CK_CNT = CK_PSC / (PSC+1)
  • 计数器溢出频率:CK_CNT_OV = CK_CNT/( ARR+ 1) = CK_PSC/(PSC+1)/(ARR + 1)
  • 计数器溢出时间:(PSC+1)(ARR + 1) / CK_PSC

(二)定时器中断基本结构

                                                                                                                                      图来自江协科技

(三)配置流程

  1. 配置定时器基础工作参数:HAL_TIM_Base_Init()
  2. 定时器基础MSP初始化:HAL_TIM_Base_Msplnit() 配置NVIC、CLOCK等
  3. 使能更新中断并启动计数器:HAL_TIM_Base_Start_IT()
  4. 设置优先级,使能中断:HAL_NVIC_SetPriority(), HAL_NVIC_EnableIRQ()
  5. 编写中断服务函数:TIMx_IRQHandler()等 → HAL_TIM_IRQHandler()
  6. 编写定时器溢出回调函数:HAL_TIM_PeriodElapsedCallback()

(四)代码实现

TIM_HandleTypeDef htim2;


/*
计数器计数频率:CK_CNT = CK_PSC / (PSC+1)
计数器溢出频率:CK_CNT_OV = CK_CNT/( ARR+ 1)
                                = CK_PSC/(PSC+1)/(ARR + 1)
计数器溢出时间:(PSC+1)(ARR + 1) / CK_PSC
*/

//定时器中断初始化
void Timer_Tnit(u16 arr, u16 psc){
    htim2.Instance = TIM2;
    htim2.Init.Period = arr;        //自动重装载值ARR
    htim2.Init.Prescaler = psc;     //预分频值PSC
    htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;      //时钟分频因子
    htim2.Init.CounterMode = TIM_COUNTERMODE_UP;        //向上计数
    if(HAL_TIM_Base_Init(&htim2) != HAL_OK){
        Error_Handler();
    }

    HAL_TIM_Base_Start_IT(&htim2);  //开启定时器中断
}

//定时器基础MSP回调初始化函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim){
    if(htim->Instance == TIM2){
       //使能定时器7的时钟
       __HAL_RCC_TIM2_CLK_ENABLE();

       HAL_NVIC_SetPriority(TIM2_IRQn,2,0);
       HAL_NVIC_EnableIRQ(TIM2_IRQn);
    }
}

//定时器中断服务函数
void TIM2_IRQHandler(void){
    HAL_TIM_IRQHandler(&htim7);
}

//定时器中断回调函数(溢出中断)
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
    if(htim->Instance == TIM2){
       LED1_TOGGLE();
    }
}

三、输出比较(PWM输出)

(一)输出比较介绍

  •  OC(Output Compare) : 输出比较
  • 输出比较可以通过比较CNT和CRR寄存器值的关系,来对输出电平进行置0、置1或者翻转的操作,用于输出一定频率和占空比的PWM波形
  • 每个高级定时器和调用定时器都用4个输出比较通道
  • 高级定时器的前三个通道额外拥有死区生成和互补输出的功能

(二)STM32输出比较模块        

输出比较模式(输出模式控制器逻辑):

模式[OC1M] 描述
冻结[000]

CNT=CCR时,REF保持为原状态

匹配时置有效电平[001]

CNT=CCR时,REF置有效电平

匹配时置无效电平[010] CNT=CCR时,REF置无效电平
匹配时电平翻转[011] CNT=CCR时,REF电平翻转
强制为无效电平[100] CNT与CCR无效,REF强制为无效电平
强制为有效电平[101] CNT与CCR无效,REF强制为有效电平
PWM模式1[110]

向上计数:CNT<CCR时,REF置有效电平,CNT>=CCR时,REF置无效电平

向下计数:CNT>CCR时,REF置无效电平,CNT<=CCR时,REF置有效电平

PWM模式2[111]

向上计数::CNT<CCR时,REF置无效电平,CNT>=CCR时,REF置有效电平

向下计数::CNT>CCR时,REF置有效电平,CNT<=CCR时,REF置无效电平

(三)PWM基本结构

  • PWM频率:Freq = CK_PSC /(PSC + 1) / (ARR + 1)
  • PWM占空比: Duty = CRR / (ARR + 1)
  • PWM分辨率:Reso = 1 / (ARR + 1)

(四)配置流程

  1. 配置定时器基础工作参数:HAL_TIME_PWM_Init()
  2. 定时器PWM输出MSP初始化:HAL_TIM_PWM_MspInit() 配置NVIC、CLOCK、GPIO等
  3. 配置PWM模式、比较值:HAL_TIM_PWM_ConfigChannel()
  4. 使能输出并启动计数器:HAL_WIN_PWM_Start()
  5. 修改比较值控制占空比(可选):__HAL_TIM_PWM_COMPARE()
  6. 是能通道预装载值(可选):__HAL_TIME_PWM_OSxPRELOAD()

(五)代码实现

TIM_HandleTypeDef htim3;
void MYPWM_Init(u16 arr, u16 psc)
{
    // 初始化定时器3
    //配置定时器基础工作参数
    htim3.Instance = TIM3;
    htim3.Init.Prescaler = psc;     // PSC
    htim3.Init.CounterMode = TIM_COUNTERMODE_UP;    //向上计数模式
    htim3.Init.Period = arr;     // ARR值,
    htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    HAL_TIM_PWM_Init(&htim3);

    // 配置PWM通道1
    sConfigOC.OCMode = TIM_OCMODE_PWM1;    //PWM模式1
    sConfigOC.Pulse = 500; // 占空比 = 500/1000 = 50%    
    sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;    //低电平有效
    HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1);

    // 启动PWM
    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
}
//PWM初始化回调函数
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim){
    if(htim->Instance == TIM3){        //将PA6复用为定时器3通道1
        GPIO_InitTypeDef GPIO_InitStruct = {0};
        __HAL_RCC_TIM3_CLK_ENABLE();           //使能定时器3
        __HAL_RCC_GPIOA_CLK_ENABLE();           //开启GPIOA时钟

        GPIO_InitStruct.Pin=GPIO_PIN_6;             //PA6
        GPIO_InitStruct.Mode=GPIO_MODE_AF_PP;   //复用推挽输出
        GPIO_InitStruct.Pull=GPIO_NOPULL;          //不上下拉
        GPIO_InitStruct.Sped=GPIO_SPEED_FREQ_LOW;     //高速
        HAL_GPIO_Init(GPIOF,&GPIO_InitStruct);
    }
}

//修改占空比的值:修改比较值CRR
void ChangeDuty(float per){
    u32 compare = 0;
    uint32_t arr = __HAL_TIM_GET_AUTORELOAD(&htim3); // 获取ARR值
    compare = (uint32_t)((float)arr * per); // 计算CCR值
    TIM14->CCR1=compare;
}
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐