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; end reg 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; end wire 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 end reg [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 end assign ps2_byte=ps2_asci; endmodule