STM32基本定时器原理笔记

stm32基本定时器学习

写于2024/8/15 晚


在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); //主函数只需要初始化定时器,具体功能在中断函数中实现
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值