avr-gcc中關(guān)于delay延時(shí)函數(shù)的應(yīng)用修改版
#i nclude
就可以使用了。這個(gè)頭文件定義了兩個(gè)級別的延時(shí)函數(shù)分別是:
void
void
不過不可以高興的太早,因?yàn)橐谀愕?strong>avr-gcc中正確使用它們是有條件的,下面我將慢慢道來。
這個(gè)參數(shù)和 Makefile 中的 F_CPU 值有關(guān),Makefile 所定義的的F_CPU 變量的值會(huì)傳遞給編譯器。你如果用AVR_studio 4.1X來編輯和調(diào)試,用內(nèi)嵌AVR-GCC的進(jìn)行編譯,并且讓AVR_studio 幫你自動(dòng)生成Makefile 的話,那你可以在:
寫下你的F_CPU的值,F(xiàn)_CPU這個(gè)值表示你的AVR單片機(jī)的工作頻率。單位是 Hz ,不是 MHZ,不要寫錯(cuò)。如 7.3728M
你會(huì)發(fā)現(xiàn)在"delay.h" 頭文件中有這個(gè)樣的一個(gè)定義如下:
#ifndef F_CPU
# warning "F_CPU not defined for
# define F_CPU 1000000UL
#endif
這是為了在你沒有定義F_CPU這個(gè)變量(包括空),或是AVR_studio Frequency沒有給值的時(shí)候,提供一個(gè)默認(rèn)的 1MHz頻率值。讓編譯器編譯時(shí)不至于出錯(cuò)。
下面是這兩個(gè)函數(shù)的實(shí)體:
void _delay_us(double __us)
{
uint8_t __ticks;
double __tmp = ((F_CPU) / 3e6) * __us;
if (__tmp < 1.0)
else if (__tmp > 255)
else
_delay_loop_1(__ticks);
}
void _delay_ms(double __ms)
{
uint16_t __ticks;
double __tmp = ((F_CPU) / 4e3) * __ms;
if (__tmp < 1.0)
else if (__tmp > 65535)
else
_delay_loop_2(__ticks);
}
你會(huì)發(fā)現(xiàn)他們都分別調(diào)用了
而這兩個(gè)函數(shù)又如下所示:
void
{
__asm__ volatile (
);
}
從其函數(shù)注釋里面可以了解到,該函數(shù)用來延遲3個(gè)晶振時(shí)鐘周期,不包括程序調(diào)用和退出該函數(shù)所花費(fèi)的時(shí)間。該函數(shù)的形參__count是一個(gè)8位的變量,由此,我們就可以根據(jù)系統(tǒng)采用的晶振頻率算出該函數(shù)最大的延遲時(shí)間了:
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
依此類推。
1MHz時(shí):
8MHz時(shí):
............
F_CPU
依此類推。
void _delay_loop_2(uint16_t __count)
{
__asm__ volatile (
"1: sbiw %0,1" ""
"brne 1b"
: "=w" (__count)
: "0" (__count)
);
}
{
__asm__ volatile (
);
}
該函數(shù)延時(shí)4個(gè)晶振周期,形參是一個(gè)16位的變量,同樣我們也可以算出該函數(shù)最大的延遲時(shí)間:
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
依此類推。
1MHz時(shí):
8MHz時(shí):
............
F_CPU
依此類推。
重要提示:_delay_loop_1(0)、_delay_loop_1(256)延時(shí)是一樣的??!
同理,_delay_loop_2(0)、_delay_loop_2(65536)延時(shí)也是一樣的!!這些函數(shù)的延時(shí)都是最長的延時(shí)。
這兩個(gè)函數(shù)都是avr-gcc 的 inline匯編格式寫的,具體的語法規(guī)則我就不多說了。可以參考avr-libc。不過這兩個(gè)函數(shù)很簡單,很容易明白。一個(gè)是字節(jié)遞減,一個(gè)是字遞減。如果你認(rèn)真看上面幾個(gè)函數(shù),你就會(huì)發(fā)現(xiàn)要正確使用它們是有如下條件的:
1. 首先,你要正確定義你的 F_CPU 的值,也就是你的AVR單片機(jī)實(shí)際的頻率。否則延時(shí)不準(zhǔn)。(延時(shí)只在數(shù)字上不準(zhǔn)確,具體可以計(jì)算)
2. 你在編譯時(shí)一定要打開優(yōu)化,Makefile中OPT 不要選 0 ,如果AVR_studio 不要選O0 。
3. 你在使用這兩個(gè)delay()時(shí),傳遞給兩個(gè)函數(shù)的實(shí)參要使用常量,不要使用變量。
4. 設(shè)置的時(shí)間參數(shù)__ms , __us 是有范圍的,不要超過范圍。__ms:1 - [262.14 ms / (F_CPU/1e6) ], __us:1- [768 us / (F_CPU/1e6)] 。 [...] 表取整數(shù)部分.(此處結(jié)論錯(cuò)誤?)。
同理,_delay_loop_2(0)、_delay_loop_2(65536)延時(shí)也是一樣的!!這些函數(shù)的延時(shí)都是最長的延時(shí)。
這兩個(gè)函數(shù)都是avr-gcc 的 inline匯編格式寫的,具體的語法規(guī)則我就不多說了。可以參考avr-libc。不過這兩個(gè)函數(shù)很簡單,很容易明白。一個(gè)是字節(jié)遞減,一個(gè)是字遞減。如果你認(rèn)真看上面幾個(gè)函數(shù),你就會(huì)發(fā)現(xiàn)要正確使用它們是有如下條件的:
__us的最大值應(yīng)該是768us(1M頻率下) MAX_VALUE = 256*3/F_CPU s,最小值3個(gè)時(shí)鐘周期MIN_VALUE = 1*3/F_CPU s;
,__ms最大值MAX_VALUE = 65536*4/F_CPU s,MIN_VALUE = 1*4/F_CPU s;
只有具備了上面的條件你才可以正確使用延時(shí)函數(shù) _delay_us () 和 _delay_ms () 。對于第三個(gè)條件,為什么要選用常量,還有第二個(gè)條件為什么要打開優(yōu)化選項(xiàng)。這是為了讓編譯器在編譯的時(shí)候就把延時(shí)的值計(jì)算好,而不是把它編譯到程序中,在運(yùn)行時(shí)才進(jìn)行計(jì)算,那樣的話,一是會(huì)增加代碼的長度,還會(huì)使你的延時(shí)程序的延時(shí)時(shí)間加長,或是變得不可預(yù)料。產(chǎn)生時(shí)序的錯(cuò)誤。
,__ms最大值MAX_VALUE
只有具備了上面的條件你才可以正確使用延時(shí)函數(shù) _delay_us () 和 _delay_ms () 。對于第三個(gè)條件,為什么要選用常量,還有第二個(gè)條件為什么要打開優(yōu)化選項(xiàng)。這是為了讓編譯器在編譯的時(shí)候就把延時(shí)的值計(jì)算好,而不是把它編譯到程序中,在運(yùn)行時(shí)才進(jìn)行計(jì)算,那樣的話,一是會(huì)增加代碼的長度,還會(huì)使你的延時(shí)程序的延時(shí)時(shí)間加長,或是變得不可預(yù)料。產(chǎn)生時(shí)序的錯(cuò)誤。
在08版本中已經(jīng)修改,具體函數(shù)如下:
void
_delay_us(double __us)
{
uint8_t __ticks;
double __tmp = ((F_CPU) / 3e6) * __us;
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);
}
_delay_us(double __us)
{
}
當(dāng)__us過大的時(shí)候,就會(huì)調(diào)用_delay_ms();由上面可以知道8M時(shí)候_delay_ms最小可以延時(shí)4/8000000=0.5us 1M時(shí),最小延時(shí)4/1000000=4us,可以連接上。
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 = 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);
}
_delay_ms(double __ms)
{
}
當(dāng)__ms過大時(shí),只采用__ticks --的方式延時(shí)。先延時(shí)一個(gè)262ms(1M,32ms 8M),然后用遞減方式。
評論