SysTick(System Timer)是一种系统计时器,它是一个24位只能向下递减的计数器(计数器每计数一次的时间为1/SYSCLK),通常用于嵌入式系统中,用于提供基本的系统定时和时钟服务。SysTick定时器是ARM Cortex-M处理器架构中的一个标准组件,存在于内核中。
一、主要功能
1、延时
SysTick的主要功能:实现简单的延时。
其配置为:
通过配置计数初值,在时钟驱动下,实现计数递减,当计数至0后,又可以重新开始计数。通过这种方式,SysTick可以精准地控制延时时间。
SysTick定时器有两个时钟源可以选择,具体取决于硬件设计和系统需求。这些时钟源通常与系统的主时钟(SYSCLK)有关,经过分频或其他处理后,作为SysTick的时钟输入。选择适当的时钟源对于确保SysTick的准确性和稳定性至关重要。
2、定时中断
此外,SysTick还可以用于生成定时中断,以便执行特定的任务或进行系统级的时间跟踪。当SysTick计数到0时,可以产生一个中断,这个中断可以被处理器捕获并执行相应的中断服务程序。
综上,SysTick是ARM Cortex-M处理器中一个非常重要的组件,它为嵌入式系统提供了基本的时间管理和定时服务。
二、示例说明
SysTick的使用示例会涉及初始化SysTick、配置其参数以及处理SysTick中断。以下是一个简化的SysTick使用示例,展示如何在GD32F350中实现基本的延时和中断处理功能:
1、【使用SysTick中断来实现延时功能,需确SysTick_Handler被正确配置,并且在delay_ms函数中,需设置一个标志来指示延时是否完成。当SysTick中断发生时,可在中断服务程序中检查并更新这个标志。】
#include "gd32f3xx.h"
// 延时完成的标志
volatile uint32_t delay_finished = 0;
// SysTick中断服务程序
void SysTick_Handler(void)
{
// 清除SysTick中断标志
systick_flag_clear(SYSTICK_FLAG_COUNTFLAG);
// 检查是否达到了延时结束的条件
if (delay_finished > 0) {
delay_finished--;
}
}
// 初始化SysTick定时器
void SysTick_Init(uint32_t ticks)
{
// 配置SysTick时钟源为HCLK(系统时钟)
rcu_clock_config_systick(RCU_CKSYSTICK_HCLK);
// 设置SysTick重载值
systick_set_reload(ticks - 1);
// 配置SysTick中断并启动定时器
systick_interrupt_enable();
systick_counter_enable();
// 配置NVIC来使能SysTick中断
nvic_irq_enable(SysTick_IRQn, 0, 0);
}
// 延时函数
void delay_ms(uint32_t ms)
{
uint32_t ticks = ms * (SystemCoreClock / 1000); // 计算总计数值
delay_finished = ticks; // 设置延时完成的次数
// 等待延时完成
while (delay_finished > 0);
}
int main(void)
{
// 系统初始化代码(时钟、外设等)
// ...
// 初始化SysTick定时器
SysTick_Init(SystemCoreClock / 1000); // 假设我们想要每毫秒中断一次
// 主循环
while (1)
{
// 执行主循环中的任务
// ...
// 使用延时函数
delay_ms(1000); // 延时1秒
}
}
以上示例包含了GD32F350相关的头文件gd32f3xx.h。定义了SysTick的中断服务程序SysTick_Handler,在其中处理SysTick中断事件,并清除相应的中断标志。
SysTick_Init函数用于初始化SysTick定时器。它配置了SysTick的时钟源、重载值,并启用了SysTick中断和计数器。同时,通过NVIC(嵌套向量中断控制器)使能了SysTick的中断。
delay_ms函数是一个简单的延时函数,它根据系统时钟和所需的延时时间计算出需要的SysTick计数次数,并在一个循环中等待直到延时结束。
在main函数中,调用了SysTick_Init来初始化SysTick,并在主循环中使用了delay_ms函数来实现延时。
注意:由于delay_finished是一个全局变量,并且在中断服务程序中被修改,因此必须将其声明为volatile,以确保编译器不会对其进行优化,从而导致不正确的行为。
2、SysTick使用轮询方式实现延时的示例如下:
void delay_ms(uint32_t ms)
{
// 计算需要的SysTick重载值,假设SystemCoreClock是以Hz为单位的系统核心时钟
uint32_t ticks = (SystemCoreClock / 1000) * ms;
// 清除当前计数值
SysTick->VAL = 0;
// 设置SysTick重载值,并启用SysTick使用核心时钟,然后开始计数
SysTick->LOAD = ticks - 1;
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
// 轮询等待SysTick计数完成
while ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == 0);
// 停止SysTick计数器
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
}
以上示例中:LOAD寄存器设置为(SystemCoreClock / 1000) * ms - 1,这样SysTick每计数SystemCoreClock / 1000次,就代表过去了1毫秒。
在while循环中,等待SysTick->CTRL寄存器的第16位(COUNTFLAG位)变为0。当SysTick计数器递减到0时,这个位会被自动设置。所以需要等待这个位变为0,以表明计数已经完成。
在函数结束时,关闭SysTick计数器。这是因为在长时间运行的系统中,减少不必要的功耗。
三、中断优先级设置
SysTick中断优先级的配置主要取决于系统的具体需求和设计考虑。不同的优先级设置会影响到SysTick中断的响应速度和系统中其他中断的处理。
所以在配置时,需要综合考虑实时性
、用户中断的响应速度
、中断优先级分组
以及实时操作系统
的要求等因素。
1、实时操作系统中的配置:
为提高系统的实时性,可考虑将SysTick中断优先级设置为高。高优先级的SysTick中断可以确保系统心跳的准确性,从而保证实时性。
但注意,如果系统中存在很多频繁的用户中断,高优先级的SysTick可能会不断打断用户中断,影响用户中断的实时性。
2、用户中断的响应:
如果系统中有大量且频繁的用户中断,且希望这些用户中断能够得到快速响应,可考虑将SysTick中断优先级设置为低。这样,用户中断能够抢占SysTick中断,确保用户中断的实时性。
3、配置方法:
具体配置SysTick中断优先级的方法依赖于使用的微控制器和开发环境。一般来说,可以通过配置NVIC(嵌套向量中断控制器)来实现。
例如,在STM32系列微控制器中,可以使用NVIC_SetPriority函数来设置SysTick中断的优先级。
4、中断优先级分组:
在配置SysTick中断优先级时,注意中断优先级分组。很多微控制器支持抢占优先级和子优先级的设置。抢占优先级高的中断可以打断正在执行的抢占优先级低的中断,而子优先级则用于处理具有相同抢占优先级的多个中断。
5、FreeRTOS等实时操作系统的考虑:
如果在FreeRTOS等实时操作系统中使用SysTick,需注意SysTick中断的优先级与FreeRTOS API函数调用的关系。通常,低于某个特定优先级的中断才允许调用FreeRTOS的API函数。