Keil C51精确延时程序(C语言)
51单片机C程序标准延时函数

51单片机C程序标准延时函数在此,我用的是12M晶振,一个时钟周期是1/12us,一个机器周期为12个时钟周期,则机器周期为1us,而51单片机执行一条语句,为1,2,4个机器周期不等,根据语句的长度来定,一般为1个机器周期。
而_nop_()为一条空语句,执行一次需要一个机器周期。
1us#include<intrins.h>_nop_();执行了一条_nop_();所以延时为1us;10usvoid delay10us(){_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();}执行了6条_nop_(),延时6us,主函数调用delay10us 时,先执行了LCALL指令2us,然后执行6条_nop_()语句6us,最后执行一条RET指令2us,所以总共延时10us。
100usvoid delay100us(){delay10us();delay10us();delay10us();delay10us();delay10us();delay10us();delay10us();delay10us();delay10us();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();}与上面的一样,主函数调用delay100us();先执行了LCALL语句2us,再调用9个delay10us()函数90us,然后执行了6条_nop_()语句6us,最后执行了一条RET语句2us,总共100us。
1msvoid delay1ms(){f=1;TH0=0xe1;TL0=0X13;TR0=1;while(f);}void T0_3() interrupt 1{TR0=0;f=0;}这里就直接用51单片机内部定时器延时了,如果用_nop_();如果要做到微妙不差,那程序就太长了。
这里我用的是定时器0的方式0,13位定时器,这里为了方便,我就没就EA=1;ET0=1;TM0D=0X00;写在延时函数里。
延时1us程序12mhz晶振c语言,51单片机KeilC延时程序的简单(晶振12MHz,一。。。

延时1us程序12mhz晶振c语⾔,51单⽚机KeilC延时程序的简单(晶振12MHz,⼀。
⼀. 500ms延时⼦程序void delay500ms(void){unsignedchari,j,k;for(i=15;i>0;i--)for(j=202;j>0;j--)for(k=81;k>0;k--);}产⽣的汇编:C:0x0800 7F0F MOV R7,#0x0FC:0x0802 7ECA MOV R6,#0xCAC:0x0804 7D51 MOV R5,#0x51C:0x0806 DDFE DJNZ R5,C:0806C:0x0808 DEFA DJNZ R6,C:0804C:0x080A DFF6 DJNZ R7,C:0802C:0x080C 22 RET计算分析:程序共有三层循环⼀层循环n:R5*2 = 81*2 = 162us DJNZ 2us⼆层循环m:R6*(n+3) = 202*165 = 33330us DJNZ 2us + R5赋值1us = 3us三层循环: R7*(m+3) = 15*33333 = 499995us DJNZ 2us + R6赋值1us = 3us循环外: 5us⼦程序调⽤2us +⼦程序返回2us + R7赋值1us = 5us延时总时间=三层循环+循环外= 499995+5 = 500000us =500ms计算公式:延时时间=[(2*R5+3)*R6+3]*R7+5⼆. 200ms延时⼦程序void delay200ms(void){unsignedchari,j,k;for(i=5;i>0;i--)for(j=132;j>0;j--)for(k=150;k>0;k--);}产⽣的汇编C:0x0800 7F05 MOV R7,#0x05C:0x0802 7E84 MOV R6,#0x84C:0x080C 22 RET三. 10ms延时⼦程序void delay10ms(void){unsignedchari,j,k;for(i=5;i>0;i--)for(j=4;j>0;j--)for(k=248;k>0;k--);}产⽣的汇编C:0x0800 7F05 MOV R7,#0x05C:0x0802 7E04 MOV R6,#0x04C:0x0804 7DF8 MOV R5,#0xF8C:0x0806 DDFE DJNZ R5,C:0806C:0x0808 DEFA DJNZ R6,C:0804C:0x080A DFF6 DJNZ R7,C:0802C:0x080C 22 RET四. 1s延时⼦程序void delay1s(void){unsignedcharh,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--); }对1s延时的验证:1.设置仿真的晶振为12MHz2.在延时函数设置断点3.单步运⾏程序,到达延时函数的⼊⼝4.先记下进⼊延时函数的时间5.step out跳出函数,记下此时时间,两个时间相减即为延时函数运⾏时间函数运⾏时间=1.00041400-0.00041600≈1s产⽣的汇编C:0x0808 DCFE DJNZ R4,C:0808C:0x080A DDFA DJNZ R5,C:0806C:0x080C DEF6 DJNZ R6,C:0804C:0x080E DFF2 DJNZ R7,C:0802C:0x0810 22 RET在精确延时的计算当中,最容易让⼈忽略的是计算循环外的那部分延时,在对时间要求不⾼的场合,这部分对程序不会造成影响. void mDelay(unsigned int Delay) //Delay = 1000 时间为1S{unsignedinti;for(;Delay>0;Delay--){for(i=0;i<124;i ){;}}}void waitms(inti){charm;for( ; i ;i--){for(m = 203; m ; m--){_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();}}}延时1ms的函数时钟频率12MHzunsigned intsleepTime;unsingedchar inSleep = 0;void sleepService(void)}void isr_timer(void) //假定定时器中断1ms 中断⼀次。
使用KeilC进行51单片机延时程序编写的几点心得

使用KeilC进行51单片机延时程序编写的几点心得使用Keil C进行51单片机延时程序编写的几点心得应用单片机的时候,经常会遇到需要短时间延时的情况。
需要的延时时间很短,一般都是几十到几百微妙(us)。
有时候还需要很高的精度,比如用单片机驱动DS18B20的时候,误差容许的范围在十几us以内,不然很容易出错。
这种情况下,用计时器往往有点小题大做。
而在极端的情况下,计时器甚至已经全部派上了别的用途。
这时就需要我们另想别的办法了。
以前用汇编语言写单片机程序的时候,这个问题还是相对容易解决的。
比如用的是12MHz 晶振的51,打算延时20us,只要用下面的代码,就可以满足一般的需要:mov r0,#09hloop:djnzr0,loop51 单片机的指令周期是晶振频率的1/12,也就是1us一个周期。
mov r0,#09h需要2个极其周期,djnz也需要2个极其周期。
那么存在r0里的数就是(20-2)/2。
用这种方法,可以非常方便的实现256us以下时间的延时。
如果需要更长时间,可以使用两层嵌套。
而且精度可以达到2us,一般来说,这已经足够了。
现在,应用更广泛的毫无疑问是Keil的C编译器。
相对汇编来说,C固然有很多优点,比如程序易维护,便于理解,适合大的项目。
但缺点(我觉得这是C的唯一一个缺点了)就是实时性没有保证,无法预测代码执行的指令周期。
因而在实时性要求高的场合,还需要汇编和C的联合应用。
但是是不是这样一个延时程序,也需要用汇编来实现呢?为了找到这个答案,我做了一个实验。
用C语言实现延时程序,首先想到的就是C常用的循环语句。
下面这段代码是我经常在网上看到的:void delay2(unsigned char i){for(; i != 0; i--);}。
利用Keil调试精确实现软件延时

图2 值得注意的是,用性能分析窗口来观察延时函数的执行时间要求被观察的延时函数中不能再调用其他任何子函数,被测函数只能由C的 基本语句组成,否则观测到的时候并不是整个函数的运行时间。 采用上述方法,得到了以下几个延时程序: /* * 延时400毫秒 */ void Delay400Ms(void){
while(s--){ delay_1_s();
} }
但是我碰到一个比较奇怪的问题:在实现N秒延时函数中,我不调用delay_1_s()这个延时1秒函数,而用delay_1_s()中的语句来替 换delay_1_s(),改后的函数如下:
void delayNs(uchar s) {
uchar loop=10; unint j; while(s--){
比如我需要一个400ms的延时,随便写了个两重循环,外层循环5次,内层循环暂且设为5000: void Delay400Ms(void){
uchar i=5;
unint j; while(i--){
j=5000; while(j--);
//通过keil调试来确定循环次数
} }
在main函数中调用Delay400Ms(): void main()
loop=10; //注意,不能忘了此句 while(loop--){
j=8375; while(j--); } }
}
{ while(1){ P1=0; Delay400ms();
P1=1; }
} 进入uVersion的调试状态,按F10进行单步,当黄色箭头指向Delay400ms()这条语句时记下左边窗中Sys->sec的值,如图, 是0.00042426。
转用C51编写单片机延时函数

转用C51编写单片机延时函数这里假定单片机是时钟频率为12MHz,则一个机器周期为:1us.参考了51单片机Keil C延时程序的简单研究后,我们可知道,在Keil C 中获得最为准确的延时函数将是void delay(unsigned char t){while(--t);}反汇编代码如下:执行DJNZ指令需要2个机器周期,RET指令同样需要2个机器周期,根据输入t,在不计算调用delay()所需时间的情况下,具体时间延时如下:t Delay Time(us)1 2×1+2=4 22×2+2=6 N2×N+2=2(N+1)当在main函数中调用delay(1)时,进行反汇编如下:调用delay()时,多执行了两条指令,其中MOV R,#data需要1个机器周期,LJMP需要2个机器周期,即调用delay()需要3us.Keil C仿真截图与计算过程:加上调用时间,准确的计算时间延时与Keil C仿真对比如下:(可见,仿真结果和计算结果是很接近的)t Delay Time(us)仿真11.0592 Mhz时钟(us)1 3+2×1+2=7|7.7(实际)7.60 23+2×2+2=9|9.9 9.76 N3+2×N+2=2N+5|(2N+5)*1.1/3 11|12.1 11.94 15 35|38.5 37.98 100 205|225.5 222.44 255515|566.5 558.81也就是说,这个延时函数的精度为2us,最小的时间延时为7us,最大的时间延时为3+255×2+2=515us.实际中使用11.0592 MHz的时钟,这个延时函数的精度将为2.2us,最小时间延时为7.7us,最大时间延时为566.5us.这个时间延时函数,对于与DS18B20进行单总线通信,已经足够准确了。
现在,我们将时钟换成11.0592 MHz这个实际用到的频率,每个机器周期约为1.1us.现在让我们来分析一下这个之前用过的延时函数://延时函数,对于11.0592 MHz时钟,例i=10,则大概延时10ms.void delayMs(unsigned int i){unsigned int j;while(i--){for(j=0;j 125;j++);}}它的反汇编代码如下:分析:T表示一个机器周期(调用时间相对于这个ms级的延时来说,可忽略不计)1 C:0000 MOV A,R7;1T 2DEC R7;1T低8位字节减1 3MOV R2,0x06;2T 4JNZ C:0007;2T若低8位字节不为0,则跳到C:0007 5DEC R6;1T低8位字节为0,则高8位字节减1 6C:0007 ORL A,R2;1T 7JZ C:001D;2T若高8位也减为0,则RET 8CLR A;1T A清零9 MOV R4,A;1T R4放高位10 MOV R5,A;1T R5放低位11 C:000D CLR C;1T C清零12 MOV A,R5;1T 13 SUBB A,#0x7d;1T A=A-125 14 MOV A,R4;1T 15 SUBB A,#0x00;1T A16 JNC C:0000;2T A为零则跳到C:0000 17 INC R5;1T R5增1 18 CJNE R5,#0x00,C:001B;2T R5 0,跳转到C:000D 19 INC R4;1T 20 C:001B SJMP C:000D;2T 21 C:001D RET对于delayMs(1),执行到第7行就跳到21行,共需时12T,即13.2us对于delayMs(2),需时9T+13T+124×10T+7T+12T=9T+13T+1240T+7T+12T=1281T=1409.1 us.对于delayMs(3),需时9T×(3-1)+(13T+124×10T+7T)×(3-1)+12T=1269T×(3-1)+12T=2550T=2805us.对于delayMs(N),N 1,需时1269T×(N-1)+12T=1269NT-1257T=(1395.9 N-1382.7)us.利用Keil C仿真delayMs(1)=0.00166558 s=1.67ms截图如下:由分析可知具体的计算延时时间与Keil C仿真延时对比如下:i Time Delay仿真延时1 13.2us 1.67ms 21409.1 us 3.31ms 32805us 4.96ms N(1395.9 N-1382.7)us 10 12.6ms 16.50ms 20 26.5ms 32.98ms 30 40.5ms 49.46ms 50 68.4ms 82.43ms 100 138.2ms 164.84 ms 200 277.8ms 329.56 ms 500696.6ms 824.13 ms 1000 1394.5 ms 1648.54 ms 1500 2092.5 ms 2472.34 ms 2000 2790.4 ms 3296.47 ms 55.6ms 8.26ms 73 100.5ms 120.34 ms 720 1003.7 ms=1s 1186.74 ms计算delayMs(10)得到延时时间为:12576.3 us约等于12.6ms,接近我们认为的10ms。
51单片机C语言精确延时程序(超级准)

51单片机 C语言精确延时程序(超级准)
51单片机C语言精密延时程序 程序如下: void delayms(unsigned char t) { unsigned char j; unsigned char i; do { j=3; do { i=165; do { --i; } while(i!=0); --j; } while(j!=0); --t; } while(t!=0); } 该程序延时时基为1ms,所以最大延时时间是255ms 下面是反编译的汇编程序 C:0x0031 7E03 MOV R6,#0x03 C:0x0033 7DA5 MOV R5,#0xA5 C:0x0035 DDFE DJNZ R5,C:0035 C:0x0037 DEFA DJNZ R6,C:0033 C:0x0039 DFF6 DJNZ R7,delayms(C:0031) C:0x003B 22 RET 延时时间计算公式如下: ((R5*2 + 2+1)*R6+2+1)R7
假设R7=1,上式为(165*2+3)*3+2+1 =1002us!!!!! 以上程序使用的晶振是12MHz,如果使用的是其他频率的晶振只需计算出1ms的机器周期 数,代入5*2 + 2+1)*R6+2+1,选择合适的R
C51单片机的几种常用延时程序设计2024

引言概述:C51单片机是一种广泛应用于嵌入式系统中的微控制器,它具有高度集成化、易于编程和灵活性强等特点。
在C51单片机的软件开发过程中,延时程序设计是非常重要的一部分。
本文将介绍C51单片机中几种常用的延时程序设计方法,包括循环延时、定时器延时、外部中断延时等。
这些方法不仅可以满足在实际应用中对延时的需求,而且可以提高程序的稳定性和可靠性。
正文内容:一、循环延时1. 使用循环控制语句实现延时功能,例如使用for循环、while循环等。
2. 根据需要设置延时的时间,通过循环次数来控制延时的时长。
3. 循环延时的精度受到指令执行时间的影响,可能存在一定的误差。
4. 循环延时的优点是简单易用,适用于较短的延时时间。
5. 注意在循环延时时要考虑其他任务的处理,避免长时间的等待造成程序卡死或响应延迟。
二、定时器延时1. 使用C51单片机内置的定时器模块来实现延时。
2. 配置定时器的工作模式,如工作方式、定时器精度等。
3. 设置定时器的初值和重装值,控制定时器中断的触发时间。
4. 在定时器中断服务函数中进行延时计数和延时结束标志的设置。
5. 定时器延时的优点是精确可控,适用于需要较高精度的延时要求。
三、外部中断延时1. 在C51单片机上配置一个外部中断引脚。
2. 设置外部中断中断触发条件,如上升沿触发、下降沿触发等。
3. 在外部中断中断服务函数中进行延时计数和延时结束标志的设置。
4. 外部中断延时的优点是能够快速响应外部信号,适用于实时性要求较高的场景。
5. 注意在外部中断延时时要处理好外部中断的抖动问题,确保延时的准确性。
四、内部计时器延时1. 使用C51单片机内部的计时器模块来实现延时。
2. 配置计时器的工作模式,如工作方式、计时器精度等。
3. 设置计时器的初值和重装值,使计时器按照一定的频率进行计数。
4. 根据计时器的计数值进行延时的判断和计数。
5. 内部计时器延时的优点是能够利用单片机内部的硬件资源,提高延时的准确性和稳定性。
Keil C51精确延时程序设计

Keil C51精确延时程序设计时间:2013-05-16 10:45:33 来源:电子设计工程作者:吴挺运,林成何摘要针对C语言代码的执行时间的可预见性差,结合Keil C51开发工具,分析了在Keil C51开发工具中利用C语言实现精确的延时程序的设计,指出了常用延时方法优缺点。
并通过一些实例分析了延时时间的计算方法,使C语言代码的延时时间可以被预见。
C语言中嵌套汇编语言是一种有效的方法,可以充分发挥出各语言的优势特点、提高开发效率。
关键词 Keil C51;C语言;软件延时;单片机C语言具有较强的数据处理能力、语言功能齐全、使用灵活方便、开发效率高,被广泛应用于在单片机系统开发应用中。
在单片机幕统开发的过程中,经常需要使用到延时程序,但C语言代码执行时间。
的可预见性和实时性较差,在开发一些具有严格通信时序要求的系统时,往往需要反复调试延时代码,给开发者带来了较大困难。
比如使用DS18B20进行温度测控时,必须按照其单总线通信协议,否则无法读取温度数据。
针对上述问题,结合Keil C51开发工具和Proteus仿真软件,介绍在Keil C51开发系统中,利用C语言编写的延时程序设计及其运行的时间的计算方法。
1 常用延时程序的设计方法1.1 利用定时器/计数器延时利用C51单片机内部2个16位定时器/计数器实现精确的程序,由于定时器/计数器不占用CPU的运行时间,可以提高CPU的使用效率。
但假设使用12 MHz晶振,定时器工作在方式1模式下,其最长定时时间也只能达到65.53 ms,由此,可以采用中断方式进行溢出次数累加的方法进行长时间的延时程序设计。
但在开发过程中要考虑C51自动对断点的保护和重装初值所带来的延时误差,也可以使用定时器工作在方式2模式下,减少重装初值所带来的误差。
1.2 利用空操作实现延时当所需的延时非常短,可以利用Keil C51自带intrins.h头文件中的_nop_()函数实现函数延时。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Keil C51精确延时程序
程序说明如下:
振荡频率:12MHz
机器周期=12/振荡频率=12/12000000=1us
#include <reg52.h>
void delay1(unsigned char i)
{ while(--i);
}
说明:delay1程序为:延时时间=(2*i+2)*机器周期。
i=1~255。
void delay2(unsigned char i)
{ while(i--);
}
说明:delay2程序为:延时时间=(6*i+2)*机器周期。
i=1~255。
void main (void)
{
unsigned char m;
delay1(10); //赋值并调延时程序delay1
说明:本句为赋值并调用Delayus1:延时时间=(1+2)*机器周期。
全部延时时间为:延时时间=(1+2+2*i+2)*机器周期。
i=1~255。
本例:延时时间=(1+2+2*10+2)*1us=25us
delay2(10); //赋值并调延时程序delay2
说明:本句为赋值并调用Delayus2:延时时间=(1+2)*机器周期。
全部延时时间为:延时时间=(1+2+6*i+2)*机器周期。
i=1~255。
本例:延时时间=(1+2+6*10+2)*1us=65us
m=10; //赋值,m=1~255
while(--m) ; //计算,延时时间=2*m*机器周期
说明:本两句为赋值并计算。
全部延时时间为:延时时间=(1+2*m)*机器周期。
m=1~255。
本例:延时时间=(1+2*10)*1us=25us
while(1);
}。