|
//程序名稱:簡(jiǎn)單加法
//用于練習(xí)4x4鍵盤(pán)、數(shù)碼管顯示、數(shù)組應(yīng)用等
//4x4軟鍵盤(pán)布局
// 1 2 3 A
// 4 5 6 B
// 7 8 9 C
// * 0 # D
// 程序中A加號(hào),#回車,*ESC清零
// 數(shù)碼管接P0、P2^4-P2^7
// 鍵盤(pán)接P1
//改編自 http://www.zg4o1577.cn/bbs/dpj-20218-1.html
// 1.3.6 包含綜合應(yīng)用的實(shí)用程序
#include <reg52.h>
sbit KEY_IN_1 = P1^4; //矩陣按鍵的掃描輸入引腳1
sbit KEY_IN_2 = P1^5; //矩陣按鍵的掃描輸入引腳2
sbit KEY_IN_3 = P1^6; //矩陣按鍵的掃描輸入引腳3
sbit KEY_IN_4 = P1^7; //矩陣按鍵的掃描輸入引腳4
sbit KEY_OUT_1 = P1^3; //矩陣按鍵的掃描輸出引腳1
sbit KEY_OUT_2 = P1^2; //矩陣按鍵的掃描輸出引腳2
sbit KEY_OUT_3 = P1^1; //矩陣按鍵的掃描輸出引腳3
sbit KEY_OUT_4 = P1^0; //矩陣按鍵的掃描輸出引腳4
sbit ADDR0 = P2^4;
sbit ADDR1 = P2^5;
sbit ADDR2 = P2^6;
sbit ADDR3 = P2^7;
sbit ENLED = P0;
unsigned char code LedChar[] = {
0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,
0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8e
}; //數(shù)碼管真值表
const unsigned char code KeyCodeMap[4][4] = { //矩陣按鍵編號(hào)到PC標(biāo)準(zhǔn)鍵盤(pán)鍵碼的映射表
{ 0x1B, '0', 0x0D, 0x27 }, //數(shù)字鍵0、ESC鍵、 回車鍵、 向右鍵
{ '7', '8', '9', 0x28 }, //數(shù)字鍵7、數(shù)字鍵8、數(shù)字鍵9、向下鍵
{ '4', '5', '6', 0x25 }, //數(shù)字鍵4、數(shù)字鍵5、數(shù)字鍵6、向左鍵
{ '1', '2', '3', 0x26 } //數(shù)字鍵1、數(shù)字鍵2、數(shù)字鍵3、向上鍵
};
unsigned char KeySta[4][4] = { //全部矩陣按鍵的當(dāng)前狀態(tài)
{1, 1, 1, 1},
{1, 1, 1, 1},
{1, 1, 1, 1},
{1, 1, 1, 1}
}; //由于數(shù)組不能定義成bit型,這里定義成unsigned char型
unsigned char LedBuf[6] = { //數(shù)碼管動(dòng)態(tài)掃描顯示緩沖區(qū)
0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
void DisplayNum(unsigned long num);
void KeyAction(unsigned char keycode);
void main(void)
{
unsigned char i, j;
unsigned char backup[4][4] = { //按鍵值備份,保存前一次的值
{1, 1, 1, 1},
{1, 1, 1, 1},
{1, 1, 1, 1},
{1, 1, 1, 1}
};
//選擇數(shù)碼管進(jìn)行顯示
P0 = 0xFF;
ADDR3 = 1;
ENLED = 0;
//配置T0工作在模式1,定時(shí)1ms
TMOD = 0x01;
TH0 = 0xFC;
TL0 = 0x67;
TR0 = 1;
ET0 = 1;
EA = 1;
while(1)
{
//檢索按鍵狀態(tài)的變化
for (i=0; i<4; i++)
{
for (j=0; j<4; j++)
{
if (backup[j] != KeySta[j])
{
if (backup[j] == 0) //按鍵彈起時(shí)執(zhí)行動(dòng)作
{
KeyAction(KeyCodeMap[j]);
}
backup[j] = KeySta[j];
}
}
}
}
}
void KeyAction(unsigned char keycode)
{
static unsigned long result = 0; //用于保存運(yùn)算結(jié)果
static unsigned long addend = 0; //用于保存輸入的加數(shù)
if ((keycode>='0') && (keycode<='9')) //輸入0-9的數(shù)字
{
addend = (addend*10) + (keycode-'0'); //原數(shù)據(jù)擴(kuò)大10倍,由新輸入的數(shù)字填充其個(gè)位
DisplayNum(addend); //運(yùn)算結(jié)果顯示到數(shù)碼管
}
else if (keycode == 0x26) //向上鍵A用作加號(hào),執(zhí)行加法或連加運(yùn)算
{
result += addend; //進(jìn)行加法運(yùn)算
addend = 0;
DisplayNum(result); //運(yùn)算結(jié)果顯示到數(shù)碼管
}
else if (keycode == 0x0D) //回車鍵#,執(zhí)行加法運(yùn)算(實(shí)際效果與加號(hào)并無(wú)區(qū)別)
{
result += addend; //進(jìn)行加法運(yùn)算
addend = 0;
DisplayNum(result); //運(yùn)算結(jié)果顯示到數(shù)碼管
}
else if (keycode == 0x1B) //Esc鍵*,清零結(jié)果
{
addend = 0;
result = 0;
DisplayNum(addend); //清零后的加數(shù)顯示到數(shù)碼管
}
}
void DisplayNum(unsigned long num)
{
signed char i;
unsigned char buf[4];
for (i=0; i<4; i++) //把長(zhǎng)整型數(shù)轉(zhuǎn)換為4位十進(jìn)制的數(shù)組
{
buf = num % 10;
num /= 10;
}
for (i=3; i>=1; i--) //從最高位起,遇到0即轉(zhuǎn)換為空格,遇到非0即退出
{
if (buf == 0)
{
LedBuf = 0xFF;
}
else
{
break;
}
}
for ( ; i>=0; i--) //剩余低位都如實(shí)轉(zhuǎn)換為數(shù)字
{
LedBuf = LedChar[buf];
}
}
void InterruptTimer0() interrupt 1
{
unsigned char i;
static unsigned char ledcnt = 0; //數(shù)碼管掃描計(jì)數(shù)器
static unsigned char keyout = 0; //矩陣按鍵掃描輸出計(jì)數(shù)器
static unsigned char keybuf[4][4] = { //按鍵掃描緩沖區(qū),保存一段時(shí)間內(nèi)的掃描值
{0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF}
};
TH0 = 0xFC; //溢出后進(jìn)入中斷重新賦值
TL0 = 0x67;
//將一行的4個(gè)按鍵值移入緩沖區(qū)
keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN_1;
keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN_2;
keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN_3;
keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN_4;
//消抖后更新按鍵狀態(tài)
for (i=0; i<4; i++) //每行4個(gè)按鍵,所以循環(huán)4次
{
if ((keybuf[keyout] & 0x0F) == 0x00)
{ //連續(xù)4次掃描值為0,即16ms(4*4ms)內(nèi)都只檢測(cè)到按下?tīng)顟B(tài)時(shí),可認(rèn)為按鍵已按下
KeySta[keyout] = 0;
}
else if ((keybuf[keyout] & 0x0F) == 0x0F)
{ //連續(xù)4次掃描值為1,即16ms(4*4ms)內(nèi)都只檢測(cè)到彈起狀態(tài)時(shí),可認(rèn)為按鍵已彈起
KeySta[keyout] = 1;
}
}
//執(zhí)行下一次的掃描輸出
keyout++;
keyout &= 0x03;
switch (keyout)
{
case 0:
KEY_OUT_4 = 1;
KEY_OUT_1 = 0;
break;
case 1:
KEY_OUT_1 = 1;
KEY_OUT_2 = 0;
break;
case 2:
KEY_OUT_2 = 1;
KEY_OUT_3 = 0;
break;
case 3:
KEY_OUT_3 = 1;
KEY_OUT_4 = 0;
break;
default:
break;
}
//執(zhí)行數(shù)碼管動(dòng)態(tài)掃描顯示
P0 = 0xFF;
switch (ledcnt)
{
case 0: ADDR0=0; ADDR1=1; ADDR2=1; ADDR3=1; break;
case 1: ADDR0=1; ADDR1=0; ADDR2=1; ADDR3=1; break;
case 2: ADDR0=1; ADDR1=1; ADDR2=0; ADDR3=1; break;
case 3: ADDR0=1; ADDR1=1; ADDR2=1; ADDR3=0; break;
case 4: ADDR0=1; ADDR1=1; ADDR2=1; ADDR3=1; break;
default: break;
}
P0 = LedBuf[ledcnt];
ledcnt++;
if (ledcnt >= 5)
{
ledcnt = 0;
}
}
|
|