我的C51延时程序

本文介绍了一种基于不同晶振频率的精确延时程序设计方法,适用于12MHz及11.0592MHz晶振。通过严格计算确保延时精度,并提供了1秒和1毫秒的基础延时函数。此外,还介绍了如何通过调用基础延时函数实现更长的延时。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基础延时程序经过了严格计算得出的,保证精准。

#include <intrins.h>

/********************************
*            基础延时           *
********************************/

//适用于12MHz晶振,如果不需要请注释掉
void delay1s(void)   //延时1秒 误差 0us
{
    unsigned char a,b,c;
    for(c=46;c>0;c--)
        for(b=152;b>0;b--)
            for(a=70;a>0;a--);
    _nop_();  //if Keil,require use intrins.h
}
void delay1ms(void)   //延时1毫秒 误差 0us
{
    unsigned char a,b;
    for(b=199;b>0;b--)
        for(a=1;a>0;a--);
}

//适用于11.0592MHZ晶振,如果不需要请注释掉
void delay1s(void)   //误差 -0.00000000024us

{
    unsigned char a,b,c;
    for(c=95;c>0;c--)
        for(b=26;b>0;b--)
            for(a=185;a>0;a--);
}
void delay1ms(void)   //误差 -0.651041666667us
{
    unsigned char a,b;
    for(b=4;b>0;b--)
        for(a=113;a>0;a--);
}

 

常用延时才是日常应用的主角,通过调用基础延时来实现,误差很小。

/********************************
*            常用延时           *
********************************/
void delay(unsigned int time)	//延时time秒
{
	do
		delay1s();
	while(--time);
}

void delay_ms(unsigned int time)	//延时time毫秒
{
	do
		delay1ms();
	while(--time);	 
}					  

转载于:https://www.cnblogs.com/catmelo/archive/2011/11/20/2255976.html

<think>嗯,用户问的是C51延时程序怎么知道延时了多久。这个问题看起来是关于单片机编程的,特别是针对8051系列,比如常见的AT89C51。首先,我需要回忆一下C51延时方法,通常是通过循环来实现的。用户可能想知道如何计算延时的时间,或者如何验证他们的延时函数是否准确。 用户可能是刚开始学习单片机,对延时函数的原理不太清楚。他们可能在编写程序时遇到了定时不准确的问题,或者想知道如何调整延时时间。需要从基础开始解释,确保他们理解时钟周期、机器周期这些概念。 首先,C51延时通常依赖于执行指令的时间。每个指令需要一定的时钟周期,而时钟频率由单片机的晶振决定。比如,12MHz的晶振,每个机器周期是1微秒。用户需要知道他们的单片机使用的晶振频率,这是计算的基础。 接下来,延时函数通常用嵌套循环实现,比如for循环或while循环。每条指令的执行时间需要累加起来,包括循环变量的增减和条件判断。这里可能需要举例说明,比如一个简单的for循环,计算每个循环消耗的时间,然后乘以循环次数。 不过,用户可能会遇到编译器优化的问题。不同的编译器可能会对循环进行优化,改变指令的执行次数,导致计算的时间不准确。这时候可能需要查看反汇编代码,或者使用示波器、仿真器来实际测量延时时间。 另外,定时器中断的方法可能更准确,用户可能也需要了解这一点。使用定时器可以避免依赖循环延时的不确定性,但需要配置定时器相关的寄存器,并处理中断服务程序。 用户可能没有考虑到晶振频率的重要性,或者不知道如何根据晶振频率计算机器周期。这时候需要强调晶振频率的作用,并给出具体的计算公式,比如机器周期=12/晶振频率(对于传统的12时钟周期机器周期的51单片机)。 还有,用户可能想知道如何验证他们的延时是否准确。这时候可以建议使用示波器检测某个IO口的电平变化,或者使用仿真工具来跟踪指令执行的时间。 总结一下,回答需要分步骤说明:确定晶振频率,分析延时函数的每条指令周期,计算总时间,考虑编译器优化,以及实际测量的方法。同时,指出循环延时的缺点,推荐使用定时器中断的方法提高精度。</think>关于C51延时程序如何计算延时时间的问题,我们可以通过以下步骤逐步分析: 1. **确定单片机时钟频率** - 以12MHz晶振为例(传统51单片机常用) - 1个机器周期 = 12个时钟周期 = 12×(1/12μs) = 1μs - 注意:现代51变种可能采用1T模式(1时钟周期=1机器周期) 2. **分析延时函数结构** ```c void delay(unsigned int t) { while(t--); // 典型循环延时 } ``` 3. **指令周期计算(以Keil编译器为例)** - `while(t--)` 对应的汇编指令: ``` MOV R7, ? ; 1周期 DJNZ R7, $ ; 2周期/次 RET ; 2周期 ``` - 总周期数 = 1 + (2×t) + 2 ≈ 2t+3 个机器周期 4. **实际计算示例** 假设: - 晶振=12MHz → 1μs/机器周期 - 执行`delay(1000)` - 总耗时 ≈ (2×1000 +3)×1μs = 2003μs ≈ 2ms 5. **影响精度的关键因素** - 编译器优化等级(建议关闭延时函数优化) - 循环变量类型(unsigned int比int更快) - 函数调用/返回开销 - 中断干扰(需在延时期间关闭中断) 6. **验证方法** - **示波器检测法**:翻转IO口电平测量脉冲宽度 ```c P1^0 = 1; delay(1000); P1^0 = 0; ``` - **软件仿真**:使用Keil调试模式查看周期计数器 - **定时器验证**:用定时器中断计数实际耗时 7. **改进建议** - 优先使用定时器中断实现精准延时 - 针对不同编译器需反汇编验证指令周期 - 高频晶振需考虑变量溢出问题 - 标准公式:$$T_{delay} = N \times T_{machine\ cycle}$$ 注意事项: 1. 不同编译器(如SDCC/IAR)生成的代码效率不同 2. C51的`for`循环比`while`循环多消耗2-3个周期 3. 多层嵌套循环需要逐层计算周期叠加 实际开发中推荐使用定时器中断实现精准延时,循环延时仅适用于对时间精度要求不高的场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值