基于STEP FPGA的PS2鍵盤驅(qū)動

 行業(yè)動態(tài)     |      2023-11-30 10:33:18    |      作者

硬件說明

我們的STEP-BaseBoard底板上集成了PS2鍵盤的接口,可以供大家連接PS2鍵盤或PS2鼠標(biāo)完成相應(yīng)設(shè)計,接下來我們來了解PS2接口的硬件連接及PS2鍵盤的驅(qū)動方法。PS2接口連線非常簡單,只需接4根線:

  • 4號引腳VCC接供電電源,一般為5V供電,后經(jīng)測試3.3V也可以
  • 3號引腳GND接地即可
  • 5號引腳時鐘線和1號引腳數(shù)據(jù)線為兩條雙向的信號線
  • 2號引腳和6號引腳為保留引腳,不需要連接

當(dāng)PS2鍵盤上有按鍵按動或操作的時候,鍵盤會發(fā)信號給主機(jī),PS2接口的時鐘信號和數(shù)據(jù)信號的時序如下圖:

FPGA或主機(jī)接收鍵盤發(fā)回的數(shù)據(jù),通過鍵盤的編碼規(guī)則判定鍵盤當(dāng)前的操作,掃描碼有兩種不同的類型:通碼(make code)和斷碼(break code)。當(dāng)一個鍵被按下或持續(xù)按住時,鍵盤會將該鍵的通碼發(fā)送給主機(jī);而當(dāng)一個鍵被釋放時,鍵盤會將該鍵的斷碼發(fā)送給主機(jī)。根據(jù)鍵盤按鍵掃描碼的不同,在此可將按鍵分為如下幾類:

  • 第一類按鍵,通碼為1字節(jié),斷碼為0xF0+通碼形式。如A鍵,其通碼為0x1C,斷碼為0xF0 0x1C。
  • 第二類按鍵,通碼為2字節(jié)0xE0+0xXX形式,斷碼為0xE0+0xF0+0xXX形式。如right ctrl鍵,其通碼為0xE0 0x14,斷碼為0xE0 0xF0 0x14。
  • 第三類特殊按鍵有兩個,print screen鍵通碼為0xE0 0x12 0xE0 0x7C,斷碼為0xE0 0xF0 0x7C 0xE0 0xF0 0x12; pause鍵通碼為0x E1 0x14 0x77 0xE1 0xF0 0x14 0xF0 0x77,斷碼為空。

組合按鍵的掃描碼發(fā)送按照按鍵發(fā)生的次序,如以下面順序按左SHIFT+A鍵:1按下左SHIFT鍵,2按下A鍵,3釋放A鍵,4釋放左SHIFT鍵,那么計算機(jī)上接收到的一串?dāng)?shù)據(jù)為0x12 0x1C 0xF0 0x1C 0xF0 0x12。在驅(qū)動程序設(shè)計中,就是根據(jù)這樣的分類來對不同的按鍵進(jìn)行不同處理的,當(dāng)前簡單程序只支持第一類按鍵的操作。鍵盤中不同按鍵的編碼如下:

Verilog代碼

//-------------------------------------------------------------------- //>>>>>>>>>>>>>>>>>>>>>>>>>COPYRIGHTNOTICE<<<<<<<<<<<<<<<<<<<<<<<<< //-------------------------------------------------------------------- //Module:Keyboard_PS2 // //Author:Step // //Description:PS2keyboarddriver // //-------------------------------------------------------------------- //CodeRevisionHistory: //-------------------------------------------------------------------- //Version:|Mod.Date:|ChangesMade: //V1.0|2016/04/20|Initialver //-------------------------------------------------------------------- moduleKeyboard_PS2 ( input clk_in, //系統(tǒng)時鐘 input rst_n_in, //系統(tǒng)復(fù)位,低有效 input key_clk, //PS2鍵盤時鐘輸入 input key_data, //PS2鍵盤數(shù)據(jù)輸入 output reg key_state, //鍵盤的按下狀態(tài),按下為1,松開為0 output reg [7:0] key_ascii //按鍵鍵值對應(yīng)的ASCII編碼); /* 這個模塊為FPGA驅(qū)動PS2鍵盤的簡單程序,只能支持鍵盤中第一類按鍵的單鍵按動,不支持多個按鍵同時按動 */ reg key_clk_r0=1'b1,key_clk_r1=1'b1; reg key_data_r0=1'b1,key_data_r1=1'b1; //對鍵盤時鐘數(shù)據(jù)信號進(jìn)行延時鎖存 always@(posedgeclk_inornegedgerst_n_in)begin if(!rst_n_in)begin key_clk_r0<=1'b1; key_clk_r1<=1'b1; key_data_r0<=1'b1; key_data_r1<=1'b1; endelsebegin key_clk_r0<=key_clk; key_clk_r1<=key_clk_r0; key_data_r0<=key_data; key_data_r1<=key_data_r0; endend//鍵盤時鐘信號下降沿檢測 wire key_clk_neg=key_clk_r1&(~key_clk_r0); reg [3:0] cnt; reg [7:0] temp_data; //根據(jù)鍵盤的時鐘信號的下降沿讀取數(shù)據(jù),詳細(xì)參考PS2鍵盤數(shù)據(jù)的傳輸格式及時序 always@(posedgeclk_inornegedgerst_n_in)begin if(!rst_n_in)begin cnt<=4'd0; temp_data<=8'd0; endelseif(key_clk_neg)begin if(cnt>=4'd10)cnt<=4'd0; elsecnt<=cnt+1'b1; case(cnt) 4'd0:; //起始位 4'd1:temp_data[0]<=key_data_r1;//數(shù)據(jù)位bit0 4'd2:temp_data[1]<=key_data_r1;//數(shù)據(jù)位bit1 4'd3:temp_data[2]<=key_data_r1;//數(shù)據(jù)位bit2 4'd4:temp_data[3]<=key_data_r1;//數(shù)據(jù)位bit3 4'd5:temp_data[4]<=key_data_r1;//數(shù)據(jù)位bit4 4'd6:temp_data[5]<=key_data_r1;//數(shù)據(jù)位bit5 4'd7:temp_data[6]<=key_data_r1;//數(shù)據(jù)位bit6 4'd8:temp_data[7]<=key_data_r1;//數(shù)據(jù)位bit7 4'd9:; //校驗位 4'd10:; //結(jié)束位 default:; endcase end end reg key_break=1'b0; reg [7:0] key_byte=1'b0;//根據(jù)通碼和斷碼判定按鍵的當(dāng)前是按下還是松開 always@(posedgeclk_inornegedgerst_n_in)begin if(!rst_n_in)begin key_break<=1'b0; key_state<=1'b0; key_byte<=1'b0; endelseif(cnt==4'd10&&key_clk_neg)begin if(temp_data==8'hf0)key_break<=1'b1; //收到段碼(8'hf0)表示按鍵松開,設(shè)置斷碼標(biāo)示為1 elseif(!key_break)begin //當(dāng)斷碼標(biāo)示為0時,表示當(dāng)前數(shù)據(jù)為按下數(shù)據(jù),輸出鍵值并設(shè)置按下標(biāo)示為1 key_state<=1'b1; key_byte<=temp_data; endelsebegin //當(dāng)斷碼標(biāo)示為1時,標(biāo)示當(dāng)前數(shù)據(jù)為松開數(shù)據(jù),斷碼標(biāo)示和按下標(biāo)示都清零 key_state<=1'b0; key_break<=1'b0; end endend//將鍵盤返回的有效鍵值轉(zhuǎn)換為按鍵字母對應(yīng)的ASCII碼值 always@(key_byte)begin case(key_byte)//translatekey_bytetokey_ascii 8'h15:key_ascii="Q";//8'h51;//Q 8'h1d:key_ascii="W";//8'h57;//W 8'h24:key_ascii="E";//8'h45;//E 8'h2d:key_ascii="R";//8'h52;//R 8'h2c:key_ascii="T";//8'h54;//T 8'h35:key_ascii="Y";//8'h59;//Y 8'h3c:key_ascii="U";//8'h55;//U 8'h43:key_ascii="I";//8'h49;//I 8'h44:key_ascii="O";//8'h4f;//O 8'h4d:key_ascii="P";//8'h50;//P 8'h1c:key_ascii="A";//8'h41;//A 8'h1b:key_ascii="S";//8'h53;//S 8'h23:key_ascii="D";//8'h44;//D 8'h2b:key_ascii="F";//8'h46;//F 8'h34:key_ascii="G";//8'h47;//G 8'h33:key_ascii="H";//8'h48;//H 8'h3b:key_ascii="J";//8'h4a;//J 8'h42:key_ascii="K";//8'h4b;//K 8'h4b:key_ascii="L";//8'h4c;//L 8'h1a:key_ascii="Z";//8'h5a;//Z 8'h22:key_ascii="X";//8'h58;//X 8'h21:key_ascii="C";//8'h43;//C 8'h2a:key_ascii="V";//8'h56;//V 8'h32:key_ascii="B";//8'h42;//B 8'h31:key_ascii="N";//8'h4e;//N 8'h3a:key_ascii="M";//8'h4d;//M default:; endcase end endmodule


小結(jié)

本節(jié)主要為大家講解了PS2接口電路、PS2鍵盤編碼規(guī)則及使用FPGA簡單驅(qū)動PS2鍵盤的方法,需要大家掌握的同時自己創(chuàng)建工程,通過整個設(shè)計流程,生成FPGA配置文件加載測試。