色婷婷AⅤ一区二区三区|亚洲精品第一国产综合亚AV|久久精品官方网视频|日本28视频香蕉

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > 單片機驅動PS/2鍵盤

          單片機驅動PS/2鍵盤

          作者: 時間:2016-11-09 來源:網(wǎng)絡 收藏
          PS/2簡介

          PS/2設備有主從之分,主設備采用Female插座,從設備采用Male插頭.現(xiàn)在廣泛使用的PS/2鍵盤鼠標均在從設備方式下工作.PS/2接口的時鐘
          與數(shù)據(jù)線都是集電極開路結構,必須外接上拉電阻(一般上拉電阻設置在主設備中).主從設備之間數(shù)據(jù)通信采用雙向同步串行方式傳輸,時鐘信號由從設備產生.

          本文引用地址:http://cafeforensic.com/article/201611/317657.htm

          1.1 從設備到主設備的通信
          當從設備向主設備發(fā)送數(shù)據(jù)時,首先檢查時鐘線,以確認時鐘線是否為高電平.如果是高電平,從設備就可以開始傳輸數(shù)據(jù);反之,從設備要等待獲得總線的控制權,才能開始傳輸數(shù)據(jù).傳輸?shù)拿恳粠?1位組成,發(fā)送時序及每一位的含義如圖2所示.



          每一幀數(shù)據(jù)中開始位總是為0,數(shù)據(jù)校驗采用奇校驗方式,停止位始終為1.從設備到主設備通信時,從設備總是在時鐘線為高時改變數(shù)據(jù)線狀態(tài),主設備在時鐘下降沿讀人數(shù)據(jù)線狀態(tài).

          1.2 主設備到從設備的通信
          主設備與從設備進行通信時,主設備首先將時鐘線和數(shù)據(jù)線設置為“請求發(fā)送”狀態(tài),具體方式為:首先下拉時鐘線至少100us抑制通信,然后下拉數(shù)據(jù)線“請求發(fā)送”,最后釋放時鐘線.在此過程中,從設備在不超過10us的間隔內必須檢查這個狀態(tài),當設備檢測到這個狀態(tài)時,它將開始產生時鐘信號.此時數(shù)據(jù)傳輸?shù)拿恳粠?2位構成,其時序和每一位含義如圖3所示.



          與從設備到主設備通信相比,其每幀數(shù)據(jù)多了一個ACK位.這是從設備應答接收到字節(jié)的應答位,由從設備通過拉低數(shù)據(jù)線產生,應答位ACK總
          是為0.主設備到從設備通信過程中,主設備總是在時鐘線為低電平時改變數(shù)據(jù)線的狀態(tài),從設備在時鐘上升沿讀人數(shù)據(jù)線狀態(tài).

          2.1 PS/2鍵盤的編碼
          目前,PC機使用的PS/2鍵盤都默認采用第2套掃描碼集.掃描碼有兩種不同的類型:“通碼(make code)”和“斷碼(break code)”.當一個鍵被按下或持續(xù)按住時,鍵盤會將該鍵的通碼發(fā)送給主機;而當一個鍵被釋放時,鍵盤會將該鍵的斷碼發(fā)送給主機.根據(jù)鍵盤按鍵掃描碼的不同,可將按鍵分為3類:
          第1類按鍵 通碼為一個字節(jié),斷碼為0xF0+通碼形式.如A鍵,其通碼為0x1C;斷碼為0xF0 0x1C.
          第2類按鍵 通碼為兩字節(jié)0xE0+0xXX形式,斷碼為0xE0+0xF0+0xXX形式.如Right Ctrl鍵,其通碼為0xE0 0x14;斷碼為0xE0 0xF0 0x14.
          第3類特殊按鍵 有兩個,Print Screen鍵,其通碼為0xE0 0x12 0xE0 0x7C;斷碼為0xE0 0xF0 0x7C 0xE0 0xF0 0x12.Pause鍵,其通碼為0xE1 0x14 0x77 0xE1 0xF0 0xl4 0xF0 0x77;斷碼為空.
          組合按鍵掃描碼的發(fā)送是按照按鍵發(fā)生的次序,如按下面順序按左Shift十A鍵:① 按下左Shift鍵;② 按下A鍵;③ 釋放A鍵;④ 釋放左Shift鍵,那么計算機上接收到的一串數(shù)據(jù)為0x12 0x1C 0xF0 0x1C 0xF0 0x12.


          2.2 PS/2鍵盤的命令集
          主機可通過向PS/2鍵盤發(fā)送命令對鍵盤進行設置或者獲得鍵盤的狀態(tài)等操作.每發(fā)送一個字節(jié),主機都會從鍵盤獲得一個應答0xFA(“重發(fā)
          resend”和“回應echo”命令例外).驅動程序在鍵盤初始化過程中所用的指令:0xED,主機在該命令后跟隨發(fā)送一個參數(shù)字節(jié),用于指示鍵盤上Num Lock,Caps Lock,Scroll Lock Led的狀態(tài);0xF3,主機在這條命令后跟隨發(fā)送一個字節(jié)參數(shù)定義鍵盤機打的速率和延時;0xF4,用于當主機發(fā)送0xF5禁止鍵盤后,重新使能鍵盤.

          連接電路圖:

          設計程序思路:

          采用狀態(tài)機思想來解碼一幀數(shù)據(jù),定義四個狀態(tài):PS_IDLE 、PS_START、PS_PARITY、PS_STOP

          PS_IDLE狀態(tài)接受起始碼,并判斷起始碼是否有效;PS_START狀態(tài)接受8位數(shù)據(jù);PS_PARITY狀態(tài)接受奇偶校驗位;PS_STOP接受停止為,并奇偶校驗數(shù)據(jù),同時處理shift按鍵以及斷碼問題;

          定義結構體

          typedef struct ps2_frame
          {
          uchar state ;//狀態(tài)
          uchar data ;//數(shù)據(jù)
          uchar temp ;//用于移位
          uchar parity ;//奇偶校驗位
          uchar count ;//1的位數(shù)由于奇偶校驗
          uchar ready ;//一幀數(shù)據(jù)接受完畢
          uchar shift ;//shift鍵是否按下
          uchar down ;//按鍵是否彈起
          } ps2_frame ;

          下面是程序:

          頭文件


          #include "main.h"

          #define PS_DATA RA1
          #define PS_CLK RB0

          #define PS_IDLE 0x01
          #define PS_START 0x02
          //#define PS_DATA 0x03
          #define PS_PARITY 0x04
          #define PS_STOP 0x05
          //#define PS_ACK
          typedef struct ps2_frame
          {
          uchar state ;//狀態(tài)
          uchar data ;//數(shù)據(jù)
          uchar temp ;//用于移位
          uchar parity ;//奇偶校驗位
          uchar count ;//1的位數(shù)由于奇偶校驗
          uchar ready ;//一幀數(shù)據(jù)接受完畢
          uchar shift ;//shift鍵是否按下
          uchar down ;//按鍵是否彈起
          } ps2_frame ;

          void init_ps2() ;
          uchar ps_decoding(uchar data,uchar shift) ;
          #endif

          初始化和解碼子程序以及解碼表

          #include "ps2.h"

          const uchar unshifted[][2]=//shift鍵沒按下譯碼表
          {
          0x0e,`,
          0x15,q,
          0x16,1,
          0x1a,z,
          0x1b,s,
          0x1c,a,
          0x1d,w,
          0x1e,2,
          0x21,c,
          0x22,x,
          0x23,d,
          0x24,e,
          0x25,4,
          0x26,3,
          0x29, ,
          0x2a,v,
          0x2b,f,
          0x2c,t,
          0x2d,r,
          0x2e,5,
          0x31,n,
          0x32,b,
          0x33,h,
          0x34,g,
          0x35,y,
          0x36,6,
          0x39,,,
          0x3a,m,
          0x3b,j,
          0x3c,u,
          0x3d,7,
          0x3e,8,
          0x41,,,
          0x42,k,
          0x43,i,
          0x44,o,
          0x45,0,
          0x46,9,
          0x49,.,
          0x4a,/,
          0x4b,l,
          0x4c,;,
          0x4d,p,
          0x4e,-,
          0x52,/,
          0x54,[,
          0x55,=,
          0x5b,],
          0x5d,//,
          0x61,<,
          0x69,1,
          0x6b,4,
          0x6c,7,
          0x70,0,
          0x71,.,
          0x72,2,
          0x73,5,
          0x74,6,
          0x75,8,
          0x79,+,
          0x7a,3,
          0x7b,-,
          0x7c,*,
          0x7d,9,
          0,0
          };
          const uchar shifted[][2]= //shift鍵按下譯碼表
          {
          0x0e,~,
          0x15,Q,
          0x16,!,
          0x1a,Z,
          0x1b,S,
          0x1c,A,
          0x1d,W,
          0x1e,@,
          0x21,C,
          0x22,X,
          0x23,D,
          0x24,E,
          0x25,$,
          0x26,#,
          0x29, ,
          0x2a,V,
          0x2b,F,
          0x2c,T,
          0x2d,R,
          0x2e,%,
          0x31,N,
          0x32,B,
          0x33,H,
          0x34,G,
          0x35,Y,
          0x36,^,
          0x39,L,
          0x3a,M,
          0x3b,J,
          0x3c,U,
          0x3d,&,
          0x3e,*,
          0x41,<,
          0x42,K,
          0x43,I,
          0x44,O,
          0x45,),
          0x46,(,
          0x49,>,
          0x4a,?,
          0x4b,L,
          0x4c,:,
          0x4d,P,
          0x4e,_,
          0x52,",
          0x54,{,
          0x55,+,
          0x5b,},
          0x5d,|,
          0x61,>,
          0x69,1,
          0x6b,4,
          0x6c,7,
          0x70,0,
          0x71,.,
          0x72,2,
          0x73,5,
          0x74,6,
          0x75,8,
          0x79,+,
          0x7a,3,
          0x7b,-,
          0x7c,*,
          0x7d,9,
          0,0
          };

          void init_ps2()
          {
          ADCON1=0X07;//A口為普通IO
          TRISA1=1 ;
          INTCON=0 ;
          INTEDG=1 ;
          INTE=1 ;
          PEIE=1 ;
          GIE=1 ;
          }

          uchar ps_decoding(uchar data,uchar shift)
          {
          uchar temp ,i=0;
          if(shift)
          {
          while(i!=255)
          {
          if(shifted[i][0]==data)
          {
          temp=shifted[i][1] ;
          break ;
          }
          i++ ;
          }
          }
          else
          {
          while(i!=255)
          {
          if(unshifted[i][0]==data)
          {
          temp=unshifted[i][1] ;
          break ;
          }
          i++ ;
          }
          }
          return temp ;
          }

          主程序:


          #include "main.h"
          #include "t232.h"
          #include "ps2.h"

          ps2_frame ps_frame ;
          void interrupt main_int()
          {
          if(INTF)//下降沿觸發(fā)
          {
          GIE=0 ;
          INTF=0 ;
          switch(ps_frame.state)
          {
          case PS_IDLE :
          if(!PS_DATA)
          {
          ps_frame.ready=0 ;
          ps_frame.state=PS_START ;
          ps_frame.temp = 1 ;
          ps_frame.count = 0 ;
          ps_frame.data=0 ;
          }
          else
          ps_frame.state=PS_IDLE ;
          break ;
          case PS_START :
          if(PS_DATA)
          {
          ps_frame.data=ps_frame.data|ps_frame.temp ;
          ps_frame.count++ ;
          }
          ps_frame.temp=ps_frame.temp<<1 ;
          if(!ps_frame.temp)
          ps_frame.state=PS_PARITY ;
          break ;
          case PS_PARITY :
          ps_frame.parity=PS_DATA ;
          ps_frame.state=PS_STOP ;
          break ;
          case PS_STOP :
          if(PS_DATA)
          {
          if(ps_frame.parity)
          {
          if(ps_frame.count%2==0)
          ps_frame.ready=1 ;

          }
          else
          {
          if(ps_frame.count%2==1)
          ps_frame.ready=1 ;
          }
          switch(ps_frame.data)//處理通碼和斷碼
          {
          case 0xF0 :
          ps_frame.down=0 ;
          ps_frame.ready=0 ;
          break ;
          case 0x12 :
          if(!ps_frame.down)
          ps_frame.shift=0 ;
          else
          ps_frame.shift=1 ;
          ps_frame.ready=0 ;
          break ;
          case 0x59 :
          if(!ps_frame.down)
          ps_frame.shift=0 ;
          else
          ps_frame.shift=1 ;
          ps_frame.ready=0 ;
          break ;
          default :
          if(!ps_frame.down)
          {
          ps_frame.ready=0 ;
          ps_frame.down=1 ;
          }
          break ;
          }
          }

          ps_frame.state = PS_IDLE ;
          break ;
          default :
          break ;
          }
          }
          GIE=1 ;
          }

          void init_all()
          {
          init_232() ;
          init_ps2() ;
          ps_frame.state = PS_IDLE ;
          ps_frame.shift=0 ;
          ps_frame.down = 0 ;
          }
          void main()
          {
          const char str[]= "hello world !" ;
          uchar temp ;
          init_all() ;

          send_str(str) ;//測試串口
          while(1)
          {
          if(ps_frame.ready)
          {
          temp=ps_decoding(ps_frame.data,ps_frame.shift) ;

          put_char(temp) ;
          ps_frame.ready=0 ;
          }
          }
          }



          關鍵詞: 單片機驅動PS2鍵

          評論


          技術專區(qū)

          關閉