此试验我一人调试许久都未成功,但发送ff时,读出来的数据确是对的,一开始让我窃喜,但发送f4时,读出来的数据确是错的,哎让苦恼啊,能力有限,只能先暂时就这样吧,那位什么还要贴出来呢,有两个原因:
1、等自己能力达到一定时,在回过头来,把这个问题解决掉,我相信,一定能实现的。
2、晒出来就是希望能得到各位网友能帮忙指点哪个地方容易出问题。在此先拜谢了!
>>PS2鼠标实验是一个双向通信实验,那就得知道PS2鼠标传输协议,本人觉得自己对PS2传输协议有所掌握(也许理解的还不够到位)。具体传输协议就不多描述,还是看专业的“PS/2 技术参考”。
>>在写代码之前,我参考网上一个例子,链接“http://www.360doc.com/content/13/0612/20/2260882_292421295.shtml”,这位网友例化时,看起来有点累,思路基本能看懂,自己稍微整理了一下,整体框架如下图。
步骤:
1、先由控制模块启动发送模块,把指令“0XF4”发送给鼠标。
2、发送模块发送完后,产生一个发送完标志,传给控制模块,在由控制模块启动接收模块。
3、接收模块接收完数据,产生一个接收完标志,传给控制模块,模块在进行相应的数据处理。
4、数据处理完后,传给显示模块进行显示。
代码实现:
ps2_data_control.v

1 module ps2_data_control( 2 //input 3 sys_clk, 4 rst_n, 5 send_done_sig, //发送完标志 6 rx_done_sig, //接收完标志 7 data_buf, //接收到的数据 8 9 //output 10 rx_en, //接收使能 11 send_en, //发送使能 12 send_cmd, //要发送的命令 13 dis_data_low1, //要显示的数据 14 dis_data_hig1, 15 16 dis_data_low2, //要显示的数据 17 dis_data_hig2, 18 19 dis_data_low3, //要显示的数据 20 dis_data_hig3, 21 22 dis_data_low4, //要显示的数据 23 dis_data_hig4, 24 25 dis_data_btn 26 ); 27 input sys_clk; 28 input rst_n; 29 input send_done_sig; 30 input rx_done_sig; 31 input [7:0] data_buf; 32 33 output rx_en; 34 output send_en; 35 output [7:0] send_cmd; 36 output [7:0] dis_data_low1; 37 output [7:0] dis_data_hig1; 38 output [7:0] dis_data_low2; 39 output [7:0] dis_data_hig2; 40 output [7:0] dis_data_low3; 41 output [7:0] dis_data_hig3; 42 output [7:0] dis_data_low4; 43 output [7:0] dis_data_hig4; 44 output [7:0] dis_data_btn; 45 /**********************************************************************/ 46 parameter T100MS = 23'd4_999_999; 47 parameter T500MS = 25'd24_999_999; 48 parameter T100US = 13'd4_999; 49 parameter PS2_RST = 8'hf4; //复位cmd 50 parameter PS2_EN = 8'hf4; //数据报告使能cmd 51 parameter IDLE = 4'd0, 52 SEND_PS2_RST = 4'd1, 53 RX_EN1 = 4'd2, 54 RX_ANSWER_FA = 4'd3, 55 RX_ANSWER_AA = 4'd4, 56 RX_ANSWER_ID = 4'd5, 57 SEND_PS2_EN = 4'd6, 58 RX_EN2 = 4'd7, 59 RX_ANSWER2 = 4'd8, 60 RX_BYTE1 = 4'd9, 61 RX_BYTE2 = 4'd10, 62 RX_BYTE3 = 4'd11, 63 DELAY = 4'd12, 64 STOP = 4'd13; 65 /**********************************************************************/ 66 //assign send_cmd = STREAM; 67 /**********************************************************************/ 68 //200us计数器 69 reg [24:0] cnt; 70 always @(posedge sys_clk or negedge rst_n) 71 if(!rst_n) 72 cnt <= 25'd0; 73 else if(!cnt_en || cnt == T500MS) 74 cnt <= 25'd0; 75 else 76 cnt <= cnt + 1'b1; 77 /**********************************************************************/ 78 reg send_en; 79 reg rx_en; 80 reg [7:0] data_answer; //保存应答位 81 reg x_sign; //x的符号位 82 reg y_sign; //y的符号位 83 reg [7:0] x_move; //x的偏移量 84 reg [7:0] y_move; //y的偏移量 85 reg [3:0] state; 86 reg [7:0] dis_data_temp1; 87 reg [7:0] dis_data_temp2; 88 reg [7:0] dis_data_temp3; 89 reg [7:0] dis_data_temp4; 90 reg [7:0] dis_data_btn; 91 reg cnt_en; 92 reg [7:0] send_cmd; 93 always @(posedge sys_clk or negedge rst_n) 94 if(!rst_n) begin 95 send_en <= 1'b0; 96 rx_en <= 1'b0; 97 data_answer <= 8'h00; 98 x_sign <= 1'b0; 99 y_sign <= 1'b0; 100 state <= IDLE; 101 dis_data_temp1 <= 8'h00; 102 dis_data_temp2 <= 8'h00; 103 dis_data_temp3 <= 8'h00; 104 dis_data_temp4 <= 8'h00; 105 cnt_en <= 1'b0; 106 dis_data_btn <= "X"; 107 send_cmd <= 8'h00; 108 end 109 else begin 110 case(state) 111 IDLE: 112 begin 113 state <= SEND_PS2_RST; 114 cnt_en <= 1'b1; 115 end 116 117 SEND_PS2_RST: //发送复位 0xff 118 if(cnt == T100MS) begin 119 cnt_en <= 1'b0; 120 send_en <= 1'b1; //启动发送 121 send_cmd <= PS2_RST; 122 state <= RX_EN1; 123 end 124 125 RX_EN1: 126 if(send_done_sig) begin 127 rx_en <= 1'b1; 128 send_en <= 1'b0; 129 state <= RX_ANSWER_FA; 130 end 131 132 RX_ANSWER_FA: //接收鼠标发回的应答数据0xfa 133 if(rx_done_sig) begin 134 dis_data_temp1 <= data_buf; 135 state <= RX_ANSWER_AA;//RX_BYTE1; 136 end 137 138 RX_ANSWER_AA: //接收鼠标发回的应答数据0xaa 139 if(rx_done_sig) begin 140 dis_data_temp2 <= data_buf; 141 state <= RX_ANSWER_ID; 142 end 143 144 RX_ANSWER_ID: //接收鼠标发回的应答数据0x00 145 if(rx_done_sig) begin 146 dis_data_temp3 <= data_buf; 147 cnt_en <= 1'b1; 148 state <= SEND_PS2_RST; 149 end 150 151 SEND_PS2_EN: //发送0xf4 152 if(cnt == T100MS)begin 153 rx_en <= 1'b0; 154 cnt_en <= 1'b0; 155 send_en <= 1'b1; //启动发送 156 send_cmd <= PS2_EN; 157 state <= RX_EN2; 158 end 159 160 RX_EN2: 161 if(send_done_sig) begin 162 rx_en <= 1'b1; //启动接收 163 send_en <= 1'b0; 164 state <= RX_ANSWER2; 165 end 166 167 RX_ANSWER2: //第二次应答位 168 if(rx_done_sig) begin 169 dis_data_temp4 <= data_buf; 170 state <= RX_BYTE1; 171 end 172 173 RX_BYTE1: 174 if(rx_done_sig) begin 175 if(data_buf[0] == 1'b1)//左键被按下 176 dis_data_btn <= "L"; 177 else if(data_buf[1] == 1'b1) //右键被按下 178 dis_data_btn <= "R"; 179 else if(data_buf[2] == 1'b1) //中键被按下 180 dis_data_btn <= "M"; 181 182 x_sign <= data_buf[4]; 183 y_sign <= data_buf[5]; 184 185 state <= RX_BYTE2; 186 end 187 188 RX_BYTE2: 189 if(rx_done_sig) begin //接收到第二个字节 190 x_move <= data_buf; 191 state <= RX_BYTE3; 192 end 193 194 RX_BYTE3: //接收到第三个字节 195 if(rx_done_sig) begin 196 y_move <= data_buf; 197 state <= STOP; 198 cnt_en <= 1'b1; 199 end 200 201 STOP: 202 if(cnt == T100MS) begin 203 cnt_en <= 1'b0; 204 state <= RX_BYTE1; 205 end 206 endcase 207 end 208 209 reg [7:0] dis_data_low1; 210 always @(dis_data_temp1[3:0]) 211 case(dis_data_temp1[3:0]) 212 4'h0: dis_data_low1 = "0"; 213 4'h1: dis_data_low1 = "1"; 214 4'h2: dis_data_low1 = "2"; 215 4'h3: dis_data_low1 = "3"; 216 4'h4: dis_data_low1 = "4"; 217 4'h5: dis_data_low1 = "5"; 218 4'h6: dis_data_low1 = "6"; 219 4'h7: dis_data_low1 = "7"; 220 4'h8: dis_data_low1 = "8"; 221 4'h9: dis_data_low1 = "9"; 222 4'ha: dis_data_low1 = "a"; 223 4'hb: dis_data_low1 = "b"; 224 4'hc: dis_data_low1 = "c"; 225 4'hd: dis_data_low1 = "d"; 226 4'he: dis_data_low1 = "e"; 227 4'hf: dis_data_low1 = "f"; 228 endcase 229 230 reg [7:0] dis_data_hig1; 231 always @(dis_data_temp1[7:4]) 232 case(dis_data_temp1[7:4]) 233 4'h0: dis_data_hig1 = "0"; 234 4'h1: dis_data_hig1 = "1"; 235 4'h2: dis_data_hig1 = "2"; 236 4'h3: dis_data_hig1 = "3"; 237 4'h4: dis_data_hig1 = "4"; 238 4'h5: dis_data_hig1 = "5"; 239 4'h6: dis_data_hig1 = "6"; 240 4'h7: dis_data_hig1 = "7"; 241 4'h8: dis_data_hig1 = "8"; 242 4'h9: dis_data_hig1 = "9"; 243 4'ha: dis_data_hig1 = "a"; 244 4'hb: dis_data_hig1 = "b"; 245 4'hc: dis_data_hig1 = "c"; 246 4'hd: dis_data_hig1 = "d"; 247 4'he: dis_data_hig1 = "e"; 248 4'hf: dis_data_hig1 = "f"; 249 endcase 250 251 reg [7:0] dis_data_low2; 252 always @(dis_data_temp2[3:0]) 253 case(dis_data_temp2[3:0]) 254 4'h0: dis_data_low2 = "0"; 255 4'h1: dis_data_low2 = "1"; 256 4'h2: dis_data_low2 = "2"; 257 4'h3: dis_data_low2 = "3"; 258 4'h4: dis_data_low2 = "4"; 259 4'h5: dis_data_low2 = "5"; 260 4'h6: dis_data_low2 = "6"; 261 4'h7: dis_data_low2 = "7"; 262 4'h8: dis_data_low2 = "8"; 263 4'h9: dis_data_low2 = "9"; 264 4'ha: dis_data_low2 = "a"; 265 4'hb: dis_data_low2 = "b"; 266 4'hc: dis_data_low2 = "c"; 267 4'hd: dis_data_low2 = "d"; 268 4'he: dis_data_low2 = "e"; 269 4'hf: dis_data_low2 = "f"; 270 endcase 271 272 reg [7:0] dis_data_hig2; 273 always @(dis_data_temp2[7:4]) 274 case(dis_data_temp2[7:4]) 275 4'h0: dis_data_hig2 = "0"; 276 4'h1: dis_data_hig2 = "1"; 277 4'h2: dis_data_hig2 = "2"; 278 4'h3: dis_data_hig2 = "3"; 279 4'h4: dis_data_hig2 = "4"; 280 4'h5: dis_data_hig2 = "5"; 281 4'h6: dis_data_hig2 = "6"; 282 4'h7: dis_data_hig2 = "7"; 283 4'h8: dis_data_hig2 = "8"; 284 4'h9: dis_data_hig2 = "9"; 285 4'ha: dis_data_hig2 = "a"; 286 4'hb: dis_data_hig2 = "b"; 287 4'hc: dis_data_hig2 = "c"; 288 4'hd: dis_data_hig2 = "d"; 289 4'he: dis_data_hig2 = "e"; 290 4'hf: dis_data_hig2 = "f"; 291 endcase 292 293 reg [7:0] dis_data_low3; 294 always @(dis_data_temp3[3:0]) 295 case(dis_data_temp3[3:0]) 296 4'h0: dis_data_low3 = "0"; 297 4'h1: dis_data_low3 = "1"; 298 4'h2: dis_data_low3 = "2"; 299 4'h3: dis_data_low3 = "3"; 300 4'h4: dis_data_low3 = "4"; 301 4'h5: dis_data_low3 = "5"; 302 4'h6: dis_data_low3 = "6"; 303 4'h7: dis_data_low3 = "7"; 304 4'h8: dis_data_low3 = "8"; 305 4'h9: dis_data_low3 = "9"; 306 4'ha: dis_data_low3 = "a"; 307 4'hb: dis_data_low3 = "b"; 308 4'hc: dis_data_low3 = "c"; 309 4'hd: dis_data_low3 = "d"; 310 4'he: dis_data_low3 = "e"; 311 4'hf: dis_data_low3 = "f"; 312 endcase 313 314 reg [7:0] dis_data_hig3; 315 always @(dis_data_temp3[7:4]) 316 case(dis_data_temp3[7:4]) 317 4'h0: dis_data_hig3 = "0"; 318 4'h1: dis_data_hig3 = "1"; 319 4'h2: dis_data_hig3 = "2"; 320 4'h3: dis_data_hig3 = "3"; 321 4'h4: dis_data_hig3 = "4"; 322 4'h5: dis_data_hig3 = "5"; 323 4'h6: dis_data_hig3 = "6"; 324 4'h7: dis_data_hig3 = "7"; 325 4'h8: dis_data_hig3 = "8"; 326 4'h9: dis_data_hig3 = "9"; 327 4'ha: dis_data_hig3 = "a"; 328 4'hb: dis_data_hig3 = "b"; 329 4'hc: dis_data_hig3 = "c"; 330 4'hd: dis_data_hig3 = "d"; 331 4'he: dis_data_hig3 = "e"; 332 4'hf: dis_data_hig3 = "f"; 333 endcase 334 335 reg [7:0] dis_data_low4; 336 always @(dis_data_temp4[3:0]) 337 case(dis_data_temp4[3:0]) 338 4'h0: dis_data_low4 = "0"; 339 4'h1: dis_data_low4 = "1"; 340 4'h2: dis_data_low4 = "2"; 341 4'h3: dis_data_low4 = "3"; 342 4'h4: dis_data_low4 = "4"; 343 4'h5: dis_data_low4 = "5"; 344 4'h6: dis_data_low4 = "6"; 345 4'h7: dis_data_low4 = "7"; 346 4'h8: dis_data_low4 = "8"; 347 4'h9: dis_data_low4 = "9"; 348 4'ha: dis_data_low4 = "a"; 349 4'hb: dis_data_low4 = "b"; 350 4'hc: dis_data_low4 = "c"; 351 4'hd: dis_data_low4 = "d"; 352 4'he: dis_data_low4 = "e"; 353 4'hf: dis_data_low4 = "f"; 354 endcase 355 356 reg [7:0] dis_data_hig4; 357 always @(dis_data_temp4[7:4]) 358 case(dis_data_temp4[7:4]) 359 4'h0: dis_data_hig4 = "0"; 360 4'h1: dis_data_hig4 = "1"; 361 4'h2: dis_data_hig4 = "2"; 362 4'h3: dis_data_hig4 = "3"; 363 4'h4: dis_data_hig4 = "4"; 364 4'h5: dis_data_hig4 = "5"; 365 4'h6: dis_data_hig4 = "6"; 366 4'h7: dis_data_hig4 = "7"; 367 4'h8: dis_data_hig4 = "8"; 368 4'h9: dis_data_hig4 = "9"; 369 4'ha: dis_data_hig4 = "a"; 370 4'hb: dis_data_hig4 = "b"; 371 4'hc: dis_data_hig4 = "c"; 372 4'hd: dis_data_hig4 = "d"; 373 4'he: dis_data_hig4 = "e"; 374 4'hf: dis_data_hig4 = "f"; 375 endcase 376 endmodule 377
ps2_send_control.v (注意ps2_clk和ps2_data控制方向)

1 module ps2_send_control( 2 //input 3 sys_clk, 4 rst_n, 5 send_en, //发送使能 6 send_cmd, //要发送的数据 0xf4 7 8 //output 9 send_done_sig,//发送完标志 10 11 //inout 12 ps2_clk, //鼠标时钟 13 ps2_data //鼠标数据 14 ); 15 16 input sys_clk; 17 input rst_n; 18 input send_en; 19 input [7:0] send_cmd; 20 21 output send_done_sig; 22 23 inout ps2_clk; 24 inout ps2_data; 25 /**************************************************************/ 26 parameter T200US = 14'd9999; 27 parameter T40US = 11'd1999; 28 parameter IDLE = 3'd0, 29 PS2_CLK_SET0 = 3'd1, //时钟拉低 30 PS2_DATA_SET0 = 3'd2, //数据拉低 31 PS2_CLK_SET1 = 3'd3, //释放时钟,拉高 32 SEND_DATA = 3'd4, //发送8bit数据和校验位 33 PS2_DATA_SET1 = 3'd5, //释放数据,拉高 34 STOP = 3'd6; 35 /**************************************************************/ 36 //如果send_data中有偶数个1,那么^send_data结果为0,否则为1,在取反即为奇校验位应设置的值 37 wire odd_parity; 38 assign odd_parity = ~(^send_cmd); 39 //上面这句,一位网友说是下面的操作方式 40 // ~(odd_parity ^send_cmd[0]) -> ~(~(odd_parity ^send_cmd[0]) ^send_cmd[1]) 41 // -> ~(~(~(odd_parity ^send_cmd[0]) ^send_cmd[1]) ^send_cmd[2])... 一次类推 42 /**************************************************************/ 43 //控制鼠标时钟和数据的方向 44 //link_clk = 1,ps2_clk为output ,link_clk = 0,ps2_clk为input,FPGA内部得把该管脚设置为高阻态,以便接收时钟 45 //link_data = 1,ps2_data为output ,link_data = 0,ps2_data为input,FPGA内部得把该管脚设置为高阻态,以便接受数据 46 assign ps2_clk = link_clk ? ps2_clk_out : 1'bz; 47 assign ps2_data = link_data ? ps2_data_out : 1'bz; 48 /**************************************************************/ 49 //200us计数器 50 reg [13:0] cnt; 51 always @(posedge sys_clk or negedge rst_n) 52 if(!rst_n) 53 cnt <= 14'd0; 54 else if(!cnt_en || cnt == T200US) 55 cnt <= 14'd0; 56 else 57 cnt <= cnt + 1'b1; 58 /**************************************************************/ 59 reg ps2_clk_1; 60 reg ps2_clk_2; 61 always @(posedge sys_clk or negedge rst_n) 62 if(!rst_n) begin 63 ps2_clk_1 <= 1'b1; 64 ps2_clk_2 <= 1'b1; 65 end 66 else begin 67 ps2_clk_1 <= ps2_clk; 68 ps2_clk_2 <= ps2_clk_1; 69 end 70 71 wire ps2_clk_n; 72 assign ps2_clk_n = ps2_clk_2& (~ps2_clk_1); 73 /**************************************************************/ 74 reg link_clk; 75 reg link_data; 76 reg cnt_en; 77 reg ps2_clk_out; 78 reg ps2_data_out; 79 reg send_done_sig; 80 reg [2:0] state; 81 reg [3:0] i; 82 reg [8:0] s_data; 83 always @(posedge sys_clk or negedge rst_n) 84 if(!rst_n) begin 85 link_clk <= 1'b0; 86 link_data <= 1'b0; 87 cnt_en <= 1'b0; 88 ps2_clk_out <= 1'b1; 89 ps2_data_out <= 1'b1; 90 send_done_sig <= 1'b0; 91 state <= IDLE; 92 i <= 4'd0; 93 s_data <= 9'd0; 94 end 95 else if(send_en) begin 96 case(state) 97 IDLE: 98 begin 99 state <= PS2_CLK_SET0; 100 s_data <= /*{1'b0,send_cmd}*/{odd_parity,send_cmd}; 101 end 102 103 PS2_CLK_SET0: 104 begin 105 link_clk <= 1'b1; //输出状态 106 ps2_clk_out <= 1'b0; 107 cnt_en <= 1'b1; //启动计数器 108 state <= PS2_DATA_SET0; 109 end 110 111 PS2_DATA_SET0: 112 if(cnt == T200US) begin //200us后 拉低数据线 113 cnt_en <= 1'b0; 114 link_data <= 1'b1; 115 ps2_data_out <= 1'b0; 116 state <= PS2_CLK_SET1; 117 end 118 119 PS2_CLK_SET1: 120 /*if(cnt == T40US)*/begin 121 // cnt_en <= 1'b0; 122 link_clk <= 1'b0; //输入状态 link_clk置0的话,LCD上没有数据显示,写0还能显示几个数据 123 // ps2_clk_out <= 1'b1; //释放时钟线 124 state <= SEND_DATA; 125 end 126 127 SEND_DATA: 128 if(ps2_clk_n) begin //在时钟的下降沿设置数据 129 if(i == 4'd9) begin 130 i <= 4'd0; 131 state <= PS2_DATA_SET1; 132 end 133 else begin 134 link_clk <= 1'b0; 135 link_data <= 1'b1; 136 ps2_data_out <= s_data[i]; 137 i <= i + 1'b1; 138 state <= SEND_DATA; 139 end 140 end 141 142 PS2_DATA_SET1: //释放数据线 发送停止位 143 if(ps2_clk_n) begin 144 link_data <= 1'b1; 145 ps2_data_out <= 1'b1; 146 state <= STOP; 147 send_done_sig <= 1'b1; 148 end 149 150 STOP: 151 begin 152 link_data <= 1'b0; //link_data置1的话,LCD上没有数据显示,写0还能显示几个数据 153 state <= IDLE; 154 end 155 endcase 156 end 157 158 endmodule
ps2_rx_control.v

1 module ps2_rx_control( 2 //input 3 sys_clk, 4 rst_n, 5 ps2_clk_in, //鼠标时钟 6 ps2_data_in, //鼠标数据 7 rx_en, //接收模块使能信号 8 9 //output 10 rx_done_sig, //接收完标志信号 11 data_buf //保存接收到的数据 12 ); 13 input sys_clk; 14 input rst_n; 15 input ps2_clk_in; 16 input ps2_data_in; 17 input rx_en; 18 19 output rx_done_sig; 20 output [7:0] data_buf; 21 /**************************************************************/ 22 reg ps2_clk_in_1; 23 reg ps2_clk_in_2; 24 wire ps2_clk_in_n; 25 always @(posedge sys_clk or negedge rst_n) 26 if(!rst_n) begin 27 ps2_clk_in_1 <= 1'b1; 28 ps2_clk_in_2 <= 1'b1; 29 end 30 else begin 31 ps2_clk_in_1 <= ps2_clk_in; 32 ps2_clk_in_2 <= ps2_clk_in_1; 33 end 34 35 assign ps2_clk_in_n = ps2_clk_in_2 & (~ps2_clk_in_1); 36 /**************************************************************/ 37 reg [3:0] i; 38 reg [7:0] data_buf; 39 reg rx_done_sig; 40 always @(posedge sys_clk or negedge rst_n) 41 if(!rst_n) begin 42 i <= 4'd0; 43 data_buf <= 8'h00; 44 rx_done_sig <= 1'b0; 45 end 46 else if(rx_en/*ps2_clk_in_n*/) begin //ps2_clk_in_n不能写在这个地方,rx_done_sig置1和置0没必要等到ps2_clk_in下降沿时设置,否则会出问题 47 case(i) 48 4'd0: 49 if(ps2_clk_in_n) begin 50 i <= i + 1'b1; //起始位不处理 51 end 52 4'd1,4'd2,4'd3,4'd4,4'd5,4'd6,4'd7,4'd8: //接收8位数据 53 if(ps2_clk_in_n) begin 54 i <= i + 1'b1; 55 data_buf[i-1] <= ps2_data_in; 56 end 57 58 4'd9: 59 if(ps2_clk_in_n) 60 i <= i + 1'b1; //奇校验位不处理 61 62 4'd10: 63 if(ps2_clk_in_n) 64 i <= i + 1'b1; //停止位不处理 65 66 4'd11: 67 begin 68 rx_done_sig <= 1'b1; //标志着一帧数据接收完 69 i <= i + 1'b1; 70 end 71 72 4'd12: 73 begin 74 rx_done_sig <= 1'b0; //置0,给下次接收做好准备 75 i <= 4'd0; 76 end 77 endcase 78 end 79 80 endmodule 81 82
LCD12864.v

1 module LCD12864( 2 //input 3 sys_clk, 4 rst_n, 5 dis_data_low1, 6 dis_data_hig1, 7 8 dis_data_low2, 9 dis_data_hig2, 10 11 dis_data_low3, 12 dis_data_hig3, 13 14 dis_data_low4, 15 dis_data_hig4, 16 17 dis_data_btn, 18 19 //output 20 lcd_rs, 21 lcd_rw, 22 lcd_en, 23 lcd_data, 24 lcd_psb 25 ); 26 input sys_clk;// 50MHZ 27 input rst_n; 28 input [7:0] dis_data_low1; 29 input [7:0] dis_data_hig1; 30 input [7:0] dis_data_low2; 31 input [7:0] dis_data_hig2; 32 input [7:0] dis_data_low3; 33 input [7:0] dis_data_hig3; 34 input [7:0] dis_data_low4; 35 input [7:0] dis_data_hig4; 36 37 input [7:0] dis_data_btn; 38 39 output lcd_rs;//H:data L:command 40 output lcd_rw;//H:read module L:write module 41 output lcd_en;//H active 42 output [7:0] lcd_data; 43 output lcd_psb;//H:parallel module L:SPI module 44 45 /***************************************************/ 46 parameter T3MS = 18'd149_999; 47 parameter IDLE = 5'd0, 48 INIT_FUN_SET1 = 5'd1, 49 INIT_FUN_SET2 = 5'd2, 50 INIT_DISPLAY = 5'd3, 51 INIT_CLEAR = 5'd4, 52 INIT_DOT_SET = 5'd5, 53 SET_DDRAM = 5'd6, 54 WRITE_DATA0 = 5'd7, 55 WRITE_DATA1 = 5'd8, 56 WRITE_DATA2 = 5'd9, 57 WRITE_BLANK1 = 5'd10, 58 WRITE_DATA3 = 5'd11, 59 WRITE_DATA4 = 5'd12, 60 WRITE_BLANK2 = 5'd13, 61 WRITE_DATA5 = 5'd14, 62 WRITE_DATA6 = 5'd15, 63 SET_DDRAM1 = 5'd16, 64 WRITE_DATA7 = 5'd17, 65 WRITE_DATA8 = 5'd18, 66 WRITE_DATA9 = 5'd19, 67 SET_DDRAM2 = 5'd20, 68 WRITE_DATA10 = 5'd21, 69 WRITE_DATA11 = 5'd22; 70 71 /***************************************************/ 72 //产生周期为6MS的lcd_clk给LCD 73 reg [17:0] cnt; 74 reg lcd_clk; 75 always @(posedge sys_clk or negedge rst_n) 76 if(!rst_n) begin 77 cnt <= 18'd0; 78 lcd_clk <= 1'b0; 79 end 80 else if(cnt == T3MS)begin 81 cnt <= 18'd0; 82 lcd_clk <= ~lcd_clk; 83 end 84 else 85 cnt <= cnt + 1'b1; 86 87 /***************************************************/ 88 reg lcd_rs; 89 always @(posedge lcd_clk or negedge rst_n) 90 if(!rst_n) 91 lcd_rs <= 1'b0; 92 else if( (state == WRITE_DATA1) || (state == WRITE_DATA2) 93 || (state == WRITE_DATA3) || (state == WRITE_DATA4) 94 || (state == WRITE_DATA5) || (state == WRITE_DATA6) 95 || (state == WRITE_DATA7) || (state == WRITE_DATA8) 96 || (state == WRITE_DATA9) || (state == WRITE_DATA10) 97 || (state == WRITE_DATA11) || (state == WRITE_DATA0) 98 ||(state == WRITE_BLANK1) || (state == WRITE_BLANK2)) 99 lcd_rs <= 1'b1; //写数据模式 100 else 101 lcd_rs <= 1'b0; //写命令模式 102 /***************************************************/ 103 reg [4:0] state; 104 reg [7:0] lcd_data; 105 reg [6:0] num; 106 reg en; 107 always @(posedge lcd_clk or negedge rst_n) 108 if(!rst_n) begin 109 state <= IDLE; 110 lcd_data <= 8'h00; 111 en <= 1'b1; 112 num <= 6'd0; 113 end 114 else 115 case(state) 116 IDLE: 117 begin 118 state <= INIT_FUN_SET1; 119 lcd_data <= 8'hzz; 120 en <= 1'b1; 121 end 122 123 INIT_FUN_SET1: 124 begin 125 lcd_data <= 8'h30; //功能设定 126 state <= INIT_FUN_SET2; 127 end 128 129 INIT_FUN_SET2: 130 begin 131 lcd_data <= 8'h30; //功能设定 132 state <= INIT_DISPLAY; 133 end 134 135 INIT_DISPLAY: 136 begin 137 lcd_data <= 8'h0c; //显示设定 138 state <= INIT_CLEAR; 139 end 140 141 INIT_CLEAR: 142 begin 143 lcd_data <= 8'h01; //清屏 144 state <= INIT_DOT_SET; 145 end 146 147 INIT_DOT_SET: 148 begin 149 lcd_data <= 8'h06; //进入点设定 150 state <= SET_DDRAM; 151 end 152 153 SET_DDRAM: 154 begin 155 lcd_data <= 8'h90;//2 line 156 state <= WRITE_DATA0; 157 end 158 159 WRITE_DATA0: ////ff应答:: 160 begin 161 if(num == 7'd7) 162 state <= WRITE_DATA1; 163 else begin 164 num <= num + 1'b1; 165 lcd_data <= dis_data; 166 state <= WRITE_DATA0; 167 end 168 end 169 170 WRITE_DATA1: //回应的第一个数据高字节 171 begin 172 lcd_data <= dis_data_hig1; 173 state <= WRITE_DATA2; 174 end 175 176 WRITE_DATA2://回应的第一个数据低字节 177 begin 178 lcd_data <= dis_data_low1; 179 state <= WRITE_BLANK1; 180 end 181 182 WRITE_BLANK1: //写一个空格 183 begin 184 lcd_data <= " "; 185 state <= WRITE_DATA3; 186 end 187 188 WRITE_DATA3: //回应的第二个数据高字节 189 begin 190 lcd_data <= dis_data_hig2; 191 state <= WRITE_DATA4; 192 end 193 194 WRITE_DATA4://回应的第二个数据低字节 195 begin 196 lcd_data <= dis_data_low2; 197 state <= WRITE_BLANK2; 198 end 199 200 WRITE_BLANK2: //写一个空格 201 begin 202 lcd_data <= " "; 203 state <= WRITE_DATA5; 204 end 205 206 WRITE_DATA5: //回应的第三个数据高字节 207 begin 208 lcd_data <= dis_data_hig3; 209 state <= WRITE_DATA6; 210 end 211 212 WRITE_DATA6://回应的第三个数据低字节 213 begin 214 lcd_data <= dis_data_low3; 215 state <= SET_DDRAM1; 216 end 217 218 SET_DDRAM1: 219 begin 220 lcd_data <= 8'h88;//3 line 221 state <= WRITE_DATA7; 222 end 223 224 WRITE_DATA7: //f4应答 225 begin 226 if(num == 7'd14) begin 227 state <= WRITE_DATA8; 228 end 229 else begin 230 num <= num + 1'b1; 231 lcd_data <= dis_data; 232 state <= WRITE_DATA7; 233 end 234 end 235 236 //// 237 WRITE_DATA8: //第二次回应的高字节 238 begin 239 lcd_data <= dis_data_hig4; 240 state <= WRITE_DATA9; 241 end 242 243 WRITE_DATA9://第二次回应的低字节 244 begin 245 lcd_data <= dis_data_low4; 246 state <= SET_DDRAM2; 247 end 248 249 SET_DDRAM2: 250 begin 251 lcd_data <= 8'h98;//4 line 252 state <= WRITE_DATA10; 253 end 254 255 WRITE_DATA10: 256 begin 257 if(num == 7'd19) begin 258 num <= 7'd0; 259 state <= WRITE_DATA11; 260 end 261 else begin 262 num <= num + 1'b1; 263 lcd_data <= dis_data; 264 state <= WRITE_DATA10; 265 end 266 end 267 268 WRITE_DATA11: 269 begin 270 lcd_data <= dis_data_btn; 271 state <= SET_DDRAM; 272 end 273 /* STOP: 274 begin 275 en <= 1'b0;//显示完了,lcd_e就一直拉为低 276 state <= STOP; 277 end */ 278 279 default: state <= IDLE; 280 endcase 281 282 reg [7:0] dis_data; 283 always @(posedge sys_clk or negedge rst_n) 284 if(!rst_n) 285 dis_data <= 8'hzz; 286 else 287 case(num) 288 //ff应答: 289 7'd0 : dis_data <= "f";//8'h66; 290 7'd1 : dis_data <= "f";//8'h66; 291 7'd2 : dis_data <= 8'hd3; 292 7'd3 : dis_data <= 8'ha6; 293 7'd4 : dis_data <= 8'hb4; 294 7'd5 : dis_data <= 8'hf0; 295 7'd6 : dis_data <= " "; 296 //f4应答: 297 7'd7 : dis_data <= "f"; 298 7'd8 : dis_data <= "4"; 299 7'd9 : dis_data <= 8'hd3; 300 7'd10 : dis_data <= 8'ha6; 301 7'd11 : dis_data <= 8'hb4; 302 7'd12 : dis_data <= 8'hf0; 303 7'd13 : dis_data <= " "; 304 //按键: 305 7'd14 : dis_data <= 8'hb0; 306 7'd15 : dis_data <= 8'hb4; 307 7'd16 : dis_data <= 8'hbc; 308 7'd17 : dis_data <= 8'hfc; 309 7'd18 : dis_data <= " "; 310 default: dis_data <= 8'h00; 311 endcase 312 /***************************************************/ 313 assign lcd_rw = 1'b0;//只有写模式 314 assign lcd_psb = 1'b1;//并口模式 315 assign lcd_en = en ? lcd_clk : 1'b0; 316 /***************************************************/ 317 endmodule
ps2_mouse_top.v

1 module ps2_mouse_top( 2 //input 3 sys_clk, 4 rst_n, 5 6 //inout 7 ps2_clk, 8 ps2_data, 9 10 //output 11 lcd_rs, 12 lcd_rw, 13 lcd_en, 14 lcd_data, 15 // lcd_psb 16 ); 17 18 19 input sys_clk; 20 input rst_n; 21 22 inout ps2_clk; 23 inout ps2_data; 24 25 output lcd_rs;//H:data L:command 26 output lcd_rw;//H:read module L:write module 27 output lcd_en;//H active 28 output [7:0] lcd_data; 29 //output lcd_psb;//H:parallel module L:SPI module 30 31 wire send_done_sig; 32 wire rx_done_sig; 33 wire [7:0] data_buf; 34 wire rx_en; 35 wire send_en; 36 wire [7:0] send_cmd; 37 wire [7:0] dis_data_low1; 38 wire [7:0] dis_data_hig1; 39 wire [7:0] dis_data_low2; 40 wire [7:0] dis_data_hig2; 41 wire [7:0] dis_data_low3; 42 wire [7:0] dis_data_hig3; 43 wire [7:0] dis_data_low4; 44 wire [7:0] dis_data_hig4; 45 wire [7:0] dis_data_btn; 46 //控制模块例化 47 ps2_data_control u1_control( 48 //input 49 .sys_clk(sys_clk), 50 .rst_n(rst_n), 51 .send_done_sig(send_done_sig), //发送完标志 52 .rx_done_sig(rx_done_sig), //接收完标志 53 .data_buf(data_buf), //接收到的数据 54 55 //output 56 .rx_en(rx_en), //接收使能 57 .send_en(send_en), //发送使能 58 .send_cmd(send_cmd), //要发送的命令 59 .dis_data_low1(dis_data_low1), //要显示的数据 60 .dis_data_hig1(dis_data_hig1), 61 62 .dis_data_low2(dis_data_low2), //要显示的数据 63 .dis_data_hig2(dis_data_hig2), 64 65 .dis_data_low3(dis_data_low3), //要显示的数据 66 .dis_data_hig3(dis_data_hig3), 67 68 .dis_data_low4(dis_data_low4), //要显示的数据 69 .dis_data_hig4(dis_data_hig4), 70 71 .dis_data_btn(dis_data_btn) 72 ); 73 //显示模块例化 74 LCD12864 u2_lcd( 75 //input 76 .sys_clk(sys_clk), 77 .rst_n(rst_n), 78 .dis_data_low1(dis_data_low1), //要显示的数据 79 .dis_data_hig1(dis_data_hig1), 80 81 .dis_data_low2(dis_data_low2), //要显示的数据 82 .dis_data_hig2(dis_data_hig2), 83 84 .dis_data_low3(dis_data_low3), //要显示的数据 85 .dis_data_hig3(dis_data_hig3), 86 87 .dis_data_low4(dis_data_low4), //要显示的数据 88 .dis_data_hig4(dis_data_hig4), 89 90 .dis_data_btn(dis_data_btn), 91 92 //output 93 .lcd_rs(lcd_rs), 94 .lcd_rw(lcd_rw), 95 .lcd_en(lcd_en), 96 .lcd_data(lcd_data), 97 // .lcd_psb(lcd_psb) 98 ); 99 //发送模块例化 100 ps2_send_control u3_send( 101 //input 102 .sys_clk(sys_clk), 103 .rst_n(rst_n), 104 .send_en(send_en), //发送使能 105 .send_cmd(send_cmd), //要发送的命令 0xf4 106 107 //output 108 .send_done_sig(send_done_sig),//发送完标志 109 110 //inout 111 .ps2_clk(ps2_clk), //鼠标时钟 112 .ps2_data(ps2_data) //鼠标数据 113 ); 114 //接收模块例化 115 ps2_rx_control u4_rx( 116 //input 117 .sys_clk(sys_clk), 118 .rst_n(rst_n), 119 .ps2_clk_in(ps2_clk), //鼠标时钟 120 .ps2_data_in(ps2_data), //鼠标数据 121 .rx_en(rx_en), //接收模块使能信号 122 123 //output 124 .rx_done_sig(rx_done_sig), //接收完标志信号 125 .data_buf(data_buf) //保存接收到的数据 126 ); 127 endmodule
现象1、发送0xff命令给鼠标时,PS/2 技术参考上有写,发送此命令进入复位模式,鼠标并会给主机三个数据0xfa、0xaa、0x00(ID)作为回应,如下图,显示是正确的,那说明传送和接收应该没错,但在发送0xf4命令,按道理接收到回应数据应该是0xfa,而这里没有收到数据:
现象2、若直接先发送0xf4命令时,接收到回应的数据是0xfe,按复位又变为0xfc,在按一次又变为0xfe,反复按复位,一直在这两数据变动,查PS/2 技术参考资料,说是校验位出错或是干扰造成,换了两个板子都是这样,换了鼠标也是这样。如下图:
以上两个现象让我彻底的无语了,估计我现在的思维已定死了,无法想到其他方法去调试,想写个仿真嘛,又觉得比较棘手,毕竟要模拟一个鼠标还是有费点功夫,哎。。
按键 后面本来是要显示 左(L)右(R)中(M)几个字母,若没有接收到数据,显示默认值X。