差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
ps2键盘模块 [2017/06/09 17:10]
anran [硬件说明]
ps2键盘模块 [2017/06/09 17:13] (当前版本)
anran [相关资料]
行 37: 行 37:
 // >>>>>>>>>>>>>>>>>>>>>>>>>​ COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<​ // >>>>>>>>>>>>>>>>>>>>>>>>>​ COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<​
 // -------------------------------------------------------------------- // --------------------------------------------------------------------
-// Module: ​Array_KeyBoard+// Module: ​Keyboard_PS2
 //  // 
 // Author: Step // Author: Step
 //  // 
-// Description: ​Array_KeyBoard+// Description: ​PS2 keyboard driver
 //  // 
 // Web: www.stepfapga.com // Web: www.stepfapga.com
-//+// 
 // -------------------------------------------------------------------- // --------------------------------------------------------------------
 // Code Revision History : // Code Revision History :
 // -------------------------------------------------------------------- // --------------------------------------------------------------------
 // Version: |Mod. Date:   ​|Changes Made: // Version: |Mod. Date:   ​|Changes Made:
-// V1.0     |2015/11/11   |Initial ver+// V1.0     |2016/04/20   |Initial ver
 // -------------------------------------------------------------------- // --------------------------------------------------------------------
-module ​Array_KeyBoard #+module ​Keyboard_PS2
 ( (
- parameter NUM_FOR_200HZ = 60000 //​定义计数器cnt的计数范围,例化时可更改 +input clk_in,​ //​系统时钟 
-+input rst_n_in,​ //​系统复位,低有效 
-+input key_clk,​ //​PS2键盘时钟输入 
- input clk_in,​ //​系统时钟 +input key_data, //PS2盘数据输入 
- input rst_n_in,​ //​系统复位,低有效 +output reg key_state, //键盘的下状态,按下为1,松开为0 
- input [3:0] col, //矩阵按列接口 +output reg [7:0] key_ascii //按键键值对应ASCII编码
- output reg [3:0] row, //矩阵键行接口 +
- output reg [15:0] key_out //消抖后信号+
 ); );
 +
 /* /*
-因使用4x4矩阵按键,通过扫描方法实现,所以里使用状态机实现,共分4种状态 +个模块FPGA驱动PS2键盘简单程序只能支持盘中第一类按键的单键不支持多个按键同时 
-在其中某一状态时间里对应的4个按相当于独立按键,可独立按键的周期采样法采样 +*/
-周期采样时每隔20ms采样一次对应这里状态机每隔20ms循环一次,每状态对应5ms时间 +
-对矩阵按键实现原理不明白的,请去了解矩阵键实现原理 +
-*/  +
- localparam STATE0 = 2'​b00;​ +
- localparam STATE1 = 2'​b01;​ +
- localparam STATE2 = 2'​b10;​ +
- localparam STATE3 = 2'b11;+
  
- //器计数分频实现5ms周期信号clk_200hz +reg key_clk_r0 = 1'​b1,​key_clk_r1 = 1'b1;  
- reg [15:​0] cnt;​ +reg key_data_r0 = 1'​b1,​key_data_r1 = 1'​b1;​ 
- reg clk_200hz;​ +//对键盘时钟信号进行延时锁存 
- always@(posedge clk_in or negedge rst_n_in) begin +always @ (posedge clk_in or negedge rst_n_in) begin 
- if(!rst_n_in) begin //​复位时计数器cnt清零,clk_200hz信号起始电平为低电平 + if(!rst_n_in) begin 
- cnt ​<= 16'd0+ key_clk_r0 ​<= 1'b1
- clk_200hz ​<= 1'b0+ key_clk_r1 ​<= 1'b1
- end else begin + key_data_r0 <= 1'b1
- if(cnt >((NUM_FOR_200HZ>>​1) - 1)) begin //​数字逻辑中右移1位相当于除2 + key_data_r1 ​<= 1'b1
- cnt <= 16'd0+ end else begin 
- clk_200hz ​<= ~clk_200hz; //​clk_200hz信号取反 + key_clk_r0 ​<= key_clk
- end else begin + key_clk_r1 ​<= key_clk_r0
- cnt ​<= cnt + 1'b1+ key_data_r0 <= key_data; 
- clk_200hz ​<= clk_200hz+ key_data_r1 <= key_data_r0;​
- end +
- end+
  end  end
 +end
  
- reg [1:0] c_state+//​键盘时钟信号下降沿检测 
- //状态机根据clk_200hz信号在4个状态间循环每个状态对矩阵按键的行接口单行有效 +wire key_clk_neg = key_clk_r1 & (~key_clk_r0);​  
- always@(posedge ​clk_200hz ​or negedge rst_n_in) begin + 
- if(!rst_n_in) begin +reg [3:0] cnt;  
- c_state ​<= STATE0+reg [7:​0] temp_data
- row <= 4'b1110+//根据键盘的时钟信号的下降沿读取数据详细参考PS2盘数据传输格式及时序 
- end else begin +always @ (posedge ​clk_in ​or negedge rst_n_in) begin 
- case(c_state) + if(!rst_n_in) begin 
- STATE0: begin c_state ​<= STATE1row <= 4'b1101end //状态c_state跳转及对应状态下矩阵按键的row输出 + cnt <= 4'd0
- STATE1begin c_state ​<= STATE2row <= 4'b1011; end + temp_data ​<= 8'd0
- STATE2begin c_state ​<= STATE3row <= 4'b0111end + end else if(key_clk_neg) ​begin  
- STATE3begin c_state ​<= STATE0row <= 4'b1110end + if(cnt >= 4'd10cnt <= 4'd0; 
- default:begin c_state ​<= STATE0row <= 4'b1110end + else cnt <= cnt + 1'​b1;​ 
- endcase + case (cnt) 
- end+ 4'd0: ; //起始位 
 + 4'd1temp_data[0] ​<= key_data_r1 //​数据位bit0 
 + 4'd2temp_data[1] ​<= key_data_r1 //​数据位bit1 
 + 4'd3: temp_data[2] <= key_data_r1 //​数据位bit2 
 + 4'd4temp_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'd7temp_data[6] ​<= key_data_r1 //​数据位bit6 
 + 4'​d8:​ temp_data[7] ​<= key_data_r1; ​ //​数据位bit7 
 + 4'd9: ; //校验位 
 + 4'​d10:;​ //​结束位 
 + default: ; 
 + endcase
  end  end
-  +end 
- //因为每个状态中单行有效,过对列接口的电平状态采样得到对应4个按键的状态,依次循环 + 
- always@(negedge clk_200hz ​or negedge rst_n_in) begin +reg key_break = 1'​b0; ​   
- if(!rst_n_in) begin +reg [7:​0] key_byte = 1'b0; 
- key_out ​<= 16'hffff+//根据码和断码判定按键的当前是按下还是松开 
- end else begin +always @ (posedge clk_in ​or negedge rst_n_in) begin  
- case(c_state) + if(!rst_n_in) begin 
- STATE0:​key_out[3:​0] ​<= col; //采集当前状态的列数据给对应的寄存器位 + key_break ​<= 1'b0
- STATE1:​key_out[7:​4] ​<= col+ key_state <= 1'​b0;​ 
- STATE2:​key_out[11:​8] ​<= col+ key_byte <= 1'​b0;​ 
- STATE3:​key_out[15:​12] ​<= col+ end else if(cnt==4'​d10 && key_clk_neg) ​begin  
- default:​key_out ​<= 16'hffff; + if(temp_data == 8'hf0key_break ​<= 1'b1; //​收到段码(8'​hf0)表示按键松开,设置断码标示为1 
- endcase+ else if(!key_break) begin  //当断码标示为0时,表示当前数据为按下数据,输出键并设置按下标示为1 
 + key_state ​<= 1'b1
 + key_byte ​<= temp_data;  
 + end else begin //​当断码标示为1时,标示当前数据为松开数据,断码标示和按下标示都清零 
 + key_state ​<= 1'b0
 + key_break ​<= 1'b0;
  end  end
  end  end
 +end
  
 +//​将键盘返回的有效键值转换为按键字母对应的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 endmodule
  
行 133: 行 175:
 ====小结==== ====小结====
 ------ ------
-本节主要为大家讲解了矩阵按的工作原理软件设计,需要大家掌握的同时自己创建工程,通过整个设计流程,生成FPGA配置文件加载测试。+本节主要为大家讲解了PS2接口电路、PS2盘编码规则使用FPGA简单驱动PS2键盘的方法,需要大家掌握的同时自己创建工程,通过整个设计流程,生成FPGA配置文件加载测试。
 \\ \\
 如果你对Diamond软件的使用不了解,请参考这里:[[lattice_diamond的使用|Diamond的使用]]。 如果你对Diamond软件的使用不了解,请参考这里:[[lattice_diamond的使用|Diamond的使用]]。
行 140: 行 182:
 ------ ------
 \\ \\
-使用[[STEP-MXO2第二代]]的矩阵按键程序: ​ 后续会有下载连接 ​ 待更新+使用[[STEP-MXO2第二代]]的PS2盘驱动程序: ​ 后续会有下载连接 ​ 待更新
 \\ \\
-使用[[STEP-MAX10]]的矩阵按键程序: ​ 后续会有下载连接 ​ 待更新+使用[[STEP-MAX10]]的PS2盘驱动程序: ​ 后续会有下载连接 ​ 待更新
 \\ \\