一、延时函数
void DelayMS(uint32_t Millisecond)
{
DelayTick = Millisecond;
while (0 != DelayTick)
{
}
}
二、延时原理
这段代码是一个简单的延时函数,其原理是基于一个循环等待的操作。下面是对其原理的详细解释:
-
函数定义:
void DelayMS(uint32_t Millisecond)
: 这是一个函数定义,函数名为DelayMS
,它接受一个无符号32位整数参数Millisecond
,表示需要延时的毫秒数。 -
变量赋值:
DelayTick = Millisecond;
: 这里将传入的毫秒数赋值给DelayTick
变量。这意味着,我们需要等待DelayTick
次某个事件(通常是系统滴答时钟事件)的发生。 -
循环等待:
while (0 != DelayTick) {}
: 这是一个while
循环,它会持续执行直到DelayTick
变为0。在这个循环内部,没有其他的操作(即一个大空循环),因此这个循环的执行时间会非常长。理论上,如果每次循环都需要执行一个系统滴答时钟事件,那么这个循环就会等待DelayTick
次系统滴答时钟事件的发生,从而实现相应的延时。
延时原理:
该函数的延时原理是基于一个假设:系统有一个固定的时钟频率(例如每秒1000次滴答)。如果这个假设成立,那么每次循环都会等待一个固定的时间(通常是1/1000秒)。因此,如果DelayTick
是1000,那么这个函数就会等待1秒。
但需要注意的是,这种方法的精度和可靠性都存在问题。首先,实际系统时钟频率可能并不是完全固定的。其次,该函数使用了忙等待(busy-waiting)的方式,会消耗CPU资源,且实际延时时间可能比预期更长。因此,在实际应用中,更推荐使用系统提供的延时或休眠函数,或者使用定时器中断来实现精确的延时。
在原始代码示例中,DelayTick
变量并没有在任何地方被修改,所以它不会变成0。这意味着 while (0 != DelayTick)
循环将永远为真,导致程序陷入无限循环。要使 DelayTick
变量变成0并退出循环,你需要在循环体内部添加一些代码来递减 DelayTick
的值。
这里有一个修改后的例子,它使用了一个简单的计数循环来模拟延迟。请注意,这仍然是一个忙等待实现,并且不是最高效或最准确的方法,但它展示了如何使 DelayTick
递减到0:
#include <stdint.h>
// 假设有一个全局变量或者函数内部的static变量来存储延迟的计数值
static uint32_t DelayTick;
// 假设有一个函数来提供基本的时钟或定时器功能
// 这个函数应该返回自上次调用以来经过的时钟周期数
// 这里只是一个示例,你需要根据你的硬件和编译器来实现这个函数
uint32_t GetClockCycles(void) {
// 实现获取时钟周期数的代码
// 这通常涉及到读取一个硬件计时器寄存器
// 为了简化示例,这里我们只是返回一个递增的计数值
static uint32_t counter = 0;
return counter++;
}
void DelayMS(uint32_t Millisecond) {
// 将延迟的毫秒数转换为时钟周期数
// 这里需要一个转换因子,它取决于你的系统时钟频率
// 假设我们有一个简单的转换因子(例如,每毫秒1000个时钟周期)
const uint32_t cyclesPerMillisecond = 1000;
DelayTick = Millisecond * cyclesPerMillisecond;
// 现在,我们将使用一个循环来递减DelayTick,直到它变为0
while (DelayTick > 0) {
// 在每次循环迭代中,我们检查并减少DelayTick的值
// 同时,我们也检查GetClockCycles()的返回值,以便在必要时退出循环
// 这可以防止我们的延迟函数在硬件计时器溢出时继续运行
if (GetClockCycles() >= DelayTick) {
DelayTick = 0; // 将DelayTick设置为0以退出循环
}
}
}
在这个示例中,DelayMS
函数接受一个毫秒数作为参数,并将其转换为一个时钟周期数。然后,它进入一个循环,在每次迭代中检查并减少 DelayTick
的值。我们还使用 GetClockCycles
函数来模拟一个时钟源,该函数返回自上次调用以来经过的时钟周期数。当 DelayTick
减少到0或小于或等于当前时钟周期数时,循环结束,函数返回。
请注意,这个示例是为了教育目的而简化的。在实际应用中,你应该使用操作系统提供的延迟函数(如果可用)或者硬件定时器来实现更精确和高效的延迟。此外,上述代码中的 GetClockCycles
函数需要根据你的硬件和编译器进行实现。