天天看點

郭天祥的10天學會51單片機_第二節

申請樣片:美信公司,www.maxim-ic.com,右上角有簡體中文,在右邊直接購買标題的下面有申請樣品,點選後新頁面下打開工業控制,在資料資料中找DS12CR887,在右上角的型号搜尋欄中填入DS12CR887點選搜尋,新網頁打開後在右邊有資料資料可以下載下傳,在該頁面的下面找樣品與定購資訊,找到DS12CR887,點選超級連結,打開新頁面,在新頁面下的下面下載下傳DS12CR887-5+,點選樣品,在新頁面下填寫資料,點選送出;一周申請一次

AD公司,www.analog.com也可以申請樣品

TI公司,www.ti.com,可以一個月申請一次

While (表達式)

{語句(内部也可為空)}

特點:先判斷表達式,後執行語句。

原則:若表達式不是0,即為真,那麼執行語句。否則跳出while 語句。

寫程式時頭腦中要形成一種時序的概念,寫程式控制單片機,讓單片機控制外圍器件,單片機按照指令的從上而下的順序一條一條執行

一般單片機的程式要先進入一個大循環

Tab鍵是語句行右移,Shift+Tab是左移

While(1)就是始終進行循環

兩個原則:一是大循環用While(1)加大括号,在大括号中進行總程式的循環;二是如果要程式停止在某一行,用While(1)加分号(;),程式永遠不會往下執行

軟體仿真:工具欄上的列印機按鈕右邊的按鈕Start,點選後進入調試模式,

工具欄上出現的按鈕,第一個按鈕,RST外形的按鈕是複位CPU,作用是功能複位,将指針指到程式的開始;第二個按鈕,Run按鈕,全速執行;第三個按鈕,Halt按鈕,停止按鈕;第四個按鈕,Step into按鈕,進入函數體内部(進入子函數常用),單步執行,一條一條走;第五個按鈕,Step over按鈕,一次執行一個語句;黃色箭頭指向目前語句,再點一下Step over按鈕即執行這句程式,每執行一條指令,内部所有寄存器都會發生變化,這裡可以打開菜單欄的Peripherals(硬體)下面的按鈕(中斷,IO端口,串行端口,定時器),這裡打開IO端口的Port1(P1口),再打開菜單欄的View下面的Watch & Call Stack Window,這裡選擇Watch & Call Stack Window面闆上的Watch#1頁面,這裡點選Name下面的框(或者按F2),輸入要檢視的變量,再回車,可以在變量上右鍵單擊選擇16進制或10進制,單步Step over一下,發現P1口的第零位勾沒了,即表示為零,Watch#1頁面的a的值也變了,可以設定斷點,輕按兩下某一行即設定斷點,再輕按兩下取消,這裡在第二個a=50000處設定斷點,即上一句whie(a--)執行完就停下,斷點的作用是在全速執行程式時,當要執行斷點所在的指令的時候程式就停下來,這裡a是65535,表示a已經全減空了,全減空是0,再減一下就是65535,再點下全速Run程式又停在斷點處,說明程式又進行一次循環,又到了斷點處

使用仿真晶片,安裝好仿真晶片89E516RD,再在Keil中進行設定,單擊工具欄的Option for target按鈕進行設定,點選Debug頁,點選右邊的Use Keil Monitor-51 Driver的Settings,選擇COM口,點選OK即可,下面的可打鈎的都打鈎,然後确定,用仿真晶片和普通的使用單片機不一樣,要先打開單片機的電源,點選按鈕Start進行調試,左側的資訊框出現Connected to Monitor-51 V3.4,進行單步Step over調試,第二步看見發光二極管亮,這裡走的慢,設定斷點在第二個a=50000處,然後全速Run,程式走的斷點處,再點二步就走到p1_1=1處即發光二極管熄滅,去掉斷點全速執行發光二極管就正常執行閃爍;使用仿真晶片可以知道每一條指令如何執行,每一個變量如何變化;結束調試,先按下單片機上的複位按鈕,再按下Keil軟體中的按鈕Start結束調試

看一下變量的情況,可以把該變量值改小點,然後調試

讓發光二極管每隔500ms閃爍,單片機上右下角的複位鍵左側是晶振,11.0592MHZ,單擊工具欄的Option for target按鈕進行設定,點選Target頁,對Xtal晶振頻率進行設定

在需用軟體調節時間時可以将這裡的晶振調節成和單片機闆的晶振同樣大小,這裡改成11.0592

檢視延時的時間,在調試狀态下,左側有sec(秒),機關是秒,程式單步走時間也在走,在發光二極管滅之前設定斷點,即在p1_1=1處設定斷點,全速運作一下,再看時間,這裡用了488ms,我們再微調到500ms,先結束調試,再修改程式,然後編譯,再調試;微妙級的可以忽略(開始調試前,sec是幾百微妙,可以忽略);這裡發光二極管依然是500ms閃爍,因為發光二極管的是由單片機的硬體決定的,硬體沒有變化,單片機内部晶振還是11.0592MHZ,減慢或加快閃爍速度仍要通過程式來控制

仿真時間時要,單擊工具欄的Option for target按鈕進行設定,點選Target頁,對Xtal晶振頻率進行設定

#include<reg52.h>

sbit p1_1=P1^0;

unsigned int a;

void main()

{

         while(1)

         {       

                   a=51000;

                   p1_1=0;

                   while(a--);

                   a=51000;

                   p1_1=1;

                   while(a--);

         }

}

在第一個a=51000處設定一個斷點,全速運作,到下面的斷點第二個p1_1=1處,時間是490ms,再全速運作,到第一個a=51000處的斷點,運作時間是1.107s,即運作完發光二極管滅後的時間是1.107s

每次修改完都要編譯一下再調試,否則隻會調試到上次程式的狀态

在項目中,完全是調用子程式,主程式中完全是調用子程式

For循環如果有大括号可以不加分号,循環嵌套在最後的循環結尾處加一個分号表示該嵌套包含在上一個嵌套的裡面,此時如果再寫一個循環就和上面的循環沒有關系了

宏定義時要把要定義的變量名寫在前面,類型寫在後面,結尾不用加分号

子函數在調用時要在主函數前聲明,因為要為子函數配置設定空間,如果不配置設定空間,在調用時主函數會找不到子函數

調試時,要在要調試的語句的下一句設定斷點,因為要看執行完該語句後的狀态

在聲明帶參數的子函數時,要聲明子函數内參數的類型,可以寫參數名,也可以不寫參數名,如果有多個參數,寫上類型後用逗号隔開

#include<reg52.h>

#define uint unsigned int //unsigned int為正數,是以不用考慮變量為負

#define uchar unsigned char

sbit D1=P1^0;

//void delay();

void delay(uint);

void main()

{

         while(1)

         {

                   D1=0;

                   delay(100);

                   //delay();

                   D1=1;

                   delay(100);

                   //delay();

         }

}

void delay(uint z)

{

         uint x,y;

         //uchar y;

         for(x=z;x>0;x--)

                   for(y=600;y>0;y--);  

}

51幫助文檔在Keil檔案下面的C51檔案下面的HLP檔案下面的C51lib.Chm

_crol_函數是循環左移函數,上面标有#include <intrins.h>,說明使用時要添加該頭檔案

下面又标示,unsigned char _crol_ (unsigned char c,   

                      unsigned char b);  

表示該函數傳回值是unsigned char,參數中第一個是表示要移位的變量,第二個是要移動的位數

去除目前工程的檔案,右鍵點選要删除的檔案,選擇Remove File

流水燈程式:

#include<reg52.h>

#include <intrins.h>

#define uint unsigned int

#define uchar unsigned char

uchar temp,num,num1;//因為P1口是八位的,如果定義成int型可能會出錯,是以要定義成char型

sbit beep=P2^3;

void delay(uint);

void main()

{

    temp=0xfe;

         P1=temp;

         while(1)

         {

                   temp=_crol_ (temp,1);

                   delay(100);      

                   P1=temp;

         }

}

void delay(uint z)

{

         uint x,y;

         for(x=z;x>0;x--)

                   for(y=110;y>0;y--);  

}

蜂鳴器在TX-1C型單片機實驗闆原理圖中單片機右邊鎖存器下面,FM旁邊電阻上面的18表示18歐姆,FM連接配接單片機的P2^3口;三極管有電流放大功能,三極管是壓控流型的,電壓控制電流的放大倍數,這裡用的是三極管的開關功能,PNP型,圖中的箭頭應該标在下面,

郭天祥的10天學會51單片機_第二節

三極管有三極,從左至右從上到下依次是b(基極)c(集電極)e,箭頭一般在b和e之間,由e指向b(如果是NPN型也是如此,從左至右從上到下依次是bce,箭頭一般在b和e之間,但箭頭是由b指向e);當基極b給低電平,集電極c;蜂鳴器裡面内阻極小,裡面有線圈貼合鐵片,接Vcc,線圈通電吸合鐵片産生振動發出聲音,而基極b給低電平,由c向b正向導通,PN節之間有壓降,正向導通,有壓降是以将c和e之間連通,即當給b低電平時相當于将c和e之間連通,反之如果b高電平,和c之間沒有壓降c和e之間不會導通;總結一下,給b低電平蜂鳴器響,給b高電平蜂鳴器不響

接觸式繼電器,開始a和b連通,當線圈給電産生磁場,把a和b的線圈吸過去,讓b和c連通,見下圖,繼電器線圈上面連接配接Vcc,下面連接配接三極管,三極管連接配接單片機的P2^3口

郭天祥的10天學會51單片機_第二節

驅動繼電器方法同蜂鳴器,P2^3口給低電平,繼電器工作;繼電器要反向接一個發光二極管,作用是突然關閉繼電器時,線圈中産生逆向感應電流,電流會反向流過,由d到e,這裡接二極管電流就會流向二極管,而不會流向三極管導緻bc之間的PN結擊穿

課後練習:

第一個發光管以間隔200ms閃爍:

我的方法:

#include<reg52.h>

#define uint unsigned int//unsigned int為正數,是以不用考慮變量為負

#define uchar unsigned char

sbit D1=P1^0;

void delay()

{

         uint i,j;

         for(i=115;i>0;i--)

                   for(j=200;j>0;j--);

}

void main()

{

         while(1)

         {       

                   D1=0;

                   delay();

                   D1=1;

                   delay();

         }

}

課件方法:這裡把頻率調成11.0592MHZ

#include<reg52.h>  //52單片機頭檔案

#define uint unsigned int    //宏定義

#define uchar unsigned char  //宏定義

sbit led1=P1^0;    //單片機管腳位聲明

void delay(uint z)  //延時函數,z的取值為這個函數的延時ms數,如delay(200);大約延時200ms.

{                                             //delay(500);大約延時500ms.

         uint x,y;

         for(x=z;x>0;x--)

                   for(y=110;y>0;y--);  

}

void main()                     //主函數

{

         while(1)        //大循環

         {

                   led1=0;     //點亮小燈

                   delay(200); //延時200毫秒

                   led1=1;              //熄滅小燈

                   delay(200); //延時200毫秒

         }

}

8個發光管由上至下間隔1s流動,其中每個管亮500ms,滅500ms,亮時蜂鳴器響,滅時關閉蜂鳴器,一直重複下去。

我的方法:第一步是讓第一個發光二極管亮500ms,滅500ms,亮時蜂鳴器響,滅時關閉蜂鳴器,再做流水燈

再改動完程式,編譯完,用STC軟體時要先打開一下程式檔案,然後再Download程式

#include<reg52.h>

#include <intrins.h>

#define uint unsigned int

#define uchar unsigned char

sbit beep=P2^3;

void delay(uint);

void main()

{

         uchar temp;

         temp=0xfe;

         while(1)

         {       

                   P1=temp;

                   beep=0;

                   delay(500);

                   P1=0xff;

                   beep=1;

                   delay(500);

                   temp=_crol_(temp,1);

         }

}

void delay(uint z)

{

         uint i,j;

         for(i=z;i>0;i--)

                   for(j=110;j>0;j--);

}

8個發光管來回流動,每個管亮100ms,流動時讓蜂鳴器發出"滴滴"聲。

變量的定義要一起定義在函數體的前面,否則會出錯

來回流動的意思是從第一個發光二極管流到第八個發光二極管後再從第八個發光二極管流到第一個發光二極管

#include<reg52.h>

#include <intrins.h>

#define uint unsigned int

#define uchar unsigned char

sbit beep=P2^3;

void delay(uint);

void main()

{

         uchar temp,a;

         while(1)

         {

                   temp=0xfe;

                   for(a=8;a>0;a--)

                   {       

                            P1=temp;

                            beep=0;

                            delay(100);      

                            P1=0xff;

                            beep=1;

                            delay(100);

                            temp=_crol_(temp,1);

                   }

                   temp=0x7f;

                   for(a=8;a>0;a--)

                   {       

                            P1=temp;

                            beep=0;

                            delay(100);      

                            P1=0xff;

                            beep=1;

                            delay(100);

                            temp=_cror_(temp,1);

                   }       

         }

}

void delay(uint z)

{

         uint i,j;

         for(i=z;i>0;i--)

                   for(j=110;j>0;j--);

}

用8個發光管示範出8位二進制數累加過程:

^ ~             (按位異或  按位取反)

我的方法:

#include<reg52.h>

#include <intrins.h>

#define uint unsigned int

#define uchar unsigned char

void delay(uint);

void main()

{

         uint a,temp;

         while(1)

         {

                   a=0x00;

                   for(temp=256;temp>0;temp--)

                   {

                            a++;

                            P1=~a;

                            delay(200);

                   }

         }

}

void delay(uint z)

{

         uint i,j;

         for(i=z;i>0;i--)

                   for(j=110;j>0;j--);

}

課件的方法:把計數值直接定義成uchar型,uchar型範圍是0~255,而計數個數是256,正好是0到255共256個數,就不用循環了

#include<reg52.h>  //52單片機頭檔案

#include <intrins.h> //包含有左右循環移位子函數的庫

#define uint unsigned int    //宏定義

#define uchar unsigned char  //宏定義

void delay(uint z)  //延時函數,z的取值為這個函數的延時ms數,如delay(200);大約延時200ms.

{                                             //delay(500);大約延時500ms.

         uint x,y;

         for(x=z;x>0;x--)

                   for(y=110;y>0;y--);  

}

void main()                     //主函數

{

         uchar a;

         while(1)        //大循環

         {

                   a++;

                   P1=~a;

                   delay(200);      

         }

}

8個發光管間隔200ms由上至下,再由下至上,再重複一次,然後全部熄滅再以300ms間隔全部閃爍5次。重複此過程:

我的方法:先做8個發光管間隔200ms由上至下,再由下至上,再重複一次,再做然後全部熄滅再以300ms間隔全部閃爍5次

做一部分就看下硬體狀況,調節一下,然後再做下一部分,如果有一部分不好使,可以注釋掉其它程式,單獨調試這部分,也可以單建立工程,單提出來這部分程式進行調試

我的錯誤片段:因為

void main()

{

         uint a;

         uchar temp;

         while(1)

         {

                   for(temp=2;temp>0; temp--)//總循環跳不出來

                   {

                            a=0xfe;

                            for(temp=8;temp>0;temp--)

                            {

                                     P1=a;

                                     delay(200);

                                     a=_crol_(a,1);

                            }

                            a=0x7f;

                            for(temp=8;temp>0;temp--)//從這裡出來temp的值變化了,再到總循環處,對總循環的temp造成影響,導緻總循環跳不出來

                            {

                                     P1=a;

                                     delay(200);

                                     a=_cror_(a,1);

                            }

                   }

                            a=0xfe;

                            for(temp=8;temp>0;temp--)

                            {

                                     P1=a;

                                     delay(200);

                                     a=_crol_(a,1);

                            }

                            a=0x7f;

                            for(temp=8;temp>0;temp--)

                            {

                                     P1=a;

                                     delay(200);

                                     a=_cror_(a,1);

                            }

                   a=0xff;

                   P1=a;

                   for(temp=5;temp>0;temp--)

                   {

                            delay(300);

                            a=0x00;

                            P1=a;

                            delay(300);               

                            a=0xff;

                            P1=a;

                   }

         }

}

正确的程式:

#include<reg52.h>

#include <intrins.h>

#define uint unsigned int

#define uchar unsigned char

void delay(uint z)

{

         uint x,y;

         for(x=z;x>0;x--)

                   for(y=110;y>0;y--);

}

void main()

{

         uint a;

         uchar temp,untemp;

         while(1)

         {

                   for(untemp=2;untemp>0;untemp--)

                   {

                            a=0xfe;

                            for(temp=8;temp>0;temp--)

                            {

                                     P1=a;

                                     delay(200);

                                     a=_crol_(a,1);

                            }

                            a=0x7f;

                            for(temp=8;temp>0;temp--)

                            {

                                     P1=a;

                                     delay(200);

                                     a=_cror_(a,1);

                            }

                   }

                   P1=0xff;

                   for(temp=10;temp>0;temp--)

                   {

                            delay(300);                         

                            P1=~P1;

                   }

         }

}

間隔300ms第一次一個管亮流動一次,第二次兩個管亮流動,依次到8個管亮,然後重複整個過程:

課件的方法:

+   -   *   /  (加 減 乘 除)

>   >=  <  <=  (大于  大于等于  小于  小于等于)

==  !=         (測試等于  測試不等于)

&&  ||  !      (邏輯與    邏輯或  邏輯非 )

>>  <<         (位右移    位左移)

& |             (按位與    按位或)

^ ~             (按位異或  按位取反)

利用位左移,移入第一位是零,來編寫程式

#include<reg52.h>  //52單片機頭檔案

#include <intrins.h> //包含有左右循環移位子函數的庫

#define uint unsigned int    //宏定義

#define uchar unsigned char  //宏定義

void delay(uint z)  //延時函數,z的取值為這個函數的延時ms數,如delay(200);大約延時200ms.

{                                             //delay(500);大約延時500ms.

         uint x,y;

         for(x=z;x>0;x--)

                   for(y=110;y>0;y--);  

}

void main()                    //主函數

{

         uchar a,i,j;

         while(1)        //大循環

         {

                            a=0xfe;     //賦初值

                            for(j=0;j<8;j++)

                            {

                                     for(i=0;i<8-j;i++)   //左移

                                     {

                                               P1=a;       //點亮小燈

                                               delay(200); //延時200毫秒

                                               a=_crol_(a,1); //将a變量循環左移一位

                                     }

                                     a=_crol_(a,j);   //補齊,友善下面的左移一位,通過列出數可以看出此步驟是必需要有的

                                     P1=0xff;           //全部關閉

                                     a=a<<1;             //左移一位讓多一個燈點亮,注意左移後要重新賦給變量

                            }

         }

}

間隔300ms先奇數亮再偶數亮,循環三次;一個燈上下循環三次;兩個分别從兩邊往中間流動三次;再從中間往兩邊流動三次;8個全部閃爍3次;關閉發光管,程式停止:

一步一步做,做一步調試一步,程式中每兩步之間要有空格,這樣結構清楚

#include<reg52.h>  //52單片機頭檔案

#include <intrins.h> //包含有左右循環移位子函數的庫

#define uint unsigned int    //宏定義

#define uchar unsigned char  //宏定義

void delay(uint z)  //延時函數,z的取值為這個函數的延時ms數,如delay(200);大約延時200ms.

{                                             //delay(500);大約延時500ms.

         uint x,y;

         for(x=z;x>0;x--)

                   for(y=110;y>0;y--);  

}

void main()                    //主函數

{

         uchar a,i,j;

         for(j=0;j<3;j++)      //奇偶交替

         {

                            P1=0x55;       //點亮小燈

                            delay(300); //延時300毫秒

                            P1=0xaa;

                            delay(300); //延時300毫秒

         }

         for(j=0;j<3;j++)    //流水燈

         {

                   a=0xfe;

                   for(i=0;i<8;i++)

                            {

                                     P1=a;       //點亮小燈

                                     delay(300); //延時300毫秒

                                     a=_crol_(a,1);

                            }

         }

         P1=0xff;

         for(j=0;j<3;j++)     //從兩邊往中間流

         {

                            P1=0x7e;       //點亮小燈

                            delay(300); //延時300毫秒

                            P1=0xbd;

                            delay(300); //延時300毫秒

                            P1=0xdb;       //點亮小燈

                            delay(300); //延時300毫秒

                            P1=0xe7;

                            delay(300); //延時300毫秒

         }

         P1=0xff;

         for(j=0;j<3;j++)    //從中間往兩邊流

         {

                            P1=0xe7;       //點亮小燈

                            delay(300); //延時300毫秒

                            P1=0xdb;

                            delay(300); //延時300毫秒

                            P1=0xbd;       //點亮小燈

                            delay(300); //延時300毫秒

                            P1=0x7e;

                            delay(300); //延時300毫秒

         }

         P1=0xff;

         for(j=0;j<6;j++)    //全部閃爍

         {

                            P1=~P1;       //點亮小燈

                            delay(300); //延時300毫秒

         }

         P1=0xff;

         while(1);//程式停止,把while(1)放在後面

}

繼續閱讀