开发者社区> 文艺小青年> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

MSP430学习笔记9-PS2键盘解码

简介:
+关注继续查看

PS2键盘解码的基本原理是通过外部中断读取键盘输出的串行信号,在根据扫描码进行查表解码。键盘发送往主机的信号总是在时钟的下降沿因此此中断是在下降沿触发,且时钟信号是由键盘给出,因此使用P1口中断(已经在初始化端口时设置)。发送的数据位11位,第一位是起始位,总为0,紧接是8个数据位,然后是奇校验位,最后是停止位总为1.

     本程序只能对基本按键(即键被按下时产生三个字节的扫描码的按键)做出解码,包括所有的可显示字符键和Table,Back Space和Ente三个特殊功能键。基本按键的扫描码由三个字节组成,第1个字节为接通码,第2、3字节为断开码;其中第1字节和第3字节相同,中间字节为断开标志0xf0。例如:通码和断码是以什么样的序列发送到你的计算机使得字符G 出现在你的字处理软件里呢?因为这是一个大写字母需要发生这样的事件次序按下Shift 键按下G 键释放G 键释放Shift 键,与这些时间相关的扫描码如下:Shift 键的通码12h G键的通码34h G 键的断码F0h 34h Shift 键的断码F0h 12h 因此发送到你的计算机的数据应该是12h 34h F0h 34h F0h 12h如果按键按着不放会连续发送通码命令,可以连续显示字符(没有验证,实验验证是可以的)。

      具体的说明都已经在程序中做了注释,主程序,中断服务函数中读取键盘发送的值:

  1. /***************************************************** 
  2. 程序功能:接收并解码来自标准键盘的基本按键的扫描码 
  3. 然后在1602液晶上显示。按Back Space键可以前向删除显 
  4. 示字符,按Space键可以后向删除显示字符。 
  5.  
  6. ----------------------------------------------------- 
  7. 将拨码开关的SN74LVC2454和LCD位拨至ON 
  8. 读取键盘的信号需要电平转换,注意设置SN74LVC2454的转换方向 
  9. 跳线设置:将跳线座J13的B8脚和P1.7脚短接 
  10. ----------------------------------------------------- 
  11. 测试说明:敲定标准键盘上的按键,观察液晶显示 
  12. *****************************************************/  
  13. #include  <msp430.h>  
  14. #include "cry1602.h"  
  15. #include "cry1602.C"  
  16. #include "PS2Keyboard.h"  
  17. #include "PS2Keyboard.C"  
  18.   
  19. #define SIDval  P5IN & BIT6  
  20. #define BufferSize  32      //显示缓存大小  
  21. unsigned char bitcount=11;          //位计数变量  
  22. unsigned char kb_buffer[BufferSize];    //显示缓存  
  23. unsigned char input=0;       //数据压入缓存位置指针  
  24. unsigned char output=0;      //数据弹出缓存位置指针     
  25. unsigned char pebit=0xff;    //奇偶校验标志位  
  26. unsigned char recdata=0;     //接收到的数据  
  27. unsigned char tishi[]={"this is a demo!"};  
  28.   
  29. /****************主函数****************/  
  30. void main(void)  
  31. {  
  32.     uchar disptmp,i;  
  33.     uchar x = 0,y = 0;  
  34.     uchar first = 1;  
  35.       
  36.     WDTCTL = WDTPW + WDTHOLD;       //关闭看门狗  
  37.     P6DIR |= BIT2;P6OUT &= ~BIT2;   //打开电平转换  
  38.     P2DIR |= BIT3;P2OUT |= BIT3;    //方向5V-->3.3V  
  39.     /*------选择系统主时钟为8MHz-------*/  
  40.     BCSCTL1 &= ~XT2OFF;                 // 打开XT2高频晶体振荡器  
  41.     do  
  42.     {  
  43.         IFG1 &= ~OFIFG;                 //清除晶振失败标志  
  44.         for (i = 0xFF; i > 0; i--);     //等待8MHz晶体起振  
  45.     }  
  46.     while ((IFG1 & OFIFG));             // 晶振失效标志仍然存在?  
  47.     BCSCTL2 |= SELM_2;                  //主时钟选择高频晶振  
  48.       
  49.     LcdReset();                 //复位液晶  
  50.     DispNchar(0,0,15,tishi);    //液晶显示提示信息  
  51.     Init_KB();                  //初始化键盘端口  
  52.     _EINT();                    //打开全局中断  
  53.     
  54.     while(1)  
  55.     {  
  56.         LPM3;                   //进入低功耗模式  
  57.           
  58.         if(first)  
  59.         {  
  60.             first = 0;  
  61.             LcdWriteCommand(0x01, 1);   //显示清屏  
  62.             LcdWriteCommand(0x0f, 1);   //打开游标  
  63.         }  
  64.           
  65.         disptmp = GetChar();    //读取键值对应的ASCII码  
  66.         if(disptmp != 0xff)     //取出了一个有效字符  
  67.         {  
  68.             if(disptmp == 8) //如果是退格键  
  69.             {  
  70.                 if((x == 0) && (y == 0))//如果游标在第1行第1位  
  71.                 {  
  72.                     x = 15;  
  73.                     y = 1;  
  74.                     Disp1Char(x,y,0x20); //0x20是空格的ASCII码  
  75.                     LocateXY(x,y);  
  76.                 }  
  77.                 else if((x == 0) && (y == 1))//如果游标在第2行第1位  
  78.                 {  
  79.                     x = 15;  
  80.                     y = 0;  
  81.                     Disp1Char(x,y,0x20);   
  82.                     LocateXY(x,y);  
  83.                 }  
  84.                 else  
  85.                 {  
  86.                     Disp1Char(--x,y,0x20);   
  87.                     LocateXY(x,y);  
  88.                 }  
  89.             }  
  90.             else if((disptmp == 9) || (disptmp == 13)) //如果是Table键或Enter键  
  91.             {  
  92.                 _NOP();     
  93.             }  
  94.             else    //其余字符显示  
  95.             {  
  96.                 Disp1Char(x++,y,disptmp);  
  97.                 if(x == 16)           //如果一行显示完毕  
  98.                 {  
  99.                     x = 0;  
  100.                     y ^= 1;  
  101.                     LocateXY(x,y);  //重新定位游标位置  
  102.                 }  
  103.             }  
  104.         }  
  105.     }  
  106. }  
  107.   
  108. /******************************************* 
  109. 函数名称:PORT1_ISR  
  110. 功    能:P1端口的中断服务函数,在这里接收来 
  111.           自键盘的字符 
  112.  
  113. 说明:键盘发送往主机的信号总是在时钟的下降沿 
  114. 因此此中断是在下降沿触发,且时钟信号是由键盘 
  115. 给出,因此使用P1口中断(已经在初始化端口时 
  116. 设置)。发送的数据位11位,第一位是起始位,总 
  117. 为0,紧接是8个数据位,然后是奇校验位,最后是 
  118. 停止位总为1. 
  119. 参    数:无 
  120. 返回值  :无 
  121. ********************************************/  
  122. #pragma vector=PORT1_VECTOR  
  123. __interrupt void  PORT1_ISR(void)  
  124. {  
  125.     if(P1IFG & BIT7)            //如果是clock的中断  
  126.     {  
  127.         P1IFG &=~ BIT7;         //清除中断标志   
  128.           
  129.         if(bitcount == 11)        //接收第1位  
  130.         {  
  131.             if(SIDval)          //起始位总为0如果是1就不是起始位  
  132.                 return;         //返回  
  133.             else    
  134.                 bitcount--;     //是起始位就接着接收下一位,进行计数  
  135.         }   
  136.         else if(bitcount == 2)    //接收奇偶校验位  
  137.         {     
  138.             if(SIDval)          //如果校验位等于1  
  139.                 pebit = 1;      //这个程序中只是对校验位进行读取,正确与否并为做判断  
  140.             else  
  141.                 pebit = 0;  
  142.             bitcount--;  
  143.         }  
  144.         else if(bitcount == 1)    //接收停止位  
  145.         {  
  146.             if(SIDval)          //若停止位正确  
  147.             {  
  148.                 bitcount = 11;    //复位位计数变量  
  149.                 if( Decode(recdata) )    //解码获得此键值的ASCII值并保存  
  150.                     LPM3_EXIT;           //退出低功耗模式  
  151.                 recdata = 0;          //清除接收数据  
  152.             }  
  153.             else                //如果出错  
  154.             {  
  155.                 bitcount = 11;  
  156.                 recdata = 0;      
  157.             }  
  158.         }  
  159.         else                    //接收8个数据位  
  160.         {  
  161.             recdata >>= 1;  
  162.             if(SIDval)  recdata |= 0x80;  
  163.             bitcount--;  
  164.         }  
  165.    }  
  166. }  

解码程序PS2Keyboard.C:

  1. #include <msp430x14x.h>  
  2. #include "PS2Keyboardcode.h"  
  3.   
  4. #define BufferSize  32  
  5. extern uchar kb_buffer[BufferSize];  
  6. extern uchar input;  
  7. extern uchar output;  
  8. extern uchar flag;  
  9. /******************************************* 
  10. 函数名称:PushBuff 
  11. 功    能:将一个字符压入显示缓存,如果缓存以 
  12.           满则覆盖前面的数据 
  13. 参    数:c--要显示的字符 
  14. 返回值  :无 
  15. ********************************************/  
  16. void PutChar(uchar c)  
  17. {  
  18.     kb_buffer[input] = c;  
  19.     if (input < (BufferSize-1))  
  20.         input++;   
  21.     else  
  22.         input = 0;     
  23. }  
  24. /******************************************* 
  25. 函数名称:PopChar 
  26. 功    能:从显示缓存中取出一个字符 
  27. 参    数:无 
  28. 返回值  :取出的字符 
  29. ********************************************/  
  30. uchar GetChar(void)  
  31. {  
  32.     uchar temp;  
  33.       
  34.     if(output == input)  
  35.         return 0xff;  
  36.     else  
  37.     {  
  38.         temp = kb_buffer[output];  
  39.         if(output < (BufferSize-1))  
  40.         {  
  41.             output++;  
  42.         }  
  43.         else  
  44.         {  
  45.             output = 0;  
  46.         }  
  47.         return temp;        
  48.     }          
  49. }  
  50. /******************************************* 
  51. 函数名称:Init_KB 
  52. 功    能:初始化与键盘相关的IO 
  53. 参    数:无 
  54. 返回值  :无 
  55. ********************************************/  
  56. void Init_KB(void)  
  57. {  
  58.     P1DIR &=~ BIT7;     //Clock接P1.7,设置为输入  
  59.     P5DIR &=~ BIT6;     //SID接P5.6,设置为输入  
  60.     P1IES |= BIT7;      //下降沿中断  
  61.     P1IFG = 0x00;       //中断标志清零  
  62.     P1IE  |= BIT7;      //使能时钟端口中断  
  63.     P1SEL = 0x00;       //P1口作为IO使用  
  64. }  
  65. /******************************************* 
  66. 函数名称:Decode 
  67. 功    能:对来自键盘的信息进行解码,转换成对 
  68.           应的ASCII编码并压入缓存 
  69. 参    数:sc--键盘发送过来的信息 
  70. 返回值  :是否收到有效数据:0--否,1--是 
  71. 说明    :本程序只能对基本按键(即键被按下时产 
  72.           生三个字节的扫描码的按键)做出解码, 
  73.           包括所有的可显示字符键和Table, 
  74.           Back Space和Enter三个特殊功能键。 
  75. 基本按键的扫描码由三个字节组成,第1个字节为接通 
  76. 码,第2、3字节为断开码;其中第1字节和第3字节相 
  77. 同,中间字节为断开标志0xf0。 
  78. 例如:通码和断码是以什么样的序列发送到你的计算机使得字符G 出现在你的字处理软件 
  79. 里呢?因为这是一个大写字母需要发生这样的事件次序按下Shift 键按下G 键 
  80. 释放G 键释放Shift 键,与这些时间相关的扫描码如下:Shift 键的通码12h G 
  81. 键的通码34h G 键的断码F0h 34h Shift 键的断码F0h 12h 因此发送到 
  82. 你的计算机的数据应该是12h 34h F0h 34h F0h 12h 
  83. 如果按键按着不放会连续发送通码命令,可以连续显示字符(没有验证,实验验证是可以的) 
  84. ********************************************/  
  85. uchar Decode(uchar sc)  
  86. {  
  87.       static uchar shift = 0; //Shift键是否按下标志:1--按下,0--未按  
  88.       static uchar up = 0;    //键已放开标志:       1--放开,0--按下  
  89.       uchar i,flag = 0;  
  90.         
  91.       if(sc == 0xf0)    //如果收到的是扫描码的第2个字节---0xf0:按键断开标志  
  92.       {  
  93.           up = 1;          
  94.           return 0;  
  95.       }  
  96.       else if(up == 1)  //如果收到的是扫描码的第3个字节  
  97.       {  
  98.       up = 0;       //收到第3字节表示按键已经放开  
  99.           if((sc == 0x12) || ( sc==0x59))   shift = 0;//shift按下之后放开,不进行操作  
  100.           return 0;  
  101.       }   
  102.         
  103.       //如果收到的是扫描码的第1个字节,第一个字节为通码  
  104.       if((sc == 0x12) || (sc == 0x59)) //如果是左右shift键  
  105.       {        
  106.       shift = 1;            //设置Shift按下标志  
  107.           flag = 0;  
  108.       }                              
  109.       else  
  110.       {  
  111.       if(shift) //对按下Shift的键进行解码  
  112.           {  
  113.             for(i = 0;(shifted[i][0] != sc) && shifted[i][0];i++);//查表找到对应的码值  
  114.                 if (shifted[i][0] == sc)   
  115.                 {  
  116.                      PutChar(shifted[i][1]);    //存入显示缓存  
  117.                      flag = 1;                  //解码成功标志  
  118.                 }  
  119.        }  
  120.        else  //直接对按键进行解码  
  121.        {  
  122.             for(i = 0;(unshifted[i][0] != sc) && unshifted[i][0];i++);  
  123.                 if(unshifted[i][0] == sc)    
  124.                 {  
  125.                     PutChar(unshifted[i][1]);  
  126.                     flag = 1;  
  127.                 }  
  128.        }   
  129.       }  
  130.       if(flag)  return 1;                       //根据解码是否成功返回相应的值  
  131.       else      return 0;  
  132. }  

需要查的表PS2Keyboardcode.h

  1. //不按Shift的字符对应的编码  
  2. const unsigned char unshifted[][2] =   
  3. {  
  4.     0x0d,9,     //Table  
  5.     0x0e,'`',  
  6.     0x15,'q',  
  7.     0x16,'1',  
  8.     0x1a,'z',  
  9.     0x1b,'s',  
  10.     0x1c,'a',  
  11.     0x1d,'w',  
  12.     0x1e,'2',  
  13.     0x21,'c',  
  14.     0x22,'x',  
  15.     0x23,'d',  
  16.     0x24,'e',  
  17.     0x25,'4',  
  18.     0x26,'3',  
  19.     0x29,' ',  
  20.     0x2a,'v',  
  21.     0x2b,'f',  
  22.     0x2c,'t',  
  23.     0x2d,'r',  
  24.     0x2e,'5',  
  25.     0x31,'n',  
  26.     0x32,'b',  
  27.     0x33,'h',  
  28.     0x34,'g',  
  29.     0x35,'y',  
  30.     0x36,'6',  
  31.     0x39,',',  
  32.     0x3a,'m',  
  33.     0x3b,'j',  
  34.     0x3c,'u',  
  35.     0x3d,'7',  
  36.     0x3e,'8',  
  37.     0x41,',',  
  38.     0x42,'k',  
  39.     0x43,'i',  
  40.     0x44,'o',  
  41.     0x45,'0',  
  42.     0x46,'9',  
  43.     0x49,'.',  
  44.     0x4a,'/',  
  45.     0x4b,'l',  
  46.     0x4c,';',  
  47.     0x4d,'p',  
  48.     0x4e,'-',  
  49.     0x52,0x27,  
  50.     0x54,'[',  
  51.     0x55,'=',  
  52.     0x5a,13,     //Enter  
  53.     0x5b,']',  
  54.     0x5d,0x5c,  
  55.     0x61,'<',  
  56.     0x66,8,  //Back Space  
  57.     0x69,'1',  
  58.     0x6b,'4',  
  59.     0x6c,'7',  
  60.     0x70,'0',  
  61.     0x71,',',  
  62.     0x72,'2',  
  63.     0x73,'5',  
  64.     0x74,'6',  
  65.     0x75,'8',  
  66.     0x79,'+',  
  67.     0x7a,'3',  
  68.     0x7b,'-',  
  69.     0x7c,'*',  
  70.     0x7d,'9',  
  71.     0,0  
  72. };  
  73.   
  74. //按住Shift后字符对应的编码  
  75. const unsigned char shifted[][2] =   
  76. {  
  77.     0x0d,9,     //Table  
  78.     0x0e,'~',  
  79.     0x15,'Q',  
  80.     0x16,'!',  
  81.     0x1a,'Z',  
  82.     0x1b,'S',  
  83.     0x1c,'A',  
  84.     0x1d,'W',  
  85.     0x1e,'@',  
  86.     0x21,'C',  
  87.     0x22,'X',  
  88.     0x23,'D',  
  89.     0x24,'E',  
  90.     0x25,'$',  
  91.     0x26,'#',  
  92.     0x29,' ',  
  93.     0x2a,'V',  
  94.     0x2b,'F',  
  95.     0x2c,'T',  
  96.     0x2d,'R',  
  97.     0x2e,'%',  
  98.     0x31,'N',  
  99.     0x32,'B',  
  100.     0x33,'H',  
  101.     0x34,'G',  
  102.     0x35,'Y',  
  103.     0x36,'^',  
  104.     0x39,'L',  
  105.     0x3a,'M',  
  106.     0x3b,'J',  
  107.     0x3c,'U',  
  108.     0x3d,'&',  
  109.     0x3e,'*',  
  110.     0x41,'<',  
  111.     0x42,'K',  
  112.     0x43,'I',  
  113.     0x44,'O',  
  114.     0x45,')',  
  115.     0x46,'(',  
  116.     0x49,'>',  
  117.     0x4a,'?',  
  118.     0x4b,'L',  
  119.     0x4c,':',  
  120.     0x4d,'P',  
  121.     0x4e,'_',  
  122.     0x52,'"',  
  123.     0x54,'{',  
  124.     0x55,'+',  
  125.     0x5a,13,    //Enter  
  126.     0x5b,'}',  
  127.     0x5d,'|',  
  128.     0x61,'>',  
  129.     0x66,8,     //Back Space  
  130.     0x69,'1',  
  131.     0x6b,'4',  
  132.     0x6c,'7',  
  133.     0x70,'0',  
  134.     0x71,',',  
  135.     0x72,'2',  
  136.     0x73,'5',  
  137.     0x74,'6',  
  138.     0x75,'8',  
  139.     0x79,'+',  
  140.     0x7a,'3',  
  141.     0x7b,'-',  
  142.     0x7c,'*',  
  143.     0x7d,'9',  
  144.     0,0  
  145. };  

 本文转自emouse博客园博客,原文链接:http://www.cnblogs.com/emouse/archive/2010/08/07/2198211.html,如需转载请自行联系原作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
MQ 介绍|学习笔记
快速学习 MQ 介绍
6 0
阿里云 PAI 预测算法模块介绍 | 学习笔记
快速学习阿里云 PAI 预测算法模块介绍
21 0
__eq__方法的使用 | 学习笔记
快速学习__eq__方法的使用
748 0
MQ 介绍|学习笔记
快速学习 MQ 介绍
46 0
学习C++笔记433
C++ STL 教程
26 0
学习C++笔记417
C++ Web 编程
14 0
30_Bootstrap组件_巨幕,页头,缩略图|学习笔记
快速学习30_Bootstrap组件_巨幕,页头,缩略图
38 0
重温JSP学习笔记--El函数库
EL函数库(由JSTL提供的)   * 导入标签库:       String toUpperCase(String input):把参数转换成大写       String toLowerCase(String input):把参数转换成小写       int indexOf(String i...
929 0
C#学习笔记(8)鼠标键盘事件处理
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using
954 0
文章
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载