运用Systick编写延时函数以及遇到的问题及其解决方法
我对Systick的理解
Systick属于Cotex-M4内核中的外设,是一个24位的向下递减计数器,我们每次所配置是PLL锁相环的时钟,正是Systick的时钟;定时器都有一个自动重装载值寄存器,当自动重装载值递减到0的时,会产生一次中断,而我们可以通过改变这个重装载值,来设定我们要的延时时间,从而起到延时作用。
开发平台
1、运用STM32F429在标准库上开发
2、KEIL 5.25.2.0
初始化Systick
void SYSTICK_INIT(uint16_t fosc) //F429的时钟频率为180M,所以填入的参数我会填入180
{ //这样我每一次进入中断的时间为1us。(180/180M = 1us)
if(SysTick_Config(fosc)==1) //SysTick_Config()已经在cm4.h文件里写好,直接调用
{
while(1);
}
}
编写延时函数思路
编写延时函数的思路是:我定义一个全局变量,当Systick每次进入中断时,中断服务函数让这个全局变量自减1,而我要延时多少秒,就进入这个中断多少次,而当进入延时函数时,我用一个while一直死循环来等待这个全局变量减到0为止,从而起到了精准的延时效果。
定义一个全局变量
__IO uint32_t tim_counter = 0;
延时函数的编写
void DELAY_US(__IO uint32_t US) //传入参数为要延时的时间,单位为us
{
tim_counter = US; //把实参传给全局变量,令他进入中断自减
while(tim_counter != 0); //死循环等待tim_counter减为0,不为0就一直等待
}
void DELAY_MS(__IO uint32_t MS) //传入参数为要延时的时间,单位为us
{
do{
DELAY_US(1000); //等待1ms就是等待1000us
}while(MS--);
while(tim_counter!=0); //死循环等待
}
编写中断服务函数
void SysTick_Handler(void)
{
TIMEDELAY_HANDLE();
}
void TIMEDELAY_HANDLE(void)
{
if(tim_counter != 0)
{
tim_counter--;
}
}
这样Systick中断延时函数就写好了,现在说说我在编写时遇到的问题:
原来是编译器的优化问题!
当我定义的全局变量和形式参数没有加“__IO”的时候:
我第一次写的时候没有加__IO时,发现并没有起到我想要的延时效果,所以我就F12去看一下这个__IO标识符的个什么鬼,同样在cm4.h里面定义好了,代码如下:
#ifdef __cplusplus
#define __I volatile /*!< Defines 'read only' permissions*/
#else
#define __I volatile const /*!< Defines 'read only' permissions*/
#endif
#define __O volatile /*!< Defines 'write only' permissions*/
#define __IO volatile /*!< Defines 'read / write' permissions*/
这里发现了volatile关键字,经过百度和CSDN的博客中认识到,在定义变量的时候加入volatile关键字,其实就是在跟编译器说,我定义的这个volatile变量的值是会随时发生改变的,你不要对他进行优化,不然有可能会出错。当我加入关键字后,我定义的全局变量和形式参数就不会被编译器优化,从而实现了我想要的延时功能。
当我未设置编译器的优化等级的时候:
在新建工程的时候,优化等级我默认选择了Level 1,而这仅仅这个选项,让我定义的全局变量tim_counter和形式参数都被优化了,从而需要用到__IO标识符。但如果把优化等级0,不需要用到__IO标识符也同样可以实现延时功能。
解决方法如下:
结束语
第一次写博客,可能一些写的不太好,if(有错误){欢迎在评论区里指正} 谢谢。