首先,我们需要确认一个条件:__Vendor_SysTickConfig必须等于0,我们才能使用这个配置函数。好消息是,在STM32f4xx.h头文件中,这个宏已经被定义为0,因此我们可以直接使用。
SysTick_Config函数是核心的配置函数,它的原型是__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)。此函数接受一个参数ticks,它代表定时器的重装载值。要注意的是,如果设置的值超出了24位的范围,函数将返回错误信息。
在函数内部,首先检查ticks值是否超出允许的最大值,然后设置SysTick的重装载寄存器LOAD,清零当前值寄存器VAL,并配置控制寄存器CTRL以启动定时器和中断。如果一切设置正确,函数返回0,表示成功。
SysTick定时器的时钟源通常与处理器时钟相同。以168MHz为例,每秒可以进行168,000,000次计数,这意味着每毫秒可以计数168,000次,每微秒计数168次。由于装载值是24位的,最大值是16777215,因此理论上最大延时大约是100毫秒。
在具体的应用中,我们不再需要自己编写延时函数。只需要包含core_cm4.h头文件,并在程序中调用SysTick_Config函数,传入计算好的延时值即可。然后,在中断服务例程中编写我们想要重复执行的代码。
以一个LED闪烁的例子来说,假设我们想要每50毫秒翻转一次LED的状态,我们可以在主函数中这样写:
```cpp #include "stm32f4xx.h" #include "led.h" #include "core_cm4.h"
int main() { LED_Init(); // 初始化LED灯 SysTick_Config(8400000); // 延时50ms的配置
while(1) { // 主循环保持空,所有工作在中断服务例程中完成 } }
void SysTick_Handler() { static u8 cnt = 0; SysTick->CTRL &= ~(1 << 16); // 清除计数标志位 cnt++; if(cnt == 10) { LED_Toggle(DS0); // 翻转LED状态 cnt = 0; } } ```
这里,中断服务例程通过计数器实现了一个简单的分频,因为50ms太短,人眼可能无法察觉LED的闪烁。通过在计数器达到10时才翻转LED,实际上我们将闪烁间隔增加到了500ms。
最后,将编译好的程序烧写到开发板上,如果LED能够按预期闪烁,那么就说明SysTick配置函数调用成功了。通过这种方式,我们能够以更加简洁和高效的方式利用微控制器的内置功能,提升程序的开发效率。
之前使用SysTick滴答定时器都是通过查找内核编程手册配置寄存器让SysTick滴答定时器工作的。其实在内核相关的头文件core_cm4.h中已经有SysTick滴答定时器的相关配置了。
条件__Vendor_SysTickConfig == 0成立,配置函数才能使用。
刚好在stm32f4xx.h中定义了__Vendor_SysTickConfig = 0,所以可以使用该配置函数。
观察函数__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks),其中的寄存器和我们在Systick查询定时中用到的寄存器其实是一样的。
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) {
//SysTick_LOAD_RELOAD_Msk为24,如果装载值超过24位,返回错误信息
if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) { return (1UL); } /* Reload value impossible */
SysTick- >LOAD = (uint32_t)(ticks - 1UL); /* set reload register */
//设中断端优先级
NVIC_SetPriority (SysTick_IRQn, (1UL < < __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
SysTick- >VAL = 0UL; /* 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 (0UL); /* Function successful */
}
这种方式没有分频,时钟速度为168Mhz,每秒可计数168000000次,每毫秒可计数168000次,每微秒计数168次。装载值为24位,最大为16777215,可以算得最大延时时间为100ms。
这次的程序不需要上次写的delay文件了,只要在主文件加入SysTick配置函数的头文件core_cm4.h,根据想要定时的时间,计算相应的数值,初始化SysTick配置函数。再调用中断接口封装中断函数,就可以实现SysTick中断了。
如果中断函数像之前那样可能会看不到现象,因为定时时间过短,人眼可能识别不出led灯在闪烁,这里可以添加个计数,相当于定时更长时间才执行想要的程序。
#include "stm32f4xx.h"
#include "led.h"
#include "core_cm4.h"
int main() {
LED_Init(); //初始化LED灯
SysTick_Config(8400000);//延时50ms 168000000/8400000=20 1000/20=50
while(1)
{
}
}
void SysTick_Handler() {
static u8 cnt = 0;
SysTick- >CTRL &=~ (1< < 16); //清计数标志位
cnt++;
if(cnt == 10)
{
LED_Toggle(DS0); //LED灯闪烁
cnt = 0;
}
}
编译工程项目并烧入开发板,LED灯闪烁,SysTick配置函数调用成功。