}
voidInit51(void)
{
SCON =0x50; /*mode1:
8-bitUART,enablereceiver */
TMOD =0x21; /*timer1mode2:
8-Bitreload */
/*timer0mode1:
16-bitTimer */
TH1 =BAUD_4800; /*reloadvalue9600baud */
TR1 =1; /*timer1run */
IE =0X12; /*enableSerialINT,Timer0INT */
ES =0; /*disableSerialINT*/
EA =1; /*OpenINTCtrl */
}
voidKBKeyEncode(void)
{
dataunsignedcharCurrPress=0,LastPress=0;
if((LastPress=KBKeyPress())!
=0) /*ifsomekeyispressthenstartencode*/
{
KBStartTimer(0,0); /*somekeyispressthenstartDBClkDetectionCounter*/
SysKBMsg=LastPress; /*recordthekeythatispressedthistime*/
while(!
KBCounterStop)
{
if((CurrPress=KBKeyPress())!
=0X0) /*ifsomekeyispressedduringDBClkDetectionthenjumpouttoseewetherDBclkisoccured*/
break;
}
if((KBCounterStop==0)&&(LastPress==CurrPress)) /*thiskeyDBClkoccured*/
SysKBMsg|=0X80;
KBStopTimer();
}
}
unsignedcharKBKeyPress(void)
{
dataunsignedcharKeyPress=0;
if((P1&0X03)!
=0X03)
{
DelayMS(TIME_20MS);
if((KeyPress=(P1&0X03))!
=0X03) /*somekeyispress*/
{
if(KBCounterStart)
TR0=0;
while((P1&0X03)!
=0X03); /*waituntilkeyisfree*/
DelayMS(TIME_20MS);
if(KBCounterStart)
TR0=1;
}
else /*Keyisnotrealpress*/
{
KeyPress=0;
}
}
returnKeyPress;
}
voidKBStartTimer(unsignedcharCntH,unsignedcharCntL)
{
TR0=0;
TH0=CntH;
TR0=1; /*StartCounter*/
TL0=CntL;
KBCounterFlag=1; /*thiscounterisusedbyKeyBoard*/
KBCounterStart=1;
KBCounterStop=0;
}
voidKBStopTimer(void)
{
TR0=0;
TH0=0;
TL0=0;
KBCounter=0;
KBCounterFlag=0;
KBCounterStart=0;
}
voidKBDealPressKey(void)
{
dataunsignedchartmp=0;
switch(SysKBMsg) /*hereisjustatestprogram,testtodealSgl_ClkandDB_ClkMsg*/
{
case 0X01:
tmp=0X01;break;
case 0X02:
tmp=0X02;break;
case 0X81:
tmp=0X81;break;
case 0X82:
tmp=0X82;break;
default :
break;
}
SysKBMsg=0; /*thiskeymsghasbeendone*/
96个key的零延时采集
HotPower发表于2003-11-518:
04侃单片机←返回版面
;-------96键演示程序-------------------------
;这是1个回复题中的应用示例,已通过软仿真“验证”
;这只是键扫描技术的1个“缩影”,方法实在太多.
;有“难看之处”,敬请高手们批评指教.
;HotPower将虚心接受,坚决改正.重新做人.
;发表目的:
在21IC中壮大游击队.
;----------------------------------------------------
;由于2051资源问题,本程序只取多任务键盘的压放键2个事件
;废除长压键(压键1段时间后才激活)事件
;废除长放键(放键1段时间后才激活)事件
;废除双击键事件
;废除任意组合键事件
按键扫描驱动程序
key36
temp=35;
}
else{
}
}
returnkey;//返回键码0~35或出错码0xff
}
单片机驱动标准PC机键盘的C51程序
/*---------------------------------------------------------------------------------------------------
功能:
实现pc机键盘(p/s2接口)与8位单片机连接使用
原理:
键盘时钟接在口,既8051的外部中断int0上,键盘数据接到上
每次按键,键盘会向单片机发脉冲使单片机发生外部中断,数据有口一位一位传进来
传回的数据格式为:
1位开始位(0),8位数据位(所按按键的通码,用来识别按键),1位校验位(奇校验)
1位结束位
(1)
实现:
将键盘发回的数据放到一个缓冲区里(数组),当按键结束后发生内部中断来处理所按的按键
缺点:
由于51单片机的容量有限所以缓冲区不可以开的太大,这就导致可以记录键盘的按键次数过少,
也就是容错性一般。
不过如果正常使用键盘是不会出错的
//#include""
#include""
#include""//按键通码与ascii对照表
sbitsda=p1^0;//键盘数据线
unsignedchardat=0,dat1=0,dat2=0;//接收键盘数据变量存储通码变量接受连续通码变量
unsignedcharcount=0,num=9,temp[5],shu=0;//中数次数中断控制变量缓冲区数组缓冲区指针
unsignedcharkey=0;//按键最终值
voidzhongduan()interrupt0//外部中断0用来接受键盘发来的数据
{
dat>>=1;//接受数据低->高
if(sda)dat|=0x80;
count++;
if(count==num)
{
if(count==9)
{
dat1=dat;//中断9次后为键盘所按按键的通码(开始位始终为0在第一次中断时右移中忽略)
num=20;//使中断可以继续中断11次
}
if(count==20)
{
dat2=dat;//取回第二个通码
if(dat1==0xe0||dat2==0xf0)//第一个通码是0xe0则证明所按按键为功能键,第二个通码是0xf0证明按键结束
{
temp[shu]=dat1;temp[shu+1]=dat2;shu+=2;//将所按按键存到缓冲区中
ie=0x82;//关闭外部中断并打开内部中断来处理所按按键
tr0=1;
}
else
{
temp[shu]=dat1;temp[shu+1]=dat2;shu+=2;//如果shift键被按下则记录与它同时按下的那个键
count=0;
}
if((temp[0]==18||temp[0]==89)&&(temp[2]==18||temp[2]==89))tr0=1;//如果缓冲区中有两个间隔的shift键则证明需要的铵键结束
}
}
}
voidgetkey()interrupt1//内部中断0用来处理缓冲区里的数据
{
unsignedchari=0;
tr0=0;
th0=0;
tl0=0;
count=0;//中断记数则0
if((temp[0]==18||temp[0]==89)&&temp[1]!
=0xf0)//shift被按下
{
for(i=0;i<21;i++)
{
if(addshift[0]==temp[1])//搜索shift被按下的表
{
key=addshift[1];
ie=0x83;//打开外部中断
return;
}
}
}
elseif(temp[0]==0xe0)//所按下的按键是功能键
{
for(i=0;i<80;i++)
{
if(noshift[0]==temp[1])//功能键的通码在缓冲区的第二位
{
key=noshift[1];
ie=0x83;
return;
}
}
}
else//普通按键
{
for(i=0;i<80;i++)
{
if(noshift[0]==temp[0])//普按键的通码在缓冲区的第一位
{
key=noshift[1];
ie=0x83;
return;
}
}
}
for(i=0;i<5;i++)
{
temp=0;
}
}
/*
程序效果:
按下按键,蜂鸣器响,数码管有相应的键值
显示,按下E键继电器关,按下C键继电器开。
这与上一程序的功能相同,比上一程序简洁
但理解相对困难些。
运行平台:
51hei单片机学习板
*/
#include<>//头文件
#include<>
#defineucharunsignedchar//宏定义
#defineuint unsignedint
sbitjdq=P3^5;//位声明,驱动继电器管脚
sbit fmq=P3^4;//位声明,驱动蜂鸣器管脚
codeuchartable[]={0x3f,0x06,0x5b,//数码管显示的数值
0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,
0x77,0x7c,0x39,0x5e,0x79,0x71};
codeucharkey_tab[17]={ //此数组为键盘编码
0xed,0x7e,0x7d,0x7b, //0,1,2,3,
0xbe,0xbd,0xbb,0xde, //4,5,6,7,
0xdd,0xdb,0x77,0xb7, //8,9,a,b,
0xee,0xeb,0xd7,0xe7,0xff};// c,d,e,f,
ucharl_key=0x00;//定义变量,存放键值
ucharl_keyold=0xff;//作为按键放开否的凭证
voidreadkey(); //扫描键盘,获取键值
voiddisplay(uchar*lp,ucharlc);//显示子函数
voiddelay(); //延时子函数
voidmain() //主函数
{
EA=1; //打开总中断
EX0=1;//打开外部中断
P0=0xf0;//键值高4位为高电平,低4位为低电平
while
(1)
{
display(&l_key,1);//调用显示子函数
if(l_key==14) //是否按下E键,是则关闭继电器
jdq=1;
if(l_key==12) //是否按下C键,是则打开继电器
jdq=0;
}
}
voidkey_scan()interrupt0//外部中断0,0的优先级最高
{
EX0=0; //在读键盘时,关闭外部中断,防止干扰带来的多次中断
TMOD&=0xf1;//设置定时器为工作方式1
TH0=0x2e; //设置初值,为12毫秒,十进制值为11776
TL0=0x00;
ET0=1; //开启定时器中断0
TR0=1; //启动定时器计数
}
voidtime0()interrupt1 //定时器0的中断函数
{
TR0=0; //关闭定时器0
readkey();//定时12ms后产生中断,调用此函数,读取键值
}
voidreadkey() //扫描键盘子函数
{
uchari,j,key;//定义局部变量
j=0xfe; //设定初值
key=0xff;
for(i=0;i<4;i++)//逐列扫描键盘
{
P0=j;
if((P0&0xf0