基于STEP FPGA的PS2键盘驱动

 行业动态     |      2023-11-30 10:33:18    |      作者

硬件说明

我们的STEP-BaseBoard底板上集成了PS2键盘的接口,可以供大家连接PS2键盘或PS2鼠标完成相应设计,接下来我们来了解PS2接口的硬件连接及PS2键盘的驱动方法。PS2接口连线非常简单,只需接4根线:

  • 4号引脚VCC接供电电源,一般为5V供电,后经测试3.3V也可以
  • 3号引脚GND接地即可
  • 5号引脚时钟线和1号引脚数据线为两条双向的信号线
  • 2号引脚和6号引脚为保留引脚,不需要连接

当PS2键盘上有按键按动或操作的时候,键盘会发信号给主机,PS2接口的时钟信号和数据信号的时序如下图:

FPGA或主机接收键盘发回的数据,通过键盘的编码规则判定键盘当前的操作,扫描码有两种不同的类型:通码(make code)和断码(break code)。当一个键被按下或持续按住时,键盘会将该键的通码发送给主机;而当一个键被释放时,键盘会将该键的断码发送给主机。根据键盘按键扫描码的不同,在此可将按键分为如下几类:

  • 第一类按键,通码为1字节,断码为0xF0+通码形式。如A键,其通码为0x1C,断码为0xF0 0x1C。
  • 第二类按键,通码为2字节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,断码为空。

组合按键的扫描码发送按照按键发生的次序,如以下面顺序按左SHIFT+A键:1按下左SHIFT键,2按下A键,3释放A键,4释放左SHIFT键,那么计算机上接收到的一串数据为0x12 0x1C 0xF0 0x1C 0xF0 0x12。在驱动程序设计中,就是根据这样的分类来对不同的按键进行不同处理的,当前简单程序只支持第一类按键的操作。键盘中不同按键的编码如下:

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, //系统时钟 input rst_n_in, //系统复位,低有效 input key_clk, //PS2键盘时钟输入 input key_data, //PS2键盘数据输入 output reg key_state, //键盘的按下状态,按下为1,松开为0 output reg [7:0] key_ascii //按键键值对应的ASCII编码); /* 这个模块为FPGA驱动PS2键盘的简单程序,只能支持键盘中第一类按键的单键按动,不支持多个按键同时按动 */ reg key_clk_r0=1'b1,key_clk_r1=1'b1; reg key_data_r0=1'b1,key_data_r1=1'b1; //对键盘时钟数据信号进行延时锁存 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; //根据键盘的时钟信号的下降沿读取数据,详细参考PS2键盘数据的传输格式及时序 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;//数据位bit0 4'd2:temp_data[1]<=key_data_r1;//数据位bit1 4'd3:temp_data[2]<=key_data_r1;//数据位bit2 4'd4:temp_data[3]<=key_data_r1;//数据位bit3 4'd5:temp_data[4]<=key_data_r1;//数据位bit4 4'd6:temp_data[5]<=key_data_r1;//数据位bit5 4'd7:temp_data[6]<=key_data_r1;//数据位bit6 4'd8:temp_data[7]<=key_data_r1;//数据位bit7 4'd9:; //校验位 4'd10:; //结束位 default:; endcase end end reg key_break=1'b0; reg [7:0] key_byte=1'b0;//根据通码和断码判定按键的当前是按下还是松开 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)表示按键松开,设置断码标示为1 elseif(!key_break)begin //当断码标示为0时,表示当前数据为按下数据,输出键值并设置按下标示为1 key_state<=1'b1; key_byte<=temp_data; endelsebegin //当断码标示为1时,标示当前数据为松开数据,断码标示和按下标示都清零 key_state<=1'b0; key_break<=1'b0; end endend//将键盘返回的有效键值转换为按键字母对应的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


小结

本节主要为大家讲解了PS2接口电路、PS2键盘编码规则及使用FPGA简单驱动PS2键盘的方法,需要大家掌握的同时自己创建工程,通过整个设计流程,生成FPGA配置文件加载测试。