新闻  |   论坛  |   博客  |   在线研讨会
PS/2 键盘与单片机
0750long | 2009-04-20 12:56:30    阅读:2590   发布文章

PS/2 键盘与单片机

 

rar程序打包

PS/2 键盘与单片机接口

用LCD1602显示

调试成功所以拿出来给大家分享,希望对大家有用,呵呵^_^

用PS/2键盘做系统输入部分蛮方便的哦!

可以使用Backspace/Esc/Tab/Caps Lock/Shift/Enter/Space/Arrow等按键

这是键盘通码:

点击开大图

 

/*--------------------------------------------------------------*/
//File: 鼠标液晶测试
//Date: 2009-4-19
//Time: 16:30

/*--------------------------------------------------------------*/
#include <reg52.h>
#include "PS_keyboard.H"
#include "LCD1602_8A.H"


/*--------------------------------------------------------------*/
//延时50ms 函数定义
void delay50ms(void)
{
    unsigned char i, j;
    for(i = 165; i > 0; i--)
    for(j = 150; j > 0; j--);
}


/*--------------------------------------------------------------*/
//主函数
void main(void)
{
 unsigned char x, y;

 LCD_init();     //LCD1602初始化
 keyboard_init();   //键盘初始化

 while(1)
 {
  if(r_ok == 2)
  {  
   if(keyboard_data == 0x29) LCD_printc(x++, y, ' ');    //空格
   else if(keyboard_data == 0x66) {LCD_printc(x = (--x & 0x0f), y, ' '); LCD_pos(x, y);}//退格
   else if(keyboard_data == 0x0d) LCD_pos(x+=4, y);    //制表
   else if(keyboard_data == 0x5a) LCD_pos(x = 0, y = (++y & 0x01));//回车
   else if(keyboard_data == 0x58) shift_flag = ~ shift_flag;  //大小写切换
   else if(keyboard_data == 0x76) {LCD_clr();LCD_pos(x=0, y="0");} //清屏,光标复位
   else if(keyboard_data == 0x6b) LCD_pos(x = (--x & 0x0f), y); //光标左移
   else if(keyboard_data == 0x74) LCD_pos(x = (++x & 0x0f), y); //光标右移
   else if(keyboard_data == 0x75) LCD_pos(x, y = (--y & 0x01)); //光标上移
   else if(keyboard_data == 0x72) LCD_pos(x, y = (++y & 0x01)); //光标下移

   else             //字符输出
   {
    look_ascii();          //查表
    LCD_printc(x & 0x0f, y & 0x01, keyboard_ascii);  
    if(y > 1) {y = 0; LCD_clr(); x--;}     //清屏
    x++; if(x > 15) {x = 0; y++;}      //换行
   }
    
   r_ok = 0;   //清接收标志位
   EX0 = 1;   //继续检测按键
  }
  delay50ms();
 }
}

/*--------------------------------------------------------------*/
//ASCII
unsigned char code KB_ASCII[48][3] = {
//unshifted, shifted, scan_code
'`', '~', 0x0E,
'1', '!', 0x16,
'2', '@', 0x1E,
'3', '#', 0x26,
'4', '$', 0x25,
'5', '%', 0x2E,
'6', '^', 0x36,
'7', '&', 0x3D,
'8', '*', 0x3E,
'9', '(', 0x46,
'0', ')', 0x45,
'-', '_', 0x4E,
'=', '+', 0x55,

'q', 'Q', 0x15,
'w', 'W', 0x1D,
'e', 'E', 0x24,
'r', 'R', 0x2D,
't', 'T', 0x2C,
'y', 'Y', 0x35,
'u', 'U', 0x3C,
'i', 'I', 0x43,
'o', 'O', 0x44,
'p', 'P', 0x4D,
'[', '{', 0x54,
']', '}', 0x5B,
'\\', '|',0x5D,

'a', 'A', 0x1C,
's', 'S', 0x1B,
'd', 'D', 0x23,
'f', 'F', 0x2B,
'g', 'G', 0x34,
'h', 'H', 0x33,
'j', 'J', 0x3B,
'k', 'K', 0x42,
'l', 'L', 0x4B,
';', ':', 0x4C,
'\'', '"',0x52,

'z', 'Z', 0x1A,
'x', 'X', 0x22,
'c', 'C', 0x21,
'v', 'V', 0x2A,
'b', 'B', 0x32,
'n', 'N', 0x31,
'm', 'M', 0x3A,
',', '<', 0x41,
'.', '>', 0x49,
'/', '?', 0x4A
};

 

/*--------------------------------------------------------------*/
//File: PS/2-keyboard头文件
//Date: 2009-4-18
//Time: 21:29

/*--------------------------------------------------------------*/
//防止被重复定义引用
#ifndef __PS_keyboard_H__
#define __PS_keyboard_H__
//包含头文件
#include "LCD_ASCII.H"   //键盘通码表

/*--------------------------------------------------------------*/
sbit keyboard_sda = P1^6;  //鼠标数据线
sbit keyboard_clk = P3^2;  //鼠标时钟线
sbit led    = P0^0;  //按键LED指示
sbit beep    = P0^1;  //蜂鸣器指示


/*--------------------------------------------------------------*/
//数据定义
unsigned char n;    //循环变量
unsigned int  keyboard_word; //接收字16bits
unsigned char keyboard_data; //接收字节
unsigned char keyboard_ascii; //查表得到的字符
bit shift_flag;     //shift标志位
unsigned char r_ok;    //接收数据有效


/*--------------------------------------------------------------*/
//函数声明
void INT0_init(void);      //外部中断INT0初始化
//void delay120us(void);      //延时120us 函数定义
//void keyboard_write_dat(unsigned char dat); //发送数据
void keyboard_read_dat(void);    //读出数据
void keyboard_init(void);     //键盘初始化
void look_ascii(void);      //查表字符


/*--------------------------------------------------------------*/
//外部中断INT0初始化
void INT0_init(void) 
{
    EA  = 1;   //总中断
 EX0 = 1;   //外部中断
 PX0 = 1;   //中断优先级
 IT0 = 0;   //低电平触发
}


/*--------------------------------------------------------------*/
//延时120us 函数定义
/*void delay120us(void)
{
    unsigned char i, j;
    for(i = 23; i > 0; i--)
    for(j = 1; j > 0; j--);
}


/*--------------------------------------------------------------*/
//发送数据
//发送11位数据:1START-8DATA-1PARITY-1STOP
//并接收一个应答位ack = 0 
/*void keyboard_write_dat(unsigned char dat)
{
 unsigned char i; //循环变量
 bit parity;   //奇校验位

 EX0 = 0;   //关闭外部中断
 ACC = dat;   //存入累加器A,得到P(为偶校验)
 parity = ~P;  //获得奇校验位

 keyboard_clk = 0; //拉低时钟线
 delay120us();  //至少延时100us
 keyboard_sda = 0; //发送起始位

 keyboard_clk = 1; //释放时钟线
 keyboard_sda = 1; //释放数据线

 for(i = 0; i < 8; i++)
 {         //至少要在25us内完成发送一位!!!
  while(!keyboard_clk);   //等待设备把时钟线拉高
  keyboard_sda =(bit)(dat& 0x01); //先发送最低位
  dat >>= 1;      //下降沿写入数据
  while(keyboard_clk);   //等待设备把时钟线拉低
 }

 while(!keyboard_clk);    //等待设备把时钟线拉高
 keyboard_sda = parity;    //发送奇校验位
 while(keyboard_clk);    //等待设备把时钟线拉低

 while(!keyboard_clk);    //等待设备把时钟线拉高
 keyboard_sda = 1;     //发送停止位
 while(keyboard_clk);    //等待设备把时钟线拉低

 while(!keyboard_clk);    //等待设备把时钟线拉高
 while(keyboard_sda);    //等待接收应答位(总是为0)
 while(keyboard_clk);    //等待设备把时钟线拉低

 while(!keyboard_clk);    //等待设备释放时钟线
 while(!keyboard_sda);    //等待设备释放数据线
 EX0 = 1;       //打开外部中断INT0
}


/*--------------------------------------------------------------*/
//奇校验
bit check_parity(void)

 ACC = keyboard_data;
 if(~P == (bit)(keyboard_word & 0x0200)) return 1; //奇校验成功则返回1
 else          return 0; //奇校验失败则返回0
}


/*--------------------------------------------------------------*/
//读出字节数据
void keyboard_read_dat(void)
{
 keyboard_data = (unsigned char)(keyboard_word >> 1);//去掉最高两位和最后一位
 if(check_parity()) keyboard_word = 0;    //奇校验成功//清接收数据字
 else    keyboard_data = 0;    //置零
 if(keyboard_data == 0xe0 | keyboard_data == 0xf0){;}//忽略0xe0和0xf0字节
 else 
  if(keyboard_data == 0x12 | keyboard_data == 0x59) shift_flag = ~shift_flag;//shift按键检测
  else {r_ok++; if(r_ok == 2) EX0 = 0;}  //忽略通码,取断码,接收有效,断开中断,按键处理
}


/*--------------------------------------------------------------*/
//查表字符
void look_ascii(void)
{
 unsigned char i;
 for(i = 0; i < 48; i++)
 {
  if(KB_ASCII[i][2] == keyboard_data)    //查找按键通码
  {
   keyboard_ascii = KB_ASCII[i][shift_flag]; //得到相应字符
  }
 }
}


/*--------------------------------------------------------------*/
//外部中断INT0服务
//接收11位数据:1START-8DATA-1PARITY-1STOP
void INT0_intservice(void) interrupt 0  
{
 keyboard_word >>= 1;       //先向右空移一位
 if(keyboard_sda) keyboard_word |= 0x0400;  //先接收最低位
 n++; if(n == 11) {keyboard_read_dat(); n = 0;} //接收完成则读出数据
}


/*--------------------------------------------------------------*/
//键盘初始化
void keyboard_init(void)
{
 INT0_init();  //外部中断INT0初始化
}


/*--------------------------------------------------------------*/
#endif

 

/*--------------------------------------------------------------*/
//File: LCD1602_8A.H
//Date: 08-8-9 //08-8-8 //08-8-27  //08-8-26
//Time: 20:10
//Modi: 08-8-10 9:51
//Note: LCD1602 The Best Driver for you!
//  Welcome to use. Have a good day!


/*--------------------------------------------------------------*/
//防止被重复定义
#ifndef __LCD1602_8A_H__   
#define __LCD1602_8A_H__
//所需头文件
#include <intrins.h>


/*--------------------------------------------------------------*/
//LCD1602与单片机接口定义
sfr  LCD_IO = 0xa0;   //P0-0x80,P1-0x90,P2-0xA0,P3-0xB0;
sbit LCD_RS = P1^0;   //LCD数据/命令选择端(H/L)
sbit LCD_RW = P1^1;   //LCD  读/写  选择端(H/L)
sbit LCD_EN = P1^2;   //LCD使能控制端
sbit LCD_BZ = LCD_IO^7;  //LCD忙标志位


/*--------------------------------------------------------------*/
//函数声明
void LCD_busy  (void);             //检测LCD是否忙
void LCD_init  (void);             //LCD初始化
void LCD_clr   (void);            //LCD清屏
void LCD_cmd   (unsigned char cmd);          //写入指令
void LCD_dat   (unsigned char dat);          //写入数据
void LCD_pos   (unsigned char x, unsigned char y);      //显示定位
void LCD_printc(unsigned char x, unsigned char y, unsigned char c);  //定位输出字符
//void LCD_prints(unsigned char x, unsigned char y, unsigned char *s); //定位输出字符串
//void LCD_printn(unsigned char x, unsigned char y, unsigned int num); //定位输出16位二进制数字

/*--------------------------------------------------------------*/
//检测LCD忙状态
void LCD_busy(void)
{
 do
 {
  LCD_EN = 0;
  LCD_RS = 0;   //指令
  LCD_RW = 1;   //读出
  LCD_IO = 0xff;  //除P0口外,其它口不需要此句!!! 
  LCD_EN = 1;
  _nop_();   //高电平读出 延迟时间1us
 }while(LCD_BZ);   //LCD_BZ=1表示忙,LCD_BZ=0表示空闲
 LCD_EN = 0;
}


/*--------------------------------------------------------------*/
//写入指令
void LCD_cmd(unsigned char cmd)   
{
 LCD_busy();    //检测忙
 LCD_RS = 0;    //指令
 LCD_RW = 0;    //写入
 LCD_EN = 1;
 LCD_IO = cmd;   //传指令
 LCD_EN = 0;    //下降沿有效
}


/*--------------------------------------------------------------*/
//写入数据
void LCD_dat(unsigned char dat) 
{
 LCD_busy();    //检测忙
 LCD_RS = 1;    //数据
 LCD_RW = 0;    //写入
 LCD_EN = 1;
 LCD_IO = dat;   //传数据
 LCD_EN = 0;    //下降沿有效
}


/*--------------------------------------------------------------*/
//显示定位
void LCD_pos(unsigned char x, unsigned char y)
{
 if(y) LCD_cmd(x|0xc0);//y=1第二行显示,y=0第一行显示 0<=x<16
 else LCD_cmd(x|0x80);//数据指针=80+地址码(00H~27H,40H~67H)
}


/*--------------------------------------------------------------*/
//LCD清屏
void LCD_clr(void)
{
 LCD_cmd(0x01);
}


/*--------------------------------------------------------------*/
//定位输出字符
void LCD_printc(unsigned char x, unsigned char y, unsigned char c)
{
 LCD_pos(x, y);
 LCD_dat(c);
}


/*--------------------------------------------------------------*/
//定位输出字符串
/*void LCD_prints(unsigned char x, unsigned char y, unsigned char *s)
{
 LCD_pos(x, y);
 while(*s)
 {
  LCD_dat(*s);
  s++;
 }
}


/*--------------------------------------------------------------*/
//定位输出16位二进制数字
// 0<= num <65536
/*void LCD_printn(unsigned char x, unsigned char y, unsigned int num)
{
 char i;
 unsigned char ii;
 unsigned char dat[6];
 for(i = 0; i < 6; i++) dat[i] = 0; i = 0; //初始化数据
 while(num / 10)        //拆位
 {
  dat[i] = num % 10;      //最低位
  num /= 10; i++;  
 }
 dat[i] = num;        //最高位
 ii = i;          //保存dat的位数
 for(; i >= 0; i--) dat[i] += 48;   //转化成ASCII
 LCD_prints(x, y, "     ");     //清显示区域
 LCD_pos(x, y);
 for(i = ii; i >= 0; i--) LCD_dat(dat[i]); //输出数字字符
}


/*--------------------------------------------------------------*/
//LCD初始化
void LCD_init(void)
{
 LCD_cmd(0x38);   //设置LCD为16X2显示,5X7点阵,八位数据接口 
 LCD_cmd(0x06);   //LCD显示光标移动设置(光标地址指针加1,整屏显示不移动)
 LCD_cmd(0x0f);   //LCD开显示及光标设置(光标闪烁,显示"_")
 LCD_cmd(0x01);   //清屏
}


/*--------------------------------------------------------------*/
#endif

 

以下我整理的按键代码,希望对大家有用^_^

/*--------------------------------------------------------------*/
//ASCII unshifted
unsigned char code unshifted[][2] = {
'`', 0x0E,
'1', 0x16,
'2', 0x1E,
'3', 0x26,
'4', 0x25,
'5', 0x2E,
'6', 0x36,
'7', 0x3D,
'8', 0x3E,
'9', 0x46,
'0', 0x45,
'-', 0x4E,
'=', 0x55,

'q', 0x15,
'w', 0x1D,
'e', 0x24,
'r', 0x2D,
't', 0x2C,
'y', 0x35,
'u', 0x3C,
'i', 0x43,
'o', 0x44,
'p', 0x4D,
'[', 0x54,
']', 0x5B,
'\', 0x5D,

'a', 0x1C,
's', 0x1B,
'd', 0x23,
'f', 0x2B,
'g', 0x34,
'h', 0x33,
'j', 0x3B,
'k', 0x42,
'l', 0x4B,
';', 0x4C,
''', 0x52,

'z', 0x1A,
'x', 0x22,
'c', 0x21,
'v', 0x2A,
'b', 0x32,
'n', 0x31,
'm', 0x3A,
',', 0x41,
'.', 0x49,
'/', 0x4A
}
/*--------------------------------------------------------------*/

 

/*--------------------------------------------------------------*/
//ASCII shifted
unsigned char code shifted[][2] = {
'~', 0x0E,
'!', 0x16,
'@', 0x1E,
'#', 0x26,
'$', 0x25,
'%', 0x2E,
'^', 0x36,
'&', 0x3D,
'*', 0x3E,
'(', 0x46,
')', 0x45,
'_', 0x4E,
'+', 0x55,

'Q', 0x15,
'W', 0x1D,
'E', 0x24,
'R', 0x2D,
'T', 0x2C,
'Y', 0x35,
'U', 0x3C,
'I', 0x43,
'O', 0x44,
'P', 0x4D,
'{', 0x54,
'}', 0x5B,
'|', 0x5D,

'A', 0x1C,
'S', 0x1B,
'D', 0x23,
'F', 0x2B,
'G', 0x34,
'H', 0x33,
'J', 0x3B,
'K', 0x42,
'L', 0x4B,
':', 0x4C,
'"', 0x52,

'Z', 0x1A,
'X', 0x22,
'C', 0x21,
'V', 0x2A,
'B', 0x32,
'N', 0x31,
'M', 0x3A,
'<', 0x41,
'>', 0x49,
'?', 0x4A
}
/*--------------------------------------------------------------*/

 

/*--------------------------------------------------------------*/
//ASCII
unsigned char code KB_ASCII[][3] = {
'`', '~', 0x0E,
'1', '!', 0x16,
'2', '@', 0x1E,
'3', '#', 0x26,
'4', '$', 0x25,
'5', '%', 0x2E,
'6', '^', 0x36,
'7', '&', 0x3D,
'8', '*', 0x3E,
'9', '(', 0x46,
'0', ')', 0x45,
'-', '_', 0x4E,
'=', '+', 0x55,

'q', 'Q', 0x15,
'w', 'W', 0x1D,
'e', 'E', 0x24,
'r', 'R', 0x2D,
't', 'T', 0x2C,
'y', 'Y', 0x35,
'u', 'U', 0x3C,
'i', 'I', 0x43,
'o', 'O', 0x44,
'p', 'P', 0x4D,
'[', '{', 0x54,
']', '}', 0x5B,
'\', '|', 0x5D,

'a', 'A', 0x1C,
's', 'S', 0x1B,
'd', 'D', 0x23,
'f', 'F', 0x2B,
'g', 'G', 0x34,
'h', 'H', 0x33,
'j', 'J', 0x3B,
'k', 'K', 0x42,
'l', 'L', 0x4B,
';', ':', 0x4C,
''', '"', 0x52,

'z', 'Z', 0x1A,
'x', 'X', 0x22,
'c', 'C', 0x21,
'v', 'V', 0x2A,
'b', 'B', 0x32,
'n', 'N', 0x31,
'm', 'M', 0x3A,
',', '<', 0x41,
'.', '>', 0x49,
'/', '?', 0x4A
}
/*--------------------------------------------------------------*/


/*--------------------------------------------------------------*/
//Fuction Key Funx
#define Fun1 0x05
#define Fun2 0x06
#define Fun3 0x04
#define Fun4 0x0C
#define Fun5 0x03
#define Fun6 0x0B
#define Fun7 0x83
#define Fun8 0x0A
#define Fun9 0x01
#define Fun10 0x09
#define Fun11 0x78
#define Fun12 0x07
/*--------------------------------------------------------------*/


/*--------------------------------------------------------------*/
//Small KeyBoard
KP_0,70
KP_1,69
KP_2,72
KP_3,7A
KP_4,6B
KP_5,73
KP_6,74
KP_7,6C
KP_8,75
KP_9,7D

KP_NUM,77
KP_/,4A
KP_*,7C
KP_-,7B
KP_+,79
KP_EN,5A
KP_.,71
/*--------------------------------------------------------------*/


/*--------------------------------------------------------------*/
//Left Control Key
#define ESC  0x76
#define TAB  0x0D
#define CAPS 0x58
#define L_SHFT 0x12
#define L_CTRL 0x14
#define L_GUI 0x1F
#define L_ALT 0x11
#define SPACE 0x29
#define R_ALT 0x11
#define R_GUI 0x27
#define R_CTRL 0x14
#define R_SHFT 0x59
#define ENTER 0x5A
#define BKSP 0x66
/*--------------------------------------------------------------*/


/*--------------------------------------------------------------*/
//Middle Control Key
#define INSERT 0x70
#define HOME 0x6C
#define PG_UP 0x7D
#define DELETE 0x71
#define END  0x69
#define PG_DN 0x7A
#define SCROLL 0x7E

#define U_ARROW 0x75
#define D_ARROW 0x72
#define L_ARROW 0x6B
#define R_ARROW 0x74
/*--------------------------------------------------------------*/

 

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
推荐文章
最近访客