本实验是通过LCD12864来显示键盘上被按下的按键,实验比较简单,在LCD12864固定的DDRAM地址上显示,缺点就是不能保存上一次被按的内容,后者会覆盖掉前面,所以屏上仅有一个字符显示。保存上一次内容不被覆盖掉方法还待改进。目前将就这样吧。
关于LCD12864显示可以参考“LCD12864 液晶显示-汉字及自定义显示(并口)”,代码稍微改了一下,可以参考代码。
PS2键盘解码实验也比较简单,可以参考特权的或是“verilog HDL的那些事儿”也可以在网上找到相关的资料。
ps2_control.v
1 module ps2_control( 2 //input 3 sys_clk, 4 rst_n, 5 key_clk, 6 key_data, 7 8 //output 9 data_buf, 10 ); 11 input sys_clk; //50Mhz 12 input rst_n; 13 input key_clk; //键盘时钟 14 input key_data; //键盘数据 15 16 output [7:0] data_buf; //保存要显示的数据 17 18 //*********************************************** 19 //检测key_clk的下降沿 20 //*********************************************** 21 reg key_clk_1; 22 reg key_clk_2; 23 always @(posedge sys_clk or negedge rst_n) 24 if(!rst_n) begin 25 key_clk_1 <= 1'b1; 26 key_clk_2 <= 1'b1; 27 end 28 else begin 29 key_clk_1 <= key_clk; 30 key_clk_2 <= key_clk_1; 31 end 32 33 wire key_clk_n; 34 assign key_clk_n = key_clk_2 & (~key_clk_1); 35 //*********************************************** 36 //对key_data上的数据进行保存 37 //*********************************************** 38 reg [3:0] i; 39 reg [7:0] data_temp; 40 always @(posedge sys_clk or negedge rst_n) 41 if(!rst_n) begin 42 i <= 4'd0; 43 data_temp <= 8'h00; 44 end 45 else if(key_clk_n) begin 46 case(i) 47 4'd0: i <= i + 1'b1; //起始位不处理 48 49 4'd1,4'd2,4'd3,4'd4,4'd5,4'd6,4'd7,4'd8: 50 begin 51 i <= i + 1'b1; 52 data_temp[i-1] <= key_data; 53 end 54 55 4'd9: i <= i + 1'b1; //奇校验位不处理 56 57 4'd10: i <= 4'd0; //停止位不处理 58 59 default: ; 60 endcase 61 end 62 63 reg key_f0; //松键标志位,置1表示接收到数据8'hf0,再接收到下一个数据后清零 64 reg[7:0] ps2_data; 65 always @(posedge sys_clk or negedge rst_n) //接收数据的相应处理,这里只对1byte的键值进行处理 66 if(!rst_n) begin 67 key_f0 <= 1'b0; 68 ps2_data <= 8'h00; 69 end 70 else if(i==4'd10) //刚传送完一个字节数据 71 begin 72 if(data_temp == 8'hf0) 73 key_f0 <= 1'b1; //说明有键被释放 74 else if(!key_f0) //说明有键按下 75 ps2_data <= data_temp; //锁存当前键值 76 else 77 key_f0 <= 1'b0; 78 end 79 80 reg [7:0] data_buf; 81 always @ (ps2_data) begin 82 case (ps2_data) 83 8'h15: data_buf = "Q"; 84 8'h1d: data_buf = "W"; 85 8'h24: data_buf = "E"; 86 8'h2d: data_buf = "R"; 87 8'h2c: data_buf = "T"; 88 8'h35: data_buf = "Y"; 89 8'h3c: data_buf = "U"; 90 8'h43: data_buf = "I"; 91 8'h44: data_buf = "O"; 92 8'h4d: data_buf = "P"; 93 8'h1c: data_buf = "A"; 94 8'h1b: data_buf = "S"; 95 8'h23: data_buf = "D"; 96 8'h2b: data_buf = "F"; 97 8'h34: data_buf = "G"; 98 8'h33: data_buf = "H"; 99 8'h3b: data_buf = "J"; 100 8'h42: data_buf = "K"; 101 8'h4b: data_buf = "L"; 102 8'h1a: data_buf = "Z"; 103 8'h22: data_buf = "X"; 104 8'h21: data_buf = "C"; 105 8'h2a: data_buf = "V"; 106 8'h32: data_buf = "B"; 107 8'h31: data_buf = "N"; 108 8'h3a: data_buf = "M"; 109 default: data_buf = 8'h00; 110 endcase 111 end 112 113 endmodule 114 115 116
LCD12864.v
1 module LCD12864( 2 //input 3 sys_clk, 4 rst_n, 5 data_buf, 6 7 //output 8 lcd_rs, 9 lcd_rw, 10 lcd_en, 11 lcd_data, 12 lcd_psb 13 ); 14 input sys_clk;// 50MHZ 15 input rst_n; 16 input [7:0] data_buf; 17 18 output lcd_rs;//H:data L:command 19 output lcd_rw;//H:read module L:write module 20 output lcd_en;//H active 21 output [7:0] lcd_data; 22 output lcd_psb;//H:parallel module L:SPI module 23 24 /***************************************************/ 25 parameter T3MS = 18'd149_999; 26 parameter IDLE = 4'd0, 27 INIT_FUN_SET1 = 4'd1, 28 INIT_FUN_SET2 = 4'd2, 29 INIT_DISPLAY = 4'd3, 30 INIT_CLEAR = 4'd4, 31 INIT_DOT_SET = 4'd5, 32 SET_DDRAM = 4'd6, 33 WRITE_DATA1 = 4'd7; 34 /* INIT_FUN_SET3 = 4'd8, 35 SET_CGRAM = 4'd9, 36 WRITE_DATA2 = 4'd10, 37 SET_DDRAM2 = 4'd11, 38 SET_CUSTOM_L = 4'd12, 39 SET_CUSTOM_H = 4'd13, 40 STOP = 4'd14;*/ 41 /***************************************************/ 42 //产生周期为6MS的lcd_clk给LCD 43 reg [17:0] cnt; 44 reg lcd_clk; 45 always @(posedge sys_clk or negedge rst_n) 46 if(!rst_n) begin 47 cnt <= 18'd0; 48 lcd_clk <= 1'b0; 49 end 50 else if(cnt == T3MS)begin 51 cnt <= 18'd0; 52 lcd_clk <= ~lcd_clk; 53 end 54 else 55 cnt <= cnt + 1'b1; 56 57 /***************************************************/ 58 reg lcd_rs; 59 always @(posedge lcd_clk or negedge rst_n) 60 if(!rst_n) 61 lcd_rs <= 1'b0; 62 else if(state == WRITE_DATA1) 63 lcd_rs <= 1'b1; //写数据模式 64 else 65 lcd_rs <= 1'b0; //写命令模式 66 /***************************************************/ 67 reg [3:0] state; 68 reg [7:0] lcd_data; 69 reg [6:0] num; 70 reg en; 71 always @(posedge lcd_clk or negedge rst_n) 72 if(!rst_n) begin 73 state <= IDLE; 74 lcd_data <= 8'h00; 75 en <= 1'b1; 76 num <= 6'd0; 77 end 78 else 79 case(state) 80 IDLE: 81 begin 82 state <= INIT_FUN_SET1; 83 lcd_data <= 8'hzz; 84 en <= 1'b1; 85 end 86 87 INIT_FUN_SET1: 88 begin 89 lcd_data <= 8'h30; //功能设定 90 state <= INIT_FUN_SET2; 91 end 92 93 INIT_FUN_SET2: 94 begin 95 lcd_data <= 8'h30; //功能设定 96 state <= INIT_DISPLAY; 97 end 98 99 INIT_DISPLAY: 100 begin 101 lcd_data <= 8'h0c; //显示设定 102 state <= INIT_CLEAR; 103 end 104 105 INIT_CLEAR: 106 begin 107 lcd_data <= 8'h01; //清屏 108 state <= INIT_DOT_SET; 109 end 110 111 INIT_DOT_SET: 112 begin 113 lcd_data <= 8'h06; //进入点设定 114 state <= SET_DDRAM; 115 end 116 117 SET_DDRAM: 118 begin 119 lcd_data <= 8'h94;//2 line 120 state <= WRITE_DATA1; 121 end 122 123 WRITE_DATA1: 124 begin 125 lcd_data <= data_buf; 126 state <= SET_DDRAM; //一直在同一个地方刷新显示 127 end 128 129 /* STOP: 130 begin 131 en <= 1'b0;//显示完了,lcd_e就一直拉为低 132 state <= STOP; 133 end */ 134 135 default: state <= IDLE; 136 endcase 137 138 /***************************************************/ 139 assign lcd_rw = 1'b0;//只有写模式 140 assign lcd_psb = 1'b1;//并口模式 141 assign lcd_en = en ? lcd_clk : 1'b0; 142 /***************************************************/ 143 endmodule
ps2_top.v
1 module ps2_top( 2 //input 3 sys_clk, 4 rst_n, 5 key_clk, 6 key_data, 7 8 //output 9 lcd_rs, 10 lcd_rw, 11 lcd_en, 12 lcd_data, 13 lcd_psb 14 ); 15 input sys_clk;// 50MHZ 16 input rst_n; 17 input key_clk; //键盘时钟 18 input key_data; //键盘数据 19 20 output lcd_rs;//H:data L:command 21 output lcd_rw;//H:read module L:write module 22 output lcd_en;//H active 23 output [7:0] lcd_data; 24 output lcd_psb;//H:parallel module L:SPI module 25 26 wire [7:0] data_buf; 27 28 ps2_control u1( 29 //input 30 .sys_clk(sys_clk), 31 .rst_n(rst_n), 32 .key_clk(key_clk), 33 .key_data(key_data), 34 35 //output 36 .data_buf(data_buf), 37 ); 38 39 LCD12864 u2( 40 //input 41 .sys_clk(sys_clk), 42 .rst_n(rst_n), 43 .data_buf(data_buf), 44 45 //output 46 .lcd_rs(lcd_rs), 47 .lcd_rw(lcd_rw), 48 .lcd_en(lcd_en), 49 .lcd_data(lcd_data), 50 .lcd_psb(lcd_psb) 51 ); 52 endmodule
PS2接口和LCD12864采用的是飞线连接的,显示效果图: