利用滴答定时器(SysTick)实现简单的延时函数
预备知识:
对标准库来说,如果定义了时钟频率,则系统会默认初始化该时钟频率。
SysTick是CM4的内核外设,是一个24位的向下递减计数器,每次计数时间是1/SYSCLK,即1/168000000。
SysTick计数时间的计算:t=重装载值*1/AHB时钟频率。1/AHB时钟频率即是计数一次的时间。一般把重装载值定为128000000/100000=1280,则10us中断一次;一般不设置为1us中断一次,这样中断频率太高,偏移了程序重心。
正文:
程序源码:
在main.c中
#include "sys.h" #include "led.h" // "__IO"在Core_cm4.h中被重定义,原型是"volatile" ① __IO uint32_t TimingDelay; // 延时函数 void Delay(__IO uint32_t nTime) { TimingDelay = nTime; while(TimingDelay != 0); } // 主函数 int main(void) { // 初始化LED端口 LED_Init(); // 初始化SysTick ② if(SysTick_Config(SystemCoreClock/1000)) { // Capture error while(1); } // LED闪烁 while(1) { Delay(250); GPIO_SetBits(GPIOF,GPIO_Pin_9); Delay(250); GPIO_ResetBits(GPIOF,GPIO_Pin_9); } } /*------------------------------------------------------------------------------------ 注释: ①:volatile 的作用就是指示编译器不要因优化而省略此指令,必须每次都直接读写其值。 写一段测试代码如下: u8 test; test = 1; test = 2; test = 3; 设置优化级别中级 运行后test会被直接取值为3 只有最后一个语句被编译 如用volatile: volatile u8 test; test = 1; test = 2; test = 3; 则所有语句都会被编译。test先后被设置成1、2、3 由此可以看出这个作用在IO操作,寄存器操作,特殊变量,多线程变量读写都是很重要。 ②:SysTick_Config的参数,是一个时钟次数,叫systick重装定时器的值。意思就是多少个 1/fosc 时间后中断一下。 这里 SystemCoreClock/1000 为没过1ms中断一次,SystemCoreClock为系统时钟频率。 计算方法为: SystemCoreClock ÷ timer = 1ms 假设SystemCoreClock为128M,单位为Hz。则: 1ms = 1128MHz ÷ timer = 128M/s ÷ timer 128M ------ timer = 1s ------ 0.001s 128M timer = ------ 1000 ------------------------------------------------------------------------------------*/
在stm32f4xx_it.c中
/* Includes ------------------------------------------------------------------*/ #include "stm32f4xx_it.h" /* 变量定义 ------------------------------------------------------------------*/ // 利用关键字extern,可以在一个文件中引用另一个文件中定义的变量或者函数 extern __IO uint32_t TimingDelay; /** * @brief This function handles SysTick Handler. * @param None * @retval None */ void SysTick_Handler(void) { if(TimingDelay != 0x00) { TimingDelay--; } }
注意:
1.在stm32中,中断函数在stm32f4xx_it.c中,不能像51那样写在main.c文件下。
2.关键字extern拓展变量作用范围的用法。
3.__IO == volatile
参考资料:
https://blog.csdn.net/u010834669/article/details/80204195