51单片机精确延时
基于51单片机的精确延时(微秒级)
声明:*此文章是基于51单片机的微秒级延时函数,采用12MHz晶振。
*此文章共包含4个方面,分别是延时1us,5us,10us和任意微秒。
前三个方面是作者学习过程中从书本或网络上面总结的,并非本人所作。
但是延时任意微秒函数乃作者原创且亲测无误。
欢迎转载。
*此篇文章是作者为方便初学者使用而写的,水平有限,有误之处还望大家多多指正。
*作者:Qtel*2012.4.14*QQ:97642651----------------------------------------------------------------------------------------------------------------------序:对于某些对时间精度要求较高的程序,用c写延时显得有些力不从心,故需用到汇编程序。
本人通过测试,总结了51的精确延时函数(在c语言中嵌入汇编)分享给大家。
至于如何在c 中嵌入汇编大家可以去网上查查,这方面的资料很多,且很简单。
以12MHz晶振为例,12MHz 晶振的机器周期为1us,所以,执行一条单周期指令所用时间就是1us,如NOP指令。
下面具体阐述一下。
----------------------------------------------------------------------------------------------------------------------1.若要延时1us,则可以调用_nop_();函数,此函数是一个c函数,其相当于一个NOP指令,使用时必须包含头文件“intrins.h”。
例如:#include<intrins.h>#include<reg52.h>void main(void){P1=0x0;_nop_();//延时1usP1=0xff;}----------------------------------------------------------------------------------------------------------------------2.延时5us,则可以写一个delay_5us()函数:delay_5us(){#pragma asmnop#pragma endasm}这就是一个延时5us的函数,只需要在需要延时5us时调用此函数即可。
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. 内部计时器延时的优点是能够利用单片机内部的硬件资源,提高延时的准确性和稳定性。
51单片机的几种精确延时
对于循环语句同样可以采用for,do…while,while结构来完
成,每个循环体内的变量仍然采用无符号字符变量。
unsigned char i,j
for(i=255;i>0;i--)
for(j=255;j>0;j--);
或
unsigned char i,j
{unsigned char b,c;
b="j";
c="k";
do{
do{
do{k--};
while(k);
k="c";
j--;};
while(j);
j=b;
i--;};
while(i);
在实际应用中,定时常采用中断方式,如进行适当的循环可实现几秒甚至更长时间的延时。使用定时器/计数器延时从程序的执行效率和稳定性两方面考虑都是最佳的方案。但应该注意,C51编写的中断服务程序编译后会自动加上PUSH ACC、PUSH PSW、POP PSW和POP ACC语句,执行时占用了4个机器周期;如程序中还有计数值加1语句,则又会占用1个机器周期。这些语句所消耗的时间在计算定时初值时要考虑进去,从初值中减去以达到最小误差的目的。
51单片机的几种精确延时实现延时
51单片机的几种精确延时实现延时通常有两种方法:一种是硬件延时,要用到定时器/计数器,这种方法可以提高CPU的工作效率,也能做到精确延时;另一种是软件延时,这种方法主要采用循环体进行。
1使用定时器/计数器实现精确延时
单片机系统一般常选用11.059 2 MHz、12 MHz或6 MHz晶振。第一种更容易产生各种标准的波特率,后两种的一个机器周期分别为1μs和2μs,便于精确延时。本程序中假设使用频率为12 MHz的晶振。最长的延时时间可达216=65 536μs。若定时器工作在方式2,则可实现极短时间的精确延时;如使用其他定时方式,则要考虑重装定时初值的时间(重装定时器初值占用2个机器周期)。
Keil C51程序设计中几种精确延时方法
Keil C51程序设计中几种精确延时方法摘要实际的单片机应用系统开发过程中,由于程序功能的需要,经常编写各种延时程序,延时时间从数微秒到数秒不等,对于许多C51开发者特别是初学者编制非常精确的延时程序有一定难度。
本文从实际应用出发,讨论几种实用的编制精确延时程序和计算程序执行时间的方法,并给出各种方法使用的详细步骤,以便读者能够很好地掌握理解。
关键词Keil C51 精确延时程序执行时间引言单片机因具有体积小、功能强、成本低以及便于实现分布式控制而有非常广泛的应用领域[1]。
单片机开发者在编制各种应用程序时经常会遇到实现精确延时的问题,比如按键去抖、数据传输等操作都要在程序中插入一段或几段延时,时间从几十微秒到几秒。
有时还要求有很高的精度,如使用单总线芯片DS18B20时,允许误差范围在十几微秒以内[2],否则,芯片无法工作。
用51汇编语言写程序时,这种问题很容易得到解决,而目前开发嵌入式系统软件的主流工具为C语言,用C51写延时程序时需要一些技巧[3]。
因此,在多年单片机开发经验的基础上,介绍几种实用的编制精确延时程序和计算程序执行时间的方法。
实现延时通常有两种方法:一种是硬件延时,要用到定时器/计数器,这种方法可以提高CPU的工作效率,也能做到精确延时;另一种是软件延时,这种方法主要采用循环体进行。
1 使用定时器/计数器实现精确延时单片机系统一般常选用11.059 2 MHz、12 MHz或6 MHz晶振。
第一种更容易产生各种标准的波特率,后两种的一个机器周期分别为1 μs和2 μs,便于精确延时。
本程序中假设使用频率为12 MHz的晶振。
最长的延时时间可达216=65 536 μs。
若定时器工作在方式2,则可实现极短时间的精确延时;如使用其他定时方式,则要考虑重装定时初值的时间(重装定时器初值占用2个机器周期)。
在实际应用中,定时常采用中断方式,如进行适当的循环可实现几秒甚至更长时间的延时。
51单片机延时函数
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,并设置定时器中断。
在中断服务程序中,我们进行相应的操作来实现精确的延时。
这种方法需要使用到单片机的定时器中断功能,相对复杂一些,但是可以实现精确的延时。
关于51精确延时及keil仿真延时时间
假设参数变量 i 的初值为 m,参数变量 j 的初值为 n,参数变量 k 的初值为 l,则总延时时间为:l 乘以(n 乘以(m 乘以 T+2T)+2T)+3T,其中 T 为 DJNZ 和 MOV 指令执行的时间。当 m=n=l 时,精确延时为 9T,最短;当 m=n=l=256 时,精确延时到 169080102029da1.html 三、下面介绍一下如何用 keil 仿真延时时间 测试函数: void TempDelay (unsigned char idata us) { while(us--); } 测试用例: TempDelay(80); //530uS TempDelay(14); //100uS
LOOP2: MOV R6,#0FFH LOOP1: DJNZ R6,LOOP1 DJNZ R7,LOOP2 这些指令的组合在汇编语言中采用 DJNZ 指令来做延时用,因此它的时间 精确计算也是很简单,假上面变量 i 的初值为 m,变量 j 的初值为 n,则总延 时时间为:m 乘以(n 乘以 T+T),其中 T 为 DJNZ 指令执行时间(DJNZ 指令为 双周期指令)。这里的+T 为 MOV 这条指令所使用的时间。同样对于更长时间 的延时,可以采用多重循环来完成。 只要在程序设计循环语句时注意以上几个问题。 下面给出有关在 C51 中延时子程序设计时要注意的问题 1、在 C51 中进行精确的延时子程序设计时,尽量不要或少在延时子程序 中定义局部变量,所有的延时子程序中变量通过有参函数传递。 2、在延时子程序设计时,采用 dowhile,结构做循环体要比 for 结构做循 环体好。 3、在延时子程序设计时,要进行循环体嵌套时,采用先内循环,再减减比 先减减,再内循环要好。
while(i); 或 unsigned char i,j i=255; while(i) {j=255; while(j) {j--}; i--; } 这三种方法都是用 DJNZ 指令嵌套实现循环的,由 C51 编译器用下面的指 令组合来完成的 MOV R7,#0FFH
51单片机延时程序
51单片机延时程序51单片机延时程序应用单片机的时候,经常会遇到需要短时间延时的情况。
需要的延时时间很短,一般都是几十到几百微妙(us)。
有时候还需要很高的精度,比如用单片机驱动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 6003 JZ ?C00100003 1F DEC R70004 80FA SJMP ?C0007; SOURCE LINE # 210006 ?C0010:0006 22 RET; FUNCTION _delay2 (END)真是不看不知道~~~一看才知道这个延时程序是多么的不准点~~~光看主要的那四条语句,就需要6个机器周期。
mcs-51单片机中汇编程序延时的精确算法。
MCS-51单片机中汇编程序延时的精确算法一、引言MCS-51单片机是一种常用的微控制器,其汇编程序编写对于工程师来说是极为重要的。
在MCS-51单片机中,延时是一种常见的需求,通过延时可以控制程序的执行速度和时间间隔。
而对于汇编程序中的延时算法,精确度的要求往往较高,特别是在一些实时系统中。
本文将针对MCS-51单片机中汇编程序延时的精确算法展开论述。
二、延时的需求在MCS-51单片机中,实现一定时间的延时是非常常见的需求。
在控制LED灯的闪烁过程中,需要一定的时间间隔来控制LED的亮灭频率;在读取传感器数据的过程中,需要一定的时间延时以确保传感器数据的准确性。
精确和可控的延时算法对于MCS-51单片机的应用来说是至关重要的。
三、常见的延时算法在MCS-51单片机的汇编程序中,常见的延时算法包括循环延时、定时器延时和脉冲宽度调制(PWM)延时等。
这些延时算法各有优缺点,需要根据具体的应用场景选择合适的算法。
1. 循环延时循环延时是一种简单而粗糙的延时算法,其原理是通过空转循环来消耗一定的CPU周期来实现延时。
这种延时算法的缺点是精度较差,受到CPU主频和编译器优化等因素的影响较大,不适合对延时精度有较高要求的场景。
2. 定时器延时定时器延时是一种利用MCS-51单片机内部定时器来实现延时的算法。
通过设置定时器的初值和计数方式,可以实现一定范围内的精确延时。
定时器延时的优点是精度高,不受CPU主频影响,适用于对延时精度要求较高的场景。
3. 脉冲宽度调制(PWM)延时脉冲宽度调制(PWM)延时是一种通过调节脉冲信号的宽度来实现延时的算法。
这种延时算法在一些特定的应用场景中具有较高的灵活性和精度。
例如在直流电机的速度调节过程中常常会采用PWM延时算法来实现精确的速度控制。
四、精确延时算法针对MCS-51单片机中汇编程序延时的精确算法,我们可以结合定时器延时和脉冲宽度调制(PWM)延时的优点,设计一种精确度较高的延时算法。
51单片机精确延时程序
51 单片机精确延时程序51 单片机精确延时程序(晶振12MHz,一个机器周期1us.)几个精确延时程序:在精确延时的计算当中,最容易让人忽略的是计算循环外的那部分延时,在对时间要求不高的场合,这部分对程序不会造成影响.一. 500ms 延时子程序程序:.(晶振12MHz,一个机器周期1us.)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--);}计算分析:程序共有三层循环一层循环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){unsigned 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){unsigned 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){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--);}void delay1s(void)//12M 晶振,延时999999.00us {unsigned char i,j,k;for(i=46;i>0;i--)for(j=152;j>0;j--)for(k=70;k>0;k--);}扩展阅读:单片机延时问题20 问。
单片机C51延时时间怎样计算
单片机C51延时时间怎样计算
1. 延时函数:C51中提供了一个延时函数`delay(`,可以用来实现简单的延时操作。
该函数的参数为延时的时间,单位是毫秒(ms)。
2.单片机时钟频率:C51的时钟频率一般为12MHz,即每秒钟钟脉冲个数为12,000,000次。
3.定时/计数器模块:C51中的定时/计数器模块可以用来精确控制延时时间。
其中,TMOD寄存器用来设置定时器的工作模式,THx和TLx寄存器用来设置定时器的初值。
4.定时器计数:C51的定时器工作时,会不断地进行计数。
当计数值达到设定的初值时,会触发中断或者产生一个标志位,可以利用这个特性来实现精确的延时操作。
5.延时时间计算公式:延时时间(单位:毫秒)=计数器初值*定时器计数时间/定时器时钟频率
延时时间计算的具体步骤如下:
1.确定延时所需的毫秒数。
2.确定定时器的工作模式。
3.根据定时器的工作模式,设置THx和TLx寄存器的初值。
4.根据定时器的时钟频率和计数器初值,计算延时时间。
延时函数的缺点是,它是通过循环执行一段无用指令来实现延时的,因此在延时期间无法执行其他操作,延时的精度也不够高。
如果需要精确的延时时间,可以利用定时/计数器模块来实现。
mcs-51单片机中汇编程序延时的精确算法。 -回复
mcs-51单片机中汇编程序延时的精确算法。
-回复MCs51单片机中的汇编程序延时是一种非常重要的功能,它可以用于控制程序的执行速度,并保证特定操作之间的时间间隔。
在本文中,我们将详细介绍MCs51单片机中汇编程序延时的精确算法,并一步一步回答与此主题相关的问题。
首先,让我们了解一下MCs51单片机的基本原理。
MCs51是一种8位微控制器,广泛应用于各种嵌入式系统中。
它的工作原理是通过读取和执行存储在其内部存储器中的指令来完成各种任务。
延时指令是一种特殊的指令,用于使程序在一定时间内暂停执行。
1. 什么是MCs51单片机中的延时?在MCs51单片机中,延时是指在程序执行过程中暂停一段时间。
这段时间可以是固定的,也可以根据不同的需求和算法进行动态调整。
延时指令是通过向计时器/计数器寄存器写入特定的数值来实现的。
2. MCs51单片机中的延时精确性有多高?MCs51单片机可以实现非常高精度的延时,通常可以达到微秒级别。
这种高精度是由于MCs51单片机的工作频率相对较高,并且可以使用精确的定时器/计数器来控制延时。
3. MCs51单片机中的延时算法是如何工作的?MCs51单片机中的延时算法基于定时器/计数器的工作原理。
定时器/计数器是一种特殊的寄存器,可以产生固定频率的时钟信号。
通过调整寄存器的初值,可以控制定时器/计数器产生的时钟脉冲的数量。
4. 常用的基本延时算法是什么?MCs51单片机中常用的基本延时算法是利用循环来实现的。
具体而言,通过实现一个循环,使程序重复执行一定次数,从而产生延时效果。
循环的次数可以根据不同的算法和需求进行调整。
5. 延时的时间是如何计算的?在MCs51单片机中,延时的时间是通过调整循环次数来实现的。
通常情况下,每次循环的执行时间是固定的,可以根据单片机的工作频率和循环次数进行计算。
例如,如果单片机的工作频率为10MHz,每次循环需要10个时钟周期,那么延时1ms就需要执行10000次循环。
51单片机精确延时程序大集合
51单片机精确延时程序大集合51单片机精确延时程序大集合以下程序说是精确延时,实际上都不对。
调用一次差个几微秒、几百微秒,一天下来差好几分钟。
加我的QQ群有精确版本哦,不同频率的晶振都适用。
群:383977592008-04-24 12:10:26,在论坛上看到不少不错的延时程序,整理如下共同分享:精确延时计算公式:延时时间=[(2*第一层循环+3)*第二层循环+3]*第三层循环+5;延时5秒左右DELAY5S:PUSH 04H;2个机器周期PUSH 05H;2个机器周期PUSH 06H;2个机器周期MOV R4,#50;1个机器周期DELAY5S_0:MOV R5,#200;1个机器周期DELAY5S_1:MOV R6,#245;1个机器周期DJNZ R6,$;2×245=490个机器周期DJNZ R5,DELAY5S_1;这条2个机器周期,这层循环包含R5×(490+1)+2×R5=98600个机器周期DJNZ R4,DELAY5S_0;这条2个机器周期,这层循环包含R4×(98600+1)+2×R4=4930150个机器周期POP 06H;2个机器周期POP 05H;2个机器周期POP 04H;2个机器周期RET;2个机器周期;(共2+2+2+1+4930150+2+2+2+2=4930165个机器周期);513微秒延时程序DELAY: MOV R2,#0FEH;1个机器周期JUZINAIYOU: DJNZ R2,JUZINAIYOU;2×R21即2×245RET;2个机器周期;(实际上是493个机器周期);10毫秒延时程序DL10MS: MOV R3,#14HDL10MS1:LCALL DELAYDJNZ R3,DL10MS1RET;(缺DELAY);0.1s延时程序12MHzDELAY: MOV R6,#250DL1: MOV R7,#200DL2: DJNZ R6,DL2DJNZ R7,DL1RET;延时1046549微秒(12MHz);具体的计算公式是:;((((r7*2+1)+2)*r6+1)+2)*r5+1+4 = ((r7*2+3)*r6+3)*r5+5 DEL : MOV R5,#08HDEL1: MOV R6,#0FFHDEL2: MOV R7,#0FFHDJNZ R7,$DJNZ R6,DEL2DJNZ R5,DEL1RET;1秒延时子程序是以12MHz晶振DELAY:MOV R1,#50del0: mov r2,#91del1: mov r3,#100djnz r3,$djnz r2,del1djnz r1,del0Ret;1秒延时子程序是以12MHz晶振为例算指令周期耗时KK: MOV R5,#10 ;1指令周期×1K1: MOV R6,#0FFH ;1指令周期×10K2: MOV R7,#80H ;1指令周期256×10=2560K3: NOP ;1指令周期;128*256*10=327680DJNZ R7,K3 ;2指令周期2*128*256*10=655360DJNZ R6,K2 ;2指令周期2*256*10=5120DJNZ R5,K1 ;2指令周期2*10=20RET;2指令周期;21+10+2560+327680+655360+5120+20+2=990753 ;约等于1秒=1000000微秒;这个算下来也只有0.998抄T_0: MOV R7,#10;D1: MOV R6,#200;D2: MOV R5,#248;DJNZ R5,$DJNZ R6,D2;DJNZ R7,D1;RET;这样算下来应该是1.000011秒T_0: MOV R7,#10;D1: MOV R6,#200;D2: NOPMOV R5,#248;DJNZ R5,$DJNZ R6,D2;DJNZ R7,D1;RETDELAY_2S: ;10MS(11.0592mhz) MOV R3,#200JMP DELAY10MSDELAY_100MS: ;100MS(11.0592mhz) MOV R3,#10JMP DELAY10MSDELAY_10MS:MOV R3,#1DELAY10MS: ;去抖动10MS(11.0592mhz)MOV R4,#20DELAY10MSA:MOV R5,#247DJNZ R5,$DJNZ R4,DELAY10MSADJNZ R3,DELAY10MSRETDELAY_500MS: ;500MSMOV R2,#208JMP DELAY_MSDELAY_175MS: ;175MSMOV R2,#73JMP DELAY_MSdelaY_120MS: ;120MSMOV R2,#50JMP DELAY_MSdelay_60ms: ;60msMOV R2,#25JMP DELAY_MSdelay_30ms: ;30msMOV R2,#12JMP DELAY_MSDELAY_5MS: ;5MSMOV R2,#2;=================================== DELAY_MS:CALL DELAY2400DJNZ R2,DELAY_MSRET;=================================== DELAY2400: ;10x244+4=2447 /1.024=2390 MOV R0,#244 ;1 DELAY24001:MUL AB ;4MUL AB ;4DJNZ R0,DELAY24001 ;2RETDELAY: ;延时子程序(1秒)MOV R0,#0AHDELAY1: MOV R1,#00HJUZINAIYOU: MOV R2,#0B2HDJNZ R2,$DJNZ R1,JUZINAIYOUDJNZ R0,DELAY1RETMOV R2,#10 ;延时1秒LCALL DELAYMOV R2,#50 ;延时5秒LCALL DELAYDELAY: ;延时子程序PUSH R2PUSH R1PUSH R0DELAY1: MOV R1,#00HJUZINAIYOU: MOV R0,#0B2HDJNZ R0,$DJNZ R1,JUZINAIYOU ;延时 100 mSDJNZ R2,DELAY1POP R0POP R1POP R2RET1:DEL: MOV R7, #200DEL1: MOV R6, #123NOPDEL2: DJNZ R6, DEL2DJNZ R7, DEL1RET是50.001ms 算法是:0.001ms+200*0.001ms+200*0.001ms+200*123*0.002ms+2 00*0.002ms ;(123*2+4)*200+12: DEL: MOV R7, #200 DEL1: MOV R6, #123 DEL2:NOPDJNZ R6,DEL2DJNZ R7,DEL1RETD500MS:PUSH PSWSETB RS0MOV R7,#200D51: MOV R6,#250D52: NOPNOPNOPNOPDJNZ R6,D52DJNZ R7,D51POP PSWRETDELAY: ;延时1毫秒PUSH PSW SETB RS0MOV R7,#50D1: MOV R6,#10D2: DJNZ R6,$DJNZ R7,D1POP PSWRETORG 0LJMP MAINORG 000BHLJMP CTC0MAIN: MOV SP, #50HCLR EAMOV TMOD, #01HMOV TH0,#3CHMOV TL0,#0B0HMOV R4, #10SETB ET0SETB EASETB TR0SJMP $ ;CTC0: MOV TH0, #3CHMOV TL0, #0B0HDJNZ R4, LPCPL P1.0MOV R4, #10LP: RETIEND; 定时器中断延时TMOD=0x01; /*定时器0工作在模式1下(16位计数器)*/TH0=0xfd;TL0=0x83;TR0=1; /*启动定时器*/TF0==0;TR0=0;等待中断;100ms定时,11.0592晶振他定时准确啊又不影响程序运行2008-06-10 13:50:46 来源:来于网络,服务大家作者:未知【大中小】点击:9 次下面几个是单片机的延时程序(包括asm和C程序,都是我在学单片机的过程中用到的),在单片机延时程序中应考虑所使用的晶振的频率,在51系列的单片机中我们常用的是11.0592MHz和12.0000MHz的晶振,而在AVR单片机上常用的有8.000MHz和4.000MH的晶振所以在网上查找程序时如果涉及到精确延时则应该注意晶振的频率是多大。
51在不用定时器时的精确延时
有个好帖,从精度考虑,它得研究结果是:void delay2(unsigned char i) //延时2us{while(--i);}为最佳方法。
分析:假设外挂12M(之后都是在这基础上讨论)我编译了下,传了些参数,并看了汇编代码,观察记录了下面的数据:delay2(0):延时518us 518-2*256=6delay2(1):延时7us(原帖写“5us”是错的,^_^)delay2(10):延时25us 25-20=5delay2(20):延时45us 45-40=5delay2(100):延时205us 205-200=5delay2(200):延时405us 405-400=5见上可得可调度为2us,而最大误差为6us。
精度是很高了!但这个程序的最大延时是为518us 显然不能满足实际需要,因为很多时候需要延迟比较长的时间。
那么,接下来讨论将t分配为两个字节,即uint型的时候,会出现什么情况。
void delay8(uint t){while(--t);}我编译了下,传了些参数,并看了汇编代码,观察记录了下面的数据:delay8(0):延时524551us 524551-8*65536=263delay8(1):延时15usdelay8(10):延时85us 85-80=5delay8(100):延时806us 806-800=6delay8(1000):延时8009us 8009-8000=9delay8(10000):延时80045us 80045-8000=45delay8(65535):延时524542us 524542-524280=262如果把这个程序的可调度看为8us,那么最大误差为263us,但这个延时程序还是不能满足要求的,因为延时最大为524.551ms。
那么用ulong t呢?一定很恐怖,不用看编译后的汇编代码了。
那么如何得到比较小的可调度,可调范围大,并占用比较少得RAM呢?请看下面的程序:/*--------------------------------------------------------------------程序名称:50us 延时注意事项:基于1MIPS,AT89系列对应12M晶振,W77、W78系列对应3M晶振例子提示:调用delay_50us(20),得到1ms延时全局变量:无返回:无--------------------------------------------------------------------*/void delay_50us(uint t) //50us 延时{uchar j;for(;t>0;t--)for(j=19;j>0;j--);}我编译了下,传了些参数,并看了汇编代码,观察记录了下面的数据:delay_50us(1):延时63us 63-50=13delay_50us(10):延时513us 503-500=13delay_50us(100):延时5013us 5013-5000=13delay_50us(1000):延时50022us 50022-50000=22赫赫,延时50ms,误差仅仅22us,作为C语言已经是可以接受了。
Keil C51程序设计中几种精确延时方法
对于不熟悉示波器的开发人员可用Keil
C51中的反汇编工具计算延时时间,在反汇编窗口中可用源程序和汇编程序的混合代码或汇编代码显示目标应用程序。为了说明这种方法,还使用“for
_NOP_( );
_NOP_( );
_NOP_( );
}
Delay10us( )函数中共用了6个_NOP_( )语句,每个语句执行时间为1 μs。主函数调用Delay10us(
ACC语句,执行时占用了4个机器周期;如程序中还有计数值加1语句,则又会占用1个机器周期。这些语句所消耗的时间在计算定时初值时要考虑进去,从初值中减去以达到最小误差的目的。
2 软件延时与时间计算
在很多情况下,定时器/计数器经常被用作其他用途,这时候就只能用软件方法延时。下面介绍几种软件延时的方法。
实现延时通常有两种方法:一种是硬件延时,要用到定时器/计数器,这种方法可以提高CPU的工作效率,也能做到精确延时;另一种是软件延时,这种方法主要采用循环体进行。
1 使用定时器/计数器实现精确延时
单片机系统一般常选用11.059 2 MHz、12 MHz或6
C:0x000FE4CLRA//1T
C:0x0010FEMOVR6,A//1T
C:0x0011EEMOVA,R6//1T
C:0x0012C3CLRC//1T
ms,低电平为1 ms,即for循环结构“for(j=0;j<124;j++) {;}”的执行时间为1
ms。通过改变循环次数,可得到不同时间的延时。当然,也可以不用for循环而用别的语句实现延时。这里讨论的只是确定延时的方法。
)时,先执行一个LCALL指令(2 μs),然后执行6个_NOP_( )语句(6 μs),最后执行了一个RET指令(2
Keil C51程序设计中几种精确延时方法 精确延时
Keil C51程序设计中几种精确延时方法2008-04-03 08:48实现延时通常有两种方法:一种是硬件延时,要用到定时器/计数器,这种方法可以提高CPU的工作效率,也能做到精确延时;另一种是软件延时,这种方法主要采用循环体进行。
1 使用定时器/计数器实现精确延时单片机系统一般常选用11.059 2 MHz、12 MHz或6 MHz晶振。
第一种更容易产生各种标准的波特率,后两种的一个机器周期分别为1 μs和2 μs,便于精确延时。
本程序中假设使用频率为12 MHz的晶振。
最长的延时时间可达216=65 536 μs。
若定时器工作在方式2,则可实现极短时间的精确延时;如使用其他定时方式,则要考虑重装定时初值的时间(重装定时器初值占用2个机器周期)。
在实际应用中,定时常采用中断方式,如进行适当的循环可实现几秒甚至更长时间的延时。
使用定时器/计数器延时从程序的执行效率和稳定性两方面考虑都是最佳的方案。
但应该注意,C51编写的中断服务程序编译后会自动加上PUSH ACC、PUSH PSW、POP PSW和POP ACC语句,执行时占用了4个机器周期;如程序中还有计数值加1语句,则又会占用1个机器周期。
这些语句所消耗的时间在计算定时初值时要考虑进去,从初值中减去以达到最小误差的目的。
2 软件延时与时间计算在很多情况下,定时器/计数器经常被用作其他用途,这时候就只能用软件方法延时。
下面介绍几种软件延时的方法。
2.1 短暂延时可以在C文件中通过使用带_NOP_( )语句的函数实现,定义一系列不同的延时函数,如Delay10us( )、Delay25us( )、Delay40us( )等存放在一个自定义的C文件中,需要时在主程序中直接调用。
如延时10 μs 的延时函数可编写如下:void Delay10us( ) {_NOP_( );_NOP_( );_NOP_( )_NOP_( );_NOP_( );_NOP_( );}Delay10us( )函数中共用了6个_NOP_( )语句,每个语句执行时间为1 μs。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Keil C51中几种精确延时程序设计方法更新于2009-02-03 01:37:21 文章出处:与非网Keil C51 定时器精确延时程序执行时间引言单片机因具有体积小、功能强、成本低以及便于实现分布式控制而有非常广泛的应用领域[1]。
单片机开发者在编制各种应用程序时经常会遇到实现精确延时的问题,比如按键去抖、数据传输等操作都要在程序中插入一段或几段延时,时间从几十微秒到几秒。
有时还要求有很高的精度,如使用单总线芯片DS18B20时,允许误差范围在十几微秒以内[2],否则,芯片无法工作。
用51汇编语言写程序时,这种问题很容易得到解决,而目前开发嵌入式系统软件的主流工具为C语言,用C51写延时程序时需要一些技巧[3]。
因此,在多年单片机开发经验的基础上,介绍几种实用的编制精确延时程序和计算程序执行时间的方法。
实现延时通常有两种方法:一种是硬件延时,要用到定时器/计数器,这种方法可以提高CPU的工作效率,也能做到精确延时;另一种是软件延时,这种方法主要采用循环体进行。
1 使用定时器/计数器实现精确延时单片机系统一般常选用11.059 2 MHz、12 MHz或6 MHz晶振。
第一种更容易产生各种标准的波特率,后两种的一个机器周期分别为1 μs和2 μs,便于精确延时。
本程序中假设使用频率为12 MHz的晶振。
最长的延时时间可达216=65 536 μs。
若定时器工作在方式2,则可实现极短时间的精确延时;如使用其他定时方式,则要考虑重装定时初值的时间(重装定时器初值占用2个机器周期)。
在实际应用中,定时常采用中断方式,如进行适当的循环可实现几秒甚至更长时间的延时。
使用定时器/计数器延时从程序的执行效率和稳定性两方面考虑都是最佳的方案。
但应该注意,C51编写的中断服务程序编译后会自动加上PUSH ACC、PUSH PSW、POP PSW和POP ACC语句,执行时占用了4个机器周期;如程序中还有计数值加1语句,则又会占用1个机器周期。
这些语句所消耗的时间在计算定时初值时要考虑进去,从初值中减去以达到最小误差的目的。
2 软件延时与时间计算在很多情况下,定时器/计数器经常被用作其他用途,这时候就只能用软件方法延时。
下面介绍几种软件延时的方法。
2.1 短暂延时可以在C文件中通过使用带_NOP_( )语句的函数实现,定义一系列不同的延时函数,如Delay10us( )、Delay25us( )、Delay40us( )等存放在一个自定义的C文件中,需要时在主程序中直接调用。
如延时10 μs的延时函数可编写如下:void Delay10us( ) {_NOP_( );_NOP_( );_NOP_( );_NOP_( );_NOP_( );_NOP_( );}Delay10us( )函数中共用了6个_NOP_( )语句,每个语句执行时间为1 μs。
主函数调用Delay10us( )时,先执行一个LCALL指令(2 μs),然后执行6个_NOP_( )语句(6 μs),最后执行了一个RET指令(2 μs),所以执行上述函数时共需要10 μs。
可以把这一函数当作基本延时函数,在其他函数中调用,即嵌套调用[4],以实现较长时间的延时;但需要注意,如在Delay40us( )中直接调用4次Delay10us( )函数,得到的延时时间将是42 μs,而不是40 μs。
这是因为执行Delay40us( )时,先执行了一次LCALL指令(2 μs),然后开始执行第一个Delay10us( ),执行完最后一个Delay10us( )时,直接返回到主程序。
依此类推,如果是两层嵌套调用,如在Delay80us( )中两次调用Delay40us( ),则也要先执行一次LCALL指令(2 μs),然后执行两次Delay40us( )函数(84 μs),所以,实际延时时间为86 μs。
简言之,只有最内层的函数执行RET指令。
该指令直接返回到上级函数或主函数。
如在De lay80μs( )中直接调用8次Delay10us( ),此时的延时时间为82 μs。
通过修改基本延时函数和适当的组合调用,上述方法可以实现不同时间的延时。
2.2 在C51中嵌套汇编程序段实现延时在C51中通过预处理指令#pragma asm和#pragma endasm可以嵌套汇编语言语句。
用户编写的汇编语言紧跟在#pragma asm之后,在#pragma endasm之前结束。
如:#pragma asm…汇编语言程序段…#pragma endasm延时函数可设置入口参数,可将参数定义为unsigned char、int或long型。
根据参数与返回值的传递规则,这时参数和函数返回值位于R7、R7R6、R7R6R5中。
在应用时应注意以下几点:◆#pragma asm、#pragma endasm不允许嵌套使用;◆在程序的开头应加上预处理指令#pragma asm,在该指令之前只能有注释或其他预处理指令;◆当使用asm语句时,编译系统并不输出目标模块,而只输出汇编源文件;◆asm只能用小写字母,如果把asm写成大写,编译系统就把它作为普通变量;◆#pragma asm、#pragma endasm和asm只能在函数内使用。
将汇编语言与C51结合起来,充分发挥各自的优势,无疑是单片机开发人员的最佳选择。
2.3 使用示波器确定延时时间熟悉硬件的开发人员,也可以利用示波器来测定延时程序执行时间。
方法如下:编写一个实现延时的函数,在该函数的开始置某个I/O口线如P1.0为高电平,在函数的最后清P1.0为低电平。
在主程序中循环调用该延时函数,通过示波器测量P1.0引脚上的高电平时间即可确定延时函数的执行时间。
方法如下:sbit T_point = P1^0;void Dly1ms(void) {unsigned int i,j;while (1) {T_point = 1;for(i=0;i<2;i++){for(j=0;j<124;j++){;}}T_point = 0;for(i=0;i<1;i++){for(j=0;j<124;j++){;}}}}void main (void) {Dly1ms();}把P1.0接入示波器,运行上面的程序,可以看到P1.0输出的波形为周期是3 ms的方波。
其中,高电平为2 ms,低电平为1 ms,即for循环结构“for(j=0;j<124;j++) {;}”的执行时间为1 ms。
通过改变循环次数,可得到不同时间的延时。
当然,也可以不用for循环而用别的语句实现延时。
这里讨论的只是确定延时的方法。
2.4 使用反汇编工具计算延时时间对于不熟悉示波器的开发人员可用Keil C51中的反汇编工具计算延时时间,在反汇编窗口中可用源程序和汇编程序的混合代码或汇编代码显示目标应用程序。
为了说明这种方法,还使用“for (i=0;i<DlyT;i++) {;}”。
在程序中加入这一循环结构,首先选择build taget,然后单击start/stop debug session按钮进入程序调试窗口,最后打开Disassembly window,找出与这部分循环结构相对应的汇编代码,具体如下:C:0x000FE4CLRA//1TC:0x0010FEMOVR6,A//1TC:0x0011EEMOVA,R6//1TC:0x0012C3CLRC//1TC:0x00139FSUBBA,DlyT //1TC:0x00145003JNCC:0019//2TC:0x00160E INCR6//1TC:0x001780F8SJMPC:0011//2T可以看出,0x000F~0x0017一共8条语句,分析语句可以发现并不是每条语句都执行DlyT次。
核心循环只有0x0011~0x0017共6条语句,总共8个机器周期,第1次循环先执行“CLR A”和“MOV R6,A”两条语句,需要2个机器周期,每循环1次需要8个机器周期,但最后1次循环需要5个机器周期。
DlyT次核心循环语句消耗(2+DlyT×8+5)个机器周期,当系统采用12 MHz时,精度为7 μs。
当采用while (DlyT--)循环体时,DlyT的值存放在R7中。
相对应的汇编代码如下:C:0x000FAE07MOVR6, R7//1TC:0x00111F DECR7//1TC:0x0012EE MOVA,R6//1TC:0x001370FAJNZC:000F//2T循环语句执行的时间为(DlyT+1)×5个机器周期,即这种循环结构的延时精度为5 μs。
通过实验发现,如将while (DlyT--)改为while (--DlyT),经过反汇编后得到如下代码:C:0x0014DFFE DJNZR7,C:0014//2T可以看出,这时代码只有1句,共占用2个机器周期,精度达到2 μs,循环体耗时DlyT×2个机器周期;但这时应该注意,DlyT初始值不能为0。
这3种循环结构的延时与循环次数的关系如表1所列。
表1 循环次数与延时时间关系单位:μs注意:计算时间时还应加上函数调用和函数返回各2个机器周期时间。
2.5 使用性能分析器计算延时时间很多C程序员可能对汇编语言不太熟悉,特别是每个指令执行的时间是很难记忆的,因此,再给出一种使用Keil C51的性能分析器计算延时时间的方法。
这里还以前面介绍的for (i=0;i<124;i++)结构为例。
使用这种方法时,必须先设置系统所用的晶振频率,选择Options for target中的target选项,在Xtal(MHz)中填入所用晶振的频率。
将程序编译后,分别在_point = 1和T_point = 0处设置两个运行断点。
选择start/stop debug session按钮进入程序调试窗口,分别打开Performance Analyzer window和Disassembly window。
运行程序前,要首先将程序复位,计时器清零;然后按F5键运行程序,从程序效率评估窗口的下部分可以看到程序到了第一个断点,也就是所要算的程序段的开始处,用了389 μs;再按F5键,程序到了第2个断点处也就是所要算的程序段的结束处,此时时间为1 386 μs。
最后用结束处的时间减去开始处时间,就得到循环程序段所占用的时间为997 μs。
当然也可以不用打开Performance Analyzer window,这时观察左边工具栏秒(SEC)项。
全速运行时,时间不变,只有当程序运行到断点处,才显示运行所用的时间。
3 总结本文介绍了多种实现并计算延时程序执行时间的方法。