51單片機學習筆記(郭天祥版)(2)——第一課作業、流水燈、蜂鳴器


免費樣片申請(暫時無用,不說了,很簡單)


作業講解

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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM