基于89S51的PC键盘读取(PS2)
硬件描述:PS2键盘的时钟线(clk)接89S51的INT0(P3.2),数据线data接(P3.3)
LCD的控制端口分别为: RS = P2^7,RW = P2^6,EP = P2^5,数据端口为P0,液晶显示
偏压VL必须接。
/**************************************************************************** *
功能:本程序主要通过外部中断INT0及3.3端口读取PS2键盘值并通过LCD1602显
*示,键扫描码的解码通过数组方式解码,程序的解码功能主要针对数字及大小写字母和常
*用标点符号
*创建者: 曹兴
*创建日期:2008-10-11
*版本号: 2008101101
*****************************************************************************/ #include"reg51.h"
#include"stdio.h"
/*****************************端口定义***************************************/ #define DATA P0 //LCD数据传输端口
sbit RS = P2^7; //LCD控制端口定义
sbit RW = P2^6;
sbit EP = P2^5;
sbit k_data = P3^3; //PS/2数据线端口
sbit k_clk = P3^2; //PS/2时钟线端口
unsigned char bitcount = 11; //PC键盘数据长度计数
unsigned char input = 0; //缓冲区读指针
unsigned char k_buf[32]; //键盘缓冲区
//没有按下shift键的PC键盘扫描码
unsigned char code unshifted[][2]=
{28,'a',50,'b',33,'c',35,'d',36,'e',43,'f',52,'g',51,'h',67,'i',59,'j',
66,'k',75,'l',58,'m',49,'n',68,'o',77,'p',21,'q',45,'r',27,'s',44,'t',
60,'u',42,'v',29,'w',34,'x',53,'y',26,'z',69,'0',22,'1',30,'2',38,'3',
37,'4',46,'5',54,'6',61,'7',62,'8',70,'9',14,'`',78,'-',85,'=',
84,'[',91,']',76,';',65,',',73,'.',74,'/'};
//按下shift键的PC键盘扫描码
unsigned char code shifted[][2]=
{28,'A',50,'B',33,'C',35,'D',36,'E',43,'F',52,'G',51,'H',67,'I',59,'J',
66,'K',75,'L',58,'M',49,'N',68,'O',77,'P',21,'Q',45,'R',27,'S',44,'T',
60,'U',42,'V',29,'W',34,'X',53,'Y',26,'Z',69,')',22,'!',30,'@',38,'#',
37,'$',46,'%',54,'^',61,'&',62,'*',70,'(',14,'~',78,'_',85,'+',93,'|',
84,'{',91,'}',76,':',82,'"',65,'<',73,'>',74,'?'};
/***************************************************************************** *函数名称:put_k_buf
*函数功能:将解码后的字符放入键盘缓冲区内
*入口参数:k_char
*出口参数:无
*****************************************************************************/ void put_k_buf(unsigned char k_char)
{
k_buf[input] = k_char; //送键盘值ASCII码到键盘缓冲区
if(input<31)
input++;
else
input = 0;
return;
}
/*****************************************************************************
*函数名称:decode
*函数功能:解码函数,将接收到的数据转化为其对应的字符 *入口参数:k_code
*出口参数:无
*****************************************************************************/
void decode(unsigned char k_code)
{
static unsigned char shift,up,shiftup;
unsigned i;
if(k_code==0xf0) //按键释放
{
up = 1;
return;
}
if(up==1) //shift键开关
{
up = 0;
if((k_code==0x12)|(k_code==0x59))
shift = 0;
return;
}
switch(k_code)
{
case 0x12: //检测左shift键
{
shift = 1;
shiftup = 1;
}
case 0x59: //检测右shift键
{
shift = 1;
shiftup = 1;
}
default:
{
if(shift==0) //找出没有按下shift键的字符码将其存日键盘缓冲区中
{
for(i=0;unshifted[i][0]!=k_code&&unshifted[i][0];i++);
if(unshifted[i][0]==k_code)
put_k_buf(unshifted[i][1]);
}
else //找出按下shift键的字符码将其存日键盘缓冲区中
{
for(i=0;shifted[i][0]!=k_code&&shifted[i][0];i++);
if(shifted[i][0]==k_code)
put_k_buf(shifted[i][1]);
}
}
}
}
/*****************************************************************************
*函数名称:Keyboard_out
*函数功能:中断函数接受键盘发来的数据
*入口参数:无
*出口参数:无
*****************************************************************************/
void Keyboard_out(void) interrupt 0 using 0 {
static unsigned char dat;
switch(bitcount)
{
case 11: //接收起始位
{
if(k_data ) //若数据线为高则返回
return ;
else //若数据线为低则bitcount减1准备接收数据
bitcount--;
break;
}
case 2: //奇校验位
{
bitcount--;
break;
}
case 1: //停止位
{
bitcount--;
if(!k_data ) //若数据线为0,则主机禁止接收放弃数据
{
bitcount = 11;
return;
}
else //若数据线为1,则接受停止位
{
bitcount = 11;
decode(dat); //将数据进行解码
}
break;
}
default: //通过移位保存接收的8位数据
{
dat = (dat>>1);
if(k_data )
dat|=0x80;
bitcount--;
}
}
}
/*****************************************************************************
*函数名称:delayns
*函数功能:LCD延时子程序
*入口参数:time
*出口参数:无
*****************************************************************************/
void delayns(unsigned char time) {
unsigned char i;
for(;time>0;time--)
for(i = 0; i< 250; i++) ; }
/*****************************************************************************
*函数名称:lcd_buzy
*函数功能:测试LCD忙碌状态
*入口参数:无
*出口参数:result
*****************************************************************************/
bit lcd_buzy()
{
bit result;
RS = 0;
RW = 1;
EP = 1;
delayns(1); //此处延时特别重要 (必不可少)
result = (bit)(DATA & 0x80);
delayns(1);
EP = 0;
return result;
}
/*****************************************************************************
*函数名称:lcd_w_order
*函数功能:写指令数据到LCD子程序
*入口参数:cmd
*出口参数:无
*****************************************************************************/
void lcd_w_order(unsigned char cmd) {
while(lcd_buzy()); //判断LCD是否忙碌
RS = 0;
RW = 0;
EP = 1;
DATA = cmd;
delayns(1);
EP = 0;
}
/*****************************************************************************
*函数名称:lcd_w_data
*函数功能:写入显示数据到LCD子程序
*入口参数:dat
*出口参数:五
*****************************************************************************/
void lcd_w_data(unsigned char dat) {
while(lcd_buzy()); //判断LCD是否忙碌
RS = 1;
RW = 0;
EP = 1;
DATA = dat;
delayns(1);
EP = 0;
}
/*****************************************************************************
*函数名称:lcd_post
*函数功能:设定显示位置子程序
*入口参数:pos
*出口参数:无
*****************************************************************************/
void lcd_post(unsigned char pos)
{
lcd_w_order(pos | 0x80);
}
/*****************************************************************************
*函数名称:lcd_init
*函数功能:LCD初始化子程序
*入口参数:无
*出口参数:无
*****************************************************************************/
void lcd_init()
{
lcd_w_order(0x38); //显示模式设置
delayns(1);
lcd_w_order(0x0c); //显示光标设置,开显示
delayns(1);
lcd_w_order(0x06); //显示光标移动(右移)
delayns(1);
lcd_w_order(0x01); //清屏
delayns(1);
}
/*****************************************************************************
*函数名称:main
*函数功能:本程序主要通过外部中断INT0及3.3端口读取PS2键盘值并通过LCD1602显示,键
*扫描码的解码通过数组方式解码,程序的解码功能主要针对数字及大小写字母和常用标点 *符号
*入口参数:无
*出口参数:无
*****************************************************************************/
void main()
{
unsigned char j,i=0;
EA = 1;
IT0 = 1;
EX0 = 1;
while(1)
{
i=0;
lcd_init(); // 初始化LCD
delayns(10);
lcd_post(0x00); //设置显示位置
while(i