51单片机C程序标准延时函数
- 格式:doc
- 大小:14.50 KB
- 文档页数:4
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;写在延时函数里。
51单片机C语言延时程序几种方式对比51单片机C语言延时程序的简单研究应用单片机的时候,经常会遇到需要短时间延时的情况。
需要的延时时间很短,一般都是几十到几百微妙(us)。
有时候还需要很高的精度,比如用单片机驱动DS18B20(ds18b20型单线智能温度传感器又称数字温度传感器,属于新一代适配微处理器的智能温度传感器,可广泛用于工业、民用、军事等领域的温度测量及控制仪器、测控系统和大型设备中。
它具有体积小,接口方便,传输距离远等特点。
)的时候,误差容许的范围在十几us以内,不然很容易出错。
这种情况下,用计时器往往有点小题大做。
而在极端的情况下,计时器甚至已经全部派上了别的用途。
这时就需要我们另想别的办法了。
以前用汇编语言写单片机程序的时候,这个问题还是相对容易解决的。
比如用的是12MHz晶振的51,打算延时20us,只要用下面的代码,就可以满足一般的需要:mov r0, #09hloop:djnz r0, 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 C 根据这段代码产生的汇编代码找了出来:; FUNCTION _delay2 (BEGIN); SOURCE LINE # 18;---- Variable "i" assigned to Register "R7" ----; SOURCE LINE # 19; SOURCE LINE # 200000?C0007:0000 EF MOV A,R70001 6003JZ?C00100003 1F DEC R70004 80FA SJMP?C0007; SOURCE LINE # 210006?C0010:0006 22RET; FUNCTION _delay2 (END)真是不看不知道~~~一看才知道这个延时程序是多么的不准点~~~光看主要的那四条语句,就需要6个机器周期。
51 单片机定时器延时1s函数1.引言1.1 概述本文介绍了51单片机中的定时器功能以及如何通过定时器实现延时1秒的函数。
在单片机应用中,定时器是一种非常重要且常用的功能模块之一。
它能够精确计时,并可用于实现周期性的任务触发、计时、脉冲输出等功能。
本文首先将对51单片机进行简要介绍,包括其基本概念、结构和特点。
随后,重点讲解了定时器的基本原理和功能。
定时器通常由一个计数器和一组控制寄存器组成,通过预设计数器的初值和控制寄存器的配置来实现不同的计时功能。
接着,本文详细介绍了如何通过编程实现一个延时1秒的函数。
延时函数是单片机开发中常用的功能,通过定时器的计时功能可以实现精确的延时控制。
本文将以C语言为例,介绍延时函数的编写步骤和原理,并给出示例代码和详细的说明。
最后,本文对所述内容进行了总结,并展望了定时器在单片机应用中的广泛应用前景。
通过学习定时器的相关知识和掌握延时函数的编写方法,我们可以更好地应用定时器功能,提高单片机应用的效率和精确性。
综上所述,通过本文的学习,读者可全面了解51单片机中定时器的功能和应用,并能够掌握延时函数的编写方法,为单片机应用开发提供一定的参考和指导。
1.2 文章结构本文以51单片机定时器功能为主题,旨在介绍如何使用定时器进行延时操作。
文章分为引言、正文和结论三个主要部分。
在引言部分,首先会对文章的背景进行概述,介绍单片机的基本概念和应用领域。
然后,给出本文的整体结构,并阐述文章的目的和意义。
正文部分将分为两个小节。
在2.1节中,将对单片机进行详细介绍,包括其构造与工作原理。
这部分的内容将帮助读者全面了解单片机的基本知识,为后续的定时器功能介绍打下基础。
2.2节将重点介绍定时器的功能和特点。
这部分将涵盖定时器的基本原理、工作模式以及在实际应用中的使用方法。
同时,还将详细讲解如何使用定时器进行1秒钟的延时操作,包括具体的代码实现和注意事项。
结论部分将对全文进行总结,并强调定时器的重要性和应用前景。
转用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。
引言概述: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. 内部计时器延时的优点是能够利用单片机内部的硬件资源,提高延时的准确性和稳定性。
51单片机延时函数在嵌入式系统开发中,51单片机因其易于学习和使用、成本低廉等优点被广泛使用。
在51单片机的程序设计中,延时函数是一个常见的需求。
通过延时函数,我们可以控制程序的执行速度,实现定时器功能,或者在需要的时候进行延时操作。
本文将介绍51单片机中常见的延时函数及其实现方法。
一、使用for循环延时这种方法不精确,但是对于要求不高的场合,可以用来估算延时。
cvoid delay(unsigned int time){unsigned int i,j;for(i=0;i<time;i++)for(j=0;j<1275;j++);}这个延时函数的原理是:在第一个for循环中,我们循环了指定的时间次数(time次),然后在每一次循环中,我们又循环了1275次。
这样,整个函数的执行时间就是time乘以1275,大致上形成了一个延时效果。
但是需要注意的是,这种方法因为硬件和编译器的不同,延时时间会有很大差异,所以只适用于对延时时间要求不精确的场合。
二、使用while循环延时这种方法比使用for循环延时更精确一些,但是同样因为硬件和编译器的不同,延时时间会有差异。
cvoid delay(unsigned int time){unsigned int i;while(time--)for(i=0;i<1275;i++);}这个延时函数的原理是:我们先进入一个while循环,在这个循环中,我们循环指定的时间次数(time次)。
然后在每一次循环中,我们又循环了1275次。
这样,整个函数的执行时间就是time乘以1275,大致上形成了一个延时效果。
但是需要注意的是,这种方法因为硬件和编译器的不同,延时时间会有差异,所以只适用于对延时时间要求不精确的场合。
三、使用定时器0实现精确延时这种方法需要在单片机中开启定时器0,并设置定时器中断。
在中断服务程序中,我们进行相应的操作来实现精确的延时。
这种方法需要使用到单片机的定时器中断功能,相对复杂一些,但是可以实现精确的延时。
C程序中可使用不同类型的变量来进行延时设计。
经实验测试,使用unsi gned char类型具有比un signe d int更优化的代码,在使用时应该使用unsi gned char作为延时变量。
以某晶振为12MHz的单片机为例,晶振为12MH z即一个机器周期为1us。
一. 500ms延时子程序程序:void delay500ms(void){unsign ed char i,j,k;for(i=15;i>0;i--)for(j=202;j>0;j--)for(k=81;k>0;k--);}计算分析:程序共有三层循环一层循环n:R5*2 = 81*2 = 162usDJNZ 2us二层循环m:R6*(n+3) = 202*165 = 33330u s 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){unsign ed char i,j,k;for(i=5;i>0;i--)for(j=132;j>0;j--)for(k=150;k>0;k--); }三. 10ms延时子程序程序:void delay10ms(void){unsign ed char i,j,k;for(i=5;i>0;i--)for(j=4;j>0;j--)for(k=248;k>0;k--); }四. 1s延时子程序程序:void delay1s(void){unsign ed 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--);}参考链接:http://www.picav/news/2010-04/2106.htm摘要实际的单片机应用系统开发过程中,由于程序功能的需要,经常编写各种延时程序,延时时间从数微秒到数秒不等,对于许多C51开发者特别是初学者编制非常精确的延时程序有一定难度。
在此,我用的是12M晶振,一个时钟周期是1/12us,一个机器周期为12个时钟周期,则机器周期为1us,而51单片机执行一条语句,为1,2,4个机器周期不等,根据语句的长度来定,一般为1个机器周期。
而_nop_()为一条空语句,执行一次需要一个机器周期。
1us
#include<>
_nop_();
执行了一条_nop_();所以延时为1us;
10us
void delay10us()
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}
执行了6条_nop_(),延时6us,主函数调用delay10us 时,先执行了LCALL指令2us,然后执行6条_nop_()语句6us,最后执行一条RET指令2us,所以总共延时
10us。
100us
void 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。
1ms
void 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;写在延时函数里。
需要自己写在主函数里,其实这里我也没用到什么精确计算方法,而是用keil仿真和粗约计算
的来的,先计算要定时1ms时,定时器需计1000个数,但单片机执行delay1ms()函数里的语句时大约会花20us,那么就得对定时器赋980个初值,则TH0=0xe1; TL0=0x0c;然后用keil仿真,延时了1007us说明还应给定时器多赋6个值,则修改TL0=0x13;这时仿真就微妙不差。
希望读者指出不当之处!。