日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

avr-gcc中关于delay延时函数的应用修改版[ourdev]

發布時間:2023/12/15 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 avr-gcc中关于delay延时函数的应用修改版[ourdev] 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在51中我們的延時函數都是自己編寫的,無論是在匯編中還是在C言語中。雖然有模板,有時還是有點煩。呵呵。不過在應用avr 單片機的時候我們就有福了。因為avr-gcc 提供給我們很方便的delay 延時函數, 只有在源文件包含:

#include <util/delay.h>

就可以使用了。這個頭文件定義了兩個級別的延時函數分別是:

void _delay_us (double __us) ; //微秒級 void _delay_ms (double __ms); //毫秒級
不過不可以高興的太早,因為要在你的avr-gcc中正確使用它們是有條件的,下面我將慢慢道來。

這個參數和 Makefile 中的 F_CPU 值有關,Makefile 所定義的的F_CPU 變量的值會傳遞給編譯器。你如果用AVR_studio 4.1X來編輯和調試,用內嵌AVR-GCC的進行編譯,并且讓AVR_studio 幫你自動生成Makefile 的話,那你可以在:
Project -> Configuration Options -> Gerneral -> Frequency? ? ?如下圖:


寫下你的F_CPU的值,F_CPU這個值表示你的AVR單片機的工作頻率。單位是 Hz ,不是 MHZ,不要寫錯。如 7.3728M???則 F_CPU = 7372800。
你會發現在"delay.h" 頭文件中有這個樣的一個定義如下: #ifndef F_CPU # warning "F_CPU not defined for <util/delay.h>" # define F_CPU 1000000UL // 1MHz #endif
這是為了在你沒有定義F_CPU這個變量(包括空),或是AVR_studio Frequency沒有給值的時候,提供一個默認的 1MHz頻率值。讓編譯器編譯時不至于出錯。

下面是這兩個函數的實體:
void _delay_us(double __us) // 微秒{uint8_t __ticks;double __tmp = ((F_CPU) / 3e6) * __us; // 3e6 是因為調用的_delay_loop_1()是三條指令的if (__tmp < 1.0)__ticks = 1;else if (__tmp > 255)__ticks = 0;else__ticks = (uint8_t)__tmp;_delay_loop_1(__ticks);}void _delay_ms(double __ms) // 毫秒{uint16_t __ticks;double __tmp = ((F_CPU) / 4e3) * __ms; // 4e3 是因為調用的_delay_loop_2()是四條指令的if (__tmp < 1.0)__ticks = 1;else if (__tmp > 65535)__ticks = 0;else__ticks = (uint16_t)__tmp;_delay_loop_2(__ticks);}
你會發現他們都分別調用了??_delay_loop_1(); 和_delay_loop_2(); 這兩個函數
而這兩個函數又如下所示:
void _delay_loop_1(uint8_t __count){__asm__ volatile ("1: dec %0" "\n\t""brne 1b": "=r" (__count): "0" (__count));}

從其函數注釋里面可以了解到,該函數用來延遲3個晶振時鐘周期,不包括程序調用和退出該函數所花費的時間。該函數的形參__count是一個8位的變量,由此,我們就可以根據系統采用的晶振頻率算出該函數最大的延遲時間了:
1MHz時:??MAX_DELAY_TIME?=?(1/1000000)*3*256?=?0.000768?S?=?768?uS
8MHz時:??MAX_DELAY_TIME?=?(1/8000000)*3*256?=?0.000096?S?=?96??uS
............
F_CPU?????MAX_DELAY_TIME?=?(1/F_CPU)*3*256
依此類推。
void _delay_loop_2(uint16_t __count){__asm__ volatile ("1: sbiw %0,1" "\n\t""brne 1b": "=w" (__count): "0" (__count));}

該函數延時4個晶振周期,形參是一個16位的變量,同樣我們也可以算出該函數最大的延遲時間:
1MHz時:??MAX_DELAY_TIME?=?(1/1000000)*4*65535?=?0.26214?S?=?262.1?mS
8MHz時:??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)延時是一樣的!!
同理,_delay_loop_2(0)、_delay_loop_2(65536)延時也是一樣的!!這些函數的延時都是最長的延時。



這兩個函數都是avr-gcc 的 inline匯編格式寫的,具體的語法規則我就不多說了。可以參考avr-libc。不過這兩個函數很簡單,很容易明白。一個是字節遞減,一個是字遞減。如果你認真看上面幾個函數,你就會發現要正確使用它們是有如下條件的:
????????1.?首先,你要正確定義你的 F_CPU 的值,也就是你的AVR單片機實際的頻率。否則延時不準。(延時只在數字上不準確,具體可以計算)
????????2. 你在編譯時一定要打開優化,Makefile中OPT 不要選 0 ,如果AVR_studio 不要選O0 。
????????3. 你在使用這兩個delay()時,傳遞給兩個函數的實參要使用常量,不要使用變量。
????????4. 設置的時間參數__ms , __us 是有范圍的,不要超過范圍。__ms:1 - [262.14 ms / (F_CPU/1e6) ],??__us:1- [768 us / (F_CPU/1e6)]???。 [...]??表取整數部分.(此處結論錯誤?)。
__us的最大值應該是768us(1M頻率下)???MAX_VALUE?=?256*3/F_CPU s,最小值3個時鐘周期MIN_VALUE?=?1*3/F_CPU s;
,__ms最大值MAX_VALUE?=?65536*4/F_CPU s,MIN_VALUE?=?1*4/F_CPU s;



只有具備了上面的條件你才可以正確使用延時函數 _delay_us () 和 _delay_ms () 。對于第三個條件,為什么要選用常量,還有第二個條件為什么要打開優化選項。這是為了讓編譯器在編譯的時候就把延時的值計算好,而不是把它編譯到程序中,在運行時才進行計算,那樣的話,一是會增加代碼的長度,還會使你的延時程序的延時時間加長,或是變得不可預料。產生時序的錯誤。 在08版本中已經修改,具體函數如下: 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);}

當__us過大的時候,就會調用_delay_ms();由上面可以知道8M時候_delay_ms最小可以延時4/8000000=0.5us??1M時,最小延時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);}

當__ms過大時,只采用__ticks --的方式延時。先延時一個262ms(1M,32ms 8M),然后用遞減方式。

總結

以上是生活随笔為你收集整理的avr-gcc中关于delay延时函数的应用修改版[ourdev]的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。