第一篇:單片機c語言學習心得轉載
單片機c語言學習心得
(一)相信很多愛好電子的朋友,對單片機這個詞應該都不會陌生了吧。不過有些朋友可能只聽說他叫單片機,他的全稱是什么也許并不太清楚,更不用說他的英文全稱和簡稱了。單片機是一塊在集成電路芯片上集成了一臺有一定規模的微型計算機。簡稱為:單片微型計算機或單片機(Single Chip Computer)。單片機的應用到處可見,應用領域廣泛,主要應用在智能儀表、實時控制、通信、家電等方面。不過這一切都沒什么關系,因為我(當然也包括任何人)都是從不知道轉變成知道的,再轉變成精通的?,F在我只想把我學習單片機的經歷,詳細地講敘給大家聽聽,可能有些大蝦會笑話我,想:那么簡單的東西還在這里賣弄。但是你錯了,我只是把我個人學習的經歷講述一遍而已,僅僅對那些想學習單片機,但又找不到好方法或者途徑的朋友,提供一個幫助,使他們在學習過程中,盡量少走些彎路而已!
首先,你必須有學習單片機的熱情,不是說今天去圖書館看了一個下午關于單片機的書,而明天玩上半天,后天就不知道那個本書在講什么東西了。還是先說說我吧,我從大二的第一個學期期末的時候才開始接觸單片機,但在這之前,正如上面所說的:我知道有種芯片叫單片機,但是具體長成什么樣子,卻一點也不知道!看到這里很多朋友一定會忍不住發笑。嘿嘿,你可千萬別笑,有些大四畢業的人也同樣不知道單片機長成什么樣子呢!而我對單片機的癡迷更是常人所不能想象的地步,大二的期末考試,我全放棄了復習,每當室友拿著書在埋頭復習的時候,我卻捧著自己從圖書館借的單片機書在那看,雖然有很多不懂,但是我還是堅持了下來,當時我就想過,為了單片機值不值得我這樣去付出,或許這也是在一些三流學校的好處吧,考試掛科后,明年開學交上幾十元一門的補考費,應該大部分都能過了。于是,我橫下一條心,堅持看我的單片機書和資料。當你明白了單片機是這么一回事的時候,顯而易見的問題出來了:我要選擇那種語言為單片機編寫程序呢?這個問題,困擾了我好久。具體選擇C51還是A51呢?匯編在我們大二之前并沒有開過課,雖然看著人家的講解,很容易明白單片機的每一時刻的具體工作情況,但是一合上書或者資料,自己卻什么也不知道了,根本不用說自己寫程序了。于是,我最終還是決定學C51,畢竟C51和我們課上講的C語言,有些類似,編程的思想可以說是相通的。而且C51還有更大的優點就是編寫大程序時的優越性更不言而喻,當然在那時,我并沒有想的那么深遠,C51的特點,還是在后來的實踐過程中,漸漸體會到的!朋友如果你選擇了C51,那么請繼續往下看,如果你選擇了A51,那么你可以不要看了!因為下面講的全是C方面的,完全在浪費你的時間!呵呵 ^_^
第二,既然你想學好單片機,你必須得舍得花錢,如果不買些芯片回來自己動手焊焊拆拆的(但是在后期會介紹給大家一個很好用的硬件仿真軟件,并不需要你用實驗板和仿真器了,直接在你的PC上完成,但是軟件畢竟是軟件,從某個特定的意義上來說是并不能代替硬件的),即使你每天捧著本書,把那本書翻爛,也永遠學不會單片機的!剛接觸單片機的朋友,看了資料,一定會對以下幾個詞見的比較多,但是具體的概念還是比較模糊,現作如下說明:
(1)編程器編程器是用來燒單片機芯片的,是把HEX或者BIN文件燒到單片機ROM里的。
(2)實驗板實驗板是專為初學者根據某些要求而特做的板,一般上面就有一個單片機的最小系統,使用者只需寫好程序,燒好芯片,放到上面加以驗證的這么一個工具。有了實驗板,對與初學者來說,省去了焊個最小系統的麻煩。但是對于電子開發人員來說,作用并不是很大
(3)仿真器仿真器是直接把HEX或者BIN文件暫時放在一個芯片里,再通過這個芯片的引腳連接到實驗板或者系統上工作。這樣以來,可以省去了來回插拔芯片帶來的不必要麻煩。
我一開始也不知道上面3個的概念和作用,嘿嘿,原本想買個實驗板(不想焊板,因為不可能為了點亮幾個流水燈,而去焊個單片機的最小系統)的,可是結果,確和我想的正好相反,人家出售的是編程器。等貨物寄到后,才知道自己搞錯了!汗。。嘿嘿?,F在想想實在是又氣又笑。我花了160大樣買了個編程器(很不幸的是,這個編程器更本用不了,一燒芯片,芯片就燒壞了)把我給氣的,這個編程器,現在還躺在我的抽屜里呢不過,現在想想,唯一讓我覺得欣慰的是,那個老板每次能解答我的問題,連那種超級幼稚的問題,他也能不嫌麻煩地盡量幫我解答!這點讓我很感動!
第三,想學單片機的必需品--PC。因為寫程序,編譯或者是仿真都是通過PC完成的。如果沒有PC,什么也做不了?。∮辛薖C最好還要可以上網,因為如果你沒有可以和你交流單片機的人,遇到自己解決不了的問題,一直都想不通,那么估計你學習單片機的熱情就會隨著時間的推移而慢慢耗盡。如果你能上網通過論壇或者QQ群,問題就很快得到解決。這樣的學習效率一定很高!真正的高手是從論壇中泡出來的!
有了上述3個條件后,你就可以開始學你的單片機了。但是,真的做起來并沒有我所說的那么簡單。你一定會遇到很多很多的問題。比如為了讓單片機實現某個功能,你可能不知道怎么去寫某個程序?;蚴悄憧炊速Y料上某個相似的程序,你自己卻寫不出來。遇到類似的情況,記住:千萬不要急噪,就行!
(二)說了這么多了,相信你也看了很多資料了,手頭應該也有必備的工具了吧!(不要忘了上面講過幾個條件的哦)。那個單片機究竟有什么功能和作用呢?先不要著急!接下來讓我們點亮一個LED(搞電子的應該知道LED是什么吧^_^)我們在單片機最小系統上接個LED,看我們能否點亮它!對了,上面也有好幾次提到過單片機最小系統了,所謂單片機最小系統就是在單片機上接上最少的外圍電路元件讓單片機工作。一般只須連接晶體、VCC、GND、RST即可,一般情況下,AT89C51的31腳須接高電平。
#include
//在Keil安裝文件夾中,找到相應的文件,比較一下便知!sbit P1_0 = P1 ^ 0;
void main(void)
{
while(1)
{
P1_0 = 0;//低電平有效,如果把LED反過來接那么就是高電平有效}
}
就那么簡單,我們就把接在單片機P1_0上的LED點亮了,當然LED是低電平,才能點亮。因為我們把LED的正通過電阻接至VCC。
P1_0 = 0;類似與C語言中的賦值語句,即把 0 賦給單片機的P1_0引腳,讓它輸出相應的電平。那么這樣就能達到了我們預先的要求了。while(1)語句只是讓單片機工作在死循環狀態,即一直輸出低電平。如果我們要試著點亮其他的LED,也類似上述語句。這里就不再講了。
點亮了幾個LED后,是不是讓我們聯想到了繁華的街區上流動的彩燈。我們是不是也可以讓幾個LED依次按順序亮呢?答案是肯定的!其實顯示的原理很簡單,就是讓一個LED滅后,另一個立即亮,依次輪流下去。假設我們有8個LED分別接在P1口的8個引腳上。硬件連接,在P1_1--P1_7上再接7個LED即可。例程如下:
#include
sbit P1_0 = P1 ^ 0;
sbit P1_1 = P1 ^ 1;
sbit P1_2 = P1 ^ 2;
sbit P1_3 = P1 ^ 3;
sbit P1_4 = P1 ^ 4;
sbit P1_5 = P1 ^ 5;
sbit P1_6 = P1 ^ 6;
sbit P1_7 = P1 ^ 7;
void Delay(unsigned char a)
{
unsigned char i;
while(--a!= 0)
{
for(i = 0;i < 125;i++);//一個;表示空語句,CPU空轉。
}//i 從0加到125,CPU大概就耗時1毫秒}
void main(void)
{
while(1)
{
P1_0 = 0;
Delay(250);
P1_0 = 1;
P1_1 = 0;
Delay(250);
P1_1 = 1;
P1_2 = 0;
Delay(250);
P1_2 = 1;
P1_3 = 0;
Delay(250);
P1_3 = 1;
P1_4 = 0;
Delay(250);
P1_4 = 1;
P1_5 = 0;
Delay(250);
P1_5 = 1;
P1_6 = 0;
Delay(250);
P1_6 = 1;
P1_7 = 0;
Delay(250);
P1_7 = 1;
}
}
sbit 定義位變量,unsigned char a 定義無符字符型變量a,以節省單片機內部資源,其有效值為0~255。main函數調用Delay()函數。Delay函數使單片機空轉,LED持續點亮后,再滅,下一個LED亮。while(1)產生循環。
第二篇:單片機C語言學習心得
8、指針的使用
8.1 在定義的時候,*ap中的‘*’是指針類型說明符;
在進行指針預算時,x = *ap 中的‘*’是指針運算符。8.2 如果在已定義好的指針變量,并引用,即
int *ap, int a;ap = &a;則在進行指針運算的時候:
(1)*ap與a是等價的,即 *ap就是a;
(2)&*ap:由于*ap與a等價,則&*ap與&a等價(地址);
(3)*&a:由于&a = ap,則*&a與*ap等價,即*&a與a等價(變量);(4)*ap++相當于a++。
8.3 指向數組的指針變量的定義,應用,賦值:
int a[10];int *app;則有兩種方法:app = &a[0];或 app = &a;(1)app+I 或a+i就是數組元素a[i]的地址;(2)*(app+i)或 *(a+i)就是元素a[i]中的內容;
(3)指針變量也可以帶下表,即app[i]與*(app+i)等價。8.4 數組和指針可以互換,但在代碼執行的效率上卻大不相同。用數組找元素必須每次計算元素的地址,效率不高;而用指針則直接指向某個元素,不必每次計算地址,可以大大的提高運算效率。8.5 關于指針的運算:
(1)p++(或p+=1):使指針p指向下一個數組元素,地址加1;
(2)*p++:先得到p指向的變量值,再執行p加1,指向下一個數組元素;(3)*++p:先使p加1,指向下一個數組元素,再去p指向的變量值;(4)(*p)++:表示p指向的變量值加1;
(5)若p指向當前數組中的第i個元素,則:
(p--)與a[i--] 等價:先執行*p,然后p自減;(++p)與a[++i] 等價:先執行p自加,再執行*p;(--p)與a[--p] 等價:先執行p自減,再執行*p。
8.6 指向多維數組:
定義一個二維數組:a[3][4];定義一個指針變量:(*p)[4];(注意:列數相同(第二維相同))使指針變量指向數組:p = a;此時: p與a等價:指向數組a[3][4]的第0行首地址;
p+1與a+1等價:指向數組a[3][4]的第1行首地址; p+2與a+2等價:指向數組a[3][4]的第2行首地址;
而:
*(p+1)+3與& a[1][3]等價,指向a[1][3]的地址;
*(*(p+1)+3)與a[1][3]等價,表示a[1][3]的值; 一般的:對于數組a[i][j]來講,有
*(p+i)+j相當于&a[i][j],表示第i行第j列元素的地址; *(*(p+i)+j)相當于a[i][j],表示第i行第j列元素的值。
8.7 指向結構體:
如果指針p指向結構體數組msg1[0]的首地址,則:
(1)(*p).flg與p->flg和msg1[0].flg三者完全等價,即(*p).成員名 與p->成員名 以及 結構體數組元素成員名三種形式是等價的;
(2)p+1:使指針指向結構數組msg1[0]的下一個元素msg1[1]的首地址;(3)由于指向運算符->的優先級高于自加運算符++,則:
(++p)->flg:先使p自加1指向msg1[1]的地址,再指向msg1[1]的flg成員值;(p++)->flg:先得到msg1[0].flg的值,再使p自加1指向msg1[1]的首地址;
p->flg++:先得到msg1[0].flg的值,使用完后再使msg1[0].flg的值加1; ++p->flg:先將msg1[0].flg的值加1,再使用。
第三篇:單片機C語言學習心得
8、指針的使用
8.1 在定義的時候,*ap中的‘*’是指針類型說明符;
在進行指針預算時,x = *ap 中的‘*’是指針運算符。
8.2 如果在已定義好的指針變量,并引用,即
int *ap, int a;
ap = &a;
則在進行指針運算的時候:
(1)*ap與a是等價的,即 *ap就是a;
(2)&*ap:由于*ap與a等價,則&*ap與&a等價(地址);
(3)*&a:由于&a = ap,則*&a與*ap等價,即*&a與a等價(變量);
(4)*ap++相當于a++。
8.3 指向數組的指針變量的定義,應用,賦值:
int a[10];int *app;
則有兩種方法:app = &a[0];或 app = &a;
(1)app+I 或a+i就是數組元素a[i]的地址;
(2)*(app+i)或 *(a+i)就是元素a[i]中的內容;
(3)指針變量也可以帶下表,即app[i]與*(app+i)等價。
8.4 數組和指針可以互換,但在代碼執行的效率上卻大不相同。用數組找元素必須每次計算
元素的地址,效率不高;而用指針則直接指向某個元素,不必每次計算地址,可以大大的提高運算效率。
8.5 關于指針的運算:
(1)p++(或p+=1):使指針p指向下一個數組元素,地址加1;
(2)*p++:先得到p指向的變量值,再執行p加1,指向下一個數組元素;
(3)*++p:先使p加1,指向下一個數組元素,再去p指向的變量值;
(4)(*p)++:表示p指向的變量值加1;
(5)若p指向當前數組中的第i個元素,則:
(p--)與a[i--] 等價:先執行*p,然后p自減;
(++p)與a[++i] 等價:先執行p自加,再執行*p;
(--p)與a[--p] 等價:先執行p自減,再執行*p。
8.6 指向多維數組:
定義一個二維數組:a[3][4];定義一個指針變量:(*p)[4];(注意:列數相同(第二維相同))
使指針變量指向數組:p = a;
此時: p與a等價:指向數組a[3][4]的第0行首地址;
p+1與a+1等價:指向數組a[3][4]的第1行首地址;
p+2與a+2等價:指向數組a[3][4]的第2行首地址;
而:*(p+1)+3與& a[1][3]等價,指向a[1][3]的地址;*(*(p+1)+3)與a[1][3]等價,表示a[1][3]的值; 一般的:對于數組a[i][j]來講,有*(p+i)+j相當于&a[i][j],表示第i行第j列元素的地址; *(*(p+i)+j)相當于a[i][j],表示第i行第j列元素的值。
8.7 指向結構體:
如果指針p指向結構體數組msg1[0]的首地址,則:
(1)(*p).flg與p->flg和msg1[0].flg三者完全等價,即(*p).成員名 與p->成員名 以及 結
構體數組元素成員名三種形式是等價的;
(2)p+1:使指針指向結構數組msg1[0]的下一個元素msg1[1]的首地址;
(3)由于指向運算符->的優先級高于自加運算符++,則:
(++p)->flg:先使p自加1指向msg1[1]的地址,再指向msg1[1]的flg成員值;(p++)->flg:先得到msg1[0].flg的值,再使p自加1指向msg1[1]的首地址; p->flg++:先得到msg1[0].flg的值,使用完后再使msg1[0].flg的值加1; ++p->flg:先將msg1[0].flg的值加1,再使用。
第四篇:單片機c語言學習心得(改編)
單片機c語言學習心得
(一)相信很多愛好電子的朋友,對單片機這個詞應該都不會陌生了吧。不過有些朋友可能只聽說他叫單片機,他的全稱是什么也許并不太清楚,更不用說他的英文全稱和簡稱了。單片機是一塊在集成電路芯片上集成了一臺有一定規模的微型計算機。簡稱為:單片微型計算機或單片機(Single Chip Computer)。單片機的應用到處可見,應用領域廣泛,主要應用在智能儀表、實時控制、通信、家電等方面。不過這一切都沒什么關系,因為我(當然也包括任何人)都是從不知道轉變成知道的,再轉變成精通的?,F在我只想把我學習單片機的經歷,詳細地講敘給大家聽聽,可能有些大蝦會笑話我,想:那么簡單的東西還在這里賣弄。但是你錯了,我只是把我個人學習的經歷講述一遍而已,僅僅對那些想學習單片機,但又找不到好方法或者途徑的朋友,提供一個幫助,使他們在學習過程中,盡量少走些彎路而已!
首先,你必須有學習單片機的熱情,不是說今天去圖書館看了一個下午關于單片機的書,而明天玩上半天,后天就不知道那個本書在講什么東西了。還是先說說我吧,我從大二的第一個學期期末的時候才開始接觸單片機,但在這之前,正如上面所說的:我知道有種芯片叫單片機,但是具體長成什么樣子,卻一點也不知道!看到這里很多朋友一定會忍不住發笑。嘿嘿,你可千萬別笑,有些大四畢業的人也同樣不知道單片機長成什么樣子呢!而我對單片機的癡迷更是常人所不能想象的地步,大二的期末考試,我全放棄了復習,每當室友拿著書在埋頭復習的時候,我卻捧著自己從圖書館借的單片機書在那看,雖然有很多不懂,但是我還是堅持了下來,當時我就想過,為了單片機值不值得我這樣去付出,或許這也是在一些三流學校的好處吧,考試掛科后,明年開學交上幾十元一門的補考費,應該大部分都能過了。于是,我橫下一條心,堅持看我的單片機書和資料。
當你明白了單片機是這么一回事的時候,顯而易見的問題出來了:我要選擇那種語言為單片機編寫程序呢?這個問題,困擾了我好久。具體選擇C51還是A51呢?匯編在我們大二之前并沒有開過課,雖然看著人家的講解,很容易明白單片機的每一時刻的具體工作情況,但是一合上書或者資料,自己卻什么也不知道了,根本不用說自己寫程序了。于是,我最終還是決定學C51,畢竟C51和我們課上講的C語言,有些類似,編程的思想可以說是相通的。而且C51還有更大的優點就是編寫大程序時的優越性更不言而喻,當然在那時,我并沒有想的那么深遠,C51的特點,還是在后來的實踐過程中,漸漸體會到的!朋友如果你選擇了C51,那么請繼續往下看,如果你選擇了A51,那么你可以不要看了!因為下面講的全是C方面的,完全在浪費你的時間!
呵呵 ^_^
第二,既然你想學好單片機,你必須得舍得花錢,如果不買些芯片回來自己動手焊焊拆拆的(但是在后期會介紹給大家一個很好用的硬件仿真軟件,并不需要你用實驗板和仿真器了,直接在你的PC上完成,但是軟件畢竟是軟件,從某個特定的意義上來說是并不能代替硬件的),即使你每天捧著本書,把那本書翻爛,也永遠學不會單片機的!剛接觸單片機的朋友,看了資料,一定會對以下幾個詞見的比較多,但是具體的概念還是比較模糊,現作如下說明:
(1)編程器
編程器是用來燒單片機芯片的,是把HEX或者BIN文件燒到單片機ROM里的。
(2)實驗板
實驗板是專為初學者根據某些要求而特做的板,一般上面就有一個單片機的最小系統,使用者只需寫好程序,燒好芯片,放到上面加以驗證的這么一個工具。有了實驗板,對與初學者來說,省去了焊個最小系統的麻煩。但是對于電子開發人員來說,作用并不是很大
(3)仿真器
仿真器是直接把HEX或者BIN文件暫時放在一個芯片里,再通過這個芯片的引腳連接到實驗板或者系統上工作。這樣以來,可以省去了來回插拔芯片帶來的不必要麻煩。
我一開始也不知道上面3個的概念和作用,嘿嘿,原本想買個實驗板(不想焊板,因為不可能為了點亮幾個流水燈,而去焊個單片機的最小系統)的,可是結果,確和我想的正好相反,人家出售的是編程器。等貨物寄到后,才知道自己搞錯了!汗。。嘿嘿?,F在想想實在是又氣又笑。我花了160大樣買了個編程器(很不幸的是,這個編程器更本用不了,一燒芯片,芯片就燒壞了)把我給氣的,這個編程器,現在還躺在我的抽屜里呢不過,現在想想,唯一讓我覺得欣慰的是,那個老板每次能解答我的問題,連那種超級幼稚的問題,他也能不嫌麻煩地盡量幫我解答!這點讓我很感動!
第三,想學單片機的必需品--PC。因為寫程序,編譯或者是仿真都是通過PC完成的。如果沒有PC,什么也做不了??!有了PC最好還要可以上網,因為如果你沒有可以和你交流單片機的人,遇到自己解決不了的問題,一直都想不通,那么估計你學習單片機的熱情就會隨著時間的推移而慢慢耗盡。如果你能上網通過論壇或者QQ群,問題就很快得到解決。這樣的學習效率一定很高!真正的高手是從論壇中泡出來的!
有了上述3個條件后,你就可以開始學你的單片機了。但是,真的做起來并沒有我所說的那么簡單。你一定會遇到很多很多的問題。比如為了讓單片機實現某個功能,你可能不知道怎么去寫某個程序?;蚴悄憧炊速Y料上某個相似的程序,你自己卻寫不出來。遇到類似的情況,記?。呵f不要急噪,就行!
(二)說了這么多了,相信你也看了很多資料了,手頭應該也有必備的工具了吧!(不要忘了上面講過幾個條件的哦)。那個單片機究竟有什么功能和作用呢?先不要著急!接下來讓我們點亮一個LED(搞電子的應該知道LED是什么吧^_^)
我們在單片機最小系統上接個LED,看我們能否點亮它!對了,上面也有好幾次提到過單片機最小系統了,所謂單片機最小系統就是在單片機上接上最少的外圍電路元件讓單片機工作。一般只須連接晶體、VCC、GND、RST即可,一般情況下,AT89C51的31腳須接高電平。
#include
//頭文件定義?;蛴?include
//在Keil安裝文件夾中,找到相應的文件,比較一下便知!
sbit P1_0 = P1 ^ 0;
void main(void)
{
while(1)
{
P1_0 = 0;//低電平有效,如果把LED反過來接那么就是高電平有效
}
}
就那么簡單,我們就把接在單片機P1_0上的LED點亮了,當然LED是低電平,才能點亮。因為我們把LED的正通過電阻接至VCC。
P1_0 = 0;類似與C語言中的賦值語句,即把 0 賦給單片機的P1_0引腳,讓它輸出相應的電平。那么這樣就能達到了我們預先的要求了。while(1)語句只是讓單片機工作在死循環狀態,即一直輸出低電平。如果我們要試著點亮其他的LED,也類似上述語句。這里就不再講了。
點亮了幾個LED后,是不是讓我們聯想到了繁華的街區上流動的彩燈。我們是不是也可以讓幾個LED依次按順序亮呢?答案是肯定的!其實顯示的原理很簡單,就是讓一個LED滅后,另一個立即亮,依次輪流下去。假設我們有8個LED分別接在P1口的8個引腳上。硬件連接,在P1_1--P1_7上再接7個LED即可。例程如下:
#include
sbit P1_0 = P1 ^ 0;
sbit P1_1 = P1 ^ 1;
sbit P1_2 = P1 ^ 2;
sbit P1_3 = P1 ^ 3;
sbit P1_4 = P1 ^ 4;
sbit P1_5 = P1 ^ 5;
sbit P1_6 = P1 ^ 6;
sbit P1_7 = P1 ^ 7;
void Delay(unsigned char a)
{
unsigned char i;
while(--a!= 0)
{
for(i = 0;i < 125;i++);//一個;表示空語句,CPU空轉。
}
//i 從0加到125,CPU大概就耗時1毫秒
}
void main(void)
{
while(1)
{
P1_0 = 0;
Delay(250);
P1_0 = 1;
P1_1 = 0;
Delay(250);
P1_1 = 1;
P1_2 = 0;
Delay(250);
P1_2 = 1;
P1_3 = 0;
Delay(250);
P1_3 = 1;
P1_4 = 0;
Delay(250);
P1_4 = 1;
P1_5 = 0;
Delay(250);
P1_5 = 1;
P1_6 = 0;
Delay(250);
P1_6 = 1;
P1_7 = 0;
Delay(250);
P1_7 = 1;
}
}
sbit 定義位變量,unsigned char a 定義無符字符型變量a,以節省單片機內部資源,其有效值為0~255。main函數調用Delay()函數。Delay函數使單片機空轉,LED持續點亮后,再滅,下一個LED亮。while(1)產生循環。
(三)上面我們講了如何使LED產生流動,但是你是否發現一個問題:寫的太冗長了!能不能再簡單點呢?可以!可以使用C51的內部函數INTRINS.H實現。函數unsigned char _crol_(unsigned char a, unsigned char n)可以使變量a循環左移n位,如果我們先給P1口賦0000 0001那么當n為1時,便會產生和上面一樣的效果!
#include
#include
void Delay(unsigned char a)
{
unsigned char i;
while(a--!= 0)
{
for(i = 0;i < 125;i++);
}
}
void main(void)
{
unsigned char b, i;
while(1)
{
b = 0xfe;
for(i = 0;i < 8;i++)
{
P1 = char _crol_(b, 1);
b = P1;
Delay(250);
}
}
}
INTRINS.H函數中的unsigned char _cror_(unsigned char a, unsigned char n)右移也可以實現同樣的效果!這里就不再累述。
流水燈的花樣很多,我還寫過那種拉幕式的流動等,程序很簡單,有興趣的朋友,可以自己試著寫寫!
對了,講了那么多,有些朋友一定還不知道編譯軟件怎么用?這里給大家介紹幾個吧?WAVE(偉福)大家一定聽說過吧!還有一個就是KEIL2,我用的就是KEIL2,下面就來講講如何使用KEIL2這個編譯軟件!
1.安裝軟件,這個應該不用再講了吧!
2.安裝完后,啟動KEIL軟件左擊Project-->New Project-->輸入文件名-->選擇我們所以使用的芯片(這里我們一般用到Atmel的AT89C51或AT89C2051,點確定。
3.點File-->New-->輸入我們編寫的程序,保存為.C文件。(一般情況下,我們保存的文件名和前面的工程名一樣。)
4.展開Target 1-->右擊Source Group 1-->Add Files to Group 'Source Group 1'-->選擇剛才保存的.C文件點擊ADD后,關閉對話框。這樣.C文件就被加到了Source Group 1 下。
5.右擊Target 1-->Options
for 'Target 1'-->Target中填寫晶體的大小,Output中,在Create HEX Files 前打上鉤,點確定。
6.點Project-->Rebuild All Traget Files,若提示
creating hex file from “XXX”...“XXX”5000)/ 256;//載入高8位初值
TL0 =(655365000)/ 256;//載入高8位初值。若在12M晶體下,定時5000微秒,即為5毫秒;但是如果不是在12M下,那又該怎么計算了呢?如果是11.0592M呢?還記不記得,我們前面講過的機器周期和時鐘周期的概念? ^_^忘了,還是看看前面吧!呵呵!沒事,學習嘛,忘了再翻翻書,看看就可以了!其實上訴的5000 = 1 * C 很顯然C=5000,但是如果是11.0592M那么就不是1了,應該是1.085了,那么5000 = 1.085 * C,則C就為5000 / 1.085 = ? 具體多少,大家自己去算算吧?同理TL0也是一樣的!但是,細心的朋友會發現網上或者是資料上的TH0,TL0并不是和上面一樣的,而是直接TH0 = 0XEC;TL0 = 0X78 是不是和上面的一樣的,別忘了單片機也是計算機的一種哦。用C的話,直接寫上計算公式就行,計算就交給單片機完成。
TR0 = 1;這句就是啟動定時器0,開始記數!哦,還有一點,有些朋友會問,你是65536是哪里來的呢?呵呵你可別忘了:設置定時器0 工作方式0是16位的(2的16次方是多少,自己算算就知道了)簡單吧?但是如何和中斷一起使用呢?請繼續看下面的講解!
TMOD = 0X01;//設置定時器0 工作方式0
TH0 =(655365000)% 256;//載入低8位初值
TR0 = 1;
//啟動定時器
EA = 1;//開總中斷
ET0 = 1;//開定時器中斷。若為0則表示關閉!
這樣我們,就初始化定時器T0和中斷了,也就是定時器滿5毫秒后,產生一次中斷。產生中斷后,我們怎么處理呢?嘿嘿!仔細想想?^_^ 每次中斷后,我們可以讓一個變量自加1,那么200次中斷后,不就是1秒的時間了嗎?比起上面我們說的延時來出來是不是更加精確多了呢?那是肯定的!但是想想1秒種的時間就讓單片機產生那么多次的中斷,單片機會不會累著呢?恩,那么不好。如果在12M的晶體下,T0每次中斷不是可以產生最多65.336毫秒的時間嗎?那么我們讓他每50毫秒中斷一次好了!這樣我們就20次搞定一秒的時間了!
·爽·
好了,講了那么多,現在我們來寫個時間的程序吧!
^_^
#include
#define HI
((6553650000)% 256)#define _TH0_TL0_
(65536-50000)#define M
//(1000/25)
/**********************************************************************************************/ unsigned hou = 12, min = 0, sec = 0;unsigned char SEG_TAB_B[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//0-9數字 unsigned char SEG_TAB_A[ ] = {0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};//0.-9.數字
/*********************************************************************************************/ void Delay(unsigned char a)//延時程序a*1MS {
unsigned char j;
while(a--!= 0)
{
for(j = 0;j < 125;j++);
} }
/*********************************************************************************************/ void Disp(void)//數碼管顯示 {
P2_0 = 1;
P1 = SEG_TAB_B[ hou / 10 ];
Delay(5);
P2_0 = 0;
P2_1 = 1;
P1 = SEG_TAB_A[ hou % 10 ];
Delay(5);
P2_1 = 0;
P2_2 = 1;
P1 = SEG_TAB_B[ min / 10 ];
Delay(5);
P2_2 = 0;
P2_3 = 1;
P1 =S EG_TAB_A[ min % 10 ];
Delay(5);
P2_3 = 0;
P2_4 = 1;
P1 = SEG_TAB_B[ sec / 10 ];
Delay(5);
P2_4 = 0;
P2_5 = 1;
P1 = SEG_TAB_B[ sec % 10 ];
Delay(5);
P2_5 = 0;}
/********************************************************************************************/ void IsrTimer0(void)interrupt 1 using 1
//定時50ms {
static unsigned char count = 0;
//定義靜態變量count
count++;
if(count == M)
{
count = 0;
sec++;
if(sec == 60)
{
min++;
sec = 0;
if(min == 60)
{
hou++;
min = 0;
if(hou == 24)
{
hou = 0;
}
}//if
}//if
}//if }
/******************************************************************************************/ void Timer0Init(void)//定時器0 {
TMOD = 0x01;
TH0 = HI;
TL0 = LO;
TR0 = 1;
ET0 = 1;
EA = 1;
}
/******************************************************************************************/ void main(void)//主函數 {
Timer0Init();
while(1)
{
Disp();
} }
簡單吧,還是有點看不懂哦,那你自己慢慢體會吧,如果你自己能寫個時鐘程序來,那么你的51單片機也就學了80 % 了。中斷和定時/記數器器,是個很重要的東西,幾乎用到單片機的地方都會涉及到中斷和定時!所以大家要好好掌握哦!^_^
哈哈,趕緊編譯HEX文件,搭好硬件,燒入單片機,上電看看效果先!呵呵,現在你應該有成就感了吧,想不到一個時鐘居然那么簡單,嘿嘿!但是問題來了!時鐘雖然做出來了,但是他的精度怎么樣呢?一兩個小時,或許看不出什么誤差,但是一天或者一年呢?暈,我的天呀,要是按年來算的話,那這個時鐘根本沒有實用價值!人家都說用C寫不出,精度高的時鐘程序來的!!是不是有點后悔了,去學匯編吧!但是既然選擇了C,那么就不要后悔!嘿嘿,想想C的高級語言,怎么會輸給匯編呢 ^_^ 呵呵!看下面這段代碼:
static unsigned char count = 0;
TR0 = 0;
TL0 +=(_TH0_TL0_ + 9)% 256;
TH0 +=(_TH0_TL0_ + 9)/ 256 +(char)CY;
TR0 = 1;
count++;
在中斷處理服務程序中,我們加入上面的代碼。TR0 = 0;先關閉定時器T0,然后重新給TH0和TL0 賦值,再開啟 TR0 = 1;燒入單片機看看效果,怎么樣,你第一次精確多了吧。但是還是有誤差!郁悶!為什么呢?那是硬件造成的誤差,我們可以用軟件來彌補!我們先把時鐘點亮,讓他走上幾個小時或者是幾天,看看到底誤差是多少!取個平均值。(這里比如我們10小時快1秒)那么可以通過以下語句
if(hour % 10 = 0)
{
sec--;
} 來彌補!這樣可能會出現這樣的現象:秒直接跳變!我們可以再通過細分來實現,不要10小時那么大,小些的就行!具體的操作還是留給朋友們吧!
(七)這回我們來講講鍵盤,大家肯定見過銀行柜員機吧,取錢輸入密碼就要用到鍵盤,超市購物取回寄存物品要輸入密碼,還有你現在在用的PC機的鍵盤。但是鍵盤的是怎么工作的呢?一般有2種方式:(1)掃描法,不斷掃描鍵盤的狀態,送CPU判斷并處理。如果鍵盤數目一大的話,顯然不適合(2)線反轉法,通過行列狀態的改變來判斷有無鍵被按下!
現在我們在P1口接個4*4的鍵盤,P1.0--P1.3接行,P1.4---P1.7接列,再接4個4K7的上拉電阻至VCC。代碼如下:
//----鍵盤掃描法程序-------//----用數碼管顯示相應的鍵值-----//P1.0--P1.3接行-------//P1.4---P1.7接列-------#include
unsigned char code tab[ ]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};//0到F的16個鍵植
/******************************************************************************/ void Delayt(unsigned char t)//延時函數 {
unsigned char i;
for(t=0;i<=t;t++)
for(i=0;i<255;i++);}
/******************************************************************************/ bit pkey(void)//判斷鍵的否被按下,通過返回值確定 {
P1=0xf0;
if(P1!=0xf0)
{
Delayt(25);
if(P1!=0xf0)
return 1;
else
return 0;
}
else
return 0;}
/******************************************************************************/ void main(void)//主函數 {
unsigned char key,j,k,s;
while(1)
{
if(pkey()==1)
{
P1=0xfe;
k=0xfe;
for(j=0;j<4;j++)
{
s=P1&0xf0;
switch(s)
{
case 0xe0: key=4*j+0;break;
case 0xd0: key=4*j+1;break;
case 0xb0: key=4*j+2;break;
case 0x70: key=4*j+3;break;
default:
break;
}
k=(k<<1)|0x01;
P1=k;
}//for
}//if
//if((P1&0xf0)==0xf0)
P0=tab[key];
P2=1;
Delayt(50);
}//while }
還有一種就是線反轉法,實現如下:
1.和掃描法相同,把列線置低電平,行置高,讀行狀態 2.與1相反,把行置低,列置高,讀列狀態
3.若有鍵按下,則為2次所讀狀態的結果即為鍵所在的位置,這樣2次輸出和2次讀入可以完成鍵的識別??!
子函數如下:
unsigned char key_vscan(void){
unsigned char row, col;
P1 = 0xF0;
row = P1&0xF0;
row = row&0xF0;
P1 = 0x0F;
col = P1&0x0F;
col = col&0x0F;
return(key_val(row|col));}
下面我們再來介紹介紹一鍵多能的程序,即按下一個鍵,可以執行不同的命令!
void main(void){
unsigned char b = 0;
while(1)
{
if(P1_0 == 0)
{
Delay(10);
if(P1_0 == 0)
{
b++;
if(b == N)//N為鍵的功能數目
{
b = 0;
}
while(P3_2 == 0);//等待鍵松開
}
}
switch(b)
{
case 1: P2_0 = 0xFE;
break;
case 2: P2_1 = 0xfd;
//..............add your code here!
}
} }
(八)/ /以上的文字寫于2005年5月,由于時間關系,一直未能將此完成,最近閑著無聊又接著寫了些文字,以下寫于2006年6月5日!
在這里我想對上面一點,作個簡單的說明,如果你是剛學單片機,那么你寫的代碼是VERY GOOD的,但是如果把上面的代碼應用于產品的話,那么我可以告訴你,上面所寫的按鍵識別代碼全部是垃圾代碼,^_^,這下傻了吧,呵呵。為什么?我的按鍵不是可以正常工作嗎?
請看這里: if(P1_0 == 0)
{
Delay(10);//問題就在這里,你讓CPU在這里空轉?
if(P1_0 == 0)
{
//...add your code here.} } 進入第1個if判斷語句后,就進入了Delay(10);再看Delay函數,完全讓CPU執行(;空語句),所以在做大的產品或者代碼時,這個是非常耗費單片機內部資源的。有什么辦法嗎?呵呵,那是肯定的。
解決方法大致有如下2種:
1.將延時函數放在中斷中,在中斷里查詢延時的標志位。/*不僅僅用于鍵盤識別,亦可以用于其他的延時代碼,見EX1*/ 2.直接在中斷中查詢按鍵的標志位.//見EX2。
EX1: unsigned char Delaytime;
void Delay(unsigned char Delaytime)// { while(Delaytime!=0);//等在這里,直到Delaytime為0。}
void Timer0_interrupt(void)interrupt 1 using 2 { if(Delaytime!=)
Delaytime--;
//...add your other code here }
Delay函數具體延時多長時間,就要看你設定的T0定時器中斷和Delaytime的乘積,比如你的定時器中斷為50MS,Delaytime為20的話,那么50MS*20=1S。
EX2:
#define Press_key = P2 ^ 7;//定義按鍵的I/O
void P_key(void){ char new_value,old_value;
new_value = Press_key;
if(new_value &&!old_value)//識別按鍵。{
Turn_On_LEd();
//...add your other code here.} old_value = new_value;}
void Timer0_interrupt(void)interrupt 1 using 2 { P_key();
//...add your other code }
當然在實際過程當中,并不是如此簡單簡潔的,還希望大家能夠舉一反三哦...^_^。
(九)寫了這么多了,大家也看了這么多了,感覺怎么樣?大家也覺得不難吧。其實51也就那么簡單,真的很希望大家看完這篇文字以后,很自信的說,51單片機也已經入門。這是對我寫怎么多文字最好的回答。時隔13個月之久再來繼續寫這些東西,沒有以前的激情和熱情,所以就草草了事結尾,希望大家不要在背地里罵我哦,^_^。當然以上講的只是最簡單的一些東西,單片機的功能非常之強大,只要你能想得到,就一定可以用單片機來實現的。當然單片機和外部其他的芯片還有很多,比如數字溫度傳感器DS18B20,實時時鐘芯片DS1302,還有比如訪問AT24CXX的EEPROM存儲器等,更多的電路,還要靠大家在平時的學習過程當中,慢慢掌握。
第五篇:單片機C語言學習
單片機C語言之一___________________________________________________________________ _____________________ 預處理 一》宏定義:
1、不帶參數:
#define 標識符 常量表達式
/*#define是宏定義命令,宏名(標識符)好習慣用大寫*/ #define NIL 0x80
2、帶參數:/*相當于小函數*/ #define 宏名(參數表)字符串
/*不僅要時行字任串替換還要進行參數的替換,在宏定義時,宏名與帶參數的括弧之間不應該加空格,否則將空格以后的字符串都作為替代字符串的一部分,這可是很容易出錯的*/ 如:#define SQ(a,b)a*b 使用:x=12;y=10;area=SQ(x,y);/*則area=12*10=120*/ 二》文件包含:
#include <文件名>或#include “文件名” /*在C中用雙引用形式更保險,在C51中常用物是尖括弧形式*/ 三》條件編譯:
/*一般源程序中的所有程序行都參加編譯,但有時希望對其中一部分內容只在滿足一定條件下才進行編譯,也就是對一部分內容指定編譯的條件。*/ #if、#elif、#else、#endif、#ifdef、#ifndef /*選擇不同的編譯范圍,產生不同的代碼,提供通用性。*/ /*如對8051在6MHZ與12MHZ下有*/ #ifdef cpu==8051 #define FREQ 6 /*程序段*/ #else #define FREQ 12/*程序段*/ #endif /*這樣下面的原程序不用做任何修改便可以使用于兩種時鐘頻率的單片機系統*/ 四》其他:
1、#error:捕捉不可預料的編譯條件
#if(myv!=0&&myv!=1)/*假定其值必為0或1*/ #error myv must be 1 or 0/*出錯時顯示*/ #endif
2、#pragma:用于在程序中向編譯器傳送各種編譯控制命令 #pragma 編譯命令序列
/*例:想按如下命令編譯ex.c c51 ex.c debug cod large可用:*/
#pragma DB CD LA #pragma disable /*禁止中斷*/
單片機C語言之二_____________________________________________________________________________________ 一》數據類型:
char int long 1:unsinged 0~255 0~65535 0~4294967295 2:signed-128~127-32768~32767-2147483648~2147483647 指針:* 3字節 位標量: sbit 特殊功能寄存器:sfr 16位特殊功能寄存器:sfr16 占2個內存單元,0~65535 可尋址位:sbit利用他可訪問51單片機的內部RAM中的可尋址位或特殊功能寄存器中的可尋址位 sfr P0=0x80;sbit P0_1=P0^1;/*將P0口的口地址定義為80H,將P0.1位定義為P1_1*/ 二》數據存貯類型
表1.C51數據存貯類型
━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━ 數據存貯類型 ┃ 與存貯空間的對應關系
━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━ data ┃ 直接尋址片內數據存貯區,訪速度快 bdata ┃ 可位尋址片內數據存貯區,允許位與字節混合訪問 idata ┃ 間接尋址片內數據存貯區,可訪問片內全部RAM地址空間
pdata ┃ 分頁尋址片外數據存貯區(256字節)由MOVX @R0訪問 xdata ┃ 片外數據存貯區(64K),由MOVX @DPTR訪問 code ┃ 代碼存貯區(64K),由MOVC @DPTR訪問
━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━ 變量的存貯類型定義: char data var /*字符變量var被定義為data存貯類型,C51編譯器將把該變量定位在51單片機片內數據區存貯區中*/ bit bdata flag /*位變量flag被定義為bdata存貯類型,C51編譯器將把該變量定位在51單片機片內數據區存貯區(RAM)中的位尋址區:20H--2FH*/
三》typedef:重新定義數據類型
typedef 已有數據類型 新的數據類型 typedef int word;/*將word定義為整型*/ word i,j;/*將i,j定義為整型*/ 四》位運算符:
━━━━┳━━━━━┳━━━━━┳━━━━━━┳━━━━━━┳━━━━━━ ~ ┃ & ┃ | ┃ ^ ┃ << ┃ >> ━━━━╋━━━━━╋━━━━━╋━━━━━━╋━━━━━━╋━━━━━━
按位取反┃ 按位與 ┃ 按位或 ┃ 按位異或 ┃ 左移 ┃ 右移
━━━━┻━━━━━┻━━━━━┻━━━━━━┻━━━━━━┻━━━━━━
對移位:如<< ,a<<2,即為將二進制的a左移兩位,若a=0x8f,即10001111,a=a<<2,將導致a=0x3c(00111100),右邊補零。五》條件運算符:
邏輯表達式? 表達式1:表達式2 六》指針與地址運算符: *取內容 &取地址
七》強制類型轉換:(類型)=表達式(char *)0xb000 八》sizeof 取數據類型、變量以及表達式的字節數的運算符; 九》continue:中斷語句:結束本次循環。
單片機C語言之三_____________________________________________________________________________________ 函數:
一》中斷服務函數與寄存器組定義:
函數類型 函數名(形式參數表)[interrupt n][using n] n為中斷號,0~31:
━━━━┳━━━━━┳━━━━━ 中斷編號┃ 中斷向量┃ 入口地址 ━━━━╋━━━━━╋━━━━━ 0 ┃ 外中斷0 ┃ 0003H ━━━━╋━━━━━╋━━━━━ 1 ┃ 定時器0 ┃ 000BH ━━━━╋━━━━━╋━━━━━ 2 ┃ 外中斷1 ┃ 0013H
━━━━╋━━━━━╋━━━━━ 3 ┃ 定時器1 ┃ 001BH ━━━━╋━━━━━╋━━━━━ 4 ┃ 串行口 ┃ 0023H ━━━━┻━━━━━┻━━━━━
后面的n指的是四個工作寄存器組的一個:0~3 對函數目標代碼影響如下:
在函數入口處將當前工作寄存器組保護到堆棧中;指定的工作寄存器內容不會改變,函數返回前將被保護的工作寄存器組從堆棧中恢復!例(定時1ms):
#include
1、如果中斷函數中用到浮點運算,必須保存浮點寄存器的狀態。(在math.h中保存浮點寄存器函數為pfsave, 恢復浮點寄存器的狀態函數為fprestore)
2、如果在中斷函數中調用了其他函數,則被調函數所使用的工作寄存器組與中斷函數的一致!*/
單片機C語言之四_____________________________________________________________________________________
一、局部變量與全局變量(外部變量):
1、全局變量若不在開頭定義則加extern
2、全局變量會使代碼長,占用內存多
二、存儲方式:
自動變量(auto):缺省,函數調用存在,退出消失。
內部變量 靜態變量(static):static int a=5;始終存在,退出不消失,但不能訪問。寄存器變量(register):速度最快。通常只給編譯器一個建議,由編譯器根 據實際情況確定。(見下)變量 全局變量(global): 外部變量
靜態變量(static): 寄存器變量例: #include
三、函數的參數和局部變量的存儲器模式: 三種存儲器模式:small,compact,large.一個函數的存儲器模式確定了函數的參數和局部變量在內存中的地址空間 small:內部ram compact, large:外部RAM 函數類型 函數名(形式參數表)[存儲器模式] 例:
#pragma large /*默認存儲器模式為large*/ extern int calc(char I,int b)small;/*指定small模式*/ extern int func(int I,float f)large;/*指定large模式*/ int large_te(int I,int k)/*未指定,按默認的large模式處理*/ { return(mtest(I,k)+2);}
利用存儲器混合模式編程,充分利用有限的存儲空間,還可加快程序的執行速度!
單片機C語言之五_____________________________________________________________________________________ 數組 1>初始化數組: unsigned char a[5]={0x11,0x22,0x33,0x44,0x55} 或
unsigned char a[ ] ={0x11,0x22,0x33,0x44,0x55,0x66} 3>數組作為函數的參數:不但可以由變量作為函數的參數外,還可以用數組名作為函數的參數。一個數組數組名表示該數組的首地址。用一個數組名作為函數的參數時,在執行函數調用的過程中參數傳遞方式采用的是地址傳遞。將實際參數數組首地址傳遞給被調函數中的形式參數數組,這樣一來兩個數組就占有同一段內存單元。見下圖:
a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] 起始地址1000 b[0] b[1] b[2] b[3] b[4] b[5] b[6] b[7] b[8] b[9] 用數組名作為函數的參數,應該在主調函數和被調函數中分別進行數組定義而不能只在一方定義數組。而且在兩個函數中定義的數組類型必須一致,如果類型不一致將導致編譯出錯。實參數組和型參數組的長度可以一致可以不一致,編譯器對形參數組的長度不做檢查,直只是將實參數組的首地址傳遞給行參數組。如果希望行參數組能得到實參數組的全部元素,則應使兩個數組的長度一致。定義型參數組時可以不指定長度,只在數組名后面跟一個方括號[]。這時為了在被調函數中處理數組元素的需要,應另外設置一個參數來傳遞數組元素的個數。
例:用數組作為函數的參數,計算兩個不同長度的數組中所有元素的平均值 #include float pot_1[2]={99.9,88.8};float pot_2[3]={11,22,33.3};average(pot_1,2);average(pot_1,3);} 單片機C語言之六_____________________________________________________________________________________ 軟件法去干擾: 工程上我們在采集數據時一般要求精度達到5%%,大于這個值將認為無效。我在實際應用中采用8535對32路數據進行采集(8535帶10位AD,帶看門狗),發現數據跳動有時達7%%,這是由于各種干擾造成的。主要來自于隨機干擾,下面就各種干擾的方法給出簡單的去除方法: 1、白噪聲:最重要的統計特性為平均值為0,可采取每路數據采集幾次求平均的方法; 2、隨機干擾:該點明顯高于或低于附近正常采樣值,故采取中值濾波法,即對被測信號連續采樣M次,進行大小排序,取大小居中的1/3個采樣值進行算術平均; 3、電源干擾:特點是有固定周期,故可采用定時采樣求平均的方法。 由于各種排序與求平均算法用C易于實現,故C常常用于采集系統中軟件去干擾。至于排序算法可參考上一篇文章,有一個經典的程序。 在實際中我們采用每路猜9個值,排序,取中間3個,求平均。然后。,每路數據幾乎不動! 單片機C語言之七_____________________________________________________________________________________ 指針:可對內存地址直接操作 基于存貯器的指以貯器類為參量,它在編譯時才被確定。因此為指針選擇存貯器的方法可以省掉,以這些指針的長度可為1個字節(idata *,data *,pdata *)或2個這節(code *,xdata *)。char xdata *address;ADC0809具有8個模擬量輸入通道,采用中斷方式,在中斷函數中讀取8個通道的A/D轉換值,分別存儲在外部RAM的1000H~1007H單元。ADC0809端口地址為00F0H。 程序定義了兩個指針變量* ADC和* ADCdata,分別指向ADC0809端口地址(00F0H)和外部RAM單元地址(1000H~1007H) 由*ADC=I送入通道數,啟動ADC0809進行A/D轉換,轉換結束時產生INT1中斷。在中斷服務函數int1()中通過temp=*ADC和*ADCdata=temp;讀取A/D轉換結果并存到外部RAM中。#include void main(){ ADC=0x00f0;/*定義端口地址和數據緩沖器地址*/ ADCdata=0x1000;I=8;/* ADC0809有8個模擬輸入通道*/ EA=1;EX1=1;IT1=1;/*開中斷*/ *ADC=I;/*啟動ADC0809*/ WHILE(I);/*等待8個通道A/D轉換完*/ } void int1()interrupt 2 { unsigned char tmp;temp=*ADC;/*讀取A/D轉換結果*/ *ADCdata=temp;/*結果值存到數據緩沖區*/ ADCdata++;/*數據緩沖區地址加1*/ i—;*ADC=I;/*啟動下一個模擬輸入通道A/D轉換*/ } 除了用指針變量來實現對內存地址的直接操作外,c51編譯器還提供一組宏,該宏定義文件為:“absacc.h”,利用它可十分方便地實現對任何內存空間的直接操作,改寫上面的程序: #include char *s=”abcdef”;int strlen(char *s);printf(“n length of ‘%%s’=%%dn”,s,strlen(s));} int strlen(char *s){ char *p=s;while(*p!=’
主站蜘蛛池模板:
日韩视频在线观看|
日韩中文高清在线专区|
成人免费视频一区二区三区|
大乳丰满人妻中文字幕日本|
欧美国产日韩a在线视频|
精品久久久久中文字幕一区|
国产精品无码天天爽视频|
中文字幕久久综合久久88|
亚洲乱色熟女一区二区三区麻豆|
国产午夜无码福利在线看网站|
久久久久久久久久久久|
а天堂中文官网|
色噜噜久久综合伊人一本|
狠狠色综合激情丁香五月|
亚洲全部无码中文字幕|
亚洲国产成人无码av在线影院l|
搡老女人老妇老熟女hd|
久久受www免费人成|
人人爽人人片人人片av|
中文字幕无码中文字幕有码a|
亚洲AV无码乱码在线观看性色|
国产免费网站看v片在线无遮挡|
超清av在线播放不卡无码|
欧美亚洲另类丝袜综合网|
av无码欧洲亚洲电影网|
亚洲成av人片不卡无码手机版|
亚洲乱码中文字幕在线|
欧美变态口味重另类在线视频|
av无码天一区二区一三区|
在线无码免费网站永久|
精品无码国产一区二区三区麻豆|
国产伦人人人人人人性|
国产一乱一伦一情|
丰满无码人妻热妇无码区|
少妇高潮a视频|
日本中国内射bbxx|
97午夜理论片影院在线播放|
97se狠狠狠狠狼亚洲综合网|
经典三级欧美在线播放|
久久国产福利一区二区|
丰满少妇被猛烈进入无码|