51单片机模拟PS2协议制作5X5矩阵工业键盘

发布者:zuiquan最新更新时间:2016-01-18 来源: eefocus关键字:51单片机  模拟PS2协议  工业键盘 手机看文章 扫描二维码
随时随地手机看文章
根据客户的要求利用单片机制作一个小的工控键盘,将下面对应的键值发送到电脑显示,利用的协议就是PS2,单片机型号为stc89c52rc,晶振为12M;
      1 0
6 5 4 3 2
7 8 9 减号 等号
y u i o p
q w e r t


#include
#include "PS2.H"

BYTE PS2RecChar=0xCC;
BOOL KeyBoardFlag=FALSE;
#define Key_line P0 //键盘行入口
#define Key_list P2 //键盘列入口

#define PS2_1      //16
#define PS2_0       //45
#define PS2_6     //36
#define PS2_5      //2e
#define PS2_4       //25
#define PS2_3        //26
#define PS2_2        //1e
#define PS2_7        //3d
#define PS2_8        //3e
#define PS2_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协议  工业键盘 引用地址:51单片机模拟PS2协议制作5X5矩阵工业键盘

上一篇:51单片机PWM电机调速程序
下一篇:基于超声波传感器的自主移动机器人的探测系统

推荐阅读最新更新时间:2024-03-16 14:44

51单片机实验2:led灯闪烁
开发板led模块电路图如下: 在keil中,sbit的声明要放在全局变量的位置,若放在函数中,会报错。 延时函数的变量使用unsigned char,而不是int,因为char所占空间为1字节,为int所占空间为4字节,因此使用char可以节约内存。但是unsigned char仅能表示0~255,所以延时函数中的参数最大为255,若要更大,则使用int。 #include reg52.h #include intrins.h #define uc unsigned char sbit led1=P2^0; void delay(uc n) { uc i,j; for(i=1;i =n;i++) fo
[单片机]
<font color='red'>51单片机</font>实验2:led灯闪烁
51单片机温度计2.0版ds18b20+0.96寸OLED IIC显示
51单片机温度计LCD1602显示成功,于是又挑战了OLED显示 main.c #include oled.h #include ds18b20_1.h void Timer0Init(void); //void Gao_Wen(void); //void GaoDiInit(void); sbit Deng=P1^0; //LED灯 sbit FengMing=P1^1; //蜂鸣器 sbit GD=P3^0; //两个功能:高限温减小,关闭LED灯 sbit GF=P3^1; //两个功能
[单片机]
51单片机是否需要上拉电阻?
学过工科的同学都学过单片机,在单片机的学习中最常见的就是51单片机。51单片机是对所有兼容Intel 8031指令系统的单片机的统称。该系列单片机的始祖是Intel的8031单片机,后来随着Flash rom技术的发展,8031单片机取得了长足的进展,成为应用最广泛的8位单片机之一,其代表型号是AT89系列,它广泛应用于工业测控系统之中。51单片机是基础入门的一个单片机,还是应用最广泛的一种。在很多单片机电路中,其I/O管脚检测信号是以高、低电平来判断是否有信号变化的,比如5V为高电平,0V为低电平。那么这些管脚如果不接上拉电阻的话,其电平信号就可能是随机的了,0V~5V之间不一定是什么状态,这样的话单片机就不能正确地判断是不是有
[单片机]
<font color='red'>51单片机</font>是否需要上拉电阻?
基于51单片机的DHT11温湿度检测控制系统设计
前 言1.1本文研究的背景及意义 粮库已经被广泛的运用,是存储粮食的一个重要方式。是粮食仓库的简称,是粮食仓储企业习惯称谓,属于全民所有制企业,是我国粮食企业的一个重要组成部分,由粮食部门统一管理,担负着国家粮食储备、地方粮食储备、粮食流通的主渠道作用,其主要任务是完成粮食的接受、保管和调运输送等粮食流通诸环节。在不同季节内,尤其是不利于存储食物的季节内进行的一种保护措施。 因此研究温湿度的控制非常有必要,它可以进一步优化储存控制方式,提升水平。 1.2研究现状 我国地大物博,各地的自然环境条件不同,所以在不利于存储粮食的自然环境中,具有可调节温湿度的可控粮库更能够创造适宜存储的条件,中国各地经济水平和发达水平有比较大的差异
[单片机]
基于<font color='red'>51单片机</font>的DHT11温湿度检测控制系统设计
51单片机8255之PC口控制
程序编写步骤: 1.设置8255工作方式(PB工作在模式0且为输出,PC上半位在工作模式0且为输入) 2.编码PA,PB口地址(PB为#0FF7DH,PC口为#FF7EH,控制端口为#0FF7FH)​ 3.布置电路图(见图一) 4.设计程序(见源程序注释) 5.调试仿真(见视频文件) 电路原理图(图一): 元器件(51芯片;74ls373锁存器;led灯若干;按钮若干;导线若干;5v电源)​​ 图一 汇编源程序: ORG 0000H; LJMP MAIN; ORG 0030H;头文件 MAIN:MOV DPTR,#0FF7FH;工作方式设置 MOV A,#81H; MOVX @DPTR,A;
[单片机]
51单片机总线驱动
全部源代码下载: http://www.51hei.com/f/128yhj.rar #include reg51.h sbit cd = P2^0; unsigned char pdata *addr; #define uchar unsigned char #define uint unsigned short void lcd_writecom_two(uchar onedat,uchar twodat,uchar com); void lcd_writedat_onebyte(uchar onedat,uchar com); uchar lcd_readdat_onebyte(uchar com); voi
[单片机]
<font color='red'>51单片机</font>总线驱动
51单片机的中断与定时计数器尝试
这是我的第一篇有关51单片机的博客,主要记录我的学习历程与中间遇到的问题,如有错漏请指出。 在我理解里面中断与定时计数器是这样的: 中断是通过检查P3.2(INT0)与P3.3(INT1)两个引脚来触发的 计数器是通过检查P3.4(T0)与P3.5(T1)两个引脚的状态,要达到一定的次数(一般是记脉冲数)才触发 定时器不需要检测引脚,直接计数 先说中断的代码 #include reg51.h #include intrins.h #define SDT P0//静态数码管定义 unsigned char temp; unsigned char code SDT_map ={0xC0,0xF9,0xA4,0xB0,
[单片机]
51单片机控制多普勒血流计系统的设计和实现
0 引言 多普勒血流计的出现标志着在微血管灌流方面取得重大进步。本设计采取双通道装置拾取多普勒信号,有效地抑制噪声信号,采用单片机来对信号进行控制及处理,既简化了电路,又有助于信号的处理及读取。运用12位的AD574A不但提高了信号精度,利用其双极性,也省去了以往信号处理中复杂的乘方、开方电路或绝对值电路。通过四位LED显示,直观、准确地读取血细胞灌流量的瞬时相对定量值,可精确到小数点后两位。并同时配有扬声器来形象表示信号的强弱和变化。还可通过绘图仪,对信号进行长时间检测、记录,以便研究和分析。 1 系统总体方案 系统组成框图如图1所示。系统工作时,从激光探头发射出一束激光照射到组织上,并穿透组织形成一个半径为1mm的半球,
[单片机]
<font color='red'>51单片机</font>控制多普勒血流计系统的设计和实现
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved