雖然Nexys3開發板是利用USB接口搭載鍵盤,可是其原理與PS/2鍵盤徹底相同,如今就僅以PS/2鍵盤爲例講解如何將鍵盤搭載在開發板上。代碼程序均在Nexys3上通過測試。測試
PS/2標準鍵盤使用6個接口,各個接口定義以下:而對於USB鍵盤,有用的接口只有兩個CLK以及DATA,同時須要+5V供電。這點很重要,可是FPGA的CMOS最大供電是3.3V,如何解決這個問題筆者也是花費了一番周折,文章末會提到。spa
PS/2標準的數據幀格式與串口通信很類似,USB就是串口通信的格式。起始爲低電平,中止位爲高電平。若是數據位中1的個數是偶數,校驗位就爲1;若是數據位中1的個數是奇數,校驗位就爲0,一般本身使用咱們都無論校驗位。其實就是奇校驗。當PC經過PS/2接口與從設備通訊時,老是利用降低沿讀取數據。鍵盤僅僅在數據線和時鐘線都爲高電平(即空閒態)時能夠把數據傳送給主機,一旦主機使用了總線,鍵盤在驅動總線前必須檢查主機當前是否仍在發送數據。爲了促進這一覈查,時鐘線將暫時做爲發送完成信號。一旦主機把時鐘線拉低,那麼鍵盤將使時鐘線變成高電平才能夠傳輸數據。設計
PS/2型鍵盤主要使用掃描碼來進行數據傳輸。每一個按鍵被按下時都會被分配固定的掃描碼,若是按鍵一直被按下,那麼該按鍵碼值將每隔100ms重複發送一次。當按鍵釋放後,一個關鍵碼F0發送後,該掃描碼纔會被髮送。當使用上檔鍵進行組合鍵時,也會產生上檔鍵的碼值,而且由主機決定究竟是哪個ASCII值。當組合鍵被釋放後,一個E0和F0關鍵碼發送後,按鍵掃描碼才被髮送。。大多數按鍵的掃描碼以下圖所示。主機也會向鍵盤發送數據。下面是主機可能發送的經常使用命令的清單。code
ED 使NumLock,CapsLock和ScrollLock LED燈發光。在接收到ED後鍵盤反饋FA碼,而後主機發送一個用來設置LED顯示狀態的字節:第0位控制ScrollLock置位,第1位控制NumLock置位,第2位控制CapsLock置位;blog
EE 用來進行鍵盤測試,當鍵盤接受EE後將反饋EE;接口
F3 設置掃描碼重複頻率,當鍵盤接受FA反饋F3後,主機將發送第二個字符用來設置重複頻率。ci
FE 從新發送。FE將使鍵盤從新發送最近的掃描碼。開發
FF 重置。重置鍵盤。get
3.源程序簡介class
PS/2鍵盤模塊接口定義:reg ps2_clk_r0,ps2_clk_r1,ps2_clk_r2; wire neg_ps2_clk; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin ps2_clk_r0 <= 1'b0; ps2_clk_r1 <= 1'b0; ps2_clk_r2 <= 1'b0; end else begin ps2_clk_r0 <= ps2_clk; ps2_clk_r1 <= ps2_clk_r0; ps2_clk_r2 <= ps2_clk_r1; end end // end always assign neg_ps2_clk = ps2_clk_r2 & (~ps2_clk_r1);
neg_ps2_clk即爲PS/2時鐘信號降低沿的有效信號。而後,利用一個寄存器和計數器,存儲8位有效數據幀。
//------------------------------------------------------ // 接受來自PS/2鍵盤的數據存儲器 reg [7:0] ps2_byte_r; // 來自PS/2的數據寄存器 reg [7:0] temp_data; // 當前接受數據寄存器 reg [3:0] num; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin num <= 4'd0; temp_data <= 8'd0; end else if (neg_ps2_clk) begin case (num) 4'd0: begin num <= num + 1'b1; end 4'd1: begin num <= num + 1'b1; temp_data[0] <= ps2_data; end 4'd2: begin num <= num + 1'b1; temp_data[1] <= ps2_data; end 4'd3: begin num <= num + 1'b1; temp_data[2] <= ps2_data; end 4'd4: begin num <= num + 1'b1; temp_data[3] <= ps2_data; end 4'd5: begin num <= num + 1'b1; temp_data[4] <= ps2_data; end 4'd6: begin num <= num + 1'b1; temp_data[5] <= ps2_data; end 4'd7: begin num <= num + 1'b1; temp_data[6] <= ps2_data; end 4'd8: begin num <= num + 1'b1; temp_data[7] <= ps2_data; end 4'd9: begin num <= num + 1'b1; end 4'd10: begin num <= 4'b0; end default: num <= 4'd0; endcase end end // end always
經過當前按鍵狀態,判斷通碼仍是斷碼,並保存在ps2_byte_r的8位寄存器內。
//------------------------------------- reg key_f0; // 鬆鍵標誌位 reg ps2_state_r; // 當前狀態,高電平表示有鍵按下 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin key_f0 <= 1'b0; ps2_state_r <= 1'b0; ps2_byte_r <= 8'd0; end else if (num == 4'd10) begin // 剛傳輸一個字節 if (temp_data == 8'hf0) begin // 斷碼的第一個字節 key_f0 <= 1'b1; end else begin if (key_f0) begin // 存儲通碼 ps2_state_r <= 1'b1; ps2_byte_r <= temp_data; key_f0 <= 1'b0; end else begin ps2_state_r <= 1'b0; key_f0 <= 1'b0; end end end else ps2_state_r <= 1'b0; end // end always
利用case判斷不一樣的通碼,來決定字符的ASCII。
//--------------------------------------- reg [7:0] ps2_ascii; //接受相應的asciiI always @(posedge clk) begin case (ps2_byte_r) 8'h15: ps2_ascii = 8'h51; //Q 8'h1d: ps2_ascii = 8'h57; //W 8'h24: ps2_ascii = 8'h45; //E 8'h2d: ps2_ascii = 8'h52; //R 8'h2c: ps2_ascii = 8'h54; //T 8'h35: ps2_ascii = 8'h59; //Y 8'h3c: ps2_ascii = 8'h55; //U 8'h43: ps2_ascii = 8'h49; //I 8'h44: ps2_ascii = 8'h4f; //O 8'h4d: ps2_ascii = 8'h50; //P 8'h1c: ps2_ascii = 8'h41; //A 8'h1b: ps2_ascii = 8'h53; //S 8'h23: ps2_ascii = 8'h44; //D 8'h2b: ps2_ascii = 8'h46; //F 8'h34: ps2_ascii = 8'h47; //G 8'h33: ps2_ascii = 8'h48; //H 8'h3b: ps2_ascii = 8'h4a; //J 8'h42: ps2_ascii = 8'h4b; //K 8'h4b: ps2_ascii = 8'h4c; //L 8'h1a: ps2_ascii = 8'h5a; //Z 8'h22: ps2_ascii = 8'h58; //X 8'h21: ps2_ascii = 8'h43; //C 8'h2a: ps2_ascii = 8'h56; //V 8'h32: ps2_ascii = 8'h42; //B 8'h31: ps2_ascii = 8'h4e; //N 8'h3a: ps2_ascii = 8'h4d; //M default ps2_ascii = 8'hfe; endcase end assign ps2_byte = ps2_ascii; assign ps2_state = ps2_state_r;
以上就是程序代碼的主要部分。最重要的仍是管腳分配文件如何解決FPGA供電不足的問題。其實也很簡單,只是咱們平時不經常使用罷了。並且這也是官方標準ucf文件的一個錯誤。只須要將PS/2鍵盤的時鐘線與數據線上拉便可,詳細內容以下(只列舉PS/2鍵盤部分):
NET "ps2_clk" LOC = L12 | IOSTANDARD = LVCMOS33 | PULLUP;
NET "ps2_data" LOC = J13 | IOSTANDARD = LVCMOS33 | PULLUP;
至此,筆者也只是將PS/2鍵盤搭載到了開發板上。可是如何更加靈活的利用鍵盤以及VGA,還須要仔細的設計各個寄存器的功能以及用法。
如下Demo內容須要鏈接VGA接口,按動鍵盤的A~Z的任意鍵,LED燈會顯示對應的ASCII值。若按動A鍵,屏幕會顯示字符a。(由於沒有時間折騰字符提取軟件,rom比較小隻存了a的一個字符。喜歡的朋友也能夠增長不少其餘的字符。)若按動其餘鍵,屏幕只顯示一個白色矩形。
4.源程序