STM32 HAL库开发学习13. 定时器及基本定时器使用_stm32定时器hal库
STM32 HAL库开发学习13. 定时器及基本定时器使用
- 一、定时器概述
-
- 1. 定时器简介
- 2. 定时器常见类型
- 3. STM32定时器特性表
-
- F1系列
- H7系列
- 二、基本定时器
-
- 1. 基本定时器功能简介
- 2. 时钟树
- 3. STM32 定时器计数模式
- 4. STM32 定时器相关寄存器
-
- (1)TIMx_CR1 设置ARR寄存器是否有缓冲、关闭/开启计数器
-
- 位7:ARPE: 自动重载预装载使能(Auto-reload preload enable)
- 位0:CEN:计数器使能(Counter enable)
- (2)TIMx_DIER
-
- 位8: UDE:更新DMA请求使能(Update DMA request enable)
- 位0:UIE:更新中断使能(Update interrupt enable)
- (3)TIMx_SR 状态寄存器
-
- 位0: UIF:更新中断标志(Update interrupt flag)
- (4)TIMx_CNT 计数器寄存器
- (5)TIMx_PSC 预分频器寄存器
- (6)TIMx_ARR 自动重装载寄存器
- 5. 定时器溢出时间计算方法
- 三、定时器配置步骤
-
- 1. 配置定时器基础工作参数
- 2. 定时器基础MSP初始化
- 3. 使能更新中断并启动计数器
- 4. 设置优先级,使能中断
- 5. 编写中断服务函数
- 6. 清除中断标志位
- 四、定时器配置实例
-
- 1. STM32CubeMX配置 启用TIM6
- 2. 启动 TIM6全局中断
- 3. 生成的部分代码
-
- main.c里TIM6初始化
- stm32f1xx_it.c 中断
- 4. 手工添加代码
-
- (1)TIM6初始化的代码里,添加启动中断
- (2)实现中断回调函数
一、定时器概述
1. 定时器简介
实现定时器的方式一般有软件、硬件两种方式,本文主要针对STM32的硬件定时器。
定时器的核心是一个计数器,该计数器会按照一定的时钟频率进行加 1 或减 1 操作。当计数器的值达到预设的阈值(即自动重装载值)时,会触发特定的事件,如产生中断、更新输出信号等。同时,计数器可以根据配置自动重新开始计数,形成周期性的定时操作。
2. 定时器常见类型
3. STM32定时器特性表
F1系列
H7系列
二、基本定时器
1. 基本定时器功能简介
基本定时器有TIM6/TIM7,其主要特性有:
- 基本定时器使用 16 位的计数器,计数模式为向上计数,即从 0 开始计数,逐步递增,直到达到自动重载寄存器(ARR)中设置的值,然后计数器会重新归零并开始下一轮计数。
- 可编程预分频器可以对定时器的时钟源进行分频,预分频系数范围通常为 1 - 65536。通过设置预分频寄存器(PSC)的值,可以调整定时器的计数频率,从而实现不同的定时精度。
- 自动重载寄存器(ARR)用于存储计数器的上限值。当计数器的值达到 ARR 中设置的值时,会产生更新事件,计数器会重新归零。
- 计数器溢出(达到 ARR 值)时会产生更新事件。更新事件可以用于触发一些操作,例如触发 DAC(数模转换器)或 ADC(模数转换器)的转换。
- 基本定时器可以产生 DMA(直接内存访问)请求。当定时器产生更新事件时,可以触发 DMA 传输,将数据从一个内存位置传输到另一个内存位置,而无需 CPU 的干预,提高系统效率。
2. 时钟树
在STM32F1中,TIM1和TIM8是挂载在APB2总线上,(最大稳定频率72MHz)
而TIM2~5挂载在APB1总线上(最大频率36MHz)。
并不是挂载在APB1上,定时器频率最大就是36MHz,还要取决于预分频系数,如下图所示的 TIM1 Timer x1,2 Multiplier。
3. STM32 定时器计数模式
4. STM32 定时器相关寄存器
(1)TIMx_CR1 设置ARR寄存器是否有缓冲、关闭/开启计数器
位7:ARPE: 自动重载预装载使能(Auto-reload preload enable)
- 0: TIMx_ARR寄存器没有缓冲,默认值,赋值后立即将ARR的值加载到影子寄存器
- 1: TIMx_ARR寄存器有缓冲,在更新事件时自动将ARR的值加载到影子寄存器
位0:CEN:计数器使能(Counter enable)
- 0:关闭计数器
- 1: 使能计数器
(2)TIMx_DIER
位8: UDE:更新DMA请求使能(Update DMA request enable)
- 0:关闭DMA请求
- 1: 使能DMA请求
位0:UIE:更新中断使能(Update interrupt enable)
- 0:关闭更新中断
- 1: 使能更新中断
(3)TIMx_SR 状态寄存器
位0: UIF:更新中断标志(Update interrupt flag)
- 0:无更新中断
- 1: 有更新中断
在中断服务函数中,需要手动清除中断标志位,否则会一直触发中断。
(4)TIMx_CNT 计数器寄存器
- 位宽为16位,用于存储计数器的值。
(5)TIMx_PSC 预分频器寄存器
- 位宽为16位,用于设置预分频器的值。
- 计数器的时钟频率 = 定时器时钟频率 / (预分频器值 + 1)。
(6)TIMx_ARR 自动重装载寄存器
- 位宽为16位,用于设置计数器的上限值。
- 当计数器的值达到 ARR 中设置的值时,会产生更新事件,计数器会重新归零。
- 如果自动重装载值为0,则计数器停止 。
5. 定时器溢出时间计算方法
定时器溢出时间 T o u t =(自动重装载值ARR+1)∗(预分频系数PSC+1)/定时器时钟频率 F t 定时器溢出时间T_{out} = (自动重装载值ARR + 1) * (预分频系数PSC + 1) / 定时器时钟频率F_t 定时器溢出时间Tout=(自动重装载值ARR+1)∗(预分频系数PSC+1)/定时器时钟频率Ft
三、定时器配置步骤
1. 配置定时器基础工作参数
HAL_TIM_Base_Init(&htim);
2. 定时器基础MSP初始化
HAL_TIM_Base_MspInit(&htim);
配置NVIC,CLOCK等, GPIO配置
3. 使能更新中断并启动计数器
HAL_TIM_Base_Start_IT(&htim);
4. 设置优先级,使能中断
HAL_NVIC_SetPriority(TIMx_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIMx_IRQn);
5. 编写中断服务函数
void TIMx_IRQHandler(void)
6. 清除中断标志位
__HAL_TIM_CLEAR_IT(&htim, TIM_IT_UPDATE);
另外有一个定时器更新中断回调函数,在中断服务函数中会自动调用,该函数用户可以自行重写:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);
四、定时器配置实例
本示例使用定时器6,实现500ms定时器更新中断,控制GPIO口翻转。本项目在之前项目基础上增加配置,省略了GPIO等配置说明 。
时钟频率设置如下:
1. STM32CubeMX配置 启用TIM6
超时时间=(499+1)*(7999+1)/8MHz = 500ms。
2. 启动 TIM6全局中断
3. 生成的部分代码
main.c里TIM6初始化
/** * @brief TIM6 Initialization Function * @param None * @retval None */static void MX_TIM6_Init(void){ /* USER CODE BEGIN TIM6_Init 0 */ /* USER CODE END TIM6_Init 0 */ TIM_MasterConfigTypeDef sMasterConfig = {0}; /* USER CODE BEGIN TIM6_Init 1 */ /* USER CODE END TIM6_Init 1 */ htim6.Instance = TIM6; htim6.Init.Prescaler = 7999; htim6.Init.CounterMode = TIM_COUNTERMODE_UP; htim6.Init.Period = 499; htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; if (HAL_TIM_Base_Init(&htim6) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM6_Init 2 */ /* USER CODE END TIM6_Init 2 */}
stm32f1xx_it.c 中断
/** * @brief This function handles TIM6 global interrupt. */void TIM6_IRQHandler(void){ /* USER CODE BEGIN TIM6_IRQn 0 */ /* USER CODE END TIM6_IRQn 0 */ HAL_TIM_IRQHandler(&htim6); /* USER CODE BEGIN TIM6_IRQn 1 */ /* USER CODE END TIM6_IRQn 1 */}
4. 手工添加代码
(1)TIM6初始化的代码里,添加启动中断
/* 在TIM6初始化函数末尾添加 *//* USER CODE BEGIN TIM6_Init 2 */HAL_TIM_Base_Start_IT(&htim6); // 启动定时器中断/* USER CODE END TIM6_Init 2 */
(2)实现中断回调函数
/* 定时器6中断回调 */void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){ if(htim->Instance == TIM6) { // 这里添加中断处理代码 HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_0); }}