1. 程式人生 > >獨立按鍵和矩陣按鍵

獨立按鍵和矩陣按鍵

 我們和微控制器之間進行資訊互動,主要包含兩大類,輸入裝置和輸出裝置。前邊講的LED小燈、數碼管、點陣都是輸出裝置,這節課我們學習一下最常用的輸入裝置——按鍵。在本節課的學習過程中我們還會穿插介紹一點硬體設計的基礎知識。

8.1 微控制器最小系統電路解析

8.1.1 電源

我們在學習過程中,很多指標都是直接用的概念指標,比如我們說+5V代表1GND代表0等等這些。但在實際電路中是沒有這麼精準的,那這些指標允許範圍是什麼呢?隨著我們所學的內容不斷增多,大家要慢慢培養一種閱讀手冊的能力。

比如我們使用STC89C52RC微控制器的時候,我們找到他的手冊的11頁,第二個選項,工作電壓:

5.5V-3.4V(5V微控制器),這個地方就說明我們這個微控制器正常的工作電壓是個範圍值,只要電源VCC5.5V3.4V之間都可以正常工作,電壓超過5.5V是絕對不允許的,會燒壞微控制器,電壓如果低於3.4V,微控制器不會損壞,但是也不能正常工作。而在這個範圍內,最典型、最常用的電壓值就是5V,這就是後面括號裡“5V微控制器”這個名稱的由來。除此之外,還有一種常用的工作電壓範圍是2.7V-3.6V、典型值是3.3V的微控制器,也就是所謂的“3.3V微控制器”了。日後隨著大家接觸的東西慢慢增多,對這點會有更深刻的理解。

現在我們再順便多瞭解一點,大家開啟74HC138的資料手冊,會發現

74HC138手冊的第二頁也有一個表格,上邊寫了74HC138的工作電壓範圍,最小值是4.75V,額定值是5V,最大值是5.25V,可以得知它的工作電壓範圍是4.75V-5.25V。這個地方講這些目的是讓大家清楚的瞭解,我們獲取器件工作引數的一個最重要,也是最權威的途徑,就是通過器件的資料手冊。

8.1.2 晶振

晶振通常分為無源晶振和有源晶振兩種型別,無源晶振一般稱之為crystal(晶體),而有源晶振則叫做oscillator(振盪器)

有源晶振是一個完整的諧振振盪器,他是利用石英晶體的壓電效應來起振,所以有源晶振需要供電,當我們把有源晶振電路做好後,不需要外接電路,它就可以主動產生振盪頻率,並且可以提供高精度的頻率基準,訊號質量比無源訊號好。

而無源晶振自身無法振盪起來,它需要晶片內部的振盪電路一起工作才能振盪,它允許不同的電壓,但是訊號質量和精度較有源晶振差一些。相對價格來說,無源晶振要比有源晶振價格便宜很多。無源晶振兩側通常都會有兩個電容,一般其容值都選在10pF~40pF之間,如果手冊中有具體電容大小的要求則要根據要求來選電容,如果手冊沒有要求,我們用20pF就是比較好的選擇,這是一個長久以來的經驗值,具有極其普遍的適用性。

我們來認識下比較常用的兩種晶振的樣貌,如圖8-1和圖8-2所示。

                                              
            

                                                       圖8-1  27Mhz有源晶振                   圖8-2  11.0592M無源晶振

有源晶振通常有4個引腳,VCCGND,晶振輸出引腳和一個沒有用到的懸空引腳。無源晶振有2個或3個引腳,如果是3個引腳的話,中間引腳是晶振的外殼,使用時要接到GND,兩側的引腳就是晶體的2個引出腳了,這兩個引腳作用是等同的,就像是電阻的2個引腳一樣,沒有正負之分。對於無源晶振,就是用我們的微控制器上的兩個晶振引腳接上去即可,而有源晶振,只接到微控制器的晶振的輸入引腳上,輸出引腳上不需要接,如圖8-3和圖8-4

                         
       


                                        圖8-3 無源晶振接法                           圖8-4 有源晶振接法

8.1.3 復位電路

我們先來分析一下我們的復位電路,如圖8-5所示。



8-5 微控制器復位電路

當這個電路處於穩態時,電容起到隔離直流的作用,隔離了+5V,而左側的復位按鍵是彈起狀態,下邊部分電路就沒有電壓差的產生,所以按鍵和電容C11以下部分的電位都是和GND相等的,也就是0V電壓。我們這個微控制器是高電平復位,低電平正常工作,所以正常工作的電壓是0V電壓,完全OK,沒有問題。

我們再來分析從沒有電到上電的瞬間,電容C11上方是5V電壓,下方是0V電壓,根據我們初中所學的知識,這個時候電容C11要進行充電,正離子從上往下充電,負電子從GND往上充電,這個時候電容對電路來說相當於一根導線,全部電壓都加在了R31這個電阻上,那麼RST埠位置是+5V電壓,隨著電容充電越來越多,即將充滿的時候,電流會越來越小,那RST埠上的電壓值等於電流乘以R31的阻值,也就會越來越小,一直到電容完全充滿後,線路上不再有電流,這個時候RSTGND的電位就相等了也就是0V了。

從這個過程上來看,我們加上這個電路,微控制器系統上電後,RST引腳會先保持一小段時間的高電平而後變成低電平,這個過程就是上電覆位的過程。那這個“一小段時間”到底是多少才合適呢?每種微控制器不完全一樣,51微控制器手冊裡寫的是持續時間不少於2個機器週期的時間。復位電壓值,每種微控制器不完全一樣,我們按照通常值0.7Vcc作為復位電壓值,復位時間的計算過程比較複雜,我這裡只給大家一個結論,時間t=1.2RC,我們用的R4700C0.0000001,那計算得知t564us,遠遠大於2個機器週期(2us),在電路設計的時候一般留夠餘量就行。

按鍵復位(即手動復位)有2個過程,按下按鍵之前,RST的電壓值是0V,當按下按鍵後電路導通,同時電容也會在瞬間進行放電,RST電壓值變化為4700Vcc/(4700+18),會處於高電平復位狀態。當鬆開按鍵後就和上電覆位類似了,先是電容充電,後電流逐漸減小直到RST電壓變0V的過程。我們按下按鍵的時間通常都會有上百毫秒,這個時間足夠復位了。按下按鍵的瞬間,電容兩端的5V電壓(注意不是電源的5VGND之間)會被直接接通,此刻會有一個瞬間的大電流衝擊,會在區域性範圍內產生電磁干擾,為了抑制這個大電流所引起的干擾,我們這裡在電容放電迴路中串入一個18歐的電阻來限流。

如果有的同學已經開始DIY設計自己的電路板的時候,那微控制器最小系統的設計現在已經有了足夠的理論依據了,可以考慮嘗試了。如在製作過程有有問題可到:微控制器論壇http://www.51hei.com/bbs/ 求助作者會不定期回覆的,基礎比較薄弱的同學先不要著急,繼續跟著往下學,把課程都學完了再動手操作也不遲,磨刀不誤砍柴工。

8.2 函式的呼叫

隨著我們程式設計的程式量的增多,如果把所有的語句都寫到main函式中,一方面程式會寫的比較亂,另外一個方面,當我們一個功能需要多次執行的時候,我們就得不斷重複寫語句,這個時候,就引入了函式呼叫的概念。

一個程式一般由若干個子程式模組組成,一個模組實現一個特定的功能,在C語言中,這個模組就用函式來表示。一個C程式一般由一個主函式和若干個其他函式構成。主函式可以呼叫其他函式,其他函式也可以相互呼叫,但其它函式不能呼叫主函式。在我們的51微控制器程式中,還有中斷服務函式,是當相應的中斷到來後自動呼叫執行的,不需要也不能由其他函式呼叫。

函式呼叫的一般形式是:

函式名(實參列表)

函式名就是需要呼叫的函式的名稱,實參列表就是根據實際呼叫函式要傳遞給被呼叫函式的引數列表,不需要傳遞引數的只加括號就可以,傳遞多個引數時要用逗號隔開。在這裡我以上節課的點陣IU的縱向移動的程式改動一下,大家先了解一下基本的函式呼叫。另外,大家不要偷懶,一定把這個程式抄下來做一下實驗加深一下自己的印象。

#include <reg52.h>

sbit  ADDR0 = P1^0;

sbit  ADDR1 = P1^1;

sbit  ADDR2 = P1^2;

sbit  ADDR3 = P1^3;

sbit  ENLED = P1^4;

unsigned char code graph[] = {

    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,

    0xC3,0xE7,0xE7,0xE7,0xE7,0xE7,0xC3,0xFF,

    0x99,0x00,0x00,0x00,0x81,0xC3,0xE7,0xFF,

    0x99,0x99,0x99,0x99,0x99,0x81,0xC3,0xFF,

    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF

};

unsigned char index = 0;   //圖片重新整理索引

void refresh();             //函式宣告

void main()

{

    P0 = 0xFF;      //P0口初始化

    ADDR3 = 0;      //選擇LED點陣

    ENLED = 0;      //LED顯示總使能

    TMOD = 0x01;    //設定定時器0為模式1

    TH0 = 0xFC;     //定時器初值,定時1ms

TL0 = 0x67;

TR0 = 1;        //開啟定時器0

    ET0 = 1;        //使能定時器0中斷

EA = 1;  //開啟總中斷開關

while(1);

}

void refresh()

{

static unsigned char j = 0;

P0 = 0xFF;      //LED點陣動態重新整理

    switch (j)

{

case 0: ADDR0=0; ADDR1=0; ADDR2=0; break;

case 1: ADDR0=1; ADDR1=0; ADDR2=0; break;

case 2: ADDR0=0; ADDR1=1; ADDR2=0; break;

case 3: ADDR0=1; ADDR1=1; ADDR2=0; break;

case 4:ADDR0=0; ADDR1=0; ADDR2=1; break;

case 5:ADDR0=1; ADDR1=0; ADDR2=1; break;

case 6:ADDR0=0; ADDR1=1; ADDR2=1; break;

case 7:ADDR0=1; ADDR1=1; ADDR2=1; break;

        default: break;

    }

    P0 = graph[index+j];

    j++;

    if (j >= 8)

    {

        j = 0;

    }

}

void InterruptTimer0() interrupt 1

{

    static unsigned char tmr = 0;

TH0 = 0xFC;     //溢位後進入中斷重新賦值

    TL0 = 0x67;

    refresh();      //函式呼叫

    tmr++;          //圖片重新整理頻率控制

    if (tmr >= 250) //每隔250ms重新整理一幀

    {

        tmr = 0;

        index++;

        if (index >= 32)

        {

            index = 0;

        }

    }

}

這個程式是對函式的簡單呼叫,但是有以下三個細節需要大家注意一下:

1、函式呼叫的時候,不需要加函式型別。在中斷函式內呼叫重新整理函式的時候我們只寫了refresh(); 而沒有加void

2、呼叫函式與被呼叫函式的位置關係,C語言規定:函式在被呼叫之前,必須先被定時或宣告。意思就是說:在一個檔案中,一個函式應該先定義,然後才能被呼叫,也就是呼叫函式應位於被呼叫函式的下方。但是作為一種通常的程式設計規範,我們推薦main函式寫在最前面(因為它起到提綱挈領的作用),其後再定義各個子函式,而中斷函式則寫在檔案的最後。這時候,我們就在檔案開頭,所有函式定義之前,開闢一塊區域,叫做函式宣告區,用來把被呼叫的子函式宣告一下,如此,該函式就可以被隨意呼叫了。如上述例程所示。

3、函式宣告的時候必須加函式型別,函式的形式引數,最後加上一個分號表示結束。這點請尤其注意,因為函式定義時最後是不能有分號的,初學者很容易因粗心大意搞錯,導致程式編譯不過。

4、函式自身的型別、宣告的型別以及呼叫的型別必須一致。我們這個例子裡refresh函式的型別是void

8.3 函式的形式引數和實際引數

上一個程式在進行函式呼叫的時候,我們不需要任何引數傳遞,所以函式定義和呼叫時refresh()括號裡是空的,但是更多的時候我們呼叫函式,主調函式和被呼叫函式之間是要有引數傳遞關係的。在呼叫一個有引數的函式時,函式名後邊括號裡中的引數叫做實際引數,簡稱實參。而被呼叫的函式在進行定義的時候,括號裡的引數就叫做形式引數,簡稱形參,我們找個簡單程式例子做說明。

unsigned char add(unsigned char x, unsigned char y);

void main()

{

    unsigned char a = 1;

unsigned char b = 2;

unsigned char c = 0;

c = add(a,b);          //呼叫時,ab就是實參,把函式的返回值賦給c

                         //運算完後,c的值就是3

while(1);

}

unsigned char add(unsigned char x, unsigned char y) //xy就是形參

{

unsigned char z = 0;

z = x + y;

return z;         //返回值z的型別就是函式add的型別

}

這個演示程式雖然很簡單,但是形參和實參以及函式返回值等全部內容都囊括在內了。主調函式main和被調函式add之間的資料通過形參和實參發生了傳遞關係,而函式運算完了也把值傳遞給了變數c,函式只要不是void型別的函式,都會有返回值,返回值型別就是函式的型別。關於形參和實參,還有以下幾點需要注意。

1、函式定義中指定的形參,在未發生函式呼叫時不佔記憶體,只有函式呼叫時,函式add中的形參才被分配記憶體單元。在呼叫結束後,形參所佔的記憶體單元也被釋放,這個前邊講過了,形參是區域性變數。