STM32学习·HAL库速通篇(六)·系统定时器——SysTick

目录
1. SysTick 简介
SysTick— 系统定时器是属于 CM3 内核中的一个外设,内嵌在 NVIC 中。系统定时器从硬件特性来看:
- 它是一个24 位向下递减计数器,最大计数值为 2²⁴‑1;
- 计数时钟通常来源于系统时钟 SYSCLK,常见配置为 72MHz;
- 每计数一次所消耗的时间为 1/SYSCLK,计时精度由系统主频决定。
由于属于内核级外设,只要是 CM3 内核的单片机,无论厂家、型号差异,其 SysTick 的寄存器定义、工作机制完全一致。
2. SysTick 工作原理
SysTick 的核心工作机制非常简洁,以向下计数 + 中断触发为核心:
计数逻辑:SysTick 从程序设定的重装载值开始,每来一个时钟周期,计数值自动减 1。当计数值递减到 0 时,会自动触发一次 SysTick 中断,并在中断后自动重新加载计数值,继续循环计数。
中断触发条件:当重装载数值寄存器中的值递减到 0 时,计数器溢出,硬件自动置位中断标志,并向 NVIC 提交中断请求。如果开启了 SysTick 中断,CPU 就会进入对应的中断服务函数。
循环工作机制:计数器归零后,会自动从重装载寄存器中取出预设值,重新开始新一轮递减,从而实现周期性定时、周期性中断,形成稳定的系统时基。
3. 中断
在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行:

在此时的断点部分,若是此时主程序还在进行例如加减乘除运算,但是突然有个更加紧急的的事情需要处理,可以在此时进行中断,优先处理更加紧急的事情,等事情处理完后,在返回主程序继续处理。
在中断这里,我们在断点处离开,编译器会自动帮我们保护现场(当前程序),等我们回来(中断完成后),继续工作。
详细的解释可以参考:
4. 工程配置
这里不再一步一步演示步骤,详细可以参考:
STM32学习·HAL库速通篇(三)·如何在STM32CubeMX新建工程_stm32cubemx 配置cmsis库-CSDN博客
唯一区别就是多声明了两个引脚:

生成代码,找到 main 函数中的 HAL_init() 函数跳转(注意先编译一下):

可以发现这样一行代码:

起作用就是使用系统定时器(SysTick)作为时基源,并配置1毫秒的时钟节拍(复位后的默认时钟为高速内部时钟HSI),我们再次跳转看一下:
/**
* @brief 该函数配置时基的来源。
* 时基源被配置为生成1毫秒的时间基准,并设置专属的Tick中断优先级。
* @note 该函数会在程序复位后由HAL_Init()自动调用,或在任何通过HAL_RCC_ClockConfig()
* 重新配置时钟时被调用。
* @note 在默认实现中,SysTick定时器是时基的来源。它用于按固定时间间隔生成中断。
* 若在外设中断服务函数(ISR)中调用HAL_Delay(),需特别注意:
* SysTick中断的优先级必须高于(数值上更小)该外设中断。否则,调用该ISR的进程会被阻塞。
* 该函数被声明为__weak(弱定义),以便用户文件中可以重写此实现。
* @param TickPriority: Tick中断的优先级。
* @retval HAL状态(成功/失败)。
*/
__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
/* 配置SysTick,使其每隔1毫秒触发一次中断 */
if (HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq)) > 0U)
{
return HAL_ERROR; // 配置失败,返回错误状态
}
/* 配置SysTick中断的优先级 */
if (TickPriority < (1UL << __NVIC_PRIO_BITS))
{
HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority, 0U); // 设置SysTick中断优先级
uwTickPrio = TickPriority; // 保存配置的优先级值
}
else
{
return HAL_ERROR; // 优先级值非法,返回错误状态
}
/* 返回函数执行状态 */
return HAL_OK; // 配置成功,返回正常状态
}

其中对于 SystemCoreClock 的值,我们跳转可以发现其值为:

那么这个 8000000 是怎么来的呢?由于我们这里使用的是高速内部晶振(HSI),其对应的复位后默认的核心时钟频率为 8MHz 也就是 8000000。
5. 代码编写
我们要如何使用呢?首先找到 stm32f1xx_it.c 文件,这里存放的是一些中断服务函数,找到 SysTick_Handler() 函数:

我们在 SysTick 中断服务函数编写代码,累加实现每隔500ms电平翻转一次:
/**
* @brief This function handles System tick timer.
*/
void SysTick_Handler(void)
{
/* USER CODE BEGIN SysTick_IRQn 0 */
// 静态变量:累计SysTick中断次数(1ms/次),仅初始化一次
static uint16_t count = 0;
// 计数自增:每1ms加1
count++;
// 累计500ms(500次中断),翻转LED电平
if(count >= 500)
{
count = 0; // 清零,重新计数
// 翻转PA0/PA1/PA2电平:亮→灭、灭→亮
HAL_GPIO_TogglePin(GPIOB, LED_R_Pin | LED_G_Pin | LED_B_Pin);
}
/* USER CODE END SysTick_IRQn 0 */
HAL_IncTick();
/* USER CODE BEGIN SysTick_IRQn 1 */
/* USER CODE END SysTick_IRQn 1 */
}
完整工程:


更多推荐
所有评论(0)