新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > AVR 中 delay 函數(shù)的調(diào)用注意事項(xiàng)!delay_ns delay_ms

AVR 中 delay 函數(shù)的調(diào)用注意事項(xiàng)!delay_ns delay_ms

作者: 時(shí)間:2016-11-23 來源:網(wǎng)絡(luò) 收藏

早就知道AVR的編譯器有自帶的延時(shí)子函數(shù)(或者說是頭文件),但一直沒時(shí)間一探究竟,今天終于揭開了其內(nèi)幕。

AVR編譯器眾多,可謂是百家齊鳴,本人獨(dú)尊WinAVR.
說明:編譯器版本W(wǎng)inAVR-20080610
先說winAVR的_Delay.h_肯定是在Include文件夾下了,進(jìn)去一看果然有,可打開一看,其曰:“This file has been moved to delay.h>."
在util文件夾中找到delay頭文件如下:
--------------------------------------------------------------------------------------------------------------------------------------------
void
_delay_us(double __us)
{
uint8_t __ticks;
double __tmp = ((F_CPU) / 3e6) * __us; //3e6=3000000
if (__tmp < 1.0)
__ticks = 1;
else if (__tmp > 255)
{
_delay_ms(__us / 1000.0);
return;
}
else
__ticks = (uint8_t)__tmp;
_delay_loop_1(__ticks);
}

本文引用地址:http://m.butianyuan.cn/article/201611/320455.htm

-----------------------------------------------------------------------------------------------------------------------------------------------
_delay_ms(double __ms)
{
uint16_t __ticks;
double __tmp = ((F_CPU) / 4e3) * __ms;
if (__tmp < 1.0)
__ticks = 1;
else if (__tmp > 65535)
{
// __ticks = requested delay in 1/10 ms
__ticks = (uint16_t) (__ms * 10.0);
while(__ticks)
{
// wait 1/10 ms
_delay_loop_2(((F_CPU) / 4e3) / 10);
__ticks --;
}
return;
}
else
__ticks = (uint16_t)__tmp;
_delay_loop_2(__ticks);
}
1、分析程序發(fā)現(xiàn)上面兩個(gè)子函數(shù),分別using _delay_loop_1() and using_delay_loop2()
2、還有一點(diǎn),用此頭文件時(shí),必須設(shè)置主頻和優(yōu)化項(xiàng),否則會(huì)出現(xiàn)如下提示:
#ifndef F_CPU
/* prevent compiler error by supplying a default */
# warning "F_CPU not defined for "
# define F_CPU 1000000UL
#endif

#ifndef __OPTIMIZE__
# warning "Compiler optimizations disabled; functions from wont work as designed"
#endif
3、通過查找發(fā)現(xiàn)_Delay_loop1()和_Delay_loop2()在文件delay_basic.h中,如下:
/** ingroup util_delay_basic

Delay loop using an 8-bit counter c __count, so up to 256 iterations are possible. (The value 256 would have to be passedas 0.) The loop executes three CPU cycles per iteration, not including the overhead the compiler needs to setup the counter register.

Thus, at a CPU speed of 1 MHz, delays of up to 768 microseconds can be achieved.
*/
上面翻譯如下:
循環(huán)變量為8位,所以可達(dá)256(其值256和0等同),每次循環(huán)好執(zhí)行3個(gè)CPU時(shí)鐘,不包括程序調(diào)用和退出該函數(shù)所花費(fèi)的時(shí)間。
如此,當(dāng)CPU為1MHZ時(shí),最大延時(shí)為768us。( 3us*256)
void _delay_loop_1(uint8_t __count)
{
__asm__ volatile (
"1: dec %0" ""
"brne 1b" a a
: "=r" (__count)
: "0" (__count)
);
}

/** ingroup util_delay_basic

Delay loop using a 16-bit counter c __count, so up to 65536 iterations are possible. (The value 65536 would have to be passed as 0.) The loop executes four CPU cycles per iteration, not including the overhead the compiler requires to setup the counter register pair.

Thus, at a CPU speed of 1 MHz, delays of up to about 262.1 milliseconds can be achieved.
*/
上面翻譯如下:
循環(huán)變量為16位,所以可達(dá)65536(其值65536和0等同),每次循環(huán)好執(zhí)行4個(gè)CPU時(shí)鐘,不包括程序調(diào)用和退出該函數(shù)所花費(fèi)的時(shí)間。
如此,當(dāng)CPU為1MHZ時(shí),最大延時(shí)大約為262.1us。( 4us*65536)
void_delay_loop_2(uint16_t __count)
{
__asm__ volatile (
"1: sbiw %0,1" ""
"brne 1b"
: "=w" (__count)
: "0" (__count)
);
}
4、有了上面的基礎(chǔ)就不難得出
#include // 頭文件

// _delay_loop_1(XX); // 8-bit count, 3 cycles/loop
// _delay_loop_2(XXXX); // 16-bit count, 4 cycles/loop

#include // 頭文件

_delay_loop_1(uint8_t __count)
1MHz時(shí): MAX_DELAY_TIME = (1/1000000)*3*256 = 0.000768 S = 768 uS
8MHz時(shí): MAX_DELAY_TIME = (1/8000000)*3*256 = 0.000096 S = 96 uS
............
F_CPU MAX_DELAY_TIME = (1/F_CPU)*3*256
依此類推。

_delay_loop_2(uint16_t __count)
1MHz時(shí): MAX_DELAY_TIME = (1/1000000)*4*65535 = 0.26214 S = 262.1 mS
8MHz時(shí): MAX_DELAY_TIME = (1/8000000)*4*65535 = 0.03277 S = 32.8 mS
............
F_CPU MAX_DELAY_TIME = (1/F_CPU)*4*65535
依此類推。

重要提示:_delay_loop_1(0)、_delay_loop_1(256)延時(shí)是一樣的!!
同理, _delay_loop_2(0)、_delay_loop_2(65536)延時(shí)也是一樣的??!這些函數(shù)的延時(shí)都是最長的延時(shí)。

重量級(jí)函數(shù)出場>>>>>>>>>>>>>_delay_us() and _delay_ms() ?。?!<<<<<<<<<<<<<<<<<

先說_delay_us(double __us),不要以為該函數(shù)的形參是double形就為所欲為,隨便付值都不會(huì)溢出了,其實(shí)這個(gè)函數(shù)的調(diào)用是有限制的,不然就會(huì)出現(xiàn)延時(shí)不對(duì)的情況。函 數(shù)的注釋里說明如下:

The maximal possible delay is 768 us / F_CPU in MHz.
在1MHz時(shí)最大延時(shí)768us?。。?!

也就是說double __us這個(gè)值在1M系統(tǒng)時(shí)鐘時(shí)最大只能是768。如果大于768,比如這樣調(diào)用延時(shí)函數(shù)_delay_us(780)會(huì)怎么樣呢??那就會(huì)和調(diào)用_delay_loop_1(0)一樣的效 果了!能延遲多少各位可以算出來。具體在各種系統(tǒng)時(shí)鐘之下這個(gè)值是多少可以通過一個(gè)公式算出來:

MAX_VALUE = 256*3000000/F_CPU

同理,分析程序,可以知道_delay_ms(double __ms)函數(shù),在1MHz系統(tǒng)時(shí)鐘下其最大延時(shí)是262.14 ms!在這里也給出該函數(shù)的形參的最大值,調(diào)用此函數(shù)時(shí)的實(shí)參都不要大于 這個(gè)值,大于這個(gè)限制值的話就和調(diào)用_delay_loop_2(0)同樣的延時(shí)效果!

MAX_VALUE = 65536*4000/F_CPU (1MHZ時(shí),能輸入的最大值為262)

從上面可以看出來,當(dāng)用延時(shí)函數(shù)時(shí),若不加注意會(huì)出錯(cuò)的(畢竟人們很難經(jīng)常記住這兩個(gè)最大值),那還有什么補(bǔ)償?shù)霓k法呢?
#include

// _delay_loop_2(XXXX); // 16-bit count, 4 cycles/loop
// _delay_loop_1(XX); // 8-bit count, 3 cycles/loop

/*------------------------------------*/
void delay_1ms(void) //1ms延時(shí)函數(shù) 主頻為8MHz
{
_delay_loop_2(2000); // 16-bit count,4 cycles/loop

} // 2000*4/FREQ

//使用不同的晶振,可以自己來計(jì)算出()里的值

/*-------------------------------------*/

void delay_nms(unsigned int n) //N ms延時(shí)函數(shù)
{
unsigned int i=0;
for (i=0;idelay_1ms();
}
/*------------------------------------ -*/

原文見:http://hi.baidu.com/xtuyvzkkkllstue/item/9654ea2f29450bc7ef10f1e2

個(gè)人的一些理解,歡迎拍磚:

(1)_delay_us(double __us)調(diào)用了子函數(shù)void _delay_loop_1(uint8_t _count),uint8_t限定了_us的取值范圍不能超過255,而_us又決定了_delay_us()能延時(shí)多久的問題,具體能延時(shí)多久就根據(jù)時(shí)鐘頻率了,如上文所說(好像原文有誤_delay_loop_1(uint8_t __count)這個(gè)地方搞成了_delay_loop_2(uint16_t __count),本篇已改正):

_delay_loop_1(uint8_t __count)
1MHz時(shí): MAX_DELAY_TIME = (1/1000000)*3*256 = 0.000768 S = 768 uS
8MHz時(shí): MAX_DELAY_TIME = (1/8000000)*3*256 = 0.000096 S = 96 uS
............
F_CPU MAX_DELAY_TIME = (1/F_CPU)*3*256

同理,_delay_ms(double _ms)也一樣,調(diào)用了子函數(shù)void _delay_loop_2(uint16_t _count),uint16_t限定了_ms的取值范圍不能超過65535,而_ms又決定了_delay_ms()能延時(shí)多久

_delay_loop_2(uint16_t __count)
1MHz時(shí): MAX_DELAY_TIME = (1/1000000)*4*65535 = 0.26214 S = 262.1 mS
8MHz時(shí): MAX_DELAY_TIME = (1/8000000)*4*65535 = 0.03277 S = 32.8 mS
............
F_CPU MAX_DELAY_TIME = (1/F_CPU)*4*65535

(2)AVR自帶delay函數(shù)延時(shí)1us、1ms跟晶振頻率沒有關(guān)系,晶振頻率只是決定了參數(shù)取值范圍,在計(jì)數(shù)延時(shí)時(shí)候F_CPU這個(gè)值抵消掉了。

(3)上文中的解決辦法是自己寫了個(gè)延時(shí)1ms的函數(shù),其實(shí)跟自帶的是一樣,自帶的如下:

void _delay_ms(double __ms)
{
uint16_t __ticks;
double __tmp = ((F_CPU) / 4e3) * __ms;
if (__tmp < 1.0)
__ticks = 1;
else if (__tmp > 65535)
__ticks = 0;/* i.e. 65536 */
else
__ticks = (uint16_t)__tmp;
_delay_loop_2(__ticks);
}

綠色部分暫且不看,紅色部分即是_ticks的值,如果晶振是8M帶入(F_CPU) / 4e3既得2000,跟上文是一樣。就是自帶的函數(shù)里面不用考慮時(shí)鐘頻率,因?yàn)樗罱K被約分。所以這個(gè)1ms延時(shí)不必自己寫了,我們只需要引用_delay_ms(1);讓它延時(shí)1ms,然后再設(shè)循環(huán)延時(shí)nms,這樣就擺脫了_delay_ms(double _ms)中_ms的范圍限制。




關(guān)鍵詞: AVRdelay函數(shù)注意事

評(píng)論


技術(shù)專區(qū)

關(guān)閉