根据客户的要求利用单片机制作一个小的工控键盘,将下面对应的键值发送到电脑显示,利用的协议就是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矩阵工业键盘相关推荐

  1. 51单片机模拟I2C协议

    什么是I2C 首先需要知道什么是I2C协议.I2C总线是由Philips公司开发的一种简单.双向二线制同步串行总线.它只需要两根线即可在连接于总线上的器件之间传送信息(摘自百度百科).I2C主要有两条 ...

  2. 51单片机模拟电梯控制(含完整代码)

    51单片机模拟电梯控制 前言 一.普中51-单核-A2开发板 二.系统功能 三 .预定义 四.电梯内按有报警按键,该功能由外部中断功能和蜂鸣器实现 五.延时函数-----电梯每上升,下降一层和开门关门 ...

  3. 使用51单片机模拟IIC从机,实现主机(51单片机)对模拟从机的读写操作

    51单片机.IIC从机模拟.IIC协议.iiC读写 1.思路 1.1写数据 1.2读数据 2.从机IIC协议 2.1起始信号和结束信号 2.2从机读取和写数据 2.3从机发送和接收ACK 2.4判断主 ...

  4. 51单片机模拟数字键盘输入以及图像显示+Proteus仿真

    51单片机模拟数字键盘输入以及图像显示+Proteus仿真 关于取模 取模软件:pctolcd2002 文字取模方式:阴码–列行式,逆向 主程序代码 //*********************** ...

  5. 51单片机最小系统的制作和程序烧录

    这篇博客就来分享一下51单片机最小系统的制作以及怎么下载程序 首先准备的材料有:一块板子,一块89c51/52的芯片,一个51芯片插座,12MHZ的晶振,一个10的电阻,一个10uf的电解电容 两个2 ...

  6. 51单片机模拟电子琴+Proteus仿真

    51单片机模拟电子琴+Proteus仿真 Proteus仿真 示例程序 #include<reg51.h> #include<intrins.h>#define uchar u ...

  7. 51单片机模拟交通信号灯控制系统设计

    51单片机模拟交通信号灯控制系统设计 设计要求: 1.用LED灯模拟十字路口交通灯控制 2.正常情况下双方向轮流通行 3.特殊情况时,A方向通行 4.紧急情况时,A和B方向都不通行 本任务涉及定时控制 ...

  8. 【51单片机】七段数码管和矩阵键盘的综合实验——计算器(思路+仿真电路+源代码)

    系列文章目录 [51单片机]矩阵键盘逐行扫描法仿真实验+超详细Proteus仿真和Keil操作步骤 [51单片机]点阵LED的显示实验 [51单片机]七段数码管显示实验+详细讲解 [51单片机]矩阵键 ...

  9. c语言变大变小的图片,51单片机模拟水滴由小变大然后滴落现象(附带C语言源码)...

    51单片机模拟水滴由小变大然后滴落现象(附带C语言源码) [复制链接] #include typedef unsigned char u8; typedef signed char v8; typed ...

最新文章

  1. RESTful之排序
  2. 选择“Win32汇编”的三大理由?
  3. 七自由度车辆稳定性数学模型和simulink求解
  4. Oracle 原理:复杂的SQL语句
  5. 个人计算机与手机的区别,手机与电脑的CPU是一回事吗?一共有六大区别,看看你知道多少!...
  6. 把数组排列成最小的数(详解)
  7. Python之turtle画小狗、狮子头和小黄人
  8. java表头表体动态返回_JAVA LIST 简单分页 集成EXT4 grid表头动态返回
  9. 基于VS2019+QT的Coin3D三维可视化库的安装预测测试
  10. javacv获取摄像头列表
  11. C++ 合并两个有序链表
  12. java cobar_Cobar-Client 实现策略总结
  13. 音频编码(PCM、G711A、G711U、AAC)理解
  14. 支付宝 android 指纹支付,支付宝更新,小米5终于用上了指纹支付
  15. Win10笔记本电脑某些应用能使用麦克风,但某些无法使用麦克风解决方法(本文以QQ为例,其他应用也适用)
  16. win11系统没有触屏怎么办 Windows11没有触屏的解决方法
  17. 1 invalid import format(s) Postman Collection Format v1 is no longer supported and can not be import
  18. SOLIDWORKS会遇到的预览问题
  19. 无魔法插件 - ChatGPT Sidebar with GPT-4
  20. 基础SQL Server 操作问题——对象‘主键’依赖于列‘ID’/标识列‘ID’的数据类型必须是int,bigint,smallint等

热门文章

  1. 深度学习——神经网络的种类(前馈神经网络,反馈神经网络,图网络)
  2. 各种车辆类型的名称大全
  3. Error1819(HY000):Your password does not satisfy the current policy requirements
  4. matlab 中@的用法
  5. matlab中函数的定义和使用
  6. 博图中热电阻/热电偶(RTD/TC)模拟量信号的处理
  7. PCL学习笔记(十八)-- ConditionalRemoval和RadiusOutliersRemoval滤波器移除离群点
  8. 用开源博客系统OneBlog来搭建自己的个人技术博客网站(java版博客系统)
  9. Win10右键菜单栏目中增加新建excel的方法教学
  10. hyperterminal使用教程_hyperterminal 教程