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,如需转载请自行联系原作者

相关文章
|
7月前
|
开发工具 Android开发
Android平台GB28181设备接入端语音广播支持PS格式
对接Android平台GB28181设备接入端语音广播的时候,我们有遇到过INVITE SDP需要PCMA格式的audio,对方同时回了PS和PCMA两种,然后,发数据的时候,直接发了PS的。
128 0
|
17天前
|
安全 Linux
嵌入式Linux系统关闭串口调试信息的输出
嵌入式Linux系统关闭串口调试信息的输出
13 1
|
9月前
|
存储 编解码
标准输入stdin与屏幕输入tslib实例细节分析
标准输入stdin与屏幕输入tslib实例细节分析
37 0
|
10月前
|
Linux API vr&ar
让终端支持播放mp3,移植mp3解码库libmad和madplay到嵌入式linux
让终端支持播放mp3,移植mp3解码库libmad和madplay到嵌入式linux
|
10月前
|
JSON 数据格式
NodeMCU ST7735 Weather Station 制作流程
NodeMCU ST7735 Weather Station 制作流程
96 0
|
编解码
FreeSwitch明明已经设置了H264,为什么通话时还是别的格式(如VP8)
FreeSwitch明明已经设置了H264,为什么通话时还是别的格式(如VP8)
156 0
【C#】【FFmpeg】获取电脑可用音视频设备并输出到下拉列表框
【C#】【FFmpeg】获取电脑可用音视频设备并输出到下拉列表框
235 0
【C#】【FFmpeg】获取电脑可用音视频设备并输出到下拉列表框
关于Qt退出码255的一点总结
Qt程序退出码255 先说症状,程序运行正常,但是在关闭程序时,却出现的异常,提示退出码为255。查看了一翻代码,也没有找到有什么问题,百度上也没找到有效的解决方法。后来偶然发现了问题所在,原因是在析构函数中,先删除了父窗体指针,再删除子窗体指针引起的。
2311 0
|
Go
一个用go写的模拟mp3文字界面播放程序
这里的技巧在于学习如何定义数据结构,更新数据结构,在哪里用指针或是地址来更新。 manger.go package library import "errors" type MusicEntry struct { Id string Name string ...
1058 0