

《姬家寨村单片机键盘鼠标显示器》
硬件设计:姬学瑞;软件编程:姬学瑞;版权所有,琴权必究!
河南省新乡市姬家寨村电子科技研究所研制!
《壹键盘》:
/*此程序在SP-518USB开发板上测试过 laosong */
/****************************************************************
程序名称: 程序自动接收PS2键盘的按键,并且显示出来。
说明:开发板上面的SE15 SE16跳线必须设置为PS2。
程序中没有做键盘数据的奇偶校验
*****************************************************************/
#include <reg51.h>
#include <intrins.h>
#include <keycode.h>
#define uint unsigned int
#define uchar unsigned char
sbit Key_Data = P3^4; /*定义Keyboard引脚*/
sbit Key_CLK = P3^3;
sbit lcd_rs_port = P2^7; /*定义LCD控制端口*/
sbit lcd_rw_port = P2^6; /*定义LCD控制端口*/
sbit lcd_en_port = P2^5; /*定义LCD控制端口*/
#define lcd_data_port P0 /*定义LCD控制端口*/
uchar IntNum = 0; /*中断次数计数*/
uchar KeyV; /*键值*/
uchar Key_UP=0, Shift = 0;/*Key_UP是键松开标识,Shift是Shift键按下标识*/
uchar BF = 0; /*标识是否有字符被收到*/
uchar DisNum = 0; //显示用指针
uchar code lcd_line0[]={" Sappire PS2 KB "};
uchar code lcd_line1[]={" PS2 KB Testing "};
void Decode(unsigned char ScanCode); /*按键处理*/
void lcd_delay(uchar ms); /*LCD1602 延时*/
void lcd_busy_wait(); /*LCD1602 忙等待*/
void lcd_command_write(uchar command); /*LCD1602 命令字写入*/
void lcd_system_reset(); /*LCD1602 初始化*/
void lcd_char_write(uchar x_pos,y_pos,lcd_dat); /*LCD1602 字符写入*/
void Delay_400Ms(); /*延时400毫秒*/
void main()
{
uchar i;
lcd_system_reset();
for(i=0;i<16;i++) lcd_char_write(i,0,lcd_line0[i]);
for(i=0;i<16;i++) lcd_char_write(i,1,lcd_line1[i]);
Delay_400Ms();
Delay_400Ms();
Delay_400Ms();
for(i=0;i<16;i++) lcd_char_write(i,1,' ');
IT1 = 0; /*设外部中断1为低电平触发*/
EX1 = 1; /*开外部中断1*/
EA = 1; /*开总中断*/
while(1){
if (BF) Decode(KeyV);
else EA = 1; //开中断
}
}
void Keyboard_out(void) interrupt 2
{
if ((IntNum > 0) && (IntNum < 9)){
KeyV = KeyV >> 1; /*因键盘数据是低>>高,结合上一句所以右移一位*/
if (Key_Data) KeyV = KeyV | 0x80; /*当键盘数据线为1时为1到最高位*/
}
IntNum++;
while (!Key_CLK); /*等待PS/2CLK拉高*/
if (IntNum > 10){
IntNum = 0; /*当中断10次后表示一帧数据收完,清变量准备下一次接收*/
BF = 1; /*标识有字符输入完了*/
EA = 0; /*关中断等显示完后再开中断 (注:如这里不用BF和关中断直接调Decode()则所Decode中所调用的所有函数要声明为再入函数)*/
}
}
void Decode(unsigned char ScanCode) /*注意:如SHIFT+G为12H 34H F0H 34H F0H 12H,也就是说shift的通码+G的通码+shift的断码+G的断码*/
{
uchar i;
uchar TempCyc;
if (!Key_UP){ /*当键盘松开时*/
switch (ScanCode){
case 0xF0 : /* 当收到0xF0,Key_UP置1表示断码开始*/
Key_UP = 1;
break;
case 0x12 : /* 左 SHIFT*/
Shift = 1;
break;
case 0x59 : /* 右 SHIFT*/
Shift = 1;
break;
default:
if (DisNum > 15){
DisNum = 0;
for(i=0;i<16;i++) lcd_char_write(i,1,' '); /*清LCD第1行显示*/
}
if(!Shift){ /*如果SHIFT没按下*/
for (TempCyc = 0;(UnShifted[TempCyc][0]!=ScanCode)&&(TempCyc<62); TempCyc++); /*查表显示*/
if (UnShifted[TempCyc][0] == ScanCode){
lcd_char_write(DisNum, 1, UnShifted[TempCyc][1]);
DisNum++;
}
}
else{ /*按下SHIFT*/
for(TempCyc = 0; (Shifted[TempCyc][0]!=ScanCode)&&(TempCyc<62); TempCyc++); /*查表显示*/
if (Shifted[TempCyc][0] == ScanCode){
lcd_char_write(DisNum, 1, Shifted[TempCyc][1]);
DisNum++;
}
}
break;
}
}
else{
Key_UP = 0;
switch (ScanCode){ /*当键松开时不处理判码,如G 34H F0H 34H 那么第二个34H不会被处理 */
case 0x12 : /* 左 SHIFT*/
Shift = 0;
break;
case 0x59 : /* 右 SHIFT*/
Shift = 0;
break;
}
}
BF = 0; /*标识字符处理完了*/
}
void lcd_delay(uchar ms) /*LCD1602 延时*/
{
uchar j;
while(ms--){
for(j=0;j<250;j++)
{;}
}
}
void lcd_busy_wait() /*LCD1602 忙等待*/
{
lcd_rs_port = 0;
lcd_rw_port = 1;
lcd_en_port = 1;
lcd_data_port = 0xff;
while (lcd_data_port&0x80);
lcd_en_port = 0;
}
void lcd_command_write(uchar command) /*LCD1602 命令字写入*/
{
lcd_busy_wait();
lcd_rs_port = 0;
lcd_rw_port = 0;
lcd_en_port = 0;
lcd_data_port = command;
lcd_en_port = 1;
lcd_en_port = 0;
}
void lcd_system_reset() /*LCD1602 初始化*/
{
lcd_delay(20);
lcd_command_write(0x38);
lcd_delay(100);
lcd_command_write(0x38);
lcd_delay(50);
lcd_command_write(0x38);
lcd_delay(10);
lcd_command_write(0x08); /* 关闭显示*/
lcd_command_write(0x01); /* 显示清屏*/
lcd_command_write(0x06); /* 显示光标移动设置*/
lcd_command_write(0x0f); /* 显示开及光标设置*/
lcd_data_port = 0xff; /*释放数据端口*/
}
void lcd_char_write(uchar x_pos,y_pos,lcd_dat) /*LCD1602 字符写入*/
{
x_pos &= 0x0f; /* X位置范围 0~15 */
y_pos &= 0x01; /* Y位置范围 0~ 1 */
if(y_pos==1) x_pos += 0x40;
x_pos += 0x80;
lcd_command_write(x_pos);
lcd_busy_wait();
lcd_rs_port = 1;
lcd_rw_port = 0;
lcd_en_port = 0;
lcd_data_port = lcd_dat;
lcd_en_port = 1;
lcd_en_port = 0;
lcd_data_port = 0xff; /*释放数据端口*/
}
//400ms延时
void Delay_400Ms()
{
uchar TempCycA = 5;
uint TempCycB;
while(TempCycA--){
TempCycB=7269;
while(TempCycB--);
}
}
《贰鼠标》:
/*此程序在SP-518USB开发板上测试过 laosong */
#include<reg52.h>
#include"mouse.h"
#include"LCD1602_4.h"
sbit Speaker_port=P3^7;
/*1MS为单位的延时程序*/
void delay_1ms(uchar x)
{
uchar j;
while(x--) { for(j=0;j<125;j++); }
}
/*喇叭发声简单程序*/
void Speaker_output()
{
uchar i;
for(i=0;i<100;i++){
Speaker_port = 0;
delay_1ms(3);
Speaker_port = 1;
delay_1ms(1);
}
}
void main()
{
LCM1602_Init();//初始化液晶1602
LCM1602_write_string(0,0,"x:----");
LCM1602_write_string(0,8,"y:----");
LCM1602_write_string(1,0,"------");
Init_mouse();
mouse_send_data(0xf4);//向鼠标发送0xF4命令,开始工作
EX1=0;//关掉外部中断以避开鼠标发回的应答
delayms(100);
EX1=1;//重开外部中断
while(1)
{
CLEARSCREEN;//清屏
LCM1602_write_string(0,0,"x:");
num(0,2,move_x);//x坐标值
LCM1602_write_string(0,8,"y:");
num(0,10,move_y);//y坐标值
if(mouse_data[0]&0x01)//如果点下左键
{
LCM1602_write_string(1,0,"left");
Speaker_output();//发出声音
}
else if(mouse_data[0]&0x02)//如果点下右键
{
LCM1602_write_string(1,0,"right");
Speaker_output();//发出声音
}
else if(mouse_data[0]&0x04)//如果点下中键
{
LCM1602_write_string(1,0,"middle");
Speaker_output();//发出声音
}
else
{
LCM1602_write_string(1,0,"nothing");
}
delayms(50);
}
}