打印
[应用相关]

STM32的延时函数的使用

[复制链接]
181|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Zuocidian|  楼主 | 2025-1-4 12:54 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
前言
延迟函数是一项常用的编程技术,用于控制程序的执行速度和时间间隔。通过合理使用延迟函数,可以使程序在需要的时候暂停一段时间,从而实现更加灵活和精确的控制。然而,在使用延迟函数时需要注意合理选择延迟时间,并避免可能存在的问题。

一、为什么用delay来延时?

1. 实现简单
delay函数的实现相对直接,通常基于循环计数器或者定时器中断来完成。例如,在STM32系列微控制器上,可以通过配置SysTick定时器来创建精确的毫秒级延时。这种方式不需要引入额外的库或依赖项,降低了系统的复杂度。

2. 不阻塞线程(适用于协程)
当提到delay时,特别是在现代编程语言如Kotlin中,delay是一个非阻塞的挂起函数,这意味着它可以暂停当前协程的执行而不阻塞整个线程。这使得应用程序能够更高效地利用系统资源,特别是在并发任务处理方面。然而,需要注意的是,这里的delay特指协程环境下的异步延迟,而不仅仅是简单的忙等待循环。

3. 精确度与灵活性
通过调整参数值,delay函数可以提供从微秒到分钟甚至更长时间的不同级别的延时精度。对于某些应用场景来说,比如需要精确控制灯光闪烁频率或是传感器采样周期的情况,这一点尤为重要。

4. 内存占用低
相比于使用操作系统提供的睡眠功能(如Linux中的sleep),delay函数往往占用较少的内存空间,因为它们不涉及复杂的上下文切换机制。这对于资源受限的嵌入式平台而言是一个显著的优势。

5. 适应性强
尽管delay函数本身是非阻塞的(在协程环境中),但在传统的单线程环境下,如果确实需要一个简单的阻塞式延时,那么也可以很容易地实现。例如,在裸机编程中,可以直接编写一个忙等待循环来达到目的。不过,这种方**持续消耗CPU周期直到延时期满,因此并不总是最优的选择。

6. 缺点:影响实时性能
虽然delay函数易于使用且效率较高,但它可能会对系统的实时响应能力产生负面影响。特别是在多任务系统中,长时间的延时可能导致其他任务得不到及时处理,从而引发优先级倒置等问题。此外,如果使用不当,还可能造成电源管理方面的挑战,比如无法进入低功耗模式。

二、使用步骤
1.delay.c
代码如下(示例):

#include "stm32f10x.h" // 包含STM32F1系列的标准库头文件
#include "delay.h"

// 定义用于微秒级延时的函数,使用NOP指令实现短时间延迟
void Delay_usnop(uint32_t time) // 更改类型为uint32_t以符合标准
{
    for (volatile uint32_t i = 0; i < time * 72; ++i) // 每个循环大约等于1微秒
    {
        __NOP(); // 使用单个NOP指令代替多个NOP指令
    }
}

// 实现微秒级延时,通过调用Delay_usnop()函数完成
void Delay_us(uint32_t time) // 改为uint32_t,避免过大数值溢出
{
    while (time--) // 对于每个需要延时的微秒调用一次Delay_usnop()
    {
        Delay_usnop(1); // 每次调用大约等于1微秒
    }
}

// 实现毫秒级延时,通过软件循环等待完成
void Delay_ms(uint32_t time)
{
    uint32_t start = SysTick->VAL;
    while ((SysTick->VAL - start) <= (SystemCoreClock / 1000 * time)) {}
}

// 初始化SysTick定时器,配置为每1ms触发一次中断
void Delay_Init(void)
{
    if (SysTick_Config(SystemCoreClock / 1000)) // 根据系统核心时钟频率计算正确的重装载值
    {
        while (1); // 如果SysTick配置失败,则在此处等待
    }
}

// 全局变量用于跟踪不同事件的时间计数
volatile uint32_t timeled[2] = { 0, 2000 }; // LED控制的时间间隔
volatile uint32_t timekey[2] = { 0, 10 };   // 按键扫描的时间间隔
volatile uint32_t timedc[2] = { 0, 10 };    // 直流电机控制的时间间隔
volatile uint32_t timedi[2] = { 0, 2000 };  // 数字输入检测的时间间隔

// SysTick定时器的中断服务例程(ISR),每1ms被调用一次
void SysTick_Handler(void)
{
    timeled[0]++; // 每隔1ms增加一次
    timekey[0]++;
    timedc[0]++;
    timedi[0]++;
}



2.delay.h
代码如下(示例):

#ifndef DELAY_H_
#define DELAY_H_

#include "stm32f10x.h" // 包含STM32F1系列的标准库头文件

// 宏定义
#define NOP() __NOP() // 定义一个宏来简化NOP指令的调用 [ty-reference](26)

// 延时函数声明
/**
* @brief 实现微秒级延时,通过调用Delay_usnop()函数完成。
* @param time 要延时的时间,单位为微秒。
*/
void Delay_us(uint32_t time);

/**
* @brief 使用NOP指令实现短时间延迟,每个循环大约等于1微秒。
* @param time 循环次数,通常与微秒数成正比。
*/
void Delay_usnop(uint32_t time);

/**
* @brief 实现毫秒级延时,通过软件循环等待完成。
* @param time 要延时的时间,单位为毫秒。
*/
void Delay_ms(uint32_t time);

/**
* @brief 初始化SysTick定时器,配置为每1ms触发一次中断。
*/
void Delay_Init(void);

// 全局变量声明
extern volatile uint32_t timeled[2]; // LED控制的时间间隔
extern volatile uint32_t timekey[2]; // 按键扫描的时间间隔
extern volatile uint32_t timedc[2];  // 直流电机控制的时间间隔
extern volatile uint32_t timedi[2];  // 数字输入检测的时间间隔

#endif /* DELAY_H_ */

当您在不同的.c文件中需要使用上述延时函数时,只需简单地添加如下行即可:

#include "delay.h"
这样做的好处是,所有的延时相关功能都被集中管理在一个单独的头文件中,便于未来的修改和扩展。此外,这种方法也遵循了C语言中“分离编译”的原则,即每个源文件只关心自己的实现细节,而公共接口则由头文件提供。

总结
delay函数是一种在编程中常见的函数,用于暂停程序的执行一段时间。它通常用于制造一个时间延迟,使程序可以按照特定的时间间隔执行。

delay函数是一种常见的用于延迟程序执行的函数。它可以用于控制程序的执行速度、行为和流程。然而,在使用delay函数时需要注意程序的实时性要求,避免影响程序的响应和性能。
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/m0_63037616/article/details/144836352

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

10

主题

20

帖子

0

粉丝