单片机延时计算
- 格式:doc
- 大小:54.00 KB
- 文档页数:15
单片机精确延时计算和中断定时单片机精确延时计算和定时中断一.延时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毫秒,使用多个循环来延时更长的时间。
软件延时的精度相对较低,受到单片机的工作频率、指令执行速度等因素的影响。
硬件延时是一种更精确的延时计算方法。
在硬件延时中,我们可以通过改变单片机的时钟频率来控制延时时间。
通过控制时钟频率,可以实现微秒级别的延时。
硬件延时的精度相对较高,但需要对单片机的时钟系统进行配置和调整。
延时计算在单片机的应用中非常重要。
在控制设备的时间间隔方面,延时计算可以实现设备的周期性工作。
例如,可以通过延时计算来控制LED灯的闪烁频率,实现呼吸灯效果。
在时序控制方面,延时计算可以实现不同操作之间的时间间隔。
例如,可以通过延时计算来控制舵机的旋转角度和速度。
延时计算的实现方法有很多种,可以根据具体需求选择合适的方法。
在选择延时计算方法时,需要考虑延时的精度、可靠性和资源占用等因素。
同时,还需要根据单片机的工作频率和指令执行速度等参数进行调整和优化。
延时计算在单片机的应用中起着重要的作用。
通过延时计算,可以实现对设备的精确控制和时序管理。
延时计算的方法和技巧也是单片机程序设计中的重要内容之一。
通过深入了解和研究延时计算,可以提高单片机程序的可靠性和性能。
希望通过本文的介绍,读者对延时计算有更深入的了解和认识。
hc单片机延时计算公式HC单片机是一种常用的微控制器芯片,它可以用来控制各种电子设备的运行。
在使用HC单片机时,我们经常需要进行延时操作,以确保各个模块的正常运行。
本文将介绍HC单片机延时计算公式,帮助读者更好地掌握HC单片机的使用技巧。
HC单片机延时计算公式的基本原理是通过定时器的计数值来实现延时操作。
在HC单片机中,定时器通常都是由内部高频振荡器提供时钟信号,使用定时器可以方便地进行精确的时间计算。
常用的HC单片机延时计算公式包括以下几种:1. 普通延时普通延时是最常见的延时方式,它的计算公式为:Delay = T * Fosc / 12,其中T表示需要延时的时间,单位为毫秒;Fosc表示晶振的频率,单位为MHz。
例如,如果需要延时10ms,晶振频率为12MHz,则Delay = 10 * 12 / 12 = 10ms。
2. 精确延时精确延时需要更高精度的计时方式,通常使用定时器的计数器来实现。
计算公式为:Delay = T * T0 / 256 / (65536 - n),其中T 表示需要延时的时间,单位为毫秒;T0表示定时器的预分频系数;n 表示定时器的计数值。
例如,如果需要延时10ms,定时器的预分频系数为1,则Delay = 10 * 1 / 256 / (65536 - n)。
3. 周期延时周期延时是一种周期性的延时方式,它的计算公式为:Delay = T* (Fosc / 4) / (256 - n),其中T表示需要延时的时间,单位为毫秒;Fosc表示晶振的频率,单位为MHz;n表示定时器的计数值。
例如,如果需要延时10ms,晶振频率为12MHz,则Delay = 10 * (12 / 4) / (256 - n)。
以上就是HC单片机延时计算公式的基本介绍,希望可以对读者在使用HC单片机时有所帮助。
同时,读者在使用HC单片机时也需要注意一些细节问题,例如需要设置好定时器的计数值、预分频系数等参数,以确保延时操作的正确性。
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开发者特别是初学者编制非常精确的延时程序有一定难度。
一、单片机晶振的作用与原理单片机晶振是单片机系统中的一个重要部件,它通过振荡产生稳定的时钟信号,为单片机的运行提供基准。
在单片机系统中,晶振的频率对系统的稳定性、精度和速度有着重要的影响。
二、晶振频率为12MHz的延时计算在单片机系统中,为了实现延时操作,一般需要通过编程来控制计时器或者循环延时的方式来实现。
对于晶振频率为12MHz的单片机系统,延时1ms的计算依据如下:1. 首先需要计算出12MHz晶振的周期,即一个晶振振荡周期的时间。
12MHz晶振的周期为1/12MHz=0.0833us。
2. 接下来将1ms转换成晶振周期数。
1ms=1000us,将1000us除以0.0833us得到12000。
即延时1ms需要进行12000个晶振周期的振荡。
3. 最后根据单片机的指令周期和频率来确定代码延时的实现方法。
以常见的晶振频率为12MHz的单片机为例,根据单片机的指令周期(一般为1/12MHz=0.0833us)和延时周期数(12000),可以编写相应的延时函数或者循环来实现1ms的延时操作。
三、12MHz晶振延时1ms的应用场景在实际的单片机应用中,常常需要进行一定时间的延时操作,例如驱动液晶屏显示、控制外围设备响应等。
12MHz晶振延时1ms的应用场景包括但不限于:LED闪烁控制、按键消抖、舵机控制、多任务调度等。
四、晶振频率选择与延时精度的关系晶振频率的选择对延时精度有着直接的影响。
一般来说,晶振频率越高,对延时精度要求越高的应用场景,而对于一般的延时控制,12MHz的晶振已经能够满足大多数的要求。
延时的精度还受到单片机的指令执行速度的影响,需要在实际应用中进行综合考量与测试。
五、总结在单片机系统中,晶振的频率选择与延时操作密切相关,12MHz晶振延时1ms的计算依据可以帮助工程师们更好地进行单片机程序的设计与开发。
需要根据实际应用场景和需求来选择合适的晶振频率,并对延时精度进行充分的考量和测试,以确保单片机系统的稳定可靠性。
单片机延时计算1.10ms延时程序(for循环嵌套)********************************************************************* 文件名称:void delay_10ms()功能:10ms延时参数:单片机晶振12MHz********************************************************************* void delay_10ms(){unsigned inti,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。
一、关于单片机周期的几个概念●时钟周期时钟周期也称为振荡周期,定义为时钟脉冲的倒数(可以这样来理解,时钟周期就是单片机外接晶振的倒数,例如12MHz的晶振,它的时间周期就是1/12 us),是计算机中最基本的、最小的时间单位。
在一个时钟周期内,CPU仅完成一个最基本的动作。
●机器周期完成一个基本操作所需要的时间称为机器周期。
以51为例,晶振12M,时钟周期(晶振周期)就是(1/12)μs,一个机器周期包执行一条指令所需要的时间,一般由若干个机器周期组成。
指令不同,所需的机器周期也不同。
对于一些简单的的单字节指令,在取指令周期中,指令取出到指令寄存器后,立即译码执行,不再需要其它的机器周期。
对于一些比较复杂的指令,例如转移指令、乘法指令,则需要两个或者两个以上的机器周期。
1.指令含义DJNZ:减1条件转移指令这是一组把减1与条件转移两种功能结合在一起的指令,共2条。
DJNZ Rn,rel ;Rn←(Rn)-1;若(Rn)=0,则PC←(PC)+2 ;顺序执行;若(Rn)≠0,则PC←(PC)+2+rel,转移到rel所在位置DJNZ direct,rel ;direct←(direct)-1;若(direct)= 0,则PC←(PC)+3;顺序执行;若(direct)≠0,则PC←(PC)+3+rel,转移到rel 所在位置2.DJNZ Rn,rel指令详解例:MOV R7,#5DEL:DJNZ R7,DEL; rel在本例中指标号DEL1.单层循环由上例可知,当Rn赋值为几,循环就执行几次,上例执行5次,因此本例执行的机器周期个数=1(MOV R7,#5)+2(DJNZ R7,DEL)×5=11,以12MHz的晶振为例,执行时间(延时时间)=机器周期个数×1μs=11μs,当设定立即数为0时,循环程序最多执行256次,即延时时间最多256μs。
2.双层循环1)格式:DELL:MOV R7,#bbDELL1:MOV R6,#aaDELL2:DJNZ R6,DELL2; rel在本句中指标号DELL2DJNZ R7,DELL1; rel在本句中指标号DELL1注意:循环的格式,写错很容易变成死循环,格式中的Rn和标号可随意指定。
单片机C51延时时间怎样计算?C程序中可使用不同类型的变量来进行延时设计。
经实验测试,使用unsigned char类型具有比unsigned int 更优化的代码,在使用时应该使用unsigned char作为延时变量。
以某晶振为12MHz的单片机为例,晶振为12MHz即一个机器周期为1us。
void delay__ms(void) //x,y,z位固定值,故不能接受参数{unsigned char i,j,k;for(i=x;i>0;i--)for(j=y;j>0;j--)for(k=z;k>0;k--);}【Delay_Time=[(2z+3)*y+3]*x+5】一. 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--);}计算分析:程序共有三层循环一层循环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--);}应用单片机的时候,经常会遇到需要短时间延时的情况。
需要的延时时间很短,一般都是几十到几百微妙(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 根据这段代码产生的汇编代码找了出来:; 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个机器周期。
也就是说,它的精度顶多也就是6us而已,这还没算上一条 lcall 和一条 ret。
如果我们把调用函数时赋的i值根延时长度列一个表的话,就是:i delay time/us0 61 122 18...因为函数的调用需要2个时钟周期的lcall,所以delay time比从函数代码的执行时间多2。
顺便提一下,有的朋友写的是这样的代码:void delay2(unsigned char i){unsigned char a;for(a = i; a != 0; a--);}可能有人认为这会生成更长的汇编代码来,但是事实证明:; FUNCTION _delay2 (BEGIN); SOURCE LINE # 18;---- Variable 'i' assigned to Register 'R7' ----; SOURCE LINE # 19; SOURCE LINE # 21;---- Variable 'a' assigned to Register 'R7' ----0000 ?C0007:0000 EF MOV A,R70001 6003 JZ ?C00100003 1F DEC R70004 80FA SJMP ?C0007; SOURCE LINE # 220006 ?C0010:0006 22 RET其生成的代码是一样的。
不过这的确不是什么好的习惯。
因为这里实在没有必要再引入多余的变量。
我们继续讨论正题。
有的朋友为了得当更长的延时,甚至用了这样的代码:void delay2(unsigned long i){for(; i != 0; i--);}这段代码产生的汇编代码是什么样子的?其实不用想也知道它是如何恐怖的$#^%&%$......让我们看一看:; FUNCTION _delay2 (BEGIN); SOURCE LINE # 180000 8F00 R MOV i+03H,R70002 8E00 R MOV i+02H,R60004 8D00 R MOV i+01H,R50006 8C00 R MOV i,R4; SOURCE LINE # 19; SOURCE LINE # 200008 ?C0007:0008 E4 CLR A0009 FF MOV R7,A000A FE MOV R6,A000B FD MOV R5,A000C FC MOV R4,A000D AB00 R MOV R3,i+03H000F AA00 R MOV R2,i+02H0011 A900 R MOV R1,i+01H0013 A800 R MOV R0,i0015 C3 CLR C0016 120000 E LCALL ?C?ULCMP0019 601A JZ ?C0010001B E500 R MOV A,i+03H001D 24FF ADD A,#0FFH001F F500 R MOV i+03H,A0021 E500 R MOV A,i+02H0023 34FF ADDC A,#0FFH0025 F500 R MOV i+02H,A0027 E500 R MOV A,i+01H0029 34FF ADDC A,#0FFH002B F500 R MOV i+01H,A002D E500 R MOV A,i002F 34FF ADDC A,#0FFH0031 F500 R MOV i,A0033 80D3 SJMP ?C0007; SOURCE LINE # 210035 ?C0010:0035 22 RET; FUNCTION _delay2 (END)呵呵,这倒是的确可以延迟很长时间~~~但是毫无精度可言了。
那么,用C到底能不能实现精确的延时呢?我把代码稍微改了一下:void delay1(unsigned char i){while(i--);}因为根据经验,越简洁的C代码往往也能得出越简洁的机器代码。
那这样结果如何呢?把它生成的汇编代码拿出来看一看就知道了。
满怀希望的我按下了“Build target”键,结果打击是巨大的:; FUNCTION _delay1 (BEGIN); SOURCE LINE # 13;---- Variable 'i' assigned to Register 'R7' ----; SOURCE LINE # 140000 ?C0004:; SOURCE LINE # 150000 AE07 MOV R6,AR70002 1F DEC R70003 EE MOV A,R60004 70FA JNZ ?C0004; SOURCE LINE # 160006 ?C0006:0006 22 RET; FUNCTION _delay1 (END)虽说生成的代码跟用for语句是不大一样,不过我可以毫无疑问的说,这两种方法的效率是一样的。
似乎到此为止了,因为我实在想不出来源程序还有什么简化的余地。
看来我就要得出来这个结论了:“如果需要us级的延时精度,需要时用汇编语言。
”但是真的是这样吗?我还是不甘心。
因为我不相信大名鼎鼎的 Keil C 编译器居然连 djnz 都不会用???因为实际上程序体里只需要一句 loop: djnz r7, loop。
近乎绝望之际(往往人在这种情况下确可以爆发出来,哦呵呵呵~~~),我随手改了一下:void delay1(unsigned char i){while(--i);}心不在焉的编译,看源码:; FUNCTION _delay1 (BEGIN); SOURCE LINE # 13;---- Variable 'i' assigned to Register 'R7' ----; SOURCE LINE # 140000 ?C0004:; SOURCE LINE # 150000 DFFE DJNZ R7,?C0004; SOURCE LINE # 160002 ?C0006:0002 22 RET; FUNCTION _delay1 (END)天~~~奇迹出现了......我想这个程序应该已经可以满足一般情况下的需要了。