第8章-函数进阶与按键(上:跟堂作业)
这节太难了,2个多小时分成
由于代码量大,把跟堂作业也搬过来了







课上例子,单键中断消抖读取
#include <reg52.h>
typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned long ulong;
sbit ADDR0 = P1 ^ 0;
sbit ADDR1 = P1 ^ 1;
sbit ADDR2 = P1 ^ 2;
sbit ADDR3 = P1 ^ 3;
sbit ENLED = P1 ^ 4;
sbit KEY1 = P2 ^ 4;
sbit KEY2 = P2 ^ 5;
sbit KEY3 = P2 ^ 6;
sbit KEY4 = P2 ^ 7;
// 数码管code
uchar code LedChar[] =
{
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
bit KeySta=1;//中断读取按键后放到这儿
void main(void)
{
uchar cnt = 0;
bit backup = 1;
bit keybuf = 1;
ENLED = 0;
ADDR3 = 1;
ADDR2 = 0;
ADDR1 = 0;
ADDR0 = 0;
TMOD=0x01;
TH0=0xF8;
TL0=0xCD;
ET0=EA=TR0=1;
P2 = 0xF7;
P0 = LedChar[cnt];
while (1)
{
if(KeySta != backup)
{
if(backup==0)
{
//松开
cnt++;
if(cnt>=10)
{
cnt=0;
}
P0=LedChar[cnt];
}
else
{
//按下
}
backup=KeySta;//保存方便,下次比对
}
}
}
void Timer0_ISR(void)interrupt 1
{
static uchar keybuf=0xFF;
TH0=0xF8;
TL0=0xCD;
keybuf=(keybuf<<1)|KEY4;//读取按键状态,累计到这个类似FIFO变量里面
if(keybuf==0)
{
//按下
KeySta=0;
}
else if(keybuf==0xFF)
{
//松开
KeySta=1;
}
else
{
//抖动
}
}
课上例子,矩阵按键中断消抖读取
#include <reg52.h>
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
typedef signed char i8;
typedef signed int i16;
typedef signed long i32;
sbit ADDR0 = P1 ^ 0;
sbit ADDR1 = P1 ^ 1;
sbit ADDR2 = P1 ^ 2;
sbit ADDR3 = P1 ^ 3;
sbit ENLED = P1 ^ 4;
//4个列,要读取
sbit KEYIN1=P2^4;
sbit KEYIN2=P2^5;
sbit KEYIN3=P2^6;
sbit KEYIN4=P2^7;
//4个行,要拉低
sbit KEYOUT1=P2^3;
sbit KEYOUT2=P2^2;
sbit KEYOUT3=P2^1;
sbit KEYOUT4=P2^0;
//保存中断消抖后,读取按键状态
u8 KeySta[4][4]=
{
{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}
};
// 数码管code
u8 code LedChar[] =
{
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
void main(void)
{
//保存上一次按键的状态
u8 backup[4][4]=
{
{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}
};
u8 i,j,cnt;
ENLED = 0;
ADDR3 = 1;
ADDR2 = 0;
ADDR1 = 0;
ADDR0 = 0;
TMOD=0x01;
TH0=0xF8;
TL0=0xCD;
ET0=EA=TR0=1;
P0 = LedChar[cnt];
while (1)
{
//扫描上一次状态和现在状态,有区别吗
for(i=0; i<4; i++) //out
{
for(j=0; j<4; j++) //in
{
if(backup[i][j]!=KeySta[i][j])
{
if(backup[i][j]==0)
{
//松开
P0=LedChar[i*4+j];
}
else
{
//按下
}
backup[i][j]=KeySta[i][j];
}
}
}
}
}
void Timer0_ISR(void)interrupt 1
{
static u8 keyout=0;//控制4个线拉低的
u8 i=0;
//保存按键每一次读取的值
static u8 keybuf[4][4]={
{0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF}
};
TH0=0xF8;
TL0=0xCD;
//读keyout拉低行的,4个列按键状态
keybuf[keyout][0]=(keybuf[keyout][0]<<1)|KEYIN1;//读第1列按键
keybuf[keyout][1]=(keybuf[keyout][1]<<1)|KEYIN2;//读第2列按键
keybuf[keyout][2]=(keybuf[keyout][2]<<1)|KEYIN3;//读第3列按键
keybuf[keyout][3]=(keybuf[keyout][3]<<1)|KEYIN4;//读第4列按键
//判断刚读取的4个按键,是否稳定
for(i=0; i<4; i++)
{
if((keybuf[keyout][i] & 0x0F) == 0x00)//稳定为0
{
KeySta[keyout][i]=0;
}
else if((keybuf[keyout][i] & 0x0F) == 0x0F)//稳定为1
{
KeySta[keyout][i]=1;
}
else
{
//抖动
}
}
//切换下一行拉低,方便下次读取
keyout++;
keyout&=0x03;
switch(keyout)
{
case 0:
KEYOUT4=1;
KEYOUT1=0;
break;
case 1:
KEYOUT1=1;
KEYOUT2=0;
break;
case 2:
KEYOUT2=1;
KEYOUT3=0;
break;
case 3:
KEYOUT3=1;
KEYOUT4=0;
break;
}
}
//分析,太费内存了把,使用了16*3约50个字节的变量
课上例子,加法器,up=加;enter是等于;
#include <reg52.h>
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
typedef signed char i8;
typedef signed int i16;
typedef signed long i32;
sbit ADDR0 = P1 ^ 0;
sbit ADDR1 = P1 ^ 1;
sbit ADDR2 = P1 ^ 2;
sbit ADDR3 = P1 ^ 3;
sbit ENLED = P1 ^ 4;
// 4个列,要读取
sbit KEYIN1 = P2 ^ 4;
sbit KEYIN2 = P2 ^ 5;
sbit KEYIN3 = P2 ^ 6;
sbit KEYIN4 = P2 ^ 7;
// 4个行,要拉低
sbit KEYOUT1 = P2 ^ 3;
sbit KEYOUT2 = P2 ^ 2;
sbit KEYOUT3 = P2 ^ 1;
sbit KEYOUT4 = P2 ^ 0;
// 保存中断消抖后,读取按键状态
u8 KeySta[4][4] =
{
{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}};
// 数码管code
u8 code LedChar[16] =
{
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E};
// 数码管缓冲区
u8 LedBuff[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
u8 code KeyCodeMap[4][4] = {
{0x31, 0x32, 0x33, 0x26}, // 数字1,2,3,UP
{0x34, 0x35, 0x36, 0x25}, // 数字4,5,6,LEFT
{0x37, 0x38, 0x39, 0x28}, // 数字7,8,9,DOWN
{0x30, 0x1B, 0x0D, 0x27}, // 数字0,ESC,ENTER,RIGHT
};
void KeyDriver();
void main(void)
{
TMOD = 0x01;
TH0 = 0xFC;
TL0 = 0x66;
ET0 = EA = TR0 = 1;
ENLED = 0;
ADDR3 = 1;
LedBuff[0] = LedChar[0];
while (1)
{
KeyDriver();
}
}
void ShowNumber(u32 num)
{
u8 buf[6];
u8 i,j;
for (i = 0; i < 6; i++)
{
buf[i] = num % 10;
num /= 10;
}
for (i = 5; i >= 1; i--)
{
if (buf[i] == 0)
{
LedBuff[i] = 0xFF; // 不显示
}
else
{
break;
}
}
for (j=0; j<=i;j++)
{
LedBuff[j] = LedChar[buf[j]];
}
}
void KeyAction(u8 keycode)
{
static u32 result = 0;
static u32 addend = 0;
if ((keycode >= 0x30) && (keycode <= 0x39))
{
// num
addend = (addend * 10) + (keycode - 0x30);
ShowNumber(addend);
}
else if (keycode == 0x26) // up,+
{
result += addend;
addend = 0;
ShowNumber(result);
}
else if (keycode == 0x0D) // enter =
{
result += addend;
addend = 0;
ShowNumber(result);
}
else if (keycode == 0x1B) // esc clear
{
addend = 0;
result = 0;
ShowNumber(0);
}
}
void KeyDriver(void)
{
// 保存上一次按键的状态
static u8 backup[4][4] = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}};
u8 i, j;
// 扫描上一次状态和现在状态,有区别吗
for (i = 0; i < 4; i++) // out
{
for (j = 0; j < 4; j++) // in
{
if (backup[i][j] != KeySta[i][j])
{
if (backup[i][j] == 0)
{
KeyAction(KeyCodeMap[i][j]);
}
else
{
// 按下
}
backup[i][j] = KeySta[i][j];
}
}
}
}
void KeyScan(void)
{
static u8 keyout = 0; // 控制4个线拉低的
u8 i = 0;
// 保存按键每一次读取的值
static u8 keybuf[4][4] = {{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}};
// 读keyout拉低行的,4个列按键状态
keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEYIN1; // 读第1列按键
keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEYIN2; // 读第2列按键
keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEYIN3; // 读第3列按键
keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEYIN4; // 读第4列按键
// 判断刚读取的4个按键,是否稳定
for (i = 0; i < 4; i++)
{
if ((keybuf[keyout][i] & 0x0F) == 0x00) // 稳定为0
{
KeySta[keyout][i] = 0;
}
else if ((keybuf[keyout][i] & 0x0F) == 0x0F) // 稳定为1
{
KeySta[keyout][i] = 1;
}
else
{
// 抖动
}
}
// 切换下一行拉低,方便下次读取
keyout++;
keyout &= 0x03;
switch (keyout)
{
case 0:
KEYOUT4 = 1;
KEYOUT1 = 0;
break;
case 1:
KEYOUT1 = 1;
KEYOUT2 = 0;
break;
case 2:
KEYOUT2 = 1;
KEYOUT3 = 0;
break;
case 3:
KEYOUT3 = 1;
KEYOUT4 = 0;
break;
}
}
void LedScan(void)
{
static u8 i = 0;
P0 = 0xFF; // 消影
switch (i)
{
case 0:
ADDR2 = 0;
ADDR1 = 0;
ADDR0 = 0;
i++;
P0 = LedBuff[0];
break;
case 1:
ADDR2 = 0;
ADDR1 = 0;
ADDR0 = 1;
i++;
P0 = LedBuff[1];
break;
case 2:
ADDR2 = 0;
ADDR1 = 1;
ADDR0 = 0;
i++;
P0 = LedBuff[2];
break;
case 3:
ADDR2 = 0;
ADDR1 = 1;
ADDR0 = 1;
i++;
P0 = LedBuff[3];
break;
case 4:
ADDR2 = 1;
ADDR1 = 0;
ADDR0 = 0;
i++;
P0 = LedBuff[4];
break;
case 5:
ADDR2 = 1;
ADDR1 = 0;
ADDR0 = 1;
P0 = LedBuff[5];
i = 0;
break;
}
}
void Timer0_ISR(void) interrupt 1
{
TH0 = 0xFC;
TL0 = 0x66;
LedScan();
KeyScan();
}
//课后作业在下一篇