免費樣片申請(暫時無用,不說了,很簡單)
作業講解
1-5點亮燈過簡單,不說了
6:嘗試讓第一個發光管閃爍
閃爍,就是亮,滅,再亮,再滅這樣一個循環的過程,就是寫程序控制某一個IO口先輸出低電平,再輸出高電平,再輸出低電平,如此循環,沒變化一個狀態要持續一個時間(即為延時)。簡單的延時就用一個while或者for循環就可以。
1 #include<reg52.h> 2 sbit p1_1=P1^0; 3 unsigned int a; 4 void main() 5 { 6 a=50000; 7 p1_1=0; 8 while(a--); 9 a=50000; 10 p1_1=1; 11 while(a--); 12 }
定義一個unsigned int(無符號整型)類型的變量a,其范圍為0-65535,若超出這個值,就會取余,例如70000,那么就會取70000-65535后的值。

這里選中這兩個,這樣如果一直插着單片機,然后更改代碼並編譯的話,會自動下載進單片機。
你可能會按照上面的方法,但這樣是不對的,不標准。因為正常執行c語言代碼時,從進入main函數開始,執行完main內部的代碼就結束了,但這里卻又重新再執行了,因為單片機會一直重復執行main函數,但有時會出錯。
正確的寫法
1 #include<reg52.h> 2 sbit p1_1=P1^0; 3 unsigned int a; 4 void main() 5 { 6 while(1) 7 { 8 a=50000; 9 p1_1=0; 10 while(a--); 11 a=50000; 12 p1_1=1; 13 while(a--); 14 } 15 }
在main函數內部再寫一個while(1),將需要循環執行的代碼放入while(1)的花括號內,這樣單片機就會一直循環while(1)內部的內容而不出錯了。
要學會軟件調試

點擊這個放大鏡一樣的東西就是打開調試了,調試前要先編譯。再次點擊就關閉。



黃色箭頭指着的就是下一條要執行的語句

這個是復位,點擊后讓調試重頭開始。

全速執行。

停止全速執行,只有在開啟全速執行后它才會變成紅色,才能使用。

進入函數內部。

執行下一調語句。

點擊Peripheral(硬件)

Interrupt:中斷
I/O-Ports:IO口
Serial:串行端口
Timer:定時器
這里選擇我們現在用到的IO口的P1口Port 1

可以看到P1上電后為oxFF,即上電后所有IO口為高電平(IO口上電后為1,其余寄存器上電后為0,上電后會自動復位,所以這里軟件的復位就可以當做上電),對應的后面8位都打了√,如果√沒了,對應的一位就變成了0。操作單片機就是對內部的寄存器(P1)進行操作。

點擊View,選上call stack window


看到,執行過的語句變成綠色,沒執行的是灰色,這里while(a--)要想執行完需要單步執行(即一次執行一句)50000次,要點50000次,很慢,所以我們可以設置斷點。

斷點就是前面出現了紅色,有的版本是紅色的圓,設置斷點的方法就是在需要的語句前方灰色處用鼠標單擊。

現在我們說一下上面的全速執行,全速執行就是一直執行,而且執行的很快,不需要你一下一下的點,但是你不知道執行到哪里了,所以我們要用到斷點,這里我們不想點擊50000次,所以我們在while(a--)后面那條語句設置斷點,再開啟全速執行,那么程序就會全速執行到斷點的位置然后停止,不會執行斷點那條語句。

這里執行完全速后,a變為了65535(也是滿,unsigned int類型的最大值,滿和空是一個概念),意思是減空了,從原本的50000,減到0后再減一次就是65535了。
硬件調試(在線調試)(仿真芯片) 你沒買,先不用看
仿真芯片有利於你領悟程序具體是怎么執行的
點開設置

點到debug這一欄。

原本是use Simulator,現在我們點擊右邊的Use,選擇keil Monitor-51 Driver,再點擊Settings設置

選擇com口,下載程序用的com幾,這里就選com幾,然后點擊ok。

之后這里全部打鈎,再確定。
仿真時必須先接通電源
然后點擊debug調試

下方會顯示連接到了(Connected to Monitor-51)
然后就按剛才方法調試即可,不同的是這里調試時,單片機也會跟着一步一步走。
這種調試你可以知道每一條指令什么時候執行,每一種變量如何變化的。
結束調制時先按下單片機上的復位按鈕,再點debug結束
接下來學習如何設置比較准確的延時時間
首先,要知道,實驗板的晶振頻率是11.0592MHz,計算機單片機的運行速度是由其決定的
下面的內容只需要知道一個機器周期是12個時鍾周期,一個時鍾周期是震盪源的周期。

在調節時間的時候,需要把keil中的晶振頻率改為和單片機的晶振頻率相同


下面打開調試狀態

會看到當程序運行到這里時是0.00042209s,先運行到燈亮

0.00042752s,然后我們運行到它滅之前看看中間有多少時間,這就是我們要的延時時間,這里要設置斷點,不然while(a--)我們要手動50000次....


時間變為了0.48893555s,離500ms近了,我們微調下,把a變為51000再運行到這里就差不多了。下面的也改。

下面我們看看如果不設置11.0592MHz晶振頻率,用默認的24MHz會怎么樣

頻率24大約是11的2倍,那么時間也差不多是1/2。
但是這里只是模擬,對單片機沒有影響,單片機還是用它本身的11.0592來計算的,不過這樣你就算不准了。
接下來學習子函數(以后寫程序都是寫在函數里,然后main全是調用)
首先介紹一下宏定義define,就相當於起一個新的名字,用法#define new_name old_name
1 #include<reg51.h> 2 #define uint unsigned int//宏定義 3 #define uchar unsigned char 4 5 void delay();//聲明函數 6 sbit D1=P1^0; 7 void main() 8 { 9 while(1) 10 { 11 D1=0; 12 delay(); 13 D1=1; 14 delay(); 15 } 16 } 17 18 void delay()//定義函數,大約是500ms的延時, 19 { 20 uint x,y; 21 for(x=100;x>0;x--) 22 { 23 for(y=600;y>0;y--) 24 { 25 26 } 27 } 28 }
這里for循環還有上面出現的while循環,當沒有內部語句時,可以省略{},直接寫分號
1 void delay(uint n) 2 { 3 uint x,y; 4 for(x=n;x>0;x--) 5 { 6 for(y=600;y>0;y--); 7 } 8 }
其它自己看懂,不再贅述了
帶參數的子函數
1 #include<reg51.h> 2 #define uint unsigned int 3 #define uchar unsigned char 4 5 void delay(uint n); 6 //void delay(uint );這里聲明也可以寫成這樣(不寫n),但建議寫上面那種,方便,上面那種只需要在函數定義那里復制過來就可以了,不會出錯。 7 sbit D1=P1^0; 8 void main() 9 { 10 while(1) 11 { 12 D1=0; 13 delay(100); 14 D1=1; 15 delay(100); 16 } 17 } 18 19 void delay(uint n) 20 { 21 uint x,y; 22 for(x=n;x>0;x--) 23 { 24 for(y=600;y>0;y--) 25 { 26 27 } 28 } 29 }
函數定義和函數聲明的參數叫做形參(形式參數),函數調用時給的數值是實參(實際參數),因為函數定義時函數是不執行的,而只有調用時,函數才執行,其中的參數會使用你傳的參數,也就是實參。
接下來我們用stc-isp來生成延時函數

打開后點擊紅框內的三角箭頭,找到軟件延時計算器

先選擇晶振頻率,再設置延時的時間,再選擇指令集STC-Y1,然后生成c代碼,最后復制就可以了
1 #include<reg51.h> 2 #define uint unsigned int 3 #define uchar unsigned char 4 5 void Delay1ms(); 6 void delay(uint n); 7 sbit D1=P1^0; 8 void main() 9 { 10 while(1) 11 { 12 D1=0; 13 delay(200); 14 D1=1; 15 delay(200); 16 } 17 } 18 19 void delay(uint n) 20 { 21 while(n--) 22 { 23 Delay1ms(); 24 } 25 } 26 void Delay1ms() //@12.000MHz 27 { 28 unsigned char i, j; 29 30 i = 2; 31 j = 239; 32 do 33 { 34 while (--j); 35 } while (--i); 36 }
定義一個延時1ms的函數,然后再定義一個帶參數的函數,調用延時1ms的函數n次,就產生了延時n ms的函數了
接下來是流水燈


找到C51文件夾中Hlp文件夾下的c51幫助文檔,在Reference里能看到庫函數,都是寫好的可以直接調用的函數
這里我們要用到_crol_

點開后可以看到介紹和例子,需要用到頭文件intrins.h,將變量c循環左移b位,返回移動后的結果。a=0xA5(1010 0101),循環左移一位變成(0100 1011),循環左移第二位(1001 0110),循環左移第三位(0010 1101)即0x2D,循環左移一次就是整體左移一次,把最高位的放到最低位。
1 #include<reg51.h> 2 #include<intrins.h> 3 4 #define uint unsigned int 5 #define uchar unsigned char 6 7 uchar temp;//為什么用uchar而不用uint? 8 9 void Delay1ms(); 10 void delay(uint n); 11 12 void main() 13 { 14 temp=0xfe; 15 P1=temp;//因為uchar有8位,而uint有16位,每組IO口也是8位,所以如果我們要用uchar 16 while(1)//先讓P1=0xfe(1111 1110) 17 { 18 delay(300);//延時300ms 19 temp=_crol_(temp,1);//改變temp的值 20 P1=temp;//改變P1的值 21 } 22 } 23 24 void delay(uint n) 25 { 26 while(n--) 27 { 28 Delay1ms(); 29 } 30 } 31 void Delay1ms() //@12.000MHz 32 { 33 unsigned char i, j; 34 35 i = 2; 36 j = 239; 37 do 38 { 39 while (--j); 40 } while (--i); 41 }
其實temp這里多余,只是想讓你知道定義變量要注意的地方,比如為什么不用unsigned int而用unsigned char
1 void main() 2 { 3 P1=0xfe; 4 while(1)//先讓P1=0xfe(1111 1110) 5 { 6 delay(300);//延時300ms 7 P1=_crol_(temp,1);//改變P1的值 8 9 } 10 }
main可以直接改成這樣
課后作業

補充一下蜂鳴器
蜂鳴器原理圖

(我的板子是第二種)(繼電器也挺重要,但暫時不說了)

FM就是P2^3口,然后接一個電阻,這里用了一個三極管,用了它的開關作用(它還有放大作用),(蜂鳴器內阻很小(忽略)),當給P2^3低電平時,ce就導通了,就有從VCC流經蜂鳴器然后經過ce的電流。
因此蜂鳴器的使用也很簡單,0就響,1就停止。
1 #include<reg51.h> 2 3 sbit beep=P2^3; 4 5 void main() 6 { 7 8 while(1) 9 { 10 beep=0; 11 } 12 }
這樣就響了
接下里是響、停循環進行
1 #include<reg51.h> 2 3 #define uint unsigned int 4 #define uchar unsigned char 5 6 sbit beep=P2^3; 7 8 void Delay1ms(); 9 void delay(uint n); 10 11 void main() 12 { 13 14 while(1) 15 { 16 beep=0; 17 delay(300); 18 beep=1; 19 delay(300); 20 } 21 } 22 23 void delay(uint n) 24 { 25 while(n--) 26 { 27 Delay1ms(); 28 } 29 } 30 void Delay1ms() //@12.000MHz 31 { 32 unsigned char i, j; 33 34 i = 2; 35 j = 239; 36 do 37 { 38 while (--j); 39 } while (--i); 40 }
這里在提一下前面說到的~(取反),原本是0,取反就是1,原本是1,取反就是0,用這個會很簡單。
1 #include<reg51.h> 2 3 #define uint unsigned int 4 #define uchar unsigned char 5 6 sbit beep=P2^3; 7 8 void Delay1ms(); 9 void delay(uint n); 10 11 void main() 12 { 13 14 while(1) 15 { 16 beep=~beep; 17 delay(300); 18 } 19 } 20 21 void delay(uint n) 22 { 23 while(n--) 24 { 25 Delay1ms(); 26 } 27 } 28 void Delay1ms() //@12.000MHz 29 { 30 unsigned char i, j; 31 32 i = 2; 33 j = 239; 34 do 35 { 36 while (--j); 37 } while (--i); 38 }
