单片机C语言的精确延时程序设计
- 格式:pdf
- 大小:97.25 KB
- 文档页数:4
单片机延时1小时的程序摘要:1.单片机延时程序背景及应用2.单片机延时1 小时的程序实现方法3.程序代码及注释4.程序测试与优化5.总结正文:1.单片机延时程序背景及应用单片机(Microcontroller Unit,简称MCU)是一种集成度较高的微处理器,广泛应用于嵌入式系统中。
在实际应用中,单片机往往需要执行一些耗时较长的操作,例如数据传输、通讯协议处理等。
为了保证系统的稳定运行,需要对这些操作进行延时处理。
本文将介绍一种实现单片机延时1 小时的程序。
2.单片机延时1 小时的程序实现方法实现单片机延时1 小时的程序,通常可以采用以下两种方法:方法一:使用定时器/计数器定时器/计数器是单片机内部的一种功能模块,可以实现对系统运行时间的测量和控制。
通过设置定时器/计数器的初值和计数周期,可以实现不同时间的延时。
方法二:利用软件循环在程序中通过无限循环实现延时,每循环一次,延时时间减少相应的执行时间。
这种方法的延时时间取决于循环次数,需要占用较多的CPU 资源。
3.程序代码及注释以下是一个使用定时器/计数器实现单片机延时1小时的程序代码示例(以STC89C52为例):```c#include <reg52.h>#include <intrins.h>sbit LED = P1 ^ 0; // 定义LED 端口void delay(unsigned int ms) // 延时函数原型声明{unsigned int i, j;for (i = ms; i > 0; i--)for (j = 114; j > 0; j--);}void main(){TMOD = 0x01; // 定时器方式1TH0 = (65536 - 45872) / 256;TL0 = (65536 - 45872) % 256;EA = 1; // 开总中断ET0 = 1; // 开定时器0 中断TR0 = 1; // 启动定时器0while (1){P1 = _crol_(P1, 1); // LED 左右移动delay(50000); // 延时50ms}}void timer0() interrupt 1 // 定时器0 中断服务函数{TH0 = (65536 - 45872) / 256;TL0 = (65536 - 45872) % 256;}```4.程序测试与优化将编写好的程序烧写到单片机中,通过观察LED 的状态变化,验证延时效果。
单片机精确延时计算和中断定时单片机精确延时计算和定时中断一.延时1. 10ms延时程序(for循环嵌套)*************************************************************** ****** 文件名称:void delay_10ms()功能:10ms延时参数:单片机晶振12MHz*************************************************************** ****** void delay_10ms(){unsigned int i, j;for(i=0;i<10;i++){for(j=0;j<124;j++);}}i 和j 定义为int整型时,for循环执行时间为8个机器周期,当i 和j 定义为char 字符型时,for 循环执行时间3个机器周期。
“;”一个机器周期,每次调用for循环2个机器周期。
则执行本段延时程序是内循环时间t1=8*124+3个机器周期,其中“8”执行for循环指令时间;“124”为for循环次数;“3”为每次调用for循环指令的时间。
外循环t2=t1*10+8*10+3其中“10”为for循环次数;“8”为一次for循环指令调用和执行时间;“10”为调用for循环次数,3为调用for循环指令时间。
所以本程序延时t=((8*124)+3)*10+8*10+3=10033=10.033ms≈10ms。
注意:变量为整型时,每次调用for循环需要3个机器周期的调用时间,执行for循环判断需要8个机器周期的执行时间;字符型变量时,每次调用for循环需要2个机器周期的调用时间,执行for循环判断需要3个机器周期的执行时间。
程序运行到第一个断点所用时间0.00038900s,运行到第二个断点所用时间为0.01042800s,则执行delay_10ms()函数所用时间为0.010428-0.000389=0.010039s= 10.039ms≈10ms。
单片机延时程序怎么写(二)引言概述:在单片机编程中,延时程序是非常常见且必要的一部分。
在上一篇文章中,我们已经介绍了如何使用循环来实现延时。
然而,这种方法可能不是最佳的选择,特别是在需要准确延时的情况下。
在本文中,我们将介绍一种更加精确和高效的延时程序编写方法。
正文内容:一、使用定时器来实现延时1. 配置定时器的基本参数,如计数模式、计数频率等。
2. 设置定时器的初值和重载值,用于设定延时的时间。
3. 启动定时器开始计时。
4. 等待定时器计时完毕,即延时时间到达。
5. 定时器计时完毕后,关闭定时器并清除中断标志。
二、使用硬件延时器来实现延时1. 硬件延时器是一种特殊的定时器,可以实现更高精度的延时。
2. 配置硬件延时器的时钟源和计数模式。
3. 设置硬件延时器的初值和重载值,用于设定延时的时间。
4. 启动硬件延时器开始计时。
5. 等待硬件延时器计时完毕,即延时时间到达。
三、使用外部晶振来实现延时1. 外部晶振可以提供更准确的时钟信号,从而实现更精确的延时。
2. 连接外部晶振到单片机的时钟输入引脚。
3. 配置单片机的时钟源为外部晶振。
4. 根据外部晶振的频率设置延时时间。
5. 使用循环检测的方法等待延时时间到达。
四、使用软件延时函数来实现延时1. 软件延时函数是一种基于循环的延时实现方法。
2. 根据单片机的时钟频率和所需延时时间计算循环次数。
3. 使用循环进行延时,每次循环耗时固定。
4. 根据所需延时时间和循环耗时计算实际应该循环的次数。
5. 注意考虑单片机的优化设置,避免编译器优化影响延时准确性。
五、延时程序的优化技巧1. 选择合适的延时方法,根据实际需求和要求选择最合适的延时实现方法。
2. 考虑延时时间的准确性,根据需求选择合适的时钟源和计数模式等参数。
3. 避免使用不必要的中断和其他程序操作,以确保延时程序的准确性。
4. 根据硬件特性和需求进行延时函数的优化,提高程序的执行效率。
5. 针对不同的延时需求,编写相应的延时函数库,方便重复使用和维护。
单片机定时器延时程序一、引言在单片机的应用中,定时器是一个非常重要的模块。
通过使用定时器,我们可以实现各种定时功能,如延时、计时等。
本文将介绍单片机定时器的延时程序,通过编写代码实现定时功能的延时操作。
二、定时器的基本原理单片机中的定时器是通过计数器的方式实现的。
定时器有一个时钟源,每个时钟周期计数器加1。
当计数器的值达到预设值时,就会触发定时器中断,并执行相应的中断服务程序。
通过改变计数器的预设值,我们可以实现不同的定时功能。
三、编写延时程序在单片机中,我们可以通过设置定时器的预设值来实现延时功能。
下面是一个简单的延时程序示例:```c#include <reg52.h>void delay(unsigned int ms){unsigned int i, j;for(i=0; i<ms; i++)for(j=0; j<1234; j++);}void main(){while(1){// 延时1秒delay(1000);// 执行其他操作}}```上述代码中,我们定义了一个delay()函数,用来实现延时操作。
delay()函数的参数ms表示延时的毫秒数。
通过for循环的嵌套,我们可以控制延时的时间。
在主函数中,我们可以调用delay()函数来实现延时操作。
在上述代码中,我们设置延时1秒,然后执行其他操作。
通过不断调用delay()函数,我们可以实现不同的延时功能。
四、延时精度问题在实际应用中,我们经常会遇到延时精度的问题。
由于单片机的时钟源和延时程序本身的执行时间误差,可能导致延时时间不准确。
为了提高延时精度,我们可以通过以下几种方法来解决:1. 使用定时器的中断功能:通过设置定时器的中断,可以在延时结束时触发中断,从而提高延时精度。
2. 调整延时参数:根据实际情况,可以适当调整延时参数,以达到所需的延时时间。
3. 使用外部时钟源:在一些对延时精度要求较高的应用中,可以使用外部时钟源来提高延时精度。
51单片机c语言延时51单片机(8051微控制器)是一种广泛使用的嵌入式系统芯片,其编程语言包括C语言和汇编语言等。
在C语言中,实现51单片机延时的方法有多种,下面介绍其中一种常用的方法。
首先,我们需要了解51单片机的指令周期和机器周期。
指令周期是指单片机执行一条指令所需的时间,而机器周期是指单片机执行一个操作所需的时间,通常以微秒为单位。
在C语言中,我们可以使用循环结构来实现延时。
#include <reg51.h> // 包含51单片机的寄存器定义void delay(unsigned int time) // 延时函数,参数为需要延时的微秒数{unsigned int i, j;for (i = 0; i < time; i++)for (j = 0; j < 1275; j++); // 1275个机器周期,约等于1ms}void main() // 主函数{while (1) // 无限循环{// 在这里添加需要延时的代码P1 = 0x00; // 例如将P1口清零delay(1000); // 延时1秒P1 = 0xFF; // 将P1口清零delay(1000); // 延时1秒}}在上面的代码中,我们定义了一个名为delay的函数,用于实现延时操作。
该函数接受一个无符号整数参数time,表示需要延时的微秒数。
在函数内部,我们使用两个嵌套的循环来计算延时时间,其中外层循环控制需要延时的次数,内层循环控制每个机器周期的时间(约为1微秒)。
具体来说,内层循环执行了约1275次操作(具体数值取决于编译器和单片机的型号),以实现约1毫秒的延时时间。
需要注意的是,由于单片机的指令周期和机器周期不同,因此我们需要根据具体的单片机型号和编译器进行调整。
在主函数中,我们使用一个无限循环来不断执行需要延时的操作。
例如,我们将P1口的所有引脚清零,然后调用delay函数进行1秒钟的延时,再将P1口清零并再次调用delay函数进行1秒钟的延时。
单片机C语言延时计算单片机是一种集成电路芯片,内部集成了微处理器、存储器、输入输出接口等主要部件。
C语言是常用的单片机编程语言,可以通过编写C程序来实现单片机的控制和功能。
在单片机编程中,延时是一种常用的操作,用于控制程序执行过程中的时间间隔。
延时的实现方法有多种,可以使用循环遍历、定时器、外部中断等方式。
在循环遍历的延时方法中,可以通过设定一个循环次数来实现延时。
具体的延时时间与循环的次数成正比关系。
例如,在一个8位单片机中,循环一次大约需要4个机器周期,因此可以通过适当设置循环次数来达到需要的延时时间。
但是,使用循环遍历的延时方法会占用CPU资源,可能会影响其他任务的执行。
另一种常用的延时方法是使用定时器。
单片机内部通常集成了一个或多个定时器,可以通过设置定时器的初值和工作模式来实现精确的延时。
例如,可以通过设置定时器的计数值和工作频率来计算出延时的时间。
在定时器工作期间,单片机可以继续执行其他任务,不会占用过多的CPU资源。
除了循环遍历和定时器方法外,还可以使用外部中断的方式来实现延时。
具体的实现方法是通过外部信号触发中断,并在中断处理程序中实现延时功能。
这种方法可以根据外部信号的频率和工作模式来调整延时时间。
在单片机编程中,为了提高代码的可读性和可重用性,可以将延时操作封装成函数。
例如,可以定义一个名为delay的函数,函数的参数为延时的时间(单位为毫秒),函数内部通过循环遍历、定时器或外部中断的方式实现延时。
延时的时间计算可以考虑单片机的工作频率、机器周期以及延时的时间要求。
单片机的工作频率可以由时钟源来决定,一般可以通过设置分频系数来调整。
机器周期是单片机执行一条指令所需的时间,通过单片机的数据手册可以查到相关的数据。
根据单片机的工作频率和机器周期,可以计算出所需的循环次数或定时器计数值。
在使用延时功能时需要注意延时时间的准确性和可调性。
准确性是指延时的实际时间与预期时间之间的误差,通过调整循环次数或定时器计数值可以实现较高的准确性。
PIC单片机C语言延时程序和循环子程序
PIC单片机C语言延时程序和循环子程序
很多朋友说C 中不能精确控制延时时间,不能象汇编那样直观。
其实不然, 对延时函数深入了解一下就能设计出一个理想的框价出来。
一般的我们都用
for(x=100;--x;){;}此句等同与x=100;while(--x){;};
或for(x=0;x 来写一个延时函数。
在这里要特别注意:X=100,并不表示只运行100 个指令时间就跳出循环。
可以看看编译后的汇编:
x=100;while(--x){;}
汇编后:
movlw 100
bcf 3,5
bcf 3,6
movwf_delay
l2 decfsz _delay
goto l2
return
从代码可以看出总的指令是是303 个,其公式是8+3*(X-1)。
注意其中循环周期是X-1 是99 个。
这里总结的是x 为char 类型的循环体,当x 为int 时候,其中受X 值的影响较大。
建议设计一个char 类型的循环体,然后再用一个循环体来调用它,可以实现精确的长时间的延时。
在网上搜了一些关于C51单片机C语言的精确延时(相对)的例子和方法现总结如下:1,_nop_() 适用于us级的少量延时标准的C语言中没有空语句。
但在单片机的C语言编程中,经常需要用几个空指令产生短延时的效果。
这在汇编语言中很容易实现,写几个nop就行了。
在keil C51中,直接调用库函数:#include<intrins.h> //声明了void _nop_(void);_nop_(); //产生一条NOP指令作用:对于延时很短的,要求在us级的,采用“_nop_”函数,这个函数相当汇编NOP指令,延时几微秒。
NOP指令为单周期指令,可由晶振频率算出延时时间,对于12M晶振,延时1uS。
2,一般延时大于10us一,定义的C51中循环变量,尽量采用无符号字符型变量。
二,在FOR循环语句中,尽量采用变量减减来做循环。
三,在do…while,while语句中,循环体内变量也采用减减方法这因为在C51编译器中,对不同的循环方法,采用不同的指令来完成的例:unsigned char i;for(i=255;i>0;i--);用keil C51编译后MOV09H,#0FFHLOOP: DJNZ09H,LOOP指令相当简洁,也很好计算精确的延时时间。
3,延时更长,达到MS级,这时需要嵌套循环循环嵌套的方法常用于达到ms级的延时。
对于循环语句同样可以采用for,do…while,while结构来完成,每个循环体内的变量仍然采用无符号字符变量。
例:unsigned char i,jfor(i=255;i>0;i--)for(j=255;j>0;j--);或unsigned char i,ji=255;do{j=255;do{j--}while(j);i--;}while(i);或unsigned char i,ji=255;while(i){j=255;while(j){j--};i--;}下面给出有关在C51中延时子程序设计时要注意的问题(一些经验之谈)1、在C51中进行精确的延时子程序设计时,尽量不要或少在延时子程序中定义局部变量,所有的延时子程序中变量通过有参函数传递。
用单片机C语言精确延时(定时)的方法
本人在闲暇的时候对单片机C语言下的各类延时程序做了下总结。
由于单
片机C语言下利用软件延时不容易做到精确的定时,所以很多人在编写延时子
程序的时候不能好好的把握延时的具体时间。
C语言下,延时程序主要有以下
几种:
一:
void delay(unsigned char k){
unsigned char i,k; //定义变量 for(i=0;ik;i++); //for循环语句
}
该程序在Keil环境下,会先将C语言转化成汇编语言,那么我们就可以根据
汇编语言来计算出精确的时间,转化具体步骤如下:
CLR A ;指令1 MOV R7,A ;指令2 LOOP: INC R7 ;指令3 CJNE R7,k,LOOP ;指令4
这里,指令1,指令2和指令3各消耗1个机器周期,指令4消耗两个机器
周期(可查此表得知:51hei/mcuteach/1312.html),而在12M的晶振下一个机
器周期是1us,在这个过程中,指令1和指令2分别执行1次,即消耗1+1us,
而指令3和指令4分别执行了k次,那么这样加起来,这个延时子程序所消耗
的具体时间就是t=1+1+(1+2)*k=3k+2us。
呵呵,这样说来,如果我们定义的k为100的话,这个延时子程序的精确时
间就是302us。
二:
void delay(unsigned char i){while(--i){;}}
同样的道理,将其反汇编,可以看到,只有一条语句:DJNZ i,$;。
张宏,等:在单片机KeilC开发环境中设计精确的延时函数图1KeilC语言延时的实现机制Fig.1Thede】ayfunctionwithKeilC表1循环体for(;i!一O;i一~)转换成的汇编代码Table1TheASMcodeofloop“for(;I>Oi一一)”可以看出,完成一次主循环的需要6个机器周期,在循环次数分别是o、1、z、3……情况下,延时函数所需的机器周期分别是3、9、15、21…….如果要调用该延时函数,需要使用delay(x)语句,其中x是延时函数主循环的次数。
决定了延时时间的长短.该语句经KeilC转换后成的汇编代码如表2.表2调用该延时函数转换成的汇编代码Table2TheASMcodeofcallingthefunction分析该语句可知,调用延时函数需要3个时钟周期来完成.如果调用延时函数时设定循环的处始值是i,可以得该延时函数的延长时间6i+3+3.该循环延时函数的延时精度是6个机器周期,假如系统使用的晶振是12MHz,则延时时间是(6i+6)/12微秒,同样道理,循环体是for(a=i;a!=O;a一一)的延时函数与此类似.2.2使用while(一一i)语句实现精度为2微秒级的延时函数如果要实现微秒级的延时精度,可以使用下面的函数代码:voiddelayl(unsignedchari){while(~一i);)循环体while(一一i)生成的汇编源代码以及机器周期数如表3.可以看出,完成一次主循环的需要2个机器周期,在循环次数分别是o、1、2、3……情况下,延时函数所需的机器周期分别是2、4、6、8…….要调用该延时函数,由表2可知需要3个时钟周期.如果调用延时函数时设定循环个数的初始值是i,可65徐州工程学院学报2007年第8期以得该延时函数的延长时间2i+2+3.假定系统使用的晶振是12MHz,则延时时间是(2i+5)/12微秒.该循环延时函数的的延时精度是2个机器周期.表3whiIe(一一il生成的汇编代码Table3TheASMcodeofloop“wh订e(一一i)”3使用一noD一()语句设计任意延时精度的延时函数一nop一()语句是KeilC语言中自己带的一个函数,其功能是相当于汇编语句中的NOP指令.该语句的功能是,例如有下面C语言语句:……一nop一();一nop一();……则编译成的汇编代码为:……N()PN()P……如果在第一个延时函数中加入一nop一()语句,就可以增加主循环的运行周期.因此将一nop一()语句与延时循环程序结合起来,可以设计任意的延时时间.分析下面实例代码:Voiddelay(unsignedchari){for(;i!=0;i一一){一nop一();一nop一();)}该代码是在延时函数代码的循环体里面加入两个一nop一()语句,编译生成的汇编代码以及机器周期数如表4.表4加入两个一nop()语句后的延时函数汇编代码Table4TheASMcodeaddedtwonop()line可以看出,因为C语言循环体加入两个nop()语句,因此汇编代码比原来多两个机器周期,完成一次主循环需要8个机器周期,在循环次数分别是O、1、2、3……情况下,延时函数所需的机器周期分别是3、11、19、27…….调用该延时函数,由表2可知需要3个时钟周期.假设调用延时函数时设定循环的初始值是i,可以得该延时函数的延长时间8i+3+3.该循环延时函数的的延时精度是8个机器周期.假定系统使用的晶振是12MHz,则延时时间是(8i+6)/12微秒.通过灵活使用nop()函数,可以灵活设计出任意精度延时函数,达到满意的延时效果.在Keilc语言中,使用nop()语句需要在程序的前面加上“#include<INTRINS.h>”语句.每一个nop()语句编译后需要一个字节的程序空间.4结语上面程序在KeiluVision7.o版本中实现.对Ke订C的编译原理的深入理解,通过恰当的语法运用,合理的语句运用,KeilC语言是可以达到满意的延时效果的.这样既可以发挥C语句的优点,又可以对外围元件进行实时的控制.66在单片机Keil C开发环境中设计精确的延时函数作者:张宏, 邢文生, ZHANG Hong, XING Wen-sheng作者单位:焦作大学,河南,焦作,454000刊名:徐州工程学院学报英文刊名:XUZHOU INSTITUTE OF TECHNOLOGY年,卷(期):2007,22(8)被引用次数:1次1.李建忠单片机原理及应用 20032.金炯泰如何使用KEIL 8051 C编译器 20023.范风强单片机语言C51应用实战集锦 20034.徐爱钧Keil Cx51 V7.0单片机高级语言编程与uVision2应用实践 20041.期刊论文邢文生.李希臣.XING Wensheng.LI Xichen nRF2401的ShockBurstTM模式及其单片机Keil C语言实现-电子工程师2007,33(1)nRF2401是单片2.4 GHz的无线收发一体芯片,只需少量外围元件便可组成射频收发电路,通过SPI接口与单片机进行通信,有功耗低、内置CRC(循环冗余校验)、有可设置地址等优点.文中主要介绍其常用的ShockBurstTM收发模式以及与单片机的硬件连接实现,并介绍单片机模拟SPI接口、nRF2401的配置实现和无线收发数据的实现.单片机采用51系列W77LE58,软件使用Keil C语言.该系统可用于点对点及点对多点的无线数据传输,传输速率最高可达到1 Mbit/s.2.学位论文周天威智能临床生化分析仪器的研究与设计2007生化分析仪是临床医学中重要的检测仪器。
(AT89C51)单片机C程序延时精度研究(转载)2009-10-13 10:11(AT89C51)单片机C程序延时精度研究在单片机应用中,经常会遇到需要短时间延时的情况,一般都是几十到几百μs,并且需要很高的精度(比如用单片机驱动DS18B20时,误差容许的范围在十几μs以内,不然很容易出错);而某些情况下延时时间较长,用计时器往往有点小题大做。
另外在特殊情况下,计时器甚至已经全部用于其他方面的定时处理,此时就只能使用软件定时了[1]。
1 C语言程序延时Keil C51的编程语言常用的有2种:一种是汇编语言;另一种是C 语言。
用汇编语言写单片机程序时,精确时间延时是相对容易解决的。
比如,用的是晶振频率为12 MHz的AT89C51,打算延时20 μs,51单片机的指令周期是晶振频率的1/12,即一个机器周期为1 μs;“MOV R0,#X”需要2个机器周期,DJNZ也需要2个机器周期,单循环延时时间t=2X+3(X为装入寄存器R0的时间常数)[2]。
这样,存入R0里的数初始化为8即可,其精度可以达到1 μs。
用这种方法,可以非常方便地实现512 μs以下时间的延时。
如果需要更长时间,可以使用两层或更多层的嵌套,当然其精度误差会随着嵌套层的增加而成倍增加。
虽然汇编语言的机器代码生成效率很高,但可读性却并不强,复杂一点的程序就更难读懂;而C语言在大多数情况下,其机器代码生成效率和汇编语言相当,但可读性和可移植性却远远超过汇编语言,且C 语言还可以嵌入汇编程序来解决高时效性的代码编写问题。
就开发周期而言,中大型软件的编写使用C 语言的开发周期通常要比汇编语言短很多,因此研究C语言程序的精确延时性能具有重要的意义[3]。
C程序中可使用不同类型的变量来进行延时设计。
经实验测试,使用unsigned char类型具有比unsigned int更优化的代码,在使用时应该使用unsigned char作为延时变量。
C语言精确延时方法有些特殊的应用会用到比较精确的延时(比如DS18B20等),而C不像汇编,延时精准度不好算。
本人经过反复调试,对照KEIL编译后的汇编源文件,得出了以下几条精确延时的语句(绝对精确!本人已通过实际测试),今天贴上来,希望对需要的朋友有所帮助。
sbit LED = P1^0; // 定义一个管脚(延时测试用)unsigned int i = 3; // 注意i,j的数据类型,unsigned char j = 3; // 不同的数据类型延时有很大不同//-----------------各种精确延时语句-----------------------------------while( (i--)!=1 ); // 延时10*i个机器周期i = 10; while( --i ); // 延时8*i+2个机器周期i = 10; while( i-- ); // 延时(i+1)*9+2个机器周期j = 5; while( --j ); // 延时2*j+1个机器周期j = 5; while( j-- ); // 延时(j+1)*6+1个机器周期i = 5;while( --i ) // 延时i*10+2个机器周期,在i*10+2个机器周期if( LED==0 ) break; // 内检测到LED管脚为低电平时跳出延时i = 5;while( LED ) // 每隔10个机器周期检测一次LED管脚状态,当LEDif( (--i)==0 ) break;// 为低时或者到了10*i+2个机器周期时跳出延时//--------------------------------------------------------------------例如18b20的复位函数(12M晶振)://************************************************************* **********// 函数功能:18B20复位// 入口参数:无// 出口参数:unsigned char x: 0:成功 1:失败//************************************************************* **********unsigned char ow_reset(void){unsigned char x=0; // 12M晶振 1个机器周期为1usDQ = 1; // DQ复位j = 10; while(--j);// 稍做延时(延时10*2+1=21个机器周期,21us)DQ = 0; // 单片机将DQ拉低j = 85; while(j--);// 精确延时(大于480us) 85*6+1=511usDQ = 1; // 拉高总线j = 10; while(j--);// 精确延时10*6+1=61usx = DQ; // 稍做延时后,return x; // 如果x=0则初始化成功 x=1则初始化失败j = 25; while(j--);// 精确延时25*6+1=151us}//************************************************************* ********************再如红外解码程序:(先说传统红外解码的弊端:程序中用了while(IR_IO);while(!IR_IO);这样的死循环,如果管脚一直处于一种状态,就会一直执行while,造成“死机”现象。
for实现C语言精确延时C语言最大的缺点就是实时性差,我在网上到看了一些关于延时的讨论,其中有篇文章51单片机Keil C延时程序的简单研究,写得不错,他是用while(--i);产生DJNZ来实现精确延时,后来有人说如果while里面不能放其它语句,否则也不行,用do-while就可以,具体怎样我没有去试.所有这些都没有给出具体的实例程序来.还看到一些延时的例子多多少少总有点延时差.为此我用for循环写了几个延时的子程序贴上来,希望能对初学者有所帮助.(晶振12MHz,一个机器周期1us.)一.500ms延时子程序程序:void delay500ms(void){unsigned char i,j,k;for(i=15;i>0;i--)for(j=202;j>0;j--)for(k=81;k>0;k--);}产生的汇编:C:0x08007F0F MOV R7,#0x0FC:0x08027ECA MOV R6,#0xCAC:0x08047D51MOV R5,#0x51C:0x0806DDFE DJNZ R5,C:0806C:0x0808DEFA DJNZ R6,C:0804C:0x080A DFF6DJNZ R7,C:0802C:0x080C22RET计算分析:程序共有三层循环一层循环n:R5*2=81*2= 162us DJNZ2us二层循环m:R6*(n+3)=202*165= 33330us DJNZ2us+R5赋值1us=3us三层循环:R7*(m+3)=15*33333= 499995us DJNZ2us+R6赋值1us=3us 循环外:5us子程序调用2us+子程序返回2us+R7赋值1us=5us延时总时间=三层循环+循环外=499995+5= 500000us=500ms计算公式:延时时间=[(2*R5+3)*R6+3]*R7+5二.200ms延时子程序程序:void delay200ms(void){unsigned char i,j,k;for(i=5;i>0;i--)for(j=132;j>0;j--)for(k=150;k>0;k--);}产生的汇编C:0x08007F05MOV R7,#0x05C:0x08027E84MOV R6,#0x84C:0x08047D96MOV R5,#0x96C:0x0806DDFE DJNZ R5,C:0806C:0x0808DEFA DJNZ R6,C:0804C:0x080A DFF6DJNZ R7,C:0802C:0x080C22RET三.10ms延时子程序:void delay10ms(void){unsigned char i,j,k;for(i=5;i>0;i--)for(j=4;j>0;j--)for(k=248;k>0;k--);}产生的汇编C:0x08007F05MOV R7,#0x05C:0x08027E04MOV R6,#0x04C:0x08047DF8MOV R5,#0xF8C:0x0806DDFE DJNZ R5,C:0806C:0x0808DEFA DJNZ R6,C:0804C:0x080A DFF6DJNZ R7,C:0802C:0x080C22RET四.1s延时子程序:void delay1s(void){unsigned char h,i,j,k;for(h=5;h>0;h--)for(i=4;i>0;i--)for(j=116;j>0;j--)for(k=214;k>0;k--);}产生的汇编C:0x08007F05MOV R7,#0x05C:0x08027E04MOV R6,#0x04C:0x08047D74MOV R5,#0x74C:0x08067CD6MOV R4,#0xD6C:0x0808DCFE DJNZ R4,C:0808C:0x080A DDFA DJNZ R5,C:0806C:0x080C DEF6DJNZ R6,C:0804C:0x080E DFF2DJNZ R7,C:0802C:0x081022RET在精确延时的计算当中,最容易让人忽略的是计算循环外的那部分延时,在对时间要求不高的场合,这部分对程序不会造成影响.。