第8章-函数进阶与按键(下,课后作业+抓波欣赏)
这节课,真麻烦,全书最难的之一,


// 课后第4题,按一个键K12-DOWN,数码管从F减到0
// 按键的扫描,也结合了http://www.dumenmen.com吴坚鸿老师的思路
// 一切皆计数
#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;
// 数码管code
u8 code LedChar[16] =
{
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
bit keyFlag = 0; // 0=没有按键;
void main(void)
{
u8 cnt;
TMOD = 0x01;
TH0 = 0xFC;
TL0 = 0x66;
ET0 = EA = TR0 = 1;
ENLED=0;
ADDR3=1;
ADDR2=0;
ADDR1=0;
ADDR0=0;
KEYOUT3=0;
cnt=0x0F;
P0 = LedChar[cnt];
while (1)
{
if(keyFlag)
{
keyFlag=0;
cnt--;
cnt&=0x0F;
P0=LedChar[cnt];
}
}
}
void Timer0_ISR(void) interrupt 1
{
static u16 cnt=0;
TH0 = 0xFC;
TL0 = 0x66;
if(KEYIN4==0)
{
cnt++;
if(cnt==40)//40ms
{
keyFlag=1;
}
}
else
{
cnt=0;
}
}
// 课后第5题,减法计算器,干脆扩展成加减乘除
// 在老师的基础上,上=加,下=减,左=乘,右=除(除数为0,不理会)
// 为了简单,不支持连续运算,必须按步奏来
// 步奏0:输入x,输入+/-号等; 得到第一个操作数x和运算符op
// 步奏1:输入y,输入等号得到结果;得到第二个操作数y,,然后计算 y = (x op y)
// 步奏2:再输入+/-号等,回到步奏1;得到下一次的运算符op,上次结果作为第一个操作数x,
// 按键的扫描,也结合了http://www.dumenmen.com吴坚鸿老师的思路
// 一切皆计数
#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;
// 数码管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 key = 0; // 0=没有按键;非零=按键code
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;
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 u8 step = 0;
static u32 result = 0;
static u32 addend = 0;
static u8 op;
if (keycode == 0x1B) // esc
{
addend = 0;
result = 0;
step = 0;
ShowNumber(0);
return;
}
switch (step)
{
case 0:
// 步奏0:输入x,输入+/-号等; 得到第一个操作数x和运算符op
if (keycode >= '0' && keycode <= '9')
{
addend = addend * 10 + keycode - '0';
ShowNumber(addend);
}
else if (keycode == 0x25 || keycode == 0x26 || keycode == 0x27 || keycode == 0x28) // 加减乘除
{
result = addend;
addend = 0;
op = keycode;
ShowNumber(0);
step++;
}
break;
case 1:
// 步奏1:输入y,输入等号得到结果;得到第二个操作数y,,然后计算 y = (x op y)
if (keycode >= '0' && keycode <= '9')
{
addend = addend * 10 + keycode - '0';
ShowNumber(addend);
}
else if (keycode == 0x0D) // enter =
{
if (op == 0x26) //+
{
result += addend;
}
else if (op == 0x28) //-
{
result -= addend;
}
else if (op == 0x25) //*
{
result *= addend;
}
else if (op == 0x27) // /
{
if (addend != 0)
{
result /= addend;
}
}
ShowNumber(result);
step++;
}
break;
case 2:
// 步奏2:再输入+/-,回到步奏1;得到下一次的运算符op,上次结果作为第一个操作数x,
if (keycode == 0x25 || keycode == 0x26 || keycode == 0x27 || keycode == 0x28) // 加减乘除
{
op = keycode;
addend = 0;
ShowNumber(0);
step = 1;
}
break;
default:
break;
}
}
void KeyDriver(void)
{
if (key)
{
KeyAction(key);
key = 0;
}
}
void KeyScan(void)
{
static u8 step = 0;
static u8 hang = 0; // 控制4个线拉低
static u16 cnt = 0;
switch (step)
{
case 0: // 拉低1行
if (hang == 0)
{
KEYOUT4 = 1;
KEYOUT1 = 0;
}
else if (hang == 1)
{
KEYOUT1 = 1;
KEYOUT2 = 0;
}
else if (hang == 2)
{
KEYOUT2 = 1;
KEYOUT3 = 0;
}
else if (hang == 3)
{
KEYOUT3 = 1;
KEYOUT4 = 0;
}
step++; // 进入下一步,1ms以后进来读取列
break;
case 1:
if (KEYIN1 && KEYIN2 && KEYIN3 && KEYIN4)
{
// 没有任何按键按下,或者发生了抖动
cnt = 0;
// 切换下一行拉低
hang++;
hang &= 0x03;
step = 0; // 回到第一步
}
else
{
cnt++; // 有按键按下,计数器++
if (cnt == 40) // 能坚持到40ms的,算一次合理按键
{
u8 lie;
if (KEYIN1 == 0)
{
lie = 0;
}
else if (KEYIN2 == 0)
{
lie = 1;
}
else if (KEYIN3 == 0)
{
lie = 2;
}
else if (KEYIN4 == 0)
{
lie = 3;
}
key = KeyCodeMap[hang][lie];
}
}
break;
}
}
void LedScan(void)
{
static u8 i = 0;
ENLED = 1; // 关闭138;
ADDR3 = 1; //确保选138的后八路
P1 &= 0xF8; // 1111-1000
P1 |= i; // xxxx-xiii;
P0=LedBuff[i];
ENLED = 0;
if (++i == 6)
{
i = 0;
}
}
void Timer0_ISR(void) interrupt 1
{
TH0 = 0xFC;
TL0 = 0x66;
LedScan();
KeyScan();
}

课后第5题,波形抓取,按键1和5


最后欣赏一下,老师课堂上的例子,波形抓取,按键1和5

