第8章-函數(shù)進(jìn)階與按鍵(下,課后作業(yè)+抓波欣賞)
這節(jié)課,真麻煩,全書最難的之一,


// 課后第4題,按一個鍵K12-DOWN,數(shù)碼管從F減到0
// 按鍵的掃描,也結(jié)合了http://www.dumenmen.com吳堅(jiān)鴻老師的思路
// 一切皆計(jì)數(shù)
#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;
// 數(shù)碼管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題,減法計(jì)算器,干脆擴(kuò)展成加減乘除
// 在老師的基礎(chǔ)上,上=加,下=減,左=乘,右=除(除數(shù)為0,不理會)
// 為了簡單,不支持連續(xù)運(yùn)算,必須按步奏來
// 步奏0:輸入x,輸入+/-號等; 得到第一個操作數(shù)x和運(yùn)算符op
// 步奏1:輸入y,輸入等號得到結(jié)果;得到第二個操作數(shù)y,,然后計(jì)算 y = (x op y)
// 步奏2:再輸入+/-號等,回到步奏1;得到下一次的運(yùn)算符op,上次結(jié)果作為第一個操作數(shù)x,
// 按鍵的掃描,也結(jié)合了http://www.dumenmen.com吳堅(jiān)鴻老師的思路
// 一切皆計(jì)數(shù)
#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;
// 數(shù)碼管code
u8 code LedChar[16] =
{
?? ?0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
?? ?0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
// 數(shù)碼管緩沖區(qū)
u8 LedBuff[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
u8 key = 0; // 0=沒有按鍵;非零=按鍵code
u8 code KeyCodeMap[4][4] =
{
?? ?{0x31, 0x32, 0x33, 0x26}, // 數(shù)字1,2,3,UP
?? ?{0x34, 0x35, 0x36, 0x25}, // 數(shù)字4,5,6,LEFT
?? ?{0x37, 0x38, 0x39, 0x28}, // 數(shù)字7,8,9,DOWN
?? ?{0x30, 0x1B, 0x0D, 0x27}, // 數(shù)字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,輸入+/-號等; 得到第一個操作數(shù)x和運(yùn)算符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,輸入等號得到結(jié)果;得到第二個操作數(shù)y,,然后計(jì)算 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;得到下一次的運(yùn)算符op,上次結(jié)果作為第一個操作數(shù)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++; // 進(jìn)入下一步,1ms以后進(jìn)來讀取列
?? ??? ?break;
?? ?case 1:
?? ??? ?if (KEYIN1 && KEYIN2 && KEYIN3 && KEYIN4)
?? ??? ?{
?? ??? ??? ?// 沒有任何按鍵按下,或者發(fā)生了抖動
?? ??? ??? ?cnt = 0;
?? ??? ??? ?// 切換下一行拉低
?? ??? ??? ?hang++;
?? ??? ??? ?hang &= 0x03;
?? ??? ??? ?step = 0; // 回到第一步
?? ??? ?}
?? ??? ?else
?? ??? ?{
?? ??? ??? ?cnt++;?? ??????? // 有按鍵按下,計(jì)數(shù)器++
?? ??? ??? ?if (cnt == 40) // 能堅(jiān)持到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; // 關(guān)閉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

