51单片机模拟PS2协议制作5X5矩阵工业键盘
根据客户的要求利用单片机制作一个小的工控键盘,将下面对应的键值发送到电脑显示,利用的协议就是PS2,单片机型号为stc89c52rc,晶振为12M;
1 | 0 | |||
6 | 5 | 4 | 3 | 2 |
7 | 8 | 9 | 减号 | 等号 |
y | u | i | o | p |
q | w | e | r | t |
#include <reg51.h>
#include "PS2.H"
BYTE PS2RecChar=0xCC;
BOOL KeyBoardFlag=FALSE;
#define Key_line P0 //键盘行入口
#define Key_list P2 //键盘列入口
#define PS2_1 0 //16
#define PS2_0 1 //45
#define PS2_6 2 //36
#define PS2_5 3 //2e
#define PS2_4 4 //25
#define PS2_3 5 //26
#define PS2_2 6 //1e
#define PS2_7 7 //3d
#define PS2_8 8 //3e
#define PS2_9 9 //46
#define PS2_dec 10 //4e
#define PS2_eq 11 //55
#define PS2_y 12 //35
#define PS2_u 13 //3c
#define PS2_i 14 //43
#define PS2_o 15 //44
#define PS2_p 16 //4d
#define PS2_q 17 //15
#define PS2_w 18 //1d
#define PS2_e 19 //24
#define PS2_r 20 //2d
#define PS2_t 21 //2c
//第二套键盘码
unsigned char PS2Value[22]={0x16,0x45,0x36,0x2e,0x25,0x26,0x1e,0x3d,0x3e,0x46,0x4e,0x55,0x35,0x3c,
0x43,0x44,0x4d,0x15,0x1d,0x24,0x2d,0x2c};
unsigned char Key_Press(void)
{
unsigned temp3;
unsigned char flag=0; //设定标志位
Key_line=0xe0; //将P0口低5位全部设置位0
temp3=Key_list; //读取P2口的状态,若果P2口的值temp3:(temp3&0xff)!=0xff成立,表示有键按下
if(((temp3&0xff)!=0xff)) //有键按下条件判断
{
flag=1;
//Key_line=0XFF; //清零键盘行端口
Key_list=0xff; //清零键盘列端口
}
else
flag=0; //无键按下标志
return flag;
}
void delay(unsigned int ms)
{
unsigned int i,j;
for(i=ms;i>0;i--)
for(j=100;j>0;j--);
}
unsigned char Key_Scan(void)
{
unsigned char temp2=0,temp3=0; //temp2用来保存行键盘数据,temp3保存列键盘数据
unsigned char temp=0,flag=0; //函数返回值temp
unsigned char i=0,key=0; //i位循环控制变量,给行送数据,key保存检测键盘按下的标志位
if((key=Key_Press())!=0) //判断是否有键按下
{
delay(30);
if((key=Key_Press())!=0)
{
for(i=0x01;i!=0x20;i=i<<1) //循环控制变量,扫描5行
{
Key_line=(~i); //将循环控制变量赋值行地址
temp2 =(~i); //保存行地址
//temp2=Key_line;
temp3=Key_list; //读取列地址数据
switch((temp3&0xff)) //判断是那列有键按下
{
case 0xfe: //第一列有键按下
switch((temp2&0xff)) //判断第一列有键按下时,对应的行按键
{
case 0xfe:
temp=23; //第一行有键按下
break; //该键无键盘号定义
case 0xfd: //第二行有键按下
temp=PS2_6;flag=1; //对应键值位PS2键盘的数字6,对应的键盘扫描码为0x36
break;
case 0xfb: //第三行有键按下
temp=PS2_7; flag=1;//对应键值位PS2键盘的数字7,对应的键盘扫描码为0x3d
break;
case 0xf7: //第四行有键按下
temp=PS2_y; flag=1; //对应键值位PS2键盘的字母y,对应的键盘扫描码为0x35
break;
case 0xef: //第五行有键按下
temp=PS2_q ;flag=1; //对应键值位PS2键盘的字母q,对应的键盘扫描码为0x15
break;
}
break;
case 0xfd:
switch((temp2&0xff)) // 第二列有键按下
{
case 0xfe: //第一行有键按下
temp=23; //该键无键盘号定义
break;
case 0xfd: //第二行有键按下
temp=PS2_5;flag=1; //对应键值位PS2键盘的数字5,对应的键盘扫描码为0x2e
break;
case 0xfb: //第三行有键按下
temp=PS2_8; flag=1; //对应键值位PS2键盘的数字8,对应的键盘扫描码为0x8e
break;
case 0xf7: //第四行有键按下
temp=PS2_u;flag=1; //对应键值位PS2键盘的字母u,对应的键盘扫描码为0x3c
break;
case 0xef: //第五行有键按下
temp=PS2_w ; flag=1; //对应键值位PS2键盘的字母w,对应的键盘扫描码为0x1d
break;
}
break;
case 0xfb:
switch((temp2&0xff)) // 第三列有键按下
{
case 0xfe: //第一行有键按下
temp=23; //该键无键盘号定义
break;
case 0xfd: //第二行有键按下
temp=PS2_4; flag=1; //对应键值位PS2键盘的数字4,对应的键盘扫描码为0x25
break;
case 0xfb: //第三行有键按下
temp=PS2_9; flag=1; //对应键值位PS2键盘的数字9,对应的键盘扫描码为0x46
break;
case 0xf7: //第四行有键按下
temp=PS2_i; flag=1; //对应键值位PS2键盘的字母i,对应的键盘扫描码为0x43
break;
case 0xef: //第五行有键按下
temp=PS2_e; flag=1; //对应键值位PS2键盘的字母e,对应的键盘扫描码为0x24
break;
}
break;
case 0xf7:
switch((temp2&0xff)) // 第四列有键按下
{
case 0xfe: //第一行有键按下
temp=PS2_1; flag=1; //对应键值位PS2键盘的数字1,对应的键盘扫描码为0x16
break;
case 0xfd: //第二行有键按下
temp=PS2_3; flag=1; //对应键值位PS2键盘的数字3,对应的键盘扫描码为0x26
break;
case 0xfb: //第三行有键按下
temp=PS2_dec;flag=1; //对应键值位PS2键盘的减号,对应的键盘扫描码为0x4e
break;
case 0xf7: //第四行有键按下
temp=PS2_o; flag=1; //对应键值位PS2键盘的字母o,对应的键盘扫描码为0x44
break;
case 0xef: //第五行有键按下
temp=PS2_r; flag=1; //对应键值位PS2键盘的字母r,对应的键盘扫描码为0x2d
break;
}
break;
case 0xef:
switch((temp2&0xff)) // 第五列有键按下
{
case 0xfe: //第一行有键按下
temp=PS2_0; flag=1; //对应键值位PS2键盘的数字0,对应的键盘扫描码为0x45
break;
case 0xfd: //第二行有键按下
temp=PS2_2; flag=1; //对应键值位PS2键盘的数字2,对应的键盘扫描码为0x1e
break;
case 0xfb: //第三行有键按下
temp=PS2_eq;flag=1; //对应键值位PS2键盘的等号,对应的键盘扫描码为0x55
break;
case 0xf7: //第四行有键按下
temp=PS2_p;flag=1; //对应键值位PS2键盘的字母p,对应的键盘扫描码为0x4d
break;
case 0xef: //第五行有键按下
temp=PS2_t;flag=1; //对应键值位PS2键盘的字母t,对应的键盘扫描码为0x2c
break;
}
break;
}
//P0=0XFF; //每当检测完一行时清零行端口和列端口
//P2=0xff;
if((key=Key_Press())!=0);
delay(30);
}
}
}
else temp=23; //无键按下返回数字23,对应数组内的0;
if(flag==1)
return temp; //返回按键扫描值
else
return 23;
}
void OnKeyBoardOnline(BOOL i)
{
KeyBoardFlag=i;
}
//---------------------------------------------------------------------------
void OnPS2ReceiveChar(BYTE ReceChar,BOOL P)
{
BOOL ParityBit=0;
ACC=ReceChar;
CY=P;
ParityBit=(BOOL)(CY?0x00:0x80);//奇校验位
if(P==ParityBit);
PS2RecChar=ReceChar;
}
//---------------------------------------------------------------------------
void OnPS2SendChar(BYTE dat)
{
BOOL ParityBit;
BYTE i;
ACC=dat;
CY=P;
ParityBit=(BOOL)(CY?0x00:0x80);//奇校验位
CLSSIGNAL();
CT_KB=OFF;
EX0=0;
H_DATA=0;Delay10us();//start bit
H_CLK=1;
Delay10us();
H_CLK=0;
Delay30us();
for(i=0;i<8;i++)
{
if(dat&0x01==0x01){H_DATA=1;Delay10us();}
else {H_DATA=0;Delay10us();}
dat>>=1;
H_CLK=1;
Delay10us();
H_CLK=0;
Delay30us();
}
H_DATA=ParityBit;Delay10us();//parity bit
H_CLK=1;
Delay10us();
H_CLK=0;
Delay30us();
H_DATA=1;Delay10us();//stop bit
H_CLK=1;
Delay10us();
H_CLK=0;
Delay30us();
IE0=0;
EX0=1;
H_CLK=1;
H_DATA=1;
CT_KB=ON;
Delay30us();
}
//---------------------------------------------------------------------------
void ExternInterrupt0(void) interrupt 0
{
BOOL ParityBit=0,CLKFlag=1;
BYTE i=0,j=8,dat=0x00;
EX0=0;
while(CLKFlag)
{
i++;
if(H_CLK==1)CLKFlag=0;
if(i>0xEE)
{
IE0=0;
EX0=1;
return ;
}
}
while(j--)//延时等待大键盘的动作
{
for(i=0;i<0x88;i++)//检查是否有数据处理 0x88
{
if(H_CLK==0)//有动作则是大键盘存在
{
OnKeyBoardOnline(TRUE);//大键盘存在,开机由大键盘应答
IE0=0;
EX0=1;
return ;//存在的话置标志位,并返回
}
}
}
OnKeyBoardOnline(FALSE);//大键盘不存在,由小键盘应答
//转到接收
for(i=0;i<8;i++)//read 8bit
{
Delay30us();
H_CLK=0;
Delay30us();
H_CLK=1;
dat=dat>>1;
if(H_DATA)dat|=0x80;
if(H_CLK==0){ return; }//如果时钟被拉低,则有错误发生
}
Delay30us();
H_CLK=0;
Delay30us();
H_CLK=1;
if(H_DATA)ParityBit=1;
else ParityBit=0;
Delay30us();
H_CLK=0;
Delay30us();
H_CLK=1;//STOP BIT H_DATA 0 ERR
Delay10us();
H_DATA=0; //ACK bit
Delay10us();
H_CLK=0;
Delay30us();Delay30us();
H_CLK=1;
Delay30us();
H_DATA=1;
OnPS2ReceiveChar(dat,ParityBit);
IE0=0;
EX0=1;
return ;
}
//---------------------------------------------------------------------------
void ProcessPS2(void)
{
if(KeyBoardFlag==FALSE)//大键盘不存在
{
if(PS2RecChar==0xF3)//1
{
OnPS2SendChar(0xFA);
PS2RecChar=0xCC;
}
else if(PS2RecChar==0x00)//11
{
OnPS2SendChar(0xFA);
PS2RecChar=0xCC;
}
else if(PS2RecChar==0x02)//111
{
OnPS2SendChar(0xFA);
PS2RecChar=0xCC;
}
else if(PS2RecChar==0x20)//1111
{
OnPS2SendChar(0xFA);
PS2RecChar=0xCC;
}
else if(PS2RecChar==0xED)//2
{
OnPS2SendChar(0xFA);
PS2RecChar=0xCC;
}
else if(PS2RecChar==0xF0)//3
{
OnPS2SendChar(0xFA);
PS2RecChar=0xCC;
}
else if(PS2RecChar==0xF2)//4
{
OnPS2SendChar(0xFA);
Delay30us();
OnPS2SendChar(0xAB);
Delay30us();
OnPS2SendChar(0x83);
PS2RecChar=0xCC;
}
else if(PS2RecChar==0xEF)//5
{
OnPS2SendChar(0xFA);
Delay30us();
OnPS2SendChar(0xBF);
Delay30us();
OnPS2SendChar(0xB0);
PS2RecChar=0xCC;
}
else if(PS2RecChar==0xF3)//6
{
OnPS2SendChar(0xFA);
PS2RecChar=0xCC;
}
else if(PS2RecChar==0xFE)//7 //resend
{
PS2RecChar=0xCC;
}
else if(PS2RecChar==0xEE)//8
{
OnPS2SendChar(0xEE);
PS2RecChar=0xCC;
}
else if(PS2RecChar==0xEE)//9
{
OnPS2SendChar(0xEE);
PS2RecChar=0xCC;
}
else if(PS2RecChar==0xF1)//10
{
OnPS2SendChar(0xFA);
PS2RecChar=0xCC;
}
else if(PS2RecChar==0xF4)//11
{
OnPS2SendChar(0xFA);
PS2RecChar=0xCC;
}
else if(PS2RecChar==0xAA)//12
{
OnPS2SendChar(0xAA);
PS2RecChar=0xCC;
}
else if(PS2RecChar==0xFF)//13
{
OnPS2SendChar(0xFA);
Delay30us();
OnPS2SendChar(0xAA);
Delay30us();
PS2RecChar=0xCC;
}
else ;
}
}
//---------------------------------------------------------------------------
void PS2Init(void)
{
IT0=0; //低电平触发中断
PX0=1;
EX0=1;
}
//---------------------------------------------------------------------------
extern void ProcessPS2(void);
extern void PS2Init(void);
void main(void)
{
unsigned char tem;
PS2Init();
ProcessPS2();
while(1)
{
tem=Key_Scan();
switch(tem&0xff)
{
case 23 :
break;
default:
{
OnPS2SendChar(PS2Value[tem]);
}
break;
}
//开机应答,使电脑能识别到键盘
//other code
}
}
仿真矩阵键盘电路图,该电路未连接PS2,但可通过LED灯观察每个按键按下之后的键值返回知否和第二套键盘码对应一致
第二套键值码对应表:
51单片机模拟PS2协议制作5X5矩阵工业键盘相关推荐
- 51单片机模拟I2C协议
什么是I2C 首先需要知道什么是I2C协议.I2C总线是由Philips公司开发的一种简单.双向二线制同步串行总线.它只需要两根线即可在连接于总线上的器件之间传送信息(摘自百度百科).I2C主要有两条 ...
- 51单片机模拟电梯控制(含完整代码)
51单片机模拟电梯控制 前言 一.普中51-单核-A2开发板 二.系统功能 三 .预定义 四.电梯内按有报警按键,该功能由外部中断功能和蜂鸣器实现 五.延时函数-----电梯每上升,下降一层和开门关门 ...
- 使用51单片机模拟IIC从机,实现主机(51单片机)对模拟从机的读写操作
51单片机.IIC从机模拟.IIC协议.iiC读写 1.思路 1.1写数据 1.2读数据 2.从机IIC协议 2.1起始信号和结束信号 2.2从机读取和写数据 2.3从机发送和接收ACK 2.4判断主 ...
- 51单片机模拟数字键盘输入以及图像显示+Proteus仿真
51单片机模拟数字键盘输入以及图像显示+Proteus仿真 关于取模 取模软件:pctolcd2002 文字取模方式:阴码–列行式,逆向 主程序代码 //*********************** ...
- 51单片机最小系统的制作和程序烧录
这篇博客就来分享一下51单片机最小系统的制作以及怎么下载程序 首先准备的材料有:一块板子,一块89c51/52的芯片,一个51芯片插座,12MHZ的晶振,一个10的电阻,一个10uf的电解电容 两个2 ...
- 51单片机模拟电子琴+Proteus仿真
51单片机模拟电子琴+Proteus仿真 Proteus仿真 示例程序 #include<reg51.h> #include<intrins.h>#define uchar u ...
- 51单片机模拟交通信号灯控制系统设计
51单片机模拟交通信号灯控制系统设计 设计要求: 1.用LED灯模拟十字路口交通灯控制 2.正常情况下双方向轮流通行 3.特殊情况时,A方向通行 4.紧急情况时,A和B方向都不通行 本任务涉及定时控制 ...
- 【51单片机】七段数码管和矩阵键盘的综合实验——计算器(思路+仿真电路+源代码)
系列文章目录 [51单片机]矩阵键盘逐行扫描法仿真实验+超详细Proteus仿真和Keil操作步骤 [51单片机]点阵LED的显示实验 [51单片机]七段数码管显示实验+详细讲解 [51单片机]矩阵键 ...
- c语言变大变小的图片,51单片机模拟水滴由小变大然后滴落现象(附带C语言源码)...
51单片机模拟水滴由小变大然后滴落现象(附带C语言源码) [复制链接] #include typedef unsigned char u8; typedef signed char v8; typed ...
最新文章
- RESTful之排序
- 选择“Win32汇编”的三大理由?
- 七自由度车辆稳定性数学模型和simulink求解
- Oracle 原理:复杂的SQL语句
- 个人计算机与手机的区别,手机与电脑的CPU是一回事吗?一共有六大区别,看看你知道多少!...
- 把数组排列成最小的数(详解)
- Python之turtle画小狗、狮子头和小黄人
- java表头表体动态返回_JAVA LIST 简单分页 集成EXT4 grid表头动态返回
- 基于VS2019+QT的Coin3D三维可视化库的安装预测测试
- javacv获取摄像头列表
- C++ 合并两个有序链表
- java cobar_Cobar-Client 实现策略总结
- 音频编码(PCM、G711A、G711U、AAC)理解
- 支付宝 android 指纹支付,支付宝更新,小米5终于用上了指纹支付
- Win10笔记本电脑某些应用能使用麦克风,但某些无法使用麦克风解决方法(本文以QQ为例,其他应用也适用)
- win11系统没有触屏怎么办 Windows11没有触屏的解决方法
- 1 invalid import format(s) Postman Collection Format v1 is no longer supported and can not be import
- SOLIDWORKS会遇到的预览问题
- 无魔法插件 - ChatGPT Sidebar with GPT-4
- 基础SQL Server 操作问题——对象‘主键’依赖于列‘ID’/标识列‘ID’的数据类型必须是int,bigint,smallint等
热门文章
- 深度学习——神经网络的种类(前馈神经网络,反馈神经网络,图网络)
- 各种车辆类型的名称大全
- Error1819(HY000):Your password does not satisfy the current policy requirements
- matlab 中@的用法
- matlab中函数的定义和使用
- 博图中热电阻/热电偶(RTD/TC)模拟量信号的处理
- PCL学习笔记(十八)-- ConditionalRemoval和RadiusOutliersRemoval滤波器移除离群点
- 用开源博客系统OneBlog来搭建自己的个人技术博客网站(java版博客系统)
- Win10右键菜单栏目中增加新建excel的方法教学
- hyperterminal使用教程_hyperterminal 教程