单片机延时时间程序怎么编程

单片机延时时间程序怎么编程,第1张

举一个例子来说明吧比如你要编一个延时50毫秒的子程序,那么步骤如下:

1、查看一下你的硬件环境,比如晶振大小,CPU型号,不用CPU指令的机器周期是不一样的。

2、计算延时需要的机器周期。比如采用12M晶振,CPU采用通用8051,那么一个机器周期为1US,50毫秒为501000=50000US,需要的机器周期=50000/1=50000。

3、试编程,如下:

程序代码 指令时间 总共时间

DELAY50MS: ;2 2

MOV R7,#A ;1 1

DELAY1:

MOV R6,#B ;1 1A

DJNZ R6,$ ;2 2BA

DJNZ R7,DELAY1 ;2 2A

RET ;2 2

所以总时间=2+1+A+2AB+2A+2=5+3A+2AB

4、凑数求A、B

根据2、3得到如下式子:

50000=5+3A+2AB

可以有很多种结果,不过最好是以A尽可能小,B尽可能大为原则,当然不能大于255

我现在凑出A=110,B=225;那么总延时时间=5+3110+2110225=49835。还差165US

5、补齐不够时间

再加一个小循环就OK了,呵呵如下:

MOV R6,#C

DJNZ R6,$

会算了吧,2C+1=165;所以C=82。

现在完整的延时程序出来了,如下:

DELAY50MS: ;2 2

MOV R7,#110 ;1 1

DELAY1:

MOV R6,#225 ;1 1110

DJNZ R6,$ ;2 2225110

DJNZ R7,DELAY1 ;2 2110

MOV R6,#82 ;1 1

DJNZ R6,$ ;2 282

RET ;2 2

很圆满:总的时间50000微妙,也就是50毫秒。这种方式编程,在该硬件环境下可以保证最大误差为1微妙。

几个精确延时程序:在精确延时的计算当中,最容易让人忽略的是计算循环外的那部分延时,在对时间要求不高的场合,这部分对程序不会造成影响。

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--);

}

扩展资料

实现延时通常有两种方法:一种是硬件延时,要用到定时器/计数器,这种方法可以提高CPU的工作效率,也能做到精确延时;另一种是软件延时,这种方法主要采用循环体进行。

在电子技术中,脉冲信号是一个按一定电压幅度,一定时间间隔连续发出的脉冲信号。脉冲信号之间的时间间隔称为周期;而将在单位时间(如1秒)内所产生的脉冲个数称为频率。

频率是描述周期性循环信号(包括脉冲信号)在单位时间内所出现的脉冲数量多少的计量名称;频率的标准计量单位是Hz(赫)。电脑中的系统时钟就是一个典型的频率相当精确和稳定的脉冲信号发生器。

51单片机的指令有单字节、双字节和三字节的,它们的指令周期不尽相同,一个单周期指令包含一个机器周期,即12个时钟周期,所以一条单周期指令被执行所占时间为12(1/ 晶振频率)= x μs。常用单片机的晶振为110592MHz,12MHz,24MHz。

其中110592MHz的晶振更容易产生各种标准的波特率,后两种的一个机器周期分别为1 μs和2 μs,便于精确延时。

这个可以做到,如果晶振是12M的话,一下方法可以实现延时1小时,精确度在秒级别。

DELAY1H:

MOV R7,#180 ;1/1000000

DLY1H:

LCALL DELAY_20S ;18019960603s +2180

DJNZ R7,DLY1H ;2180/1000000

RET 2/1000000

共延时时间:35929s误差为71秒,如果再精确的话,再加一点延时就可以了。

DELAY_20S: ;Total=19960603s

MOV R2,# ;1

DLY1:

MOV R3,#200 ;1200

DLY2:

MOV R4,#248 ;1200200

DJNZ R4,$ ;2248200200

DJNZ R3,DLY2 ;2200200

DJNZ R2,DLY1 ;2200

RET ;2

跟51的一样,具体可以根据软件调试修改时间。

WinAVR20081205 延时函数 :

void

_delay_loop_1(uint8_t __count)

{

__asm__ volatile (

"1: dec %0" "\n\t"

"brne 1b"

: "=r" (__count)

: "0" (__count)

);

}

准确延时是3__count个时钟周期 (0<__count<256)

void

_delay_loop_2(uint16_t __count)

{

__asm__ volatile (

"1: sbiw %0,1" "\n\t"

"brne 1b"

: "=w" (__count)

: "0" (__count)

);

}

准确延时是4__count+1个时钟周期 (0<__count<256256-1)

_delay_loop_1() 最小延时是3个时钟周期,最大延时是2563个时钟周期

_delay_loop_2() 最小延时是4+1个时钟周期,最大延时是2562564+1个时钟周期

void

_delay_us(double __us)

{

uint8_t __ticks;

double __tmp = ((F_CPU) / 3e6) __us;

if (__tmp < 10)

__ticks = 1;

else if (__tmp > 255)

{

_delay_ms(__us / 10000);

return;

}

else

__ticks = (uint8_t)__tmp;

_delay_loop_1(__ticks);

}

void

_delay_ms(double __ms)

{

uint16_t __ticks;

double __tmp = ((F_CPU) / 4e3) __ms;

if (__tmp < 10)

__ticks = 1;

else if (__tmp > 65535)

{

// __ticks = requested delay in 1/10 ms

__ticks = (uint16_t) (__ms 100);

while(__ticks)

{

// wait 1/10 ms

_delay_loop_2(((F_CPU) / 4e3) / 10);

__ticks --;

}

return;

}

else

__ticks = (uint16_t)__tmp;

_delay_loop_2(__ticks);

}

_dealy_us()最小延时 与 _delay_loop_1()相同,是3个时钟周期,

_delay_us(0)就是最小延时,相当于_delay_loop_1(1),

在8M时钟下,_delay_us(0375)也是最小延时(0375us是3个时钟周期)

_delay_us(07499999)仍然是最小延时,相当于_delay_loop_1(1),

而_delay_us(074999999)则相当于_delay_loop_1(2)了。

_dealy_ms() 最小延时与 _delay_loop_2()相同,是4+1个时钟周期。

_delay_ms(0)就是最小延时,相当于_delay_loop_2(1),

在8M时钟下,_delay_ms(00005)也是最小延时(00005ms相当于是4个时钟周期)

_delay_ms(00009999999)仍然是最小延时,相当于_delay_loop_2(1),

而_delay_ms(000099999999)则相当于_delay_loop_2(2)了。

_dealy_us(__us)延时精度范围:

(0 , 3个时钟周期),误差(0,3)个时钟周期

(3个时钟周期 , 768us/(F_CPU/1000000)),误差(-2,0)个时钟周期

(768us/(F_CPU/1000000) , 26214ms/(F_CPU/1000000)),误差(-2,+1)个时钟周期,

(26214ms/(F_CPU/1000000)) , 65535ms),误差8M时钟下(约+018ms,约+57ms)

_dealy_ms(__ms)延时精度范围:

(0 , 4个时钟周期),误差(1,5)个时钟周期

(4个时钟周期 , 26214ms/(F_CPU/1000000)),误差(-2,+1)个时钟周期,

(26214ms/(F_CPU/1000000)) , 65535ms),误差8M时钟下(约+018ms,约+57ms)

_dealy_us(__us)最大延时65535ms,即_delay_us(6553500);

_delay_ms(__ms)最大延时65535ms,即_delay_ms(65535);

本人水平有限,如果错漏之处,多谢指正。

补充:

1WinAVR延时库函数看起来,又是double,又是if、else,难道不耗时间?

不耗时间。WinAVR延时库函数,double都可以优化成常量,而整型常量,浮点常量运算,结果仍然仍然是常量。

编译器只要开优化,不会编译出额外的代码出来。if,else也一样。if判断条件是一个常量,也就是说某个分支一定为真,

另外的分支一定为假,编译器优化时,不会编译出额外代码。需要注意,如果要调用WinAVR延时库函数,则必须要开优化。

2怎么没有计算函数调用,返回时间?

WinAVR延时库函数全部都是内联函数,没有函数调用和返回开销。当然,这也有一个副作用,每处延时函数都会编译出一段代码,

占据更多的代码空间。

3旧版WinAVR _delay_us()最大延时768us/(F_CPU/1000000),delay_ms()最大延时是26214ms/(F_CPU/1000000)。

新版WinAVR_delay_us()和_delay_ms()最大延时都是65535ms,不过误差也相对较大,每01ms多7个时钟周期,8M时钟下,误差约为+088%。

----------------------------------

附IARAVR延时函数:

#ifndef __IAR_DELAY_H__

#define __IAR_DELAY_H__

#include <intrinsicsh>

#include "hal_typeh"

#define _delay_loop_1(A) __delay_cycles(3(A))

#define _delay_loop_2(A) __delay_cycles(4(A)+1)

#define _delay_us(A)\

__delay_cycles( (uint32) ( (double)(F_CPU) ((A)/10000000) + 05))

#define _delay_ms(A)\

__delay_cycles( (uint32) ( (double)(F_CPU)((A)/10000) + 05))

#define _delay_s(A)\

__delay_cycles( (uint32) ( (double)(F_CPU)((A)/10) + 05))

#endif

汇编程序的延时可以直接根据指令计算

在12M晶振的条件下,1个机器周期的指令为1微妙

单片机的指令分为单字节、双字节、三字节三种,其机器周期分别为1us、2us、3us [12M晶振]

对上述程序,分三部分计算:

push 06h ;1周期 1us

push 07h ;1周期 1us

MOV R6,#14H ;2周期 2us

;下面做一个整体计算 (2+192+2)14 us

DL1:MOV R7,#19H ;2周期

DL2:DJNZ R7,DL2 ;2周期

DJNZ R6,DL1 ;2周期

pop 07h;1周期 1us

pop 06h;1周期 1us

RET;1周期 1us

然后累加即可得答案

^_^ 希望对你有帮助~

以上就是关于单片机延时时间程序怎么编程全部的内容,包括:单片机延时时间程序怎么编程、【急求】设计一个延时大约0.5秒的延时子程序(晶振频率12HZ);要求:限用ASM51语言编写程序,、51单片机,求用汇编语言编写延时1小时的子程序,要精确到秒级别等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/10177407.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-06
下一篇 2023-05-06

发表评论

登录后才能评论

评论列表(0条)

保存