基于STEP FPGA的PS2鍵盤驅(qū)動(dòng)
硬件說明
我們的STEP-BaseBoard底板上集成了PS2鍵盤的接口,可以供大家連接PS2鍵盤或PS2鼠標(biāo)完成相應(yīng)設(shè)計(jì),接下來我們來了解PS2接口的硬件連接及PS2鍵盤的驅(qū)動(dòng)方法。
PS2接口連線非常簡單,只需接4根線:
當(dāng)PS2鍵盤上有按鍵按動(dòng)或操作的時(shí)候,鍵盤會(huì)發(fā)信號(hào)給主機(jī),PS2接口的時(shí)鐘信號(hào)和數(shù)據(jù)信號(hào)的時(shí)序如下圖:
FPGA或主機(jī)接收鍵盤發(fā)回的數(shù)據(jù),通過鍵盤的編碼規(guī)則判定鍵盤當(dāng)前的操作,掃描碼有兩種不同的類型:通碼(make code)和斷碼(break code)。當(dāng)一個(gè)鍵被按下或持續(xù)按住時(shí),鍵盤會(huì)將該鍵的通碼發(fā)送給主機(jī);而當(dāng)一個(gè)鍵被釋放時(shí),鍵盤會(huì)將該鍵的斷碼發(fā)送給主機(jī)。
根據(jù)鍵盤按鍵掃描碼的不同,在此可將按鍵分為如下幾類:
組合按鍵的掃描碼發(fā)送按照按鍵發(fā)生的次序,如以下面順序按左SHIFT+A鍵:1按下左SHIFT鍵,2按下A鍵,3釋放A鍵,4釋放左SHIFT鍵,那么計(jì)算機(jī)上接收到的一串?dāng)?shù)據(jù)為0x12 0x1C 0xF0 0x1C 0xF0 0x12。
在驅(qū)動(dòng)程序設(shè)計(jì)中,就是根據(jù)這樣的分類來對不同的按鍵進(jìn)行不同處理的,當(dāng)前簡單程序只支持第一類按鍵的操作。
鍵盤中不同按鍵的編碼如下:
Verilog代碼
// -------------------------------------------------------------------- // >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< // -------------------------------------------------------------------- // Module: Keyboard_PS2 // // Author: Step // // Description: PS2 keyboard driver // // -------------------------------------------------------------------- // Code Revision History : // -------------------------------------------------------------------- // Version: |Mod. Date: |Changes Made: // V1.0 |2016/04/20 |Initial ver // -------------------------------------------------------------------- module Keyboard_PS2 ( input clk_in, //系統(tǒng)時(shí)鐘 input rst_n_in, //系統(tǒng)復(fù)位,低有效 input key_clk, //PS2鍵盤時(shí)鐘輸入 input key_data, //PS2鍵盤數(shù)據(jù)輸入 output reg key_state, //鍵盤的按下狀態(tài),按下為1,松開為0 output reg [7:0] key_ascii //按鍵鍵值對應(yīng)的ASCII編碼); /* 這個(gè)模塊為FPGA驅(qū)動(dòng)PS2鍵盤的簡單程序,只能支持鍵盤中第一類按鍵的單鍵按動(dòng),不支持多個(gè)按鍵同時(shí)按動(dòng) */ reg key_clk_r0 = 1'b1,key_clk_r1 = 1'b1; reg key_data_r0 = 1'b1,key_data_r1 = 1'b1; //對鍵盤時(shí)鐘數(shù)據(jù)信號(hào)進(jìn)行延時(shí)鎖存 always @ (posedge clk_in or negedge rst_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; end else begin key_clk_r0 <= key_clk; key_clk_r1 <= key_clk_r0; key_data_r0 <= key_data; key_data_r1 <= key_data_r0; endend //鍵盤時(shí)鐘信號(hào)下降沿檢測 wire key_clk_neg = key_clk_r1 & (~key_clk_r0); reg [3:0] cnt; reg [7:0] temp_data; //根據(jù)鍵盤的時(shí)鐘信號(hào)的下降沿讀取數(shù)據(jù),詳細(xì)參考PS2鍵盤數(shù)據(jù)的傳輸格式及時(shí)序 always @ (posedge clk_in or negedge rst_n_in) begin if(!rst_n_in) begin cnt <= 4'd0; temp_data <= 8'd0; end else if(key_clk_neg) begin if(cnt >= 4'd10) cnt <= 4'd0; else cnt <= 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: ; //校驗(yàn)位 4'd10:; //結(jié)束位 default: ; endcase end end reg key_break = 1'b0; reg [7:0] key_byte = 1'b0;//根據(jù)通碼和斷碼判定按鍵的當(dāng)前是按下還是松開 always @ (posedge clk_in or negedge rst_n_in) begin if(!rst_n_in) begin key_break <= 1'b0; key_state <= 1'b0; key_byte <= 1'b0; end else if(cnt==4'd10 && key_clk_neg) begin if(temp_data == 8'hf0) key_break <= 1'b1; //收到段碼(8'hf0)表示按鍵松開,設(shè)置斷碼標(biāo)示為1 else if(!key_break) begin //當(dāng)斷碼標(biāo)示為0時(shí),表示當(dāng)前數(shù)據(jù)為按下數(shù)據(jù),輸出鍵值并設(shè)置按下標(biāo)示為1 key_state <= 1'b1; key_byte <= temp_data; end else begin //當(dāng)斷碼標(biāo)示為1時(shí),標(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) //translate key_byte to key_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ū)動(dòng)PS2鍵盤的方法,需要大家掌握的同時(shí)自己創(chuàng)建工程,通過整個(gè)設(shè)計(jì)流程,生成FPGA配置文件加載測試。
評論