PS2键盘是一种很普通的键盘,有6个接口,其实我们只需关心两个引脚,数据信号DATA,和时钟CLK信号,和串口通信差不多,DATA有12位,其中8位是有效数据位,每当CLK的下降沿到来时,开始采集数据!
键盘编码返回值,如有键盘被按下,就会发送通码,当按键被释放,就会发送断码,每个按键都分配了唯一的通码和断码,这样主机通过查唯一的扫描码就可以知道是哪个按键。按键的通码和断码组成了一套扫描码集,现在用的比较多的是第二套扫描码,多数第二套断码有2字节长,第一个字节是8'hf0;第二个字节是这个按键的通码。例如按下T键,然后再释放T键,此时发送到计算机的数据应该是:8'h2c(通码) 8'hf0 8'h2c。下面来看程序。
module ps2_key ( clk, rst_n, ps2_clk, ps2_data, ps2_byte );input clk;input rst_n;input ps2_clk;input ps2_data; output[7:0] ps2_byte;reg ps2_clk_r0;always @ (posedge clk or negedge rst_n) begin if(!rst_n) ps2_clk_r0<=1'b0; else ps2_clk_r0<=ps2_clk; endreg ps2_clk_r1;always @ (posedge clk or negedge rst_n) begin if(!rst_n) ps2_clk_r1<=1'b0; else ps2_clk_r1<=ps2_clk_r0; endwire neg_ps2_clk;assign neg_ps2_clk=ps2_clk_r1&(~ps2_clk_r0); //脉冲下降沿检测;//从PS2开始采集数据reg [3:0] cnt;always @ (posedge clk or negedge rst_n) begin if(!rst_n) cnt<=4'd0; else if(neg_ps2_clk) begin if(cnt==4'd10) cnt<=4'd0; else cnt<=cnt+1'b1; end endreg [7:0] temp_data;always @ (posedge clk or negedge rst_n) begin if(!rst_n) temp_data<=8'd0; else if(neg_ps2_clk) case(cnt) 4'd0 : ; //当cnt=0时为起始位,不做任何操作; 4'd1 : temp_data[0]=ps2_data; 4'd2 : temp_data[1]=ps2_data; 4'd3 : temp_data[2]=ps2_data; 4'd4 : temp_data[3]=ps2_data; 4'd5 : temp_data[4]=ps2_data; 4'd6 : temp_data[5]=ps2_data; 4'd7 : temp_data[6]=ps2_data; 4'd8 : temp_data[7]=ps2_data; default: ; //我们只关注八位有效数据位; endcase end//判断键盘是否松开reg key_released ; //当接收到FOh时,表示键盘已松开,key_released=1;reg[7:0]ps2_byte_r; always @ (posedge clk or negedge rst_n) begin if(!rst_n) key_released<=1'b0; else if(cnt==4'd10) //刚传送完一组数据; begin if(temp_data==8'hF0) key_released<=1'b1; else begin if(!key_released) //说明有键盘按下; ps2_byte_r<=temp_data; //锁存当前的键值; else ps2_byte_r<=8'd0; end end end // 将接受到得数据转化成ASCII码;reg[7:0] ps2_asci;always @ (*) begin case(ps2_byte_r) 8'h16 : ps2_asci<= 8'h31; //只做简单的数字处理; 8'h1E : ps2_asci <= 8'h32; 8'h26 : ps2_asci <= 8'h33; 8'h25 : ps2_asci <= 8'h34; 8'h2E : ps2_asci <= 8'h35; 8'h36 : ps2_asci <= 8'h36; 8'h3D : ps2_asci <= 8'h37; 8'h3E : ps2_asci <= 8'h38; 8'h46 : ps2_asci <= 8'h39; 8'h45 : ps2_asci <= 8'h30; default : ps2_asci<=8'hxx; endcase endassign ps2_byte=ps2_asci;endmodule