一、目录
(1)例程1:以独立键盘程序为基础将]5跳线帽切换为矩阵键盘模式后先写出其中一列矩阵按键的程序。以S7、S6、S5、S4为例。
(4)矩阵键盘例程(列扫描法)。本例以按下依次按下S4-S16按键数码管依次显示1 9、-、5、灭、为例。本例题使用静态数码管。
(5)例程5:【选修】独立键盘→矩阵键盘 列扫描(四列)扫描端口整体操作法;
二、例程
(1)例程1:以独立键盘程序为基础将]5跳线帽切换为矩阵键盘模式后先写出其中一列矩阵按键的程序。以S7、S6、S5、S4为例。
- 只在原来的KeyScan函数的第一行加上P44 = 0;即可实现在矩阵键盘中使用一列键盘;
//头文件声明区域
#include <STC15F2K60S2.H>
#include<intrins.h>
//变量声明区域
unsigned char S7_Flag = 0,S6_Flag = 0,S5_Flag = 0,S4_Flag = 0;
//函数声明区域
//毫秒级延时函数
void Delay(unsigned int ms);
//按键扫描函数
void KeyScan(void);
//程序主体
void main()
{
P2 = 0XA0;P0 = 0X00;P2 = 0X80;P0 = 0XFF;//初始化程序
while(1)
{
KeyScan();
if(S7_Flag == 1) {S7_Flag = 0; P00 = 0;}
if(S6_Flag == 1) {S6_Flag = 0; P00 = 1;}
if(S5_Flag == 1) {S5_Flag = 0; P06 = 0;}
if(S4_Flag == 1) {S4_Flag = 0; P06 = 1;}
}
}
//毫秒级延时函数
void Delay(unsigned int ms) //@11.0592MHz
{
unsigned char i, j;
while(ms--)
{
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
}
//按键扫描函数
void KeyScan(void)
{
P44 = 0;
if(P30 == 0)
{
Delay(10);
if(P30 == 0)
{
S7_Flag = 1;
while(!P30);
}
}
if(P31 == 0)
{
Delay(10);
if(P31 == 0)
{
S6_Flag = 1;
while(!P31);
}
}
if(P32 == 0)
{
Delay(10);
if(P32 == 0)
{
S5_Flag =1;
while(!P32);
}
}
if(P33 == 0)
{
Delay(10);
if(P33 == 0)
{
S4_Flag = 1;
while(!P33);
}
}
}
(2)例程2:根据例程1可以编写多列矩阵键盘程序。本例以写出第一列、第二列矩阵键盘程序按下S7、56、S5、S4、S11、510、59、S8按键,依次用第一位数码管依次显示1、2、3、4、5、6、7、8数值。
- 假设只写出第一列,将P44置为0时候,按下按键后,只要判断P30 P31 P32 P33谁为0即可;只写第二列,将P42置为0,仍是只要判断P30 P31 P32 P33谁为即可;
- 但是如果现在要同时写两列,应该如何写,思路:因为单片机程序执行的非常快,所以可以先讲P44置为0,然后对第一列进行扫描,如果有按键被按下,即可知道哪个按键被按下;如果没有按键被按下,那么将接下来P44置为1,将P42置为0,再对第二列进行扫描,不停地进行扫描,循环进行,即可知道哪个按键被按下。
//头文件声明区域
#include <STC15F2K60S2.H>
#include<intrins.h>
//变量声明区域
unsigned char S7_Flag = 0,S6_Flag = 0,S5_Flag = 0,S4_Flag = 0,S11_Flag = 0,S10_Flag = 0,S9_Flag = 0,S8_Flag = 0;
unsigned char code SEG[] = {0XF0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF};
//函数声明区域
//毫秒级延时函数
void Delay(unsigned int ms);
//按键扫描函数
void KeyScan(void);
//程序主体
void main()
{
P2 = 0XA0;P0 = 0X00;P2 = 0X80;P0 = 0XFF;//初始化程序
P2 = 0XC0;P0 = 0X01;P2 = 0XFF;P0 = 0XFF;//打开第一个数码管程序
while(1)
{
KeyScan();
if(S7_Flag == 1) {S7_Flag = 0; P0 = SEG[1];}
if(S6_Flag == 1) {S6_Flag = 0; P0 = SEG[2];}
if(S5_Flag == 1) {S5_Flag = 0; P0 = SEG[3];}
if(S4_Flag == 1) {S4_Flag = 0; P0 = SEG[4];}
if(S11_Flag == 1) {S11_Flag = 0; P0 = SEG[5];}
if(S10_Flag == 1) {S10_Flag = 0; P0 = SEG[6];}
if(S9_Flag == 1) {S9_Flag = 0; P0 = SEG[7];}
if(S8_Flag == 1) {S8_Flag = 0; P0 = SEG[8];}
}
}
//毫秒级延时函数
void Delay(unsigned int ms) //@11.0592MHz
{
unsigned char i, j;
while(ms--)
{
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
}
//按键扫描函数
void KeyScan(void)
{
P44 = 0;P42 = 1;
if(P30 == 0)
{
Delay(10);
if(P30 == 0)
{
S7_Flag = 1;
while(!P30);
}
}
if(P31 == 0)
{
Delay(10);
if(P31 == 0)
{
S6_Flag = 1;
while(!P31);
}
}
if(P32 == 0)
{
Delay(10);
if(P32 == 0)
{
S5_Flag =1;
while(!P32);
}
}
if(P33 == 0)
{
Delay(10);
if(P33 == 0)
{
S4_Flag = 1;
while(!P33);
}
}
P44 = 1;P42 = 0;
if(P30 == 0)
{
Delay(10);
if(P30 == 0)
{
S11_Flag = 1;
while(!P30);
}
}
if(P31 == 0)
{
Delay(10);
if(P31 == 0)
{
S10_Flag = 1;
while(!P31);
}
}
if(P32 == 0)
{
Delay(10);
if(P32 == 0)
{
S9_Flag =1;
while(!P32);
}
}
if(P33 == 0)
{
Delay(10);
if(P33 == 0)
{
S8_Flag = 1;
while(!P33);
}
}
}
(3)例程3:根据例程1可以编写多列矩阵键盘程序。本例以写出第一列、第二列矩阵键盘程序按下57、56、S5、54、S11、S10、59、S8按键,依次用第一位数码管依次显示1、2、3、4、5、6、7、8数值。注:使用一个按键关键词来代替某一个按键被按下。
//头文件声明区域
#include <STC15F2K60S2.H>
#include<intrins.h>
//变量声明区域
unsigned char Key_Flag = 0;
unsigned char code SEG[] = {0XF0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF};
//函数声明区域
//毫秒级延时函数
void Delay(unsigned int ms);
//按键扫描函数
void KeyScan(void);
//程序主体
void main()
{
P2 = 0XA0;P0 = 0X00;P2 = 0X80;P0 = 0XFF;//初始化程序
P2 = 0XC0;P0 = 0X01;P2 = 0XFF;P0 = 0XFF;//打开第一个数码管程序
while(1)
{
KeyScan();
switch(Key_Flag)
{
case 7:P0 = SEG[1];break;
case 6:P0 = SEG[2];break;
case 5:P0 = SEG[3];break;
case 4:P0 = SEG[4];break;
case 11:P0 = SEG[5];break;
case 10:P0 = SEG[6];break;
case 9:P0 = SEG[7];break;
case 8:P0 = SEG[8];break;
default:break;
}
}
}
//毫秒级延时函数
void Delay(unsigned int ms) //@11.0592MHz
{
unsigned char i, j;
while(ms--)
{
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
}
//按键扫描函数
void KeyScan(void)
{
P44 = 0;P42 = 1;
if(P30 == 0)
{
Delay(10);
if(P30 == 0)
{
Key_Flag = 7;
while(!P30);
}
}
if(P31 == 0)
{
Delay(10);
if(P31 == 0)
{
Key_Flag = 6;
while(!P31);
}
}
if(P32 == 0)
{
Delay(10);
if(P32 == 0)
{
Key_Flag = 5;
while(!P32);
}
}
if(P33 == 0)
{
Delay(10);
if(P33 == 0)
{
Key_Flag = 4 ;
while(!P33);
}
}
P44 = 1;P42 = 0;
if(P30 == 0)
{
Delay(10);
if(P30 == 0)
{
Key_Flag = 11;
while(!P30);
}
}
if(P31 == 0)
{
Delay(10);
if(P31 == 0)
{
Key_Flag = 10;
while(!P31);
}
}
if(P32 == 0)
{
Delay(10);
if(P32 == 0)
{
Key_Flag = 9;
while(!P32);
}
}
if(P33 == 0)
{
Delay(10);
if(P33 == 0)
{
Key_Flag = 8;
while(!P33);
}
}
}
(4)矩阵键盘例程(列扫描法)。本例以按下依次按下S4-S16按键数码管依次显示1 9、-、5、灭、为例。本例题使用静态数码管。
- 为什么要写P3 = 0X7F; 在老版的蓝桥杯中,P42和P44 是 P36和P37,89C52中并没有P42和P44引脚,后来89C52被淘汰,为了兼容MM模式(总线操作模式),为了15能够代替C52的WR和RD引脚,就把P42和P44设为WR和RD。
//头文件声明区域
#include <STC15F2K60S2.H>
#include<intrins.h>
//变量声明区域
unsigned char Key_Flag = 0;
unsigned char code SEG[] = {0XF0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF};
//函数声明区域
//毫秒级延时函数
void Delay(unsigned int ms);
//按键扫描函数
void ARRKeyScan(void);
//程序主体
void main()
{
P2 = 0XA0;P0 = 0X00;P2 = 0X80;P0 = 0XFF;//初始化程序
P2 = 0XC0;P0 = 0X01;P2 = 0XFF;P0 = 0XFF;//打开第一个数码管程序
while(1)
{
ARRKeyScan();
if(Key_Flag != 0)
{
P0 = SEG[Key_Flag];
Key_Flag = 0;
}
}
}
//毫秒级延时函数
void Delay(unsigned int ms) //@11.0592MHz
{
unsigned char i, j;
while(ms--)
{
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
}
//按键扫描函数
void ARRKeyScan(void)
{
unsigned char temp;//定义局部变量用来存储从P3口读出的数值
P44 = 0;P42 = 1;P3 = 0X7F;//0111 1111 扫描第一列
temp = P3; //将P3口读出的数字赋值给temp
temp &= 0X0F; //xxxx xxxx & 0000 1111 = 0000 xxxx temp高四位清零
if(temp != 0X0F) //如果低四位不全为1,则肯定有按键被按下
{
Delay(10); //消抖
temp = P3;
temp &= 0X0F;
if(temp != 0X0F) //真的有按键被按下
{
temp = P3;
switch(temp) //
{
case 0X7E:Key_Flag = 4;break; // 0111 1110
case 0X7D:Key_Flag = 3;break; // 0111 1101
case 0X7B:Key_Flag = 2;break; // 0111 1011
case 0X77:Key_Flag = 1;break; // 0111 0111
default:break;
}
}
while(temp != 0X0F) //等待按键松手
{
temp = P3;
temp &= 0X0F;
}
}
P44 = 1;P42 = 0;P3 = 0XBF;//1011 1111 扫描第二列
temp = P3; //将P3口读出的数字赋值给temp
temp &= 0X0F; //xxxx xxxx & 0000 1111 = 0000 xxxx temp高四位清零
if(temp != 0X0F) //如果低四位不全为1,则肯定有按键被按下
{
Delay(10); //消抖
temp = P3;
temp &= 0X0F;
if(temp != 0X0F) //真的有按键被按下
{
temp = P3;
switch(temp) //
{
case 0XBE:Key_Flag = 8;break; // 1011 1110
case 0XBD:Key_Flag = 7;break; // 1011 1101
case 0XBB:Key_Flag = 6;break; // 1011 1011
case 0XB7:Key_Flag = 5;break; // 1011 0111
default:break;
}
}
while(temp != 0X0F) //等待按键松手
{
temp = P3;
temp &= 0X0F;
}
}
P44 = 1;P42 = 1;P3 = 0XDF;//1101 1111 扫描第三列
temp = P3; //将P3口读出的数字赋值给temp
temp &= 0X0F; //xxxx xxxx & 0000 1111 = 0000 xxxx temp高四位清零
if(temp != 0X0F) //如果低四位不全为1,则肯定有按键被按下
{
Delay(10); //消抖
temp = P3;
temp &= 0X0F;
if(temp != 0X0F) //真的有按键被按下
{
temp = P3;
switch(temp) //
{
case 0XDE:Key_Flag = 11;break; // 1101 1110
case 0XDD:Key_Flag = 5;break; // 1101 1101
case 0XDB:Key_Flag = 10;break; // 1011 1011
case 0XD7:Key_Flag = 9;break; // 1011 0111
default:break;
}
}
while(temp != 0X0F) //等待按键松手
{
temp = P3;
temp &= 0X0F;
}
}
P44 = 1;P42 = 1;P3 = 0XEF;//0111 1111 扫描第四列
temp = P3; //将P3口读出的数字赋值给temp
temp &= 0X0F; //xxxx xxxx & 0000 1111 = 0000 xxxx temp高四位清零
if(temp != 0X0F) //如果低四位不全为1,则肯定有按键被按下
{
Delay(10); //消抖
temp = P3;
temp &= 0X0F;
if(temp != 0X0F) //真的有按键被按下
{
temp = P3;
switch(temp) //
{
case 0XEE:Key_Flag = 4;break; // 1110 1110
case 0XED:Key_Flag = 3;break; // 1110 1101
case 0XEB:Key_Flag = 2;break; // 1110 1011
case 0XE7:Key_Flag = 1;break; // 1110 0111
default:break;
}
}
while(temp != 0X0F) //等待按键松手
{
temp = P3;
temp &= 0X0F;
}
}
}
(5)例程5:【选修】独立键盘→矩阵键盘 列扫描(四列)扫描端口整体操作法;
- 注:矩阵键盘不设在一组1/0口上面,但又想像在一组1/0口一样操作。可想象例程4如果P44用P37代替,P42用P36代替的编程方法。
- 注:此例程是为了下文学习矩阵键盘“高低电平翻转法(线与法)”而改进设计,正常情况设计电路使用4*4矩阵键盘一般都会放置在同一组1/0端口,也就不会使用本例程这种操作。
#include <STC15F2K60S2.H> #include<intrins.h> #define uchar unsigned char #define uint unsigned int unsigned char tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF}; //unsigned char code tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF}; unsigned char SEG1,SEG2,SEG3,SEG4,SEG5,SEG6,SEG7,SEG8; unsigned char KEY_Value = 0 ; void ArrKeyScan(void); void Delay_MS(unsigned int MS); void SEG_Display12(uchar yi,uchar er); void SEG_Display34(uchar san,uchar si); void SEG_Display56(unsigned char wu,unsigned char liu); void SEG_Display78(unsigned char qi,unsigned char ba); void Key_W(unsigned char Value); unsigned char Key_R(); void main(void) { P2=0XA0;P0=0X00;P2=0X80;P0=0XFF; //初始化程序 SEG1=10,SEG2=10,SEG3=10,SEG4=10,SEG5=10; SEG6=10,SEG7=10,SEG8=10; while(1) { ArrKeyScan(); if(KEY_Value != 0) { SEG1 = KEY_Value/10 ; SEG2 = KEY_Value%10 ; KEY_Value = 0 ; } SEG_Display12(SEG1,SEG2); SEG_Display34(SEG3,SEG4); SEG_Display56(SEG5,SEG6); SEG_Display78(SEG7,SEG8); } } void ArrKeyScan(void) { unsigned char temp; //定义局部变量用来存储从P3口读出的数值? Key_W(0X7F); // 0111 1111 扫描第一列 temp = Key_R(); //将P3口读出的数字赋值给temp temp = temp & 0X0F ; // 0111 XXXX & 0000 1111 = 0000 XXXX if(temp != 0X0F) { Delay_MS(5); temp = Key_R(); //将P3口读出的数字赋值给temp temp = temp & 0X0F ; // 0111 XXXX & 0000 1111 = 0000 XXXX if(temp != 0X0F) { temp = Key_R(); switch(temp) //1110 1101 1011 0111 { case 0X7E: KEY_Value = 7 ; break; case 0X7D: KEY_Value = 6 ; break; case 0X7B: KEY_Value = 5 ; break; case 0X77: KEY_Value = 4 ; break; default : break; } while(temp != 0X0F) { temp = Key_R() ; //将P3口读出的数字赋值给temp temp = temp & 0X0F ; // 0111 XXXX & 0000 1111 = 0000 XXXX } } } Key_W(0XBF); // //0111 1111 扫描第一列 temp = Key_R() ; //将P3口读出的数字赋值给temp temp = temp & 0X0F ; // 0111 XXXX & 0000 1111 = 0000 XXXX if(temp != 0X0F) { Delay_MS(5); temp = Key_R() ; //将P3口读出的数字赋值给temp temp = temp & 0X0F ; // 0111 XXXX & 0000 1111 = 0000 XXXX if(temp != 0X0F) { temp = Key_R() ; switch(temp) //1110 1101 1011 0111 { case 0XBE: KEY_Value = 11 ; break; case 0XBD: KEY_Value = 10 ; break; case 0XBB: KEY_Value = 9 ; break; case 0XB7: KEY_Value = 8 ; break; default : break; } while(temp != 0X0F) { temp = Key_R() ; //将P3口读出的数字赋值给temp temp = temp & 0X0F ; // 0111 XXXX & 0000 1111 = 0000 XXXX } } } Key_W(0XDF); // //1101 1111 扫描第一列 temp = Key_R() ; //将P3口读出的数字赋值给temp temp = temp & 0X0F ; // 0111 XXXX & 0000 1111 = 0000 XXXX if(temp != 0X0F) { Delay_MS(5); temp = Key_R() ; //将P3口读出的数字赋值给temp temp = temp & 0X0F ; // 0111 XXXX & 0000 1111 = 0000 XXXX if(temp != 0X0F) { temp = Key_R() ; switch(temp) //1110 1101 1011 0111 { case 0XDE: KEY_Value = 15 ; break; case 0XDD: KEY_Value = 14 ; break; case 0XDB: KEY_Value = 13 ; break; case 0XD7: KEY_Value = 12 ; break; default : break; } while(temp != 0X0F) { temp = Key_R() ; //将P3口读出的数字赋值给temp temp = temp & 0X0F ; // 0111 XXXX & 0000 1111 = 0000 XXXX } } } Key_W(0XEF); // //0111 1111 扫描第一列 temp = Key_R() ; //将P3口读出的数字赋值给temp temp = temp & 0X0F ; // 0111 XXXX & 0000 1111 = 0000 XXXX if(temp != 0X0F) { Delay_MS(5); temp = Key_R() ; //将P3口读出的数字赋值给temp temp = temp & 0X0F ; // 0111 XXXX & 0000 1111 = 0000 XXXX if(temp != 0X0F) { temp = Key_R() ; switch(temp) //1110 1101 1011 0111 { case 0XEE: KEY_Value = 19 ; break; case 0XED: KEY_Value = 18 ; break; case 0XEB: KEY_Value = 17; break; case 0XE7: KEY_Value = 16; break; default : break; } while(temp != 0X0F) { temp = Key_R() ; //将P3口读出的数字赋值给temp temp = temp & 0X0F ; // 0111 XXXX & 0000 1111 = 0000 XXXX } } } } void Key_W(unsigned char Value) { unsigned char Val = Value; P3=Val;P44=Val>>7;P42=(Val&0x40)>>6; // 0111 1111 0100 0000 } unsigned char Key_R() { unsigned char Val = 0XFF,Val_P3=0,Val_P44=0,Val_P42=0; Val_P3 = P3; Val_P44 = P44; Val_P42 = P42; Val = ((Val_P3&0X3f)|(Val_P44<<7)|(Val_P42<<6)); //0011 1111 | 1000 0000 | 0100 000 return Val; } void SEG_Display12(unsigned char yi,unsigned char er) { P2=0XC0;P0=0X01; //打开控制数码管位选的锁存器,然后选中第一个数码管 P2=0XFF;P0=tab[yi]; //打开控制数码管段选的锁存器,然后给上述打开的数码管输出码值 Delay_MS(1); P0=0XFF; P2=0XC0;P0=0X02; //打开控制数码管位选的锁存器,然后选中第二个数码管 P2=0XFF;P0=tab[er]; //打开控制数码管段选的锁存器,然后给上述打开的数码管输出码值 Delay_MS(1); P0=0XFF; } void SEG_Display34(unsigned char san,unsigned char si) { P2=0XC0;P0=0X04; //打开控制数码管位选的锁存器,然后选中第三个数码管 P2=0XFF;P0=tab[san]; //打开控制数码管段选的锁存器,然后给上述打开的数码管输出码值 Delay_MS(1); P0=0XFF; P2=0XC0;P0=0X08; //打开控制数码管位选的锁存器,然后选中第四个数码管 P2=0XFF;P0=tab[si]; //打开控制数码管段选的锁存器,然后给上述打开的数码管输出码值 Delay_MS(1); P0=0XFF; } void SEG_Display56(unsigned char wu,unsigned char liu) { P2=0XC0;P0=0X10; //打开控制数码管位选的锁存器,然后选中第五个数码管 P2=0XFF;P0=tab[wu]; //打开控制数码管段选的锁存器,然后给上述打开的数码管输出码值 Delay_MS(1); P0=0XFF; P2=0XC0;P0=0X20; //打开控制数码管位选的锁存器,然后选中第六个数码管 P2=0XFF;P0=tab[liu]; //打开控制数码管段选的锁存器,然后给上述打开的数码管输出码值 Delay_MS(1); P0=0XFF; } void SEG_Display78(unsigned char qi,unsigned char ba) { P2=0XC0;P0=0X40; //打开控制数码管位选的锁存器,然后选中第七个数码管 P2=0XFF;P0=tab[qi]; //打开控制数码管段选的锁存器,然后给上述打开的数码管输出码值 Delay_MS(1); P0=0XFF; P2=0XC0;P0=0X80; //打开控制数码管位选的锁存器,然后选中第八个数码管 P2=0XFF;P0=tab[ba]; //打开控制数码管段选的锁存器,然后给上述打开的数码管输出码值 Delay_MS(1); P0=0XFF; } void Delay_MS(unsigned int MS) { unsigned char i, j; while(MS--) { _nop_(); _nop_(); _nop_(); i = 11; j = 190; do { while (--j); } while (--i); } }
(6)【选修】独立键盘→矩阵键盘 线反转操作法;
#include <STC15F2K60S2.H> #include<intrins.h> #define uchar unsigned char #define uint unsigned int unsigned char tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF}; //unsigned char code tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF}; unsigned char SEG1,SEG2,SEG3,SEG4,SEG5,SEG6,SEG7,SEG8; unsigned char KEY_Value = 0 ; void ArrKeyScan(void); void Delay_MS(unsigned int MS); void SEG_Display12(uchar yi,uchar er); void SEG_Display34(uchar san,uchar si); void SEG_Display56(unsigned char wu,unsigned char liu); void SEG_Display78(unsigned char qi,unsigned char ba); void Key_W(unsigned char Value); unsigned char Key_R(); void main(void) { P2=0XA0;P0=0X00;P2=0X80;P0=0XFF; //初始化程序,后期详解; SEG1=10,SEG2=10,SEG3=10,SEG4=10,SEG5=10; SEG6=10,SEG7=10,SEG8=10; while(1) { ArrKeyScan(); if(KEY_Value != 0) { SEG1 = KEY_Value/10 ; SEG2 = KEY_Value%10 ; KEY_Value = 0 ; } SEG_Display12(SEG1,SEG2); SEG_Display34(SEG3,SEG4); SEG_Display56(SEG5,SEG6); SEG_Display78(SEG7,SEG8); } } void ArrKeyScan(void) { unsigned char key,key1,key2; Key_W(0X0F); //P3=0XF0; //所有列全部输出低电平 if((Key_R()&0X0F)!=0X0F) //有按键被按下,能知道那一行,但不知道那一列 { Delay_MS(5); //消抖 if((Key_R()&0X0F)!=0X0F) //消抖之后继续判断,是否按键依然被按下着,证明确实有按键被按下了 key1=Key_R()&0X0F; //key1 存储按键的行值(即哪一行有按键被按下) 1110 1101 1011 0111 Key_W(0XF0); //改变为所有行全部输出低电平 if((Key_R()&0XF0)!=0XF0) //还是有按键被按下,能知道那一列,但不知道那一行 { key2=Key_R()&0XF0; //key2 存储按键的列值(即哪一行有按键被按下) 1110 1101 1011 0111 key=key1|key2; //行值与列值相或,下面就可以得出那一列哪一行被按下了 if(key!=0xff) //判断一下是都真的有按键被按下,其实这一句可以不写。 { switch(key) //分析出哪一个按键被按下了 { case 0x7e: KEY_Value = 7 ;break; case 0x7d: KEY_Value = 6 ;break; case 0x7b: KEY_Value = 5 ;break; case 0x77: KEY_Value = 4 ;break; case 0xbe: KEY_Value = 11 ;break; case 0xbd: KEY_Value = 10 ;break; case 0xbb: KEY_Value = 9 ;break; case 0xb7: KEY_Value = 8 ;break; case 0xde: KEY_Value = 15 ;break; case 0xdd: KEY_Value = 14 ;break; case 0xdb: KEY_Value = 13 ;break; case 0xd7: KEY_Value = 12 ;break; case 0xee: KEY_Value = 19 ;break; case 0xed: KEY_Value = 18 ;break; case 0xeb: KEY_Value = 17 ;break; case 0xe7: KEY_Value = 16 ;break; default: break; } } } } } void Key_W(unsigned char Value) { unsigned char Val = Value; P3=Val;P44=Val>>7;P42=(Val&0x40)>>6; // 0111 1111 0100 0000 } unsigned char Key_R() { unsigned char Val = 0XFF,Val_P3=0,Val_P44=0,Val_P42=0; Val_P3 = P3; Val_P44 = P44; Val_P42 = P42; Val = ((Val_P3&0X3f)|(Val_P44<<7)|(Val_P42<<6)); //0011 1111 | 1000 0000 | 0100 000 return Val; } void SEG_Display12(unsigned char yi,unsigned char er) { P2=0XC0;P0=0X01; //打开控制数码管位选的锁存器,然后选中第一个数码管 P2=0XFF;P0=tab[yi]; //打开控制数码管段选的锁存器,然后给上述打开的数码管输出码值 Delay_MS(1); P0=0XFF; P2=0XC0;P0=0X02; //打开控制数码管位选的锁存器,然后选中第二个数码管 P2=0XFF;P0=tab[er]; //打开控制数码管段选的锁存器,然后给上述打开的数码管输出码值 Delay_MS(1); P0=0XFF; } void SEG_Display34(unsigned char san,unsigned char si) { P2=0XC0;P0=0X04; //打开控制数码管位选的锁存器,然后选中第三个数码管 P2=0XFF;P0=tab[san]; //打开控制数码管段选的锁存器,然后给上述打开的数码管输出码值 Delay_MS(1); P0=0XFF; P2=0XC0;P0=0X08; //打开控制数码管位选的锁存器,然后选中第四个数码管 P2=0XFF;P0=tab[si]; //打开控制数码管段选的锁存器,然后给上述打开的数码管输出码值 Delay_MS(1); P0=0XFF; } void SEG_Display56(unsigned char wu,unsigned char liu) { P2=0XC0;P0=0X10; //打开控制数码管位选的锁存器,然后选中第五个数码管 P2=0XFF;P0=tab[wu]; //打开控制数码管段选的锁存器,然后给上述打开的数码管输出码值 Delay_MS(1); P0=0XFF; P2=0XC0;P0=0X20; //打开控制数码管位选的锁存器,然后选中第六个数码管 P2=0XFF;P0=tab[liu]; //打开控制数码管段选的锁存器,然后给上述打开的数码管输出码值 Delay_MS(1); P0=0XFF; } void SEG_Display78(unsigned char qi,unsigned char ba) { P2=0XC0;P0=0X40; //打开控制数码管位选的锁存器,然后选中第七个数码管 P2=0XFF;P0=tab[qi]; //打开控制数码管段选的锁存器,然后给上述打开的数码管输出码值 Delay_MS(1); P0=0XFF; P2=0XC0;P0=0X80; //打开控制数码管位选的锁存器,然后选中第八个数码管 P2=0XFF;P0=tab[ba]; //打开控制数码管段选的锁存器,然后给上述打开的数码管输出码值 Delay_MS(1); P0=0XFF; } void Delay_MS(unsigned int MS) { unsigned char i, j; while(MS--) { _nop_(); _nop_(); _nop_(); i = 11; j = 190; do { while (--j); } while (--i); } }