STM32系统滴答_及不可不知的延时技巧 - (上)

本文介绍了STM32中使用SysTick系统滴答定时器实现精确延时的方法,探讨了阻塞延时对CPU效率的影响,并提出非阻塞延时的设计思路。内容包括SysTick的寄存器、中断优先级设置以及时钟源选择,旨在帮助读者理解如何在STM32开发中实现高效延时。

我想每个单片机爱好者及工程开发设计人员都有过点灯的经历。流水灯是个好东西,尤其是在调试资源有限的环境中,有时会帮上大忙。

 

然在最初入门时,如何让这些小灯们按照我们的想法欢快地跑起来呢,绝大多数小朋友的做法是:在一个while循环里加上延时程序,让小灯在每个状态下停留一段时间,再进入下一个状态,这样小灯们就会在不同的状态中切换,就可以根据我们设计的程序闪烁了。

 

这样这里就会涉及到一个延时程序的编写的问题,而一般的做法是一个for循环里去减一个很大的数,直到为0,则延时完成,那个数的值则是根据时钟频率和指令运行周期,估算出来的,还记得较久以前看过一篇帖子介绍51单片机精确延时的几种方法,有一种方法是在keil中设定好时钟频率,然后通过软件仿真试来算延时时间,以达到较精确定时。

但这些方法一般都不够方便,延时也不够精确,更高阶一点的方法便是开一个定时器,在定时中断里面计数达到精确延时的目的。

 

STM32的应用中,可考虑利用SysTick系统嘀嗒定时器来实现。但在STM32开发手册中对它的介绍却很少,几乎到没有的程度。因为它是Cortex内核的部分,CM3为它专门开出一个异常类型,并且在中断向量表中占有一席之地(异常号15),这样它可以很方便的移植到不同厂商出CM3内核的芯片上,并且对于有实时操作系统的软件,它一般会作为整个系统的时基,这个对操作系统非常重要。有关SysTick的详细介绍可参考《Cortex-M3 权威指南》第133 页第八章及第179页第十三章。


SysTick总共有四个寄存器:

1、

165700_2voi_578802.jpg

对应于软件中 SysTick->CTRL;


2、

165821_8IRC_578802.jpg

对应于软件中 SysTick-> LOAD


3、

170003_J48T_578802.jpg

对应于软件中 SysTick-> VAL


4、

170128_tNJf_578802.jpg

要使用STM32系统滴答中断进行延时并实现LED翻转,可按以下步骤操作: ### 1. 滴答定时器概述 系统滴答定时器(Systick)是属于CM4内核中的一个外设,内嵌在NVIC中,所有基于Cortex - M3/M4内核的MCU都包含这个定时器。它由ARM公司设计,能产生中断,需要编写中断服务函数。其相关寄存器包括控制与状态寄存器STK_CTRL、重载寄存器STK_LOAD、当前值寄存器STK_VAL [^1][^3]。 ### 2. 确定时钟源与参数 以STM32F407VG为例,系统滴答定时器不需要分频,其时钟源可选择系统时钟或外部参考时钟。根据系统滴答控制与状态寄存器的第二位可知,选择1为内核时钟168MHz,最长延时时长$T = ((2^{24})/168) = 99864.375us$;系统时钟经过8分频后提供21MHz时钟给系统滴答定时器,选择0为外部参考时钟21MHz,最长延时时长$T = ((2^{24})/168)*8 = 798915us$,延时范围在99 - 798ms左右。arr寄存器为重装载值(0 - 16777215) ,因为STM32F407系列系统滴答定时器是24位递减计数器 [^2]。 ### 3. 代码实现 #### 使用STM32CubeMX创建工程 配置时钟源和定时器参数,同时配置LED对应的GPIO引脚为输出模式。 #### 代码示例 以下是一个简单的代码示例,用于实现系统滴答中断延时并翻转LED: ```c #include "stm32f4xx_hal.h" // 定义LED引脚 #define LED_PIN GPIO_PIN_13 #define LED_PORT GPIOC // 全局变量,用于记录中断次数 volatile uint32_t tick_count = 0; // 系统滴答中断处理函数 void SysTick_Handler(void) { HAL_IncTick(); tick_count++; } // 主函数 int main(void) { HAL_Init(); // 配置系统时钟 SystemClock_Config(); // 使能GPIO端口时钟 __HAL_RCC_GPIOC_CLK_ENABLE(); // 配置LED引脚 GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = LED_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct); // 配置系统滴答定时器 HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000); // 1ms中断一次 HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); while (1) { if (tick_count >= 1000) // 1000ms(1s) { HAL_GPIO_TogglePin(LED_PORT, LED_PIN); // 翻转LED状态 tick_count = 0; // 清零计数器 } } } ``` 在上述代码中,首先定义了LED引脚,然后在系统滴答中断处理函数`SysTick_Handler`中增计数器`tick_count`。在主函数中,初始化HAL库、配置系统时钟和LED引脚,接着配置系统滴答定时器使其每1ms产生一次中断。在主循环中,当`tick_count`达到1000时(即1s),翻转LED状态并清零计数器。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值