SysTick
SysTick是Cortex-M3内核中的一个外设,内嵌在NVIC中,是一个24位的系统定时器,它从重装载值向下计数一直计到0后,在下一个时钟边沿将重装载值装载到 LOAD 寄存器后,继续向下计数。
当处理器在调试期间被喊停时,SysTick也将暂停运作。
与SysTick 相关寄存器一共有如下4个:
寄存器 | 描述 |
CTRL | SysTick 控制和状态寄存器 |
LOAD | SysTick 重装载值寄存器 |
VAL | SysTick 当前值寄存器 |
CALIB | SysTick 校准寄存器(一般不需要校准不常用) |
CTRL 寄存器
CTRL寄存器可用的一共有4个位
bit 16 : COUNTFLAG 计数标志位,
如果上次处理器读取到计数器已经计到0,那么将该位置为1。可以该位来得知一轮计数是否完成。
bit 2 : CLKSOURCE Systick 时钟源选择位,
为0则为AHB/8,为1则为处理器时钟即AHB。
bit 1 : Systick 异常请求标志位,
为0表示VAL计数到0后不会触发Systick异常中断请求,为1表示VAL计数到0后会触发ystick异常中断请求。软件可以通过查询COUNTFLAG来判断SysTick是否计数到0.
bit 0 : ENABLE 计数使能位
当该位为1时使能计数器,计数器从LOAD寄存器装载reload值,并开始向下计数,当计数到0时,会置位COUNTFLAG,同时根据TICKINT的值来决定是否申请Systick 异常中断,同时计数器重新装载reload值,并开始新一轮的向下计数。
LOAD 寄存器
LOAD 寄存器的值指定了当计数器使能时或计数到0后装载到VAL寄存器的值,即指定Reload 的值.
LOAD 寄存器有效位为24位,故能装载0x000000~0xFFFFFF范围内的值。
VAL 寄存器
VAL寄存器中存放着当前计数值,读该寄存器返回 SysTick计数值,写该寄存器会使该字段清0,同时也会使COUNTFLAG位清0.
CALIB 寄存器(一般不用)
相关库函数
SysTick_Config()
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */
SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */
SysTick->VAL = 0; /* Load the SysTick Counter Value */
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
return (0); /* Function successful */
}
使用该函数可以对SysTikc初始化并且赋上重装载寄存器的值,该函数需要一个参数,这个参数就是用来设置重装载计数器的值的。该函数返回值为1时表示失败,为0时表示成功。
if (ticks > SysTick_LOAD_RELOAD_Msk) return (1);
该语句用来判断重装A载值的合法型,SysTick_LOAD_RELOAD_Msk 为宏定义,值为0xFFFFFFUL,由于LOAD寄存器有效位位24位,故大于0xFFFFFF的设定值均不合法,返回1。
SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;
将需要计数的值减1后赋值给LOAD寄存器。SysTick_LOAD_RELOAD_Msk同上表示0xFFFFFFul。
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
设置SysTick 异常中断的优先级,随后研究。
SysTick->VAL = 0;
将计数器的值清零。
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk;
配置CTRL寄存器,涉及宏定义如下图:
配置结果如下:
CLKSOURCE =1,使用系统时钟AHB——72MHz;
TICKINT=1, 开启SysTick异常中断
ENABLE=1,开启计数。
使用 SysTick 实现延时函数
如果想要定义1us,使用系统时钟AHB——72MHz,通过换算可知,重装载值应该为(72-1),如果需要定时1ms,则重装载值为(72000-1),如果需要定时1s,则不能使用上述方法,因为其结果大于0xFFFFFF,可以通过调用1000次毫秒延时来实现。
void Delay_us(uint32_t us)
{
//SysTick_Config(72000000/1000000);
SysTick_Config(SystemCoreClock/1000000);//固件库函数初始化,设置重装载值
while(us--)
{
while(!((SysTick->CTRL)&0x00010000));//不断查询计数标志位,等待计数为0
}
SysTick->CTRL = 0x00000004; //关闭计数使能
}
void Delay_ms(uint32_t xms)
{
while(xms--)
{
Delay_us(1000);
}
}
void Delay_s(uint32_t xs)
{
while(xs--)
{
Delay_ms(1000);
}
}
实物测试
利用延时函数实现LED间隔1s闪烁
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//配置时钟RCC
GPIO_InitTypeDef GPIO_InitStructure; //定义GPIO初始化结构体
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //定义GPIO模式为推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //定义引脚
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz; //定义速度
GPIO_Init(GPIOA,&GPIO_InitStructure); //GPIOA初始化
while(1)
{
GPIO_SetBits(GPIOA,GPIO_Pin_0);
Delay_s(1);
GPIO_ResetBits(GPIOA,GPIO_Pin_0);
Delay_s(1);
}
}