新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > 【51單片機】學習總結

【51單片機】學習總結

作者: 時間:2016-11-28 來源:網絡 收藏
1. Ctrl+S為保存當前文件,如圖

打開了兩個文件,可以看到有個文件是帶星號且有個紅叉的,有個紅叉說明它為當前打開的文件,也就是正在編輯的文件。當按下Ctrl+S時只保存了當前文件。另一個文件沒有保存,當你的電腦意外斷電或死機時,如果你在那之前按了Ctrl+S那么可以挽回點損失,可是另一個文件的信息可能就丟失了。所以推薦按F7(對所以文件進行編譯,并且保存),這樣就可以在編譯的同時將所以文件保存一次。所以在真正做工程的時候就要學會定期按F7,不是說一定要程序編寫完整后才按F7。
2. 默認情況下頭文件和源文件應該放在同一個文件目錄下,如果將頭文件放在一個獨立的文件夾中如名為include的文件夾,此時就讀取不出。要進行一下設置才能讀取出來。如圖:

在C51選項中的Include Paths 選項中要設置頭文件的路徑后方能打開頭文件,對頭文件進行編譯!
3. 對于不變化的變量,如數碼管顯示的數組,要通過前綴code將它放在ROM中避免占用了RAM的空間。
4. 宏定義的內容全用大寫字母,當有兩個單詞時用_將他們分開,如#define LED_SEG P1_1;在特殊情況下才用小寫字母。
5. 變量名的定義一般為 i , Led , DispBuff 即單個字母時小寫,多個字母一個單詞時首字母大寫,多個單詞時連寫且每個單詞的首字母大寫。
6. 函數名的定義一般為 delay ,write_byte 即單個單詞時全小寫,多個單詞時也是小寫,但是單詞間用 _ 隔開。
7. 不必糾結于該換行多少,空格多少,只要自己知道哪里該換行,哪里改空格就行了,像這些東西的尺度只有自己真正實踐的時候就能領悟出來。當然這沒有絕對的標準,就算是非常出色的工程師也很難做到精確的換行,當是他們的程序整體看起來整齊有可讀性高就OK了。要懂得把精力放在恰當的地方。
8. 不要太死板,一定要照著那些條條框框,但我相信小宋老師我需要向他學習,他的程序有很高的價值。
9. 中斷函數書寫

10. 在函數中無論是被調函數還是主函數都要懂得對一些變量進行初始化,這是一個好習慣,別以為沒必要,或者繁瑣。這其實不是繁瑣,而是嚴謹。寫程序就應該有嚴謹的態(tài)度。
11.main函數的標準寫法為:
int main(void)
{
……
return 0;
}
12. 在定時器溢出進入中斷時,在執(zhí)行中斷時TF0或TF1會硬件(自動)清0,從新開始計數。但在串口發(fā)送或接受標志位置1并引起中斷時,在執(zhí)行中斷過程中TI或RI 需軟件(手動)清0.
13. 有關UART通信定時器1模式2中 TH1 與 TL1(與TH1相等)的初始化。在實際計算中TH1 = 256 - 11059200/(12*32*9600); 可以計算得 TH1 = 0xFD; 但是當你把TH1 = 256 - 11059200/(12*32*9600); 寫入編譯器中讓編譯器來完成計算時,那么這樣寫就是錯誤的了,在keil里默認整數常量是 uint16 類型,取值為0~65535.故應寫為TH1 = 256 – 11059200UL/(12*32*9600UL);要注意的是keil 對這類錯誤不報錯!
14. 在串口通訊中,如:

串口調試助手一般選擇“字符格式顯示”。如果想顯示數字則寫入語句UART_send_byte(‘8’) ,要注意顯示數字時只能顯示一位即0~9;想顯示字母時可寫入語句UART_send_byte(‘A’)。注意別掉了‘’尤其是寫數字時。寫字母丟失的話還會報錯。寫數字丟失的話就不會報錯。此時顯示的是數字相應的ASII碼。
15. 若uint8 temp = ‘A’; 則 temp = ‘A’ + 1 時temp = ‘B’ , 即字符與數字相加為對應ASII碼相加。
16. 在串口調試助手中,要發(fā)送字符時不用帶‘’因為軟件已經默認帶上了。
17. 關于對數組各元素賦值,有兩種方式,如uint8 table [11] = “how are you”; 另一種是 table[0] = ‘h’; table[1] = ‘o’;……其中第一種賦值只能在定義數據類型時使用,如上所示。
在數據類型定義完畢后不能通過table [11] = “how are you”;來改變數組里面的元素,這樣做在keil 下會有警告!但不報錯,實際是不正確的。那么要改變數組的元素只能通過對里面元素逐個賦值。
18. UART通訊是從低位開始接數據,而I2C通訊是從高位開始接數據。
19. 關于bit 類型的函數。如
bit i2c_read_buf(uint8 *buf, uint8 addr, uint8 len)
{
while (len--)
{
if (i2c_readbyte(addr++, buf++))
return 1;
}
return 0;
}
在主函數中可以直接寫為bit i2c_read_buf(&a, b, c); 也可以寫為 y = bit i2c_read_buf(&a, b, c),將函數的返回值給了y。
20. uint8 table[] = “I”; 與 uint8 table[]={‘I’}; 兩者使用時等同,但是前者為字符串,故比后者多一個字節(jié)。
21. 結構體分配的地址是連續(xù)的。如:

22. 關于結構體指針問題。先看看以下一些程序通過結果進行分析得出結論.程序如下:

(1)結果為:44
是否就說明結構體指針 p 指向了整個 int a 呢?
(可以從第一個字節(jié)地址開始逐個指向下一個字節(jié)地址直到第4個為止)
(2)接著把tmp={44}該為tmp={127};
結果為:127
依然正確
(3)繼續(xù)改為tem={128};
結果為:-128
顯然不是我們想要的,倘若 p 指向了整個 int a,那么結果應該為 128 才對,顯然*p 只是指向int a的第一個地址。不會自動指向下一地址繼續(xù)將剩下的3個字節(jié)讀完,只有將剩下的三個字節(jié)讀完才能讀取一個完整的INT型數據。以上是在指針為char 類型的時候。(4)承接上面的,繼續(xù)把char *p 改為 int *p
結果為 128
正常了。為什么?因為char類型指針一次只能放一個地址(一個字節(jié)一個地址),
而int *p 一次能放4個地址,所以此時 p 可以一次指向4個int a 的四個地址
23. *p+1 的運算順序是先 *p 后 +1,不要誤以為是*(p+1).
24. 如有數組 int table[]={111,323,3423,3322}; 指針 char *p; 且 p = &table;
那么 p 指向了一個地址(table的首地址),至于可以指向幾個地址這個由指針的類型決定?,F在指針類型為char而char占一個字節(jié)只能放一個地址,所以 p 一次只能指向一個地址,所以 *p != 111,因為*p只讀取了111的第一個地址的數據,還有三個地址的數據沒讀。注意此時 p+1不指向table[1]這個元素的首地址。而是指向第一個元素的第二個地址??梢宰鲆幌赂纳苼硪淮巫x取4個地址,即讓指針一次指向int類型數據的4個地址。
把 char *p改成 int *p,這樣就可以一次指向四個地址了。則 *p = 111, *(p+1) = 232;注意括號一定要帶上,不然結果是 112.
可以得出結論。p不是指向一個地址,指向幾個地址由p 的數據類型決定。p + 1不是代表下一個地址。如 int *p,則p+1代表下一段連續(xù)的4個地址。可以理解為 p+1指向了4個連續(xù)的地址。在進行*(p+1)運算后將4個地址的數據連續(xù)讀取出來,合成了一個完整的int類型的數據。
25. 有關數組的長度。如 uint8 table[]={‘a’}; 與 uint8 table[]=”a”; 后者是用字符串形式來進行初始化。需要注意的是 若有 uint8 *p=&table. 對于兩者均有 *p=‘a’;可是對于 *(p+1)兩者的情況卻是不同的,后者有 *(p+1)= ‘’; 而前者卻沒有這種情況,在實際試驗中是要推后幾位才有這種情況。
26. 有關二進制(BCD碼)與十六進制的相互轉換,0xFF—0b1111 1111 ,0xFE—0b1111 1110.
分別寫成第一個數字或字母所對應的二進制數即可。至于二進制到16進制的轉化也是如此,倒過來就是了。反正記著,4位二進制數對應一位十六進制數。
27. 字符類型數據(uint8)在與整數運算時都是以ASII碼形式或十進制數存在的。若uint8 型變量里面放的是字母或2個BCD碼(8421),8位二進制數,在于整數進行運算時可以看出是ASII碼或十進制數的運算。
28. 別誤把if 語句當成循環(huán)語句了,if語句在執(zhí)行時先判斷括號內的語句是否成立,成立的話就執(zhí)行{}里的內容(if語句嵌套的內容)。如果成立那么執(zhí)行{}里的內容,執(zhí)行完后不再進行一次if的判斷,而是執(zhí)行下一語句,即便判斷仍然成立。主要還是要說明if不是循環(huán)語句,只判斷一次,無論成立與否,在執(zhí)行完所需內容后就直接執(zhí)行下一語句。
29. 關于取地址符號&的使用,變量本來就表示地址了,那么就不能再加&這樣會報錯。特殊例子是數組名a,它本身就代表第一個元素的首地址。但可以使用取地址符號,且不會報錯。加去地址符號后&a表示的含義發(fā)生了變化而是代表該數組的首地址,數值上似乎與a的相同,但含義卻是有差別的。
30. *p+1等價于(*p)+1,因為*優(yōu)先級高于+;*p++等價于*(p++),因為++優(yōu)先級高于*;
&a+1等價于(&a)+1.不能出現&(a+1)的情況,系統(tǒng)不認同,會報錯!
31. 對于數組 int a[4]={1,2,3,4}; 其中 a+1表示第二個元素的首地址(第一個字節(jié)的地址)。而(int)a+1表示第一個元素第二個字節(jié)的地址。
32. 關于結構體變量命名。如圖

這種命名方法在KEIL下會報錯,然而在VC++下卻沒問題。當你把code改成其他字母(不要與原來的code一樣就行),你會發(fā)現都沒問題??梢钥闯霾⒉皇敲拇笮懗鰡栴}。原因是KEIL不認同以結構體小寫字母來命名(這里是指全小寫),當你把其中一個字母該為大寫時就沒問題了。如把最后一行改成 CODE Code 讓變量名的第一個字母為大寫就行了。
33. 單片機要進行通信時要注意先關掉所有中斷(EA=0),在通信結束后才打開(EA=1).由于通信時通常要遵守時序,而中斷一旦被觸發(fā)便會打亂時序,使得傳輸數據失敗或者異常!注意通信中時序是非常重要的!
34. 在通信過程中需要注意,比如在傳輸一個字節(jié)數據時是一位一位地傳讓后湊夠8位構成一字節(jié)的。要從低位開始傳還是高位開始傳,要傳低位開始接還是高位開始接。這些不能處理好的話會直接影響到結果。也就是說發(fā)送端和接收端要保持一致,有兩種方式,一是從低位開始發(fā)(發(fā)送方),然后從低位開始接(接收方)。另一種就是從高位開始發(fā)(發(fā)送方),然后從高位開始接(接收方)。還有一個字節(jié)接收和發(fā)送的方向也要一致,只有這些保證了,才能保證信息準確傳輸。比如:在UART通信中,如果你要用單片機IO口模擬UART通信就需要注意這些,一般采取UART通信的統(tǒng)一標準,從低位開始傳輸。這樣跟標準UART器件就能很容易接上,不需要再作處理。當兩個通信器件都接標準UART接口時,那么就不用考慮這里了,這個在傳輸過程中他們自己會進行處理,我們無需考慮。只要把字節(jié)的排序弄好就行了。位的處理他們會自己完成。
35. 定時器1工作在模式1時的溢出是指在TH1=255(0xFF),TL1 =0的情況下,TL1達到255再 +1 就溢出了,此時溢出標志位TF1=1,需要清零才能讓定時器繼續(xù)工作。否則不定時,而是處于等待狀態(tài),等待TF1=0,然后才開始定時。要弄清什么時候才會溢出!
還有就是TL1每加1表示已經定時一個機器周期,在12T/11.0592MHz的單片機中機器周期為12/11059200 s 大約為1us.也就是說TL1每加1表示已經定時1us 。而TH1加1就表示已經經歷了256個機器周期。這里說的+1并不會使定時器溢出,只有TH1達到255了那么接下來的256個機器周期后就會溢出了!


關鍵詞: 51單片機學習總

評論


技術專區(qū)

關閉