STM32基本定时器原理详解笔记

stm32基本定时器学习

写于2024/8/15 晚

文章目录

  • stm32基本定时器学习
  • 1.1基本定时器简介
  • 1.1.1 特性
  • 1.2 基本框图
  • 1.2.1 基本定时器时钟源
  • 1.2.2 基本定时器触发控制器
  • 1.2.3 基本定时器时基单元
  • 1.3 STM32定时器计数模式与溢出条件
  • 1.4 基本定时器寄存器
  • 1.4.1 控制寄存器 1(TIMx_CR1)
  • 1.4.2 DMA/中断使能寄存器(TIMx_DIER)
  • 1.4.3 状态寄存器(TIMx_SR)
  • 1.4.4 计数器寄存器(TIMx_CNT)
  • 1.4.5预分频寄存器(TIMx_PSC)
  • 1.4.6 自动重载寄存器(TIMx_ARR)
  • 1.5 定时器溢出时间计算公式
  • 1.6 通过定时器中断点亮LED灯
  • 在F1系列中,一个有三种定时器,分为基本定时器,通用定时器,高级定时器

    image-20240816021813801

    三种定时器的区别为

  • 基本定时器没有输入输出通道,常用作时基,即定时功能
  • 通用定时器具有多路独立通道,可用于输入捕获/输出比较,也可用作时基
  • 高级定时器除具备通用定时器所有功能外,还具备带死区控制的互补信号输出、刹车输入等功能(可用于电机控制、数字电源设计等)
  • 1.1基本定时器简介

    1.1.1 特性

    TIM6/TIM7为F103系列的基本定时器

  • 16位递增计数器(计数值:0-65535)
  • 16位预分频器(分频系数:1-65536)
  • 可用于触发DAC在更新事件(计数器溢出)时,会产生中断/DMA请求
  • 1.2 基本框图

    image-20240815233500163

    1.2.1 基本定时器时钟源

    基本定时器可以分为三部分,第一部分为定时器时钟源,我手上的板子是正点原子的战舰开发板,可以看到图中内核框图,TIM6与TIM7是挂载在图中APB1总线上,而APB1总线最高频率为36Mhz,那么TIM6与TIM7是不是最高频率也为36Mhz呢?

    image-20240815234923914

    答案并不是,通过时钟树我们可以看到,虽然TIM6TIM7都挂载在最高时钟频率为36Mhz的APB1总线上,但如果APB1分频器不为1分频,那么TIM6TIM7的时钟频率乘2,也就是72Mhz。

    image-20240815235337637

    1.2.2 基本定时器触发控制器

    控制器除了控制定时器复位、使能、计数等功能之外,还可以用于触发 DAC 转换。

    1.2.3 基本定时器时基单元

    从图上可以看到,时基单元由三部分组成

  • 计数器寄存器(TIMx_CNT)
  • 预分频寄存器(TIMx_PSC)
  • 自动重装载寄存器(TIMx_ARR)
  • 其中预分频寄存器(TIMx_PSC)与自动重装载寄存器(TIMx_ARR)具有影子寄存器,影子寄存器是实际起作用的寄存器,当计数器寄存器(TIMx_CNT)需要进行重装载时,是将自动重装载寄存器(TIMx_ARR)的影子寄存器的值重装载进自身内。该寄存器不能直接访问,需要通过修改自动重装载寄存器,等到一次更新事件后,才会将新的重装载值载入到影子寄存器中,这才真正的修改了重装载数值。

    从图中可以看出,预分频寄存器(TIMx_PSC)和自动重装载寄存器(TIMx_ARR)都具有影子寄存器。不同点在于自动重载寄存器是否具有缓冲作用还受到 ARPE 位的控制,当该位置 0 时,ARR 寄存器不进行缓冲,我们写入新的 ARR值时,该值会马上被写入 ARR 影子寄存器中,从而直接生效;当该位置 1 时,ARR 寄存器进行缓冲,我们写入新的 ARR 值时,该值不会马上被写入 ARR 影子寄存器中,而是要等到更新事件发生才会被写入 ARR 影子寄存器,这时才生效。预分频器寄存器则没有这样相关的控制位,这就是它们不同点。

    值得注意的是,更新事件的产生有两种情况,一是由软件产生,将 TIMx_EGR 寄存器的位UG 置 1,产生更新事件后,硬件会自动将 UG 位清零。二是由硬件产生,满足以下条件即可:计数器的值等于自动重装载寄存器影子寄存器的值。下面来讨论一下硬件更新事件。基本定时器的计数器(CNT)是一个递增的计数器,当寄存器(TIMx_CR1)的 CEN 位置1,即使能定时器,每来一个 CK_CNT 脉冲,TIMx_CNT 的值就会递增加 1。当 TIMx_CNT 值与 TIMx_ARR 的设定值相等时,TIMx_CNT 的值就会被自动清零并且会生成更新事件(如果开启相应的功能,就会产生 DMA 请求、产生中断信号或者触发 DAC 同步电路),然后下一个CK_CNT 脉冲到来,TIMx_CNT 的值就会递增加 1,如此循环。在此过程中,TIMx_CNT 等于TIMx_ARR 时,我们称之为定时器溢出,因为是递增计数,故而又称为定时器上溢。定时器溢出就伴随着更新事件的发生。

    1.3 STM32定时器计数模式与溢出条件

    STM32定时器一共有三种计数模式

    计数模式 溢出条件
    递增计数模式 CNT==ARR
    递减计数模式 CNT==0
    中心对齐模式 CNT==ARR-1、CNT==1

    image-20240816002128811

    image-20240816002159691

    1.4 基本定时器寄存器

    1.4.1 控制寄存器 1(TIMx_CR1)

    image-20240816004212552

  • 位 0(CEN)用于使能或者禁止计数器,该位置 1 计数器开始工作,置 0 则停止。
  • 位 7(APRE)用于控制自动重载寄存器 ARR 是否具有缓冲作用
  • 1.4.2 DMA/中断使能寄存器(TIMx_DIER)

    image-20240816004856624

  • 该寄存器位 0(UIE)用于使能或者禁止更新中断,因为本实验我们用到中断,所以该位需要置 1。
  • 位 8(UDE)用于使能或者禁止更新 DMA 请求。
  • 1.4.3 状态寄存器(TIMx_SR)

    image-20240816005420497

    该寄存器位 0(UIF)是中断更新的标志位,当发生中断时由硬件置 1,然后就会执行中断服务函数,需要软件去清零,所以我们必须在中断服务函数里把该位清零。如果中断到来后,不把该位清零,那么系统就会一直进入中断服务函数,这显然不是我们想要的。

    1.4.4 计数器寄存器(TIMx_CNT)

    image-20240816005557337

    该寄存器位[15:0]就是计数器的实时的计数值。

    1.4.5预分频寄存器(TIMx_PSC)

    image-20240816005631238

    该寄存器是 TIM6/TIM7 的预分频寄存器,比如我们要 7200 分频,就往该寄存器写入 7199。注意这是 16 位的寄存器,写入的数值范围是 0 到 65535,分频系数范围:1 到 65536。

    1.4.6 自动重载寄存器(TIMx_ARR)

    image-20240816005735950

    该寄存器可以由 APRE 位设置是否进行缓冲。计数器的值会和 ARR 寄存器影子寄存器进行比较,当两者相等,定时器就会溢出,从而发生更新事件,如果打开更新中断,还会发生更新中断。

    1.5 定时器溢出时间计算公式

    image-20240816010104298

    1.6 通过定时器中断点亮LED灯

    LED.c

    #include  "./BSP/TIMER/timer.h"
    #include "./BSP/LED/led.h"
    
    
    TIM_HandleTypeDef g_timer_handle;
    void timer_init(uint16_t psc,uint16_t arr)
    {
        g_timer_handle.Instance =TIM6;
        g_timer_handle.Init.Prescaler = psc;
        g_timer_handle.Init.Period = arr;
        HAL_TIM_Base_Init(&g_timer_handle);				//初始化定时器参数
        HAL_TIM_Base_Start_IT(&g_timer_handle);			//使能更新中断和计时器计数
    }
    
    void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)	//在MSP函数中设置优先级和时钟
    {
        if(htim -> Instance == TIM6)
        {
            __HAL_RCC_TIM6_CLK_ENABLE();
            HAL_NVIC_SetPriority(TIM6_IRQn,2,2);
            HAL_NVIC_EnableIRQ(TIM6_IRQn);
        }
    
    }
    
    void TIM6_IRQHandler(void)							//初始化中断函数
    {
        HAL_TIM_IRQHandler(&g_timer_handle);
    
    }
    
    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    {
        if(htim -> Instance == TIM6)
        {
            LED0_TOGGLE();              				//在中断回调函数中设置LED0翻转
        
        }
    
    }
    
    

    main.c

    #include "./SYSTEM/sys/sys.h"
    #include "./SYSTEM/delay/delay.h"
    #include "./SYSTEM/usart/usart.h"
    #include "./BSP/LED/led.h"
    #include  "./BSP/TIMER/timer.h"
    
    int main(void)
    {
        HAL_Init();                                 /* 初始化HAL库 */
        sys_stm32_clock_init(RCC_PLL_MUL9);         /* 设置时钟,72M */
        delay_init(72);                             /* 初始化延时函数 */
        led_init();                                 /* 初始化LED */
        timer_init(1199,4999);						/* 设置定时器计时500ms */
        while(1)
        {
            delay_ms(500); //主函数只需要初始化定时器,具体功能在中断函数中实现
        }
    }
    
    

    作者:dianfu233

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32基本定时器原理详解笔记

    发表回复