【嵌入式】延时函数及其原理

一、延时函数 

void DelayMS(uint32_t Millisecond)
{
    DelayTick = Millisecond;

    while (0 != DelayTick)
    {
    }
}

二、延时原理

这段代码是一个简单的延时函数,其原理是基于一个循环等待的操作。下面是对其原理的详细解释:

  1. 函数定义:

    void DelayMS(uint32_t Millisecond): 这是一个函数定义,函数名为DelayMS,它接受一个无符号32位整数参数Millisecond,表示需要延时的毫秒数。
  2. 变量赋值:

    DelayTick = Millisecond;: 这里将传入的毫秒数赋值给DelayTick变量。这意味着,我们需要等待DelayTick次某个事件(通常是系统滴答时钟事件)的发生。
  3. 循环等待:

    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 函数需要根据你的硬件和编译器进行实现。

  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
第一讲:开发板和软件的操作使用 1、 介绍配件。 2、 安装软件(ICC AVR 和AVR STUDIO)及其使用,包括新建工程、程序下载,仿真调试;整板测试;板上资源。 3、 着重介绍一下USB接口的仿真器。 第二讲:AVR单片机的概述和C语言的基础知识 1、 AVR单片机的概述包括它的优点、片上资源。 2、 C语言的基础包括电平特性、2进制与16进制的表示及转换、二进制数的逻辑运算,数据类型,运算符。 3、 着重讲一下特有的BIT()操作,C中的各种语句。 4、 介绍一下AVR单片机IO口的配置。 第三讲:点亮发光二极管、驱动蜂鸣器、继电器 1、首先讲解一下原理图上开关电路、复位电路、时钟电路; 2、讲解573工作原理, 3、首先点亮一个发光二极管,然后让一个二极管亮灭变化。 4、编写函数证明573的工作原理:锁住后不导通就不能再更新数据。 5、编写延时函数,软件仿真查看延时的精确时间 6、子函数的编写(分带形参和不带形参)。 7、编写流水灯函数。 8、蜂鸣器,继电器的工作原理并编写程序。 第四讲:数码管工作原理 1、 共阴共阳数码管内部结构,显示原理。 2、 用数字万用表标定数码管的段选和位选 3、 编写程序使1个数码管上显示数字 4、 编写程序在6个数码管上滚动显示数字 5、 重点讲解动态显示,保持时间,以及扫描频率对闪烁和亮暗程度的影响。 第五讲:键盘检测原理(比较复杂) 1、 键盘作用,检测原理,如何消抖,独立键盘检测程序编写。 2、 矩阵键盘检测程序编写,涉及到返回值函数调用。 第六讲:1602液晶的使用 1、 看手册,管脚、写指令和数据、时序图。 2、 编写程序,显示光标 3、 编写程序显示字, 4、 编写程序,滚动显示字符 第七讲:中断、定时器的原理和应用(比较复杂) 1、 中断的概念,AVR单片机的中断 2、 定时/计数器1几种模式的寄存器配置 3、 定时器1普通模式下实现秒表 4、 CTC模式输出方波 5、 快速PWM模式输出PWM信号 6、 相位修正PWM模式输出PWM信号 第八讲:AD、DA简介及其应用 1、 AD简介,AVR内部AD寄存器设置 2、 编写程序控制AD读写电位器输出的模拟电压 3、 SPI串行通信简介 4、 DA简介,AD5300时序图 5、 编写程序控制DA输出模拟电压使发光二极管亮度变化 第九讲:TWI(IIC) 1、 TWI(IIC)协议简介 2、 AVR单片机内部TWI寄存器简介,操作流程 3、 具有IIC协议的数字电位器芯片AD5161的简介 4、 编写程序用独立键盘控制AD5161输出不同的阻值 第十讲:异步串口UART的简介和程序的编写 1、 UART简介 2、 AVR单片机内部与UART相关的寄存器的配置 3、 编写程序控制AVR单片机和电脑进行通信 4、 讲解串行通信时数字和字符之间的区别 第十一讲:PS2键盘、DS1302的工作原理和程序的编写 1、 AVR单片机外部中断的介绍 2、 PS2键盘的工作原理 3、 编写程序读取PS2键盘的按键值并在1602液晶上显示 4、 DS1302的工作原理 5、 编写程序控制1302工作并在1602液晶上显示时间

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值