本实验是通过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采用的是飞线连接的,显示效果图: