STM32 HAL库开发学习5. 系统滴答定时器
- 一、滴答定时器概述
- 1. 概述
- 2. 时钟源
- 3. 寄存器
- (1)控制与状态寄存器 STK_CTRL
- (2)重载寄存器 STK_LOAD
- (3)当前值寄存器 STK_VAL
- 二、HAL库滴答定时器初始化
- 三、SysTick实现微秒级延时
- 1. 使用 STM32CubeMX创建工程
- 2. 代码实现
一、滴答定时器概述
1. 概述
滴答定时器是Cortext-M内核的一个简单定时器。
滴答定时器是一个24位的递减计数器,主要用于为嵌入式系统提供基本的定时功能,也为实时操作系统RTOS提供系统节拍。
2. 时钟源
滴答定时器有两个可选的时钟源,一个是处理器内核时钟: HCLK,另一个是外部参考时钟。
当定时器启动后,它会从设定的初始值开始递减计数。每经过一个时钟周期,计数器值减1.当计数器减到0,会产生一个中断请求,并且可以根据设置重新加截初始值。
3. 寄存器
(1)控制与状态寄存器 STK_CTRL
该寄存器用于控制滴答定时器的主要功能。其中包含了启动 / 停止定时器的位(ENABLE 位),如果将此位置 1,则启动定时器;若置 0,则停止定时器。
还有用于控制中断使能的位(TICKINT 位),当这个位置 1 时,定时器计数到 0 时会产生中断;置 0 则禁止中断。
另外,有一个位用于指示定时器当前是否正在计数(COUNTFLAG 位),可以通过读取这个位来确定定时器是否已经完成了一次计数循环。
(2)重载寄存器 STK_LOAD
这个寄存器用于设置滴答定时器的初始计数值。因为定时器是 24 位的,所以可以设置的最大值为 。通过设置这个寄存器的值,可以确定定时器每次计数循环的时长。例如,根据所选的时钟源频率和想要实现的定时周期,计算出相应的初始值并写入这个寄存器。
(3)当前值寄存器 STK_VAL
可以读取当前定时器计数器的剩余值。不过需要注意的是,在某些情况下读取这个寄存器的值可能会受到限制或者需要特殊的操作顺序。例如,在一些芯片中,可能需要先暂停定时器(通过清除 ENABLE 位)才能准确读取当前值。
二、HAL库滴答定时器初始化
使用 STM32CubeMX 生成的项目里,main函数会调用 HAL_Init();
进入该函数,可以看到如下调用 :
/* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */HAL_InitTick(TICK_INT_PRIORITY);// 宏的值
#define TICK_INT_PRIORITY 15U /*!< tick interrupt priority (lowest by default) */
这里即实现了滴答定时器的初始化。
三、SysTick实现微秒级延时
本实验实现微秒及翻转IO端口。
1. 使用 STM32CubeMX创建工程
GPIO里,配置PA8为输出,
SYS里,配置时间基准源为SysTick,Debug 为Serial Wire。
RCC,时钟源,把 High Speed Clock(HSE) 选择: Crystal/Ceramic Resonator。
然后把时钟配置 HCLK设置为72MHz:
回车,提示窗口选择OK,系统自动把PLL设置好。
打开生成的项目。
2. 代码实现
/*** @brief 微秒级延时* @param us*/
void my_delay_us(uint32_t us) {uint32_t ticks_per_us = SystemCoreClock / 1000000;uint32_t start_ticks = SysTick->VAL;uint32_t delay_ticks = us * ticks_per_us;if (delay_ticks > start_ticks) {delay_ticks = delay_ticks - start_ticks + SysTick->LOAD;} else {delay_ticks = delay_ticks + SysTick->LOAD - start_ticks;}SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;while ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == 0) {if ((SysTick->LOAD - SysTick->VAL) > delay_ticks) {break;}}SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
}/*** @brief 毫秒级延时* @param ms*/
void my_delay_ms(uint32_t ms) {while (ms--) {my_delay_us(1000);}
}
main函数:
int main(void) {/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();/* USER CODE BEGIN 2 *//* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1) {/* USER CODE END WHILE */HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_8);my_delay_ms(1);/* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}
在PA8观察输出的波形: