1. Ctrl+S為保存當前文件,如圖
打開了兩個文件,可以看到有個文件是帶星號且有個紅叉的,有個紅叉說明它為當前打開的文件,也就是正在編輯的文件。當按下Ctrl+S時只保存了當前文件。另一個文件沒有保存,當你的電腦意外斷電或死機時,如果你在那之前按了Ctrl+S那么可以挽回點損失,可是另一個文件的信息可能就丟失了。所以推薦按F7(對所以文件進行編譯,并且保存),這樣就可以在編譯的同時將所以文件保存一次。所以在真正做工程的時候就要學(xué)會定期按F7,不是說一定要程序編寫完整后才按F7。
2. 默認情況下頭文件和源文件應(yīng)該放在同一個文件目錄下,如果將頭文件放在一個獨立的文件夾中如名為include的文件夾,此時就讀取不出。要進行一下設(shè)置才能讀取出來。如圖:
在C51選項中的Include Paths 選項中要設(shè)置頭文件的路徑后方能打開頭文件,對頭文件進行編譯!
3. 對于不變化的變量,如數(shù)碼管顯示的數(shù)組,要通過前綴code將它放在ROM中避免占用了RAM的空間。
4. 宏定義的內(nèi)容全用大寫字母,當有兩個單詞時用_將他們分開,如#define LED_SEG P1_1;在特殊情況下才用小寫字母。
5. 變量名的定義一般為 i , Led , DispBuff 即單個字母時小寫,多個字母一個單詞時首字母大寫,多個單詞時連寫且每個單詞的首字母大寫。
6. 函數(shù)名的定義一般為 delay ,write_byte 即單個單詞時全小寫,多個單詞時也是小寫,但是單詞間用 _ 隔開。
7. 不必糾結(jié)于該換行多少,空格多少,只要自己知道哪里該換行,哪里改空格就行了,像這些東西的尺度只有自己真正實踐的時候就能領(lǐng)悟出來。當然這沒有絕對的標準,就算是非常出色的工程師也很難做到精確的換行,當是他們的程序整體看起來整齊有可讀性高就OK了。要懂得把精力放在恰當?shù)牡胤健?br />8. 不要太死板,一定要照著那些條條框框,但我相信小宋老師我需要向他學(xué)習,他的程序有很高的價值。
9. 中斷函數(shù)書寫
10. 在函數(shù)中無論是被調(diào)函數(shù)還是主函數(shù)都要懂得對一些變量進行初始化,這是一個好習慣,別以為沒必要,或者繁瑣。這其實不是繁瑣,而是嚴謹。寫程序就應(yīng)該有嚴謹?shù)膽B(tài)度。
11.main函數(shù)的標準寫法為:
int main(void)
{
……
return 0;
}
12. 在定時器溢出進入中斷時,在執(zhí)行中斷時TF0或TF1會硬件(自動)清0,從新開始計數(shù)。但在串口發(fā)送或接受標志位置1并引起中斷時,在執(zhí)行中斷過程中TI或RI 需軟件(手動)清0.
13. 有關(guān)UART通信定時器1模式2中 TH1 與 TL1(與TH1相等)的初始化。在實際計算中TH1 = 256 - 11059200/(12*32*9600); 可以計算得 TH1 = 0xFD; 但是當你把TH1 = 256 - 11059200/(12*32*9600); 寫入編譯器中讓編譯器來完成計算時,那么這樣寫就是錯誤的了,在keil里默認整數(shù)常量是 uint16 類型,取值為0~65535.故應(yīng)寫為TH1 = 256 – 11059200UL/(12*32*9600UL);要注意的是keil 對這類錯誤不報錯!
14. 在串口通訊中,如:
串口調(diào)試助手一般選擇“字符格式顯示”。如果想顯示數(shù)字則寫入語句UART_send_byte(‘8’) ,要注意顯示數(shù)字時只能顯示一位即0~9;想顯示字母時可寫入語句UART_send_byte(‘A’)。注意別掉了‘’尤其是寫數(shù)字時。寫字母丟失的話還會報錯。寫數(shù)字丟失的話就不會報錯。此時顯示的是數(shù)字相應(yīng)的ASII碼。
15. 若uint8 temp = ‘A’; 則 temp = ‘A’ + 1 時temp = ‘B’ , 即字符與數(shù)字相加為對應(yīng)ASII碼相加。
16. 在串口調(diào)試助手中,要發(fā)送字符時不用帶‘’因為軟件已經(jīng)默認帶上了。
17. 關(guān)于對數(shù)組各元素賦值,有兩種方式,如uint8 table [11] = “how are you”; 另一種是 table[0] = ‘h’; table[1] = ‘o’;……其中第一種賦值只能在定義數(shù)據(jù)類型時使用,如上所示。
在數(shù)據(jù)類型定義完畢后不能通過table [11] = “how are you”;來改變數(shù)組里面的元素,這樣做在keil 下會有警告!但不報錯,實際是不正確的。那么要改變數(shù)組的元素只能通過對里面元素逐個賦值。
18. UART通訊是從低位開始接數(shù)據(jù),而I2C通訊是從高位開始接數(shù)據(jù)。
19. 關(guān)于bit 類型的函數(shù)。如
bit i2c_read_buf(uint8 *buf, uint8 addr, uint8 len)
{
while (len--)
{
if (i2c_readbyte(addr++, buf++))
return 1;
}
return 0;
}
在主函數(shù)中可以直接寫為bit i2c_read_buf(&a, b, c); 也可以寫為 y = bit i2c_read_buf(&a, b, c),將函數(shù)的返回值給了y。
20. uint8 table[] = “I”; 與 uint8 table[]={‘I’}; 兩者使用時等同,但是前者為字符串,故比后者多一個字節(jié)。
21. 結(jié)構(gòu)體分配的地址是連續(xù)的。如:
22. 關(guān)于結(jié)構(gòu)體指針問題。先看看以下一些程序通過結(jié)果進行分析得出結(jié)論.程序如下:
(1)結(jié)果為:44
是否就說明結(jié)構(gòu)體指針 p 指向了整個 int a 呢?
(可以從第一個字節(jié)地址開始逐個指向下一個字節(jié)地址直到第4個為止)
(2)接著把tmp={44}該為tmp={127};
結(jié)果為:127
依然正確
(3)繼續(xù)改為tem={128};
結(jié)果為:-128
顯然不是我們想要的,倘若 p 指向了整個 int a,那么結(jié)果應(yīng)該為 128 才對,顯然*p 只是指向int a的第一個地址。不會自動指向下一地址繼續(xù)將剩下的3個字節(jié)讀完,只有將剩下的三個字節(jié)讀完才能讀取一個完整的INT型數(shù)據(jù)。以上是在指針為char 類型的時候。(4)承接上面的,繼續(xù)把char *p 改為 int *p
結(jié)果為 128
正常了。為什么?因為char類型指針一次只能放一個地址(一個字節(jié)一個地址),
而int *p 一次能放4個地址,所以此時 p 可以一次指向4個int a 的四個地址
23. *p+1 的運算順序是先 *p 后 +1,不要誤以為是*(p+1).
24. 如有數(shù)組 int table[]={111,323,3423,3322}; 指針 char *p; 且 p = &table;
那么 p 指向了一個地址(table的首地址),至于可以指向幾個地址這個由指針的類型決定?,F(xiàn)在指針類型為char而char占一個字節(jié)只能放一個地址,所以 p 一次只能指向一個地址,所以 *p != 111,因為*p只讀取了111的第一個地址的數(shù)據(jù),還有三個地址的數(shù)據(jù)沒讀。注意此時 p+1不指向table[1]這個元素的首地址。而是指向第一個元素的第二個地址??梢宰鲆幌赂纳苼硪淮巫x取4個地址,即讓指針一次指向int類型數(shù)據(jù)的4個地址。
把 char *p改成 int *p,這樣就可以一次指向四個地址了。則 *p = 111, *(p+1) = 232;注意括號一定要帶上,不然結(jié)果是 112.
可以得出結(jié)論。p不是指向一個地址,指向幾個地址由p 的數(shù)據(jù)類型決定。p + 1不是代表下一個地址。如 int *p,則p+1代表下一段連續(xù)的4個地址。可以理解為 p+1指向了4個連續(xù)的地址。在進行*(p+1)運算后將4個地址的數(shù)據(jù)連續(xù)讀取出來,合成了一個完整的int類型的數(shù)據(jù)。
25. 有關(guān)數(shù)組的長度。如 uint8 table[]={‘a’}; 與 uint8 table[]=”a”; 后者是用字符串形式來進行初始化。需要注意的是 若有 uint8 *p=&table. 對于兩者均有 *p=‘a’;可是對于 *(p+1)兩者的情況卻是不同的,后者有 *(p+1)= ‘’; 而前者卻沒有這種情況,在實際試驗中是要推后幾位才有這種情況。
26. 有關(guān)二進制(BCD碼)與十六進制的相互轉(zhuǎn)換,0xFF—0b1111 1111 ,0xFE—0b1111 1110.
分別寫成第一個數(shù)字或字母所對應(yīng)的二進制數(shù)即可。至于二進制到16進制的轉(zhuǎn)化也是如此,倒過來就是了。反正記著,4位二進制數(shù)對應(yīng)一位十六進制數(shù)。
27. 字符類型數(shù)據(jù)(uint8)在與整數(shù)運算時都是以ASII碼形式或十進制數(shù)存在的。若uint8 型變量里面放的是字母或2個BCD碼(8421),8位二進制數(shù),在于整數(shù)進行運算時可以看出是ASII碼或十進制數(shù)的運算。
28. 別誤把if 語句當成循環(huán)語句了,if語句在執(zhí)行時先判斷括號內(nèi)的語句是否成立,成立的話就執(zhí)行{}里的內(nèi)容(if語句嵌套的內(nèi)容)。如果成立那么執(zhí)行{}里的內(nèi)容,執(zhí)行完后不再進行一次if的判斷,而是執(zhí)行下一語句,即便判斷仍然成立。主要還是要說明if不是循環(huán)語句,只判斷一次,無論成立與否,在執(zhí)行完所需內(nèi)容后就直接執(zhí)行下一語句。
29. 關(guān)于取地址符號&的使用,變量本來就表示地址了,那么就不能再加&這樣會報錯。特殊例子是數(shù)組名a,它本身就代表第一個元素的首地址。但可以使用取地址符號,且不會報錯。加去地址符號后&a表示的含義發(fā)生了變化而是代表該數(shù)組的首地址,數(shù)值上似乎與a的相同,但含義卻是有差別的。
30. *p+1等價于(*p)+1,因為*優(yōu)先級高于+;*p++等價于*(p++),因為++優(yōu)先級高于*;
&a+1等價于(&a)+1.不能出現(xiàn)&(a+1)的情況,系統(tǒng)不認同,會報錯!
31. 對于數(shù)組 int a[4]={1,2,3,4}; 其中 a+1表示第二個元素的首地址(第一個字節(jié)的地址)。而(int)a+1表示第一個元素第二個字節(jié)的地址。
32. 關(guān)于結(jié)構(gòu)體變量命名。如圖
這種命名方法在KEIL下會報錯,然而在VC++下卻沒問題。當你把code改成其他字母(不要與原來的code一樣就行),你會發(fā)現(xiàn)都沒問題。可以看出并不是命名的大小寫出問題。原因是KEIL不認同以結(jié)構(gòu)體小寫字母來命名(這里是指全小寫),當你把其中一個字母該為大寫時就沒問題了。如把最后一行改成 CODE Code 讓變量名的第一個字母為大寫就行了。
33. 在單片機要進行通信時要注意先關(guān)掉所有中斷(EA=0),在通信結(jié)束后才打開(EA=1).由于通信時通常要遵守時序,而中斷一旦被觸發(fā)便會打亂時序,使得傳輸數(shù)據(jù)失敗或者異常!注意通信中時序是非常重要的!
34. 在通信過程中需要注意,比如在傳輸一個字節(jié)數(shù)據(jù)時是一位一位地傳讓后湊夠8位構(gòu)成一字節(jié)的。要從低位開始傳還是高位開始傳,要傳低位開始接還是高位開始接。這些不能處理好的話會直接影響到結(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表示已經(jīng)定時一個機器周期,在12T/11.0592MHz的單片機中機器周期為12/11059200 s 大約為1us.也就是說TL1每加1表示已經(jīng)定時1us 。而TH1加1就表示已經(jīng)經(jīng)歷了256個機器周期。這里說的+1并不會使定時器溢出,只有TH1達到255了那么接下來的256個機器周期后就會溢出了!
評論