1. IO介紹
51單片機(jī)總的管腳有40個(gè),但是其中能夠作為IO使用的只有32個(gè),每8個(gè)分為一組,共4組。單片機(jī)要想實(shí)現(xiàn)預(yù)定功能必然要使用到各種IO口,來完成各項(xiàng)功能,包括點(diǎn)亮LED,連接按鍵、鍵盤,各種I2C、SPI設(shè)備等。51單片機(jī),4組IO的結(jié)構(gòu)略有不同,使用時(shí)應(yīng)當(dāng)注意。
P0屬于雙向IO,內(nèi)部沒有上拉電阻,作為輸出時(shí),最好外加上拉電阻。
P1、P2、P3屬于準(zhǔn)雙向IO?!皽?zhǔn)”體現(xiàn)在輸入時(shí),必須先輸出“1”,才能正確讀到IO的輸入情況。
?
P3口的各個(gè)IO均有復(fù)用功能:
2. IO編程
對于IO的操作無非是讀輸入和寫輸出,通過讀寫相應(yīng)的寄存器(P0、P1、P2、P3)就可以實(shí)現(xiàn)。
?
2.1 字節(jié)尋址
字節(jié)尋址可以一次把8個(gè)IO全部訪問了,使用時(shí)把Px(x=0、1、2或3)當(dāng)作無符號字符變量(unsigned char)即可。
2.2 位尋址
51單片機(jī)有一類特殊的變量——位變量(bit),可以用來保存“0”或者“1”。
為了讀寫某個(gè)IO,可以定義特殊位變量(sbit)指定某一個(gè)IO,再進(jìn)行讀寫
?
#include "reg52.h"
sbit LED=P1^0;
bit temp;
void main()
{
temp=LED;//確保temp為位變量(bit)
LED=1;
LED=0;
LED=temp;
}
?
3.常用器件的驅(qū)動(dòng)電路
3.1 LED
單片機(jī)能夠提供的電流有限,一般采用這種方式驅(qū)動(dòng)LED:
當(dāng)P2^0=1是,LED兩端電壓差位0V,LED不發(fā)光。當(dāng)P2^0=1是,LED兩端存在電壓差,LED發(fā)光,串聯(lián)電阻的作用在于限流,阻值根據(jù)電源電壓和LED工作電流決定
?
3.2?數(shù)碼管。
數(shù)碼管本質(zhì)是發(fā)光二極管按照一定位置排列的顯示數(shù)字的器件,可分為共陰極和共陽極兩類。按照數(shù)量可分為一位,兩位,四位甚至八位。
一位七段共陽極數(shù)碼管:
有的數(shù)碼管有八段,右下角會增加一個(gè)小數(shù)點(diǎn)。
?
當(dāng)驅(qū)動(dòng)兩位8段數(shù)碼管時(shí),按上面的方式會占用16個(gè)IO,這種方式成為靜態(tài)顯示。靜態(tài)顯示可以控制每一個(gè)數(shù)碼管,但是會極大的占用IO資源,當(dāng)數(shù)碼管數(shù)量較多時(shí),這種方式明顯不適合。
?
與靜態(tài)相對應(yīng)的是動(dòng)態(tài)顯示。每一個(gè)數(shù)碼管顯示一段時(shí)間,然后在切換到下一個(gè)。根據(jù)人眼的視覺暫留效應(yīng),只要刷新的頻率超過24Hz,在人眼中就是連續(xù)的。把每一位數(shù)碼管的a,b,c,d,e,f,g,dp接在同一組IO上,再用另一組IO來控制具體顯示哪一個(gè)數(shù)碼管(公共端)。
?
下面四位共陰極數(shù)碼管示例,公共端用三極管做開關(guān):
數(shù)碼管顯示段碼如下
?
unsigned char code DUMA[]={ //共陰極顯示段碼,共陽極取反即可
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f, //0-9
0x77,0x7c,0x39,0x5e,0x79,0x71 //a-f
};
?
3.3 按鍵
可以用這種最簡單的方式連接在IO上,為了保證能正確讀到輸入,先輸出“1”。如下圖,當(dāng)按鍵按下,P1^0=0, 當(dāng)按鍵松開,P1^0=1。
但實(shí)際上,由于開關(guān)接觸瞬間,電壓會產(chǎn)生不穩(wěn)定的跳變,稱為抖動(dòng),如下圖:
抖動(dòng)的時(shí)間小于10ms,因此當(dāng)我們檢測到電平變化是,延時(shí)10ms即可。
?
3.4 鍵盤
通過把按鍵組成4x4矩陣,可以使用8個(gè)IO連接16個(gè)按鍵。當(dāng)按鍵數(shù)量較多時(shí),采用這種方式可以大大節(jié)約IO資源。
下面代碼是這種矩陣鍵盤的驅(qū)動(dòng),delay10ms()根據(jù)具體的情況定義。
?
#define key_port P2
?
//檢測按鍵的返回值,可以檢測多個(gè)按鍵,返回一個(gè)16位的unsigned int型變量,某一個(gè)按鍵按下,相應(yīng)位置“1”
unsigned int KeyBoard_scan(void)
{
unsigned int ms=0,value=0;
key_port=0x0f;
while(key_port!=0x0f)
{
delay10ms();
if(key_port!=0x0f)
{
key_port=0x7f;
value |= (key_port^0x7f);
key_port=0xbf;
value |= (key_port^0xbf)<<4;
key_port=0xdf;
value |= (key_port^0xdf)<<8;
key_port=0xef;
value |= (key_port^0xef)<<12;
}
key_port=0x0f;
}
return value;
}
//檢測單個(gè)按鍵,value參數(shù)會寫回相應(yīng)鍵值0-15,返回值表示按鍵按下的時(shí)間,ms計(jì)
unsigned int KeyBoard(unsigned char *value)
{
unsigned int ms=0;
key_port=0x0f;
if(key_port!=0x0f)
{
delay10ms();
if(key_port!=0x0f)
{
ms=10;
key_port=0X0f;
switch(key_port)
{
case(0X07): *value=0;break;
case(0X0b): *value=1;break;
case(0X0d): *value=2;break;
case(0X0e): *value=3;break;
default: *value=0xff;
}
key_port=0Xf0;
switch(key_port)
{
case(0X70): *value=*value;break;
case(0Xb0): *value=*value+4;break;
case(0Xd0): *value=*value+8;break;
case(0Xe0): *value=*value+12;break;
default: *value=0xff;
}
while((key_port!=0xf0))
{
delay_ms_keyboard(1);
ms++;
}
return ms;
}
else *value=0xff;
}
else *value=0xff;
return 0;
}
?
3.5?蜂鳴器
蜂鳴器分為有源蜂鳴器和無源蜂鳴器兩種。
有源蜂鳴器用低電平就可以觸發(fā),發(fā)出的聲音頻率不會發(fā)生變化。
無源蜂鳴器需要用脈沖觸發(fā),脈沖的頻率決定了聲音的頻率。
無源蜂鳴器的驅(qū)動(dòng)電路如下:
審核編輯:湯梓紅
評論