STM32 第18讲 基本定时器(简介/计数模式/寄存器/溢出时间计算方法/实验)

基本定时器简介

STM32F407 有两个基本定时器 TIM6 和 TIM7
主要特性:
16 位自动重载递增计数器,计数值 1 ~ 65535;
16 位可编程预分频器,预分频系数 1~65536,用于对计数器时钟频率进行分频;
还可以触发 DAC 的同步电路,以及生成中断/DMA 请求。
分频 = 设置的分频系数 + 1

基本定时器框图

在这里插入图片描述

  • ①时钟源
    基本定时器时钟挂
    载在 APB1 总线,所以它的时钟来自于 APB1 总线,但是基本定时器时钟不是直接由 APB1 总线直接提供,而是先经过一个倍频器。当 APB1 的预分频器系数为 1 时,这个倍频器系数为 1,即定时器的时钟频率等于 APB1 总线时钟频率;当 APB1 的预分频器系数≥2 分频时,这个倍频器系数就为 2 , 即定时器的时钟频率等于 APB1 总 线时钟频率的两倍 。我们 在sys_stm32_clock_init 时钟设置函数已经设置 APB1 总线时钟频率为 42Mhz,APB1 总线的预分频器分频系数是 2,所以挂载在 APB1 总线的定时器时钟频率为 84Mhz。
  • ②控制器
    控制器除了控制定时器复位、使能、计数等功能之外,还可以用于触发 DAC 转换
  • ③时基单元
    时基单元包括:计数器寄存器(TIMx_CNT)、预分频器寄存器(TIMx_PSC)、自动重载寄存器(TIMx_ARR) 。基本定时器的这三个寄存器都是 16 位有效数字,即可设置值范围是 0~65535。

时基单元中的预分频器 PSC,它有一个输入和一个输出。输入 CK_PSC 来源于控制器部分,实际上就是来自于内部时钟(CK_INT),即 2 倍的 APB1 总线时钟频率(84MHz)。输出 CK_CNT是分频后的时钟,它是计数器实际的计数时钟,通过设置预分频器寄存器(TIMx_PSC)的值可以得到不同频率 CK_CNT。
在这里插入图片描述

  • 预分频器寄存器(TIMx_PSC)可以在运行过程中修改它的数值,新的预分频数值将在下一个更新事件时起作用。因为更新事件发生时,会把 TIMx_PSC 寄存器值更新到其影子寄存器中,这才会起作用。

    影子寄存器:影子寄存器是一个实际起作用的寄存器,不可直接访问。

自动重载寄存器及其影子寄存器的作用和上述同理。不同点在于自动重载寄存器是否具有缓冲作用还受到 ARPE 位的控制,当该位置 0 时,ARR 寄存器不进行缓冲,我们写入新的 ARR值时,该值会马上被写入 ARR 影子寄存器中,从而直接生效;当该位置 1 时,ARR 寄存器进行缓冲,我们写入新的 ARR 值时,该值不会马上被写入 ARR 影子寄存器中,而是要等到更新事件发生才会被写入 ARR 影子寄存器,这时才生效。

产生更新事件的两种情况:

  1. 一是由软件产生,将 TIMx_EGR 寄存器的位UG 置 1,产生更新事件后,硬件会自动将 UG 位清零。
  2. 二是由硬件产生,满足以下条件即可:计数器的值等于自动重装载寄存器影子寄存器的值。下面来讨论一下硬件更新事件。

计数模式及溢出条件

在这里插入图片描述
通过时序图理解计数模式

递增计数模式

在这里插入图片描述

递减计数模式

在这里插入图片描述

中间对齐计数模式

在这里插入图片描述

相关寄存器

控制寄存器1 (TIMx_CR1)

在这里插入图片描述

DMA/中断使能寄存器(TIMx_DIER)

用于使能更新中断
在这里插入图片描述

状态寄存器(TIMx_SR)

用于判断是否发生了更新中断,由硬件置1,软件清零
在这里插入图片描述

计数器寄存器(TIMx_CNT)

计数器实时数值,可用于设置计数器初始值
在这里插入图片描述

预分频寄存器(TIMx_PSC)

在这里插入图片描述
写入的数值范围是 0 到 65535,分频系数范围:1 到 65536。

自动重装载寄存器(TIMx_ARR)

在这里插入图片描述
计数器的值会和 ARR 寄存器影子寄存器进行比较,当两者相等,定时器就会溢出,从而发生更新事件,如果打开更新中断,还会发生更新中断。

溢出时间计算方法

在这里插入图片描述

实验

定时器中断配置步骤

  1. 配置定时器基础工作参数
  2. 定时器基础MSP初始化
  3. 使能更新中断并启动定时器
  4. 设置优先级,使能中断
  5. 编写中断服务函数
  6. 编写中断服务函数

相关HAL库函数介绍

在这里插入图片描述
关键结构体介绍

typedef struct
{
	 TIM_TypeDef *Instance; /* 外设寄存器基地址 */
	 TIM_Base_InitTypeDef Init; /* 定时器初始化结构体*/
	 HAL_TIM_ActiveChannel Channel; /* 定时器通道 */
	 DMA_HandleTypeDef *hdma[7]; /* DMA 管理结构体 */
	 HAL_LockTypeDef Lock; /* 锁定资源 */
	 __IO HAL_TIM_StateTypeDef State; /* 定时器状态 */
	 __IO HAL_TIM_ChannelStateTypeDef ChannelState; /* 定时器通道状态 */
	 __IO HAL_TIM_ChannelStateTypeDef ChannelNState; /* 定时器互补通道状态 */
	 __IO HAL_TIM_DMABurstStateTypeDef DMABurstState; /* DMA 溢出状态 */
}TIM_HandleTypeDef;


/* TIM_Base_InitTypeDef 结构体 */
typedef struct
{
	 uint32_t Prescaler; /* 预分频系数 */ 
	 uint32_t CounterMode; /* 计数模式 */
	 uint32_t Period; /* 自动重载值 ARR */
	 uint32_t ClockDivision; /* 时钟分频因子 */ 
	 uint32_t RepetitionCounter; /* 重复计数器 */
	 uint32_t AutoReloadPreload; /* 自动重载预装载使能 */
} TIM_Base_InitTypeDef;

定时器中断实验

  • 实现功能
    使用TIM6,实现500ms定时器中断,在中断中反转LED1,在main函数中通过延时函数反转LED0。
  • bitm.h
    对基本定时器,中断进行宏定义
#ifndef __BTIM_H
#define __BTIM_H

#include "./SYSTEM/sys/sys.h"


/******************************************************************************************/
/* 基本定时器 定义 */

/* TIMX 中断定义 
 * 默认是针对TIM6/TIM7
 * 注意: 通过修改这4个宏定义,可以支持TIM1~TIM8任意一个定时器.
 */
 
#define BTIM_TIMX_INT                       TIM6
#define BTIM_TIMX_INT_IRQn                  TIM6_DAC_IRQn
#define BTIM_TIMX_INT_IRQHandler            TIM6_DAC_IRQHandler
#define BTIM_TIMX_INT_CLK_ENABLE()          do{ __HAL_RCC_TIM6_CLK_ENABLE(); }while(0)  /* TIM6 时钟使能 */

/******************************************************************************************/

void btim_timx_int_init(uint16_t arr, uint16_t psc);    /* 基本定时器 定时中断初始化函数 */

#endif
  • bitm.c
  1. 基本定时器初始化函数
#include "./BSP/LED/led.h"
#include "./BSP/TIMER/btim.h"


TIM_HandleTypeDef g_timx_handler;         /* 定时器参数句柄 */
/**
* @brief       基本定时器TIMX定时中断初始化函数
* @note
*              基本定时器的时钟来自APB1,当PPRE1 ≥ 2分频的时候
*              基本定时器的时钟为APB1时钟的2倍, 而APB1为42M, 所以定时器时钟 = 84Mhz
*              定时器溢出时间计算方法: Tout = ((arr + 1) * (psc + 1)) / Ft us.
*              Ft=定时器工作频率,单位:Mhz
*
* @param       arr : 自动重装值。
* @param       psc : 时钟预分频数
* @retval      无
*/
void btim_timx_int_init(uint16_t arr, uint16_t psc)
{
   g_timx_handler.Instance = BTIM_TIMX_INT;                      /* 定时器x */
   g_timx_handler.Init.Prescaler = psc;                          /* 分频 */
   g_timx_handler.Init.CounterMode = TIM_COUNTERMODE_UP;         /* 递增计数模式 */
   g_timx_handler.Init.Period = arr;                             /* 自动装载值 */
   HAL_TIM_Base_Init(&g_timx_handler);
   
   HAL_TIM_Base_Start_IT(&g_timx_handler);                       /* 使能定时器x和定时器更新中断 */
}
  1. 底层驱动代码
**
 * @brief       定时器底层驱动,开启时钟,设置中断优先级
                此函数会被HAL_TIM_Base_Init()函数调用
 * @param       无
 * @retval      无
 */
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == BTIM_TIMX_INT)
    {
        BTIM_TIMX_INT_CLK_ENABLE();                     /* 使能TIMx时钟 */
        HAL_NVIC_SetPriority(BTIM_TIMX_INT_IRQn, 1, 3); /* 抢占1,子优先级3 */
        HAL_NVIC_EnableIRQ(BTIM_TIMX_INT_IRQn);         /* 开启ITMx中断 */
    }
}
  1. TIM中断服务函数
/**
 * @brief       基本定时器TIMX中断服务函数
 * @param       无
 * @retval      无
 */
void BTIM_TIMX_INT_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&g_timx_handler);  /* 定时器回调函数 */
}
  1. 回调函数
/**
 * @brief       回调函数,定时器中断服务函数调用
 * @param       无
 * @retval      无
 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == BTIM_TIMX_INT)
    {
        LED1_TOGGLE(); /* LED1反转 */
    }
}
  • main.c
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/TIMER/btim.h"


int main(void)
{    
    HAL_Init();                             /* 初始化HAL库 */
    sys_stm32_clock_init(336, 8, 2, 7);     /* 设置时钟,168Mhz */
    delay_init(168);                        /* 延时初始化 */
    usart_init(115200);                     /* 串口初始化为115200 */
    led_init();                             /* 初始化LED */
    btim_timx_int_init(5000 - 1, 8400 - 1); /* 84 000 000 / 84 00 = 10 000 10Khz的计数频率,计数5K次为500ms */
    
    while(1)
    {
        LED0_TOGGLE();                      /* LED0(红灯) 翻转 */
        delay_ms(200);
    }
}
  • 16
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值