AVR单片机(atmega16)的us级延时程序,用于DS18B20

AVR单片机(atmega16)的us级延时程序,用于DS18B20,第1张

跟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

首先明确机器执行一条指令耗时大概是1us那么延时10ms的程序如下:MOV AX,50L1:MOV BX,100L2:DEC BX     JNZ L2DEC AXJNZ L1执行完之后时间大约为10ms多一点

根据具体问题类型,进行步骤拆解/原因原理分析/内容拓展等。

具体步骤如下:/导致这种情况的原因主要是……

精确计算如下:

DELAY:

MOV R5,#20 ---1T

D1: MOV R6,#20--1T

D2: MOV R7,#248 -1T

DJNZ R7,$ ----2T,(2) 248 = 496

DJNZ R6,D2----2T,(1 + 496 + 2) 20 = 9980

DJNZ R5,D1----2T,(1 + 9980 + 2) 20 = 199660

RET-------2T, 1 + 199660 + 2 = 1996603

总共,耗用199660 T。

时间,关键是要取决于晶振频率。

当晶振频率=12MHz,则有 T = 1us。

延时方法很多,用定时/计数比较方便也比较精确。如果用软件延时,则可以用循环(多重、嵌套都行)。根据时间长短确定循环次数,力求精确。时间计算以机器的晶振频率为基准,算出各指令的运行时间(每条指令运行时间乘所循环的次数就是该指令的全部运行时间),所有指令运行时间的和就是延时的时间。

比如:设晶振频率为12MHz 则每机器周期为1us

513us延时程序为

DL513: MOV R7,#0FFH ;1us

DJNZ R7,$;2us 255=510us

RET ;2us

延时时间为1+510+2=513us

延时时间较长则可以用多重循环(以四重循环为例),如:

KKKK0:MOV R2,#XX ;1us

KKKK1:MOV R3,#LL ;1usXX

KKKK2:MOV R4,#NN ;1usXXLL

KKKK3:MOV R5,#MM ;1usXXLLNN

DJNZ R5,$ ;2us XXLLNNMM

DJNZ R4,KKKK3 ;2us XXLLNN

DJNZ R3,KKKK2 ;2us XXLL

DJNZ R2,KKKK1 ;2us XX

RET ;2us

延时时间为1us+1usXX+1usXXLL+1usXXLLNN+2us XXLLNNMM+2us XXLLNN+2us XXLL+2us XX+2us

适当确定四个循环次数XX、LL、NN、MM就能得到准确的延时时间。

如果在程序中X=10(你写程序时肯定会给他赋一个值,在这里假定是10),即在程序的某处会有delay(10)这样的语句。相当于循环了600X=60010=6000次。可以根据自己的需要来定。你说得对,可以写一个就行。但是有些芯片,你在控制他时,时序要求非常严格,如果延时太长或延时太短,都不会运行出结果。如果需要小延时的地方(只需几个us),只写一个就可以。如果需要延时几ms,只写一个,可能达不到延时要求。总而言之,要根据你的程序需要,时间长了,学的多了,也就懂了。希望我的回答,能给你提供点帮助

以上就是关于AVR单片机(atmega16)的us级延时程序,用于DS18B20全部的内容,包括:AVR单片机(atmega16)的us级延时程序,用于DS18B20、求汇编语言延时程序,延时10毫秒的延时程序、单片机的朋友请进!请问,最简单的延时程序是怎么计算的等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

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

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

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

发表评论

登录后才能评论

评论列表(0条)

保存