抱着“不气馁、不放弃、誓不罢休、搞不定你我还能搞其他玩意吗”的心态,调试许久的PS2鼠标实验,终于在今天被我搞定了。发几张图显摆一下,嘿嘿。。。
左键按下+鼠标移动
右键按下+鼠标移动
中键按下+鼠标移动
一、程序框架:
大概情况:
1、先由控制模块启动发送模块,把指令0xff发送给鼠标,进入复位模式。
2、发送完后,通知控制模块启动接收模块,接收鼠标应答数据fa、aa、00。
3、接收完后,在次给鼠标发送0xf4,鼠标进入待发数据状态。
4、发送完后,启动接收模块,接收鼠标应答数据fa。
5、回复的数据都OK后,就让程序进入一直处于接收数据状态,每当鼠标按下一次或移动,鼠标都会发送三个字节的数据,提取数据进行解析让在LCD实时显示。
二、鼠标和键盘不管是向鼠标发送数据还是接收数据,都有特定的格式,每一组数据都是一个起始位、8位有效数据、一个校验位、一个停止位。
三、主机到设备时序图:这里注意停止位发送完后,鼠标会在产生一个时钟,并向主机发送一个应答位,在时钟为高时,数据线是从高到底变化的,有点像主机接收设备发送过来的起始信号,伪起始信号,如果这步没处理好,启动接收模块时就会认为此时是一个起始信号,结果接收到的数据把真正起始信号“0”给处理了,我当时就在这里犯错了。主机在发送数据时,是在时钟的下降沿改变数据。
发送模块流程:(ps2_clk 和ps2_data 都定义双向端口)
1、拉低时钟,至少要保持100us,程序中设置的是200us,这个时间不是越大约好,从主机拉低时钟到设备真正产生时钟时时间不能大于15MS。
2、200us后,拉低数据线,给鼠标发送请求状态。
3、释放时钟线,link_clk设置为0,让FPGA把该ps2_clk管脚置为高阻态,在高阻态时,该管脚可以接收高低电平,也就成了输入管脚。若设置为1,那么就成了输出管脚。
assign ps2_clk = link_clk ? ps2_clk_out : 1'bz;
4、在时钟的下降沿开始发送数据,8bit数据、一位校验位、一位停止位。
5、释放数据线,鼠标发送应答位,link_data设置为0,原理同link_clk。
assign ps2_data = link_data ? ps2_data_out : 1'bz;
6、等到最后一个时钟产生完,发送完标志产生send_done_sig = 1'b1;
7、马上又进入send_done_sig清零状态,为了下次在送数据做好准备。
注意:释放时钟或释放数据一定要在准确位置释放。
四、设备到主机时序图:
时序比较简单,属于单向通信,设备发,主机只接收。程序中起始位、奇偶校验、停止位都不作处理。这个就不多讲。由于接收模块只作为接收,所以ps2_clk 和ps2_data 都定输入端口。
五、发送、接收和显示都处于待命状态后,由控制模块来协调工作,到这里,对整个控制流程应该很清楚了吧。
代码实现:(由于把所有接收到数据都显示到LCD上,所以有些地方代码写的比较繁琐,暂时先这样吧)
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_x_low, 26 dis_x_hig, 27 28 dis_y_low, 29 dis_y_hig, 30 31 dis_data_btn 32 ); 33 input sys_clk; 34 input rst_n; 35 input send_done_sig; 36 input rx_done_sig; 37 input [7:0] data_buf; 38 39 output rx_en; 40 output send_en; 41 output [7:0] send_cmd; 42 output [7:0] dis_data_low1; 43 output [7:0] dis_data_hig1; 44 output [7:0] dis_data_low2; 45 output [7:0] dis_data_hig2; 46 output [7:0] dis_data_low3; 47 output [7:0] dis_data_hig3; 48 output [7:0] dis_data_low4; 49 output [7:0] dis_data_hig4; 50 output [7:0] dis_data_btn; 51 output [7:0] dis_x_low; 52 output [7:0] dis_x_hig; 53 output [7:0] dis_y_low; 54 output [7:0] dis_y_hig; 55 /**********************************************************************/ 56 parameter T100MS = 23'd4_999_999; 57 parameter PS2_RST = 8'hff; //复位cmd 58 parameter PS2_EN = 8'hf4; //数据报告使能cmd 59 parameter IDLE = 4'd0, 60 SEND_PS2_RST = 4'd1, 61 RX_EN1 = 4'd2, 62 RX_ANSWER_FA = 4'd3, 63 RX_ANSWER_AA = 4'd4, 64 RX_ANSWER_ID = 4'd5, 65 SEND_PS2_EN = 4'd6, 66 RX_EN2 = 4'd7, 67 RX_ANSWER2 = 4'd8, 68 RX_BYTE1 = 4'd9, 69 RX_BYTE2 = 4'd10, 70 RX_BYTE3 = 4'd11, 71 DELAY = 4'd12, 72 STOP = 4'd13; 73 /**********************************************************************/ 74 reg [22:0] cnt; 75 always @(posedge sys_clk or negedge rst_n) 76 if(!rst_n) 77 cnt <= 23'd0; 78 else if(!cnt_en || cnt == T100MS) 79 cnt <= 23'd0; 80 else 81 cnt <= cnt + 1'b1; 82 /**********************************************************************/ 83 reg send_en; 84 reg rx_en; 85 reg [7:0] data_answer; //保存应答位 86 reg [7:0] x_move; //x的偏移量 87 reg [7:0] y_move; //y的偏移量 88 reg [3:0] state; 89 reg [7:0] dis_data_temp1; 90 reg [7:0] dis_data_temp2; 91 reg [7:0] dis_data_temp3; 92 reg [7:0] dis_data_temp4; 93 reg [7:0] dis_data_btn; 94 reg cnt_en; 95 reg [7:0] send_cmd; 96 always @(posedge sys_clk or negedge rst_n) 97 if(!rst_n) begin 98 send_en <= 1'b0; 99 rx_en <= 1'b0; 100 data_answer <= 8'h00; 101 state <= IDLE; 102 dis_data_temp1 <= 8'h00; 103 dis_data_temp2 <= 8'h00; 104 dis_data_temp3 <= 8'h00; 105 dis_data_temp4 <= 8'h00; 106 cnt_en <= 1'b0; 107 dis_data_btn <= "X"; 108 send_cmd <= 8'h00; 109 end 110 else begin 111 case(state) 112 IDLE: 113 begin 114 state <= SEND_PS2_RST; 115 cnt_en <= 1'b1; 116 end 117 118 SEND_PS2_RST: //发送复位 0xff 119 if(cnt == T100MS) begin 120 cnt_en <= 1'b0; 121 send_en <= 1'b1; //启动发送 122 send_cmd <= PS2_RST; 123 state <= RX_EN1;//RX_EN1; 124 end 125 else 126 state <= SEND_PS2_RST; 127 128 RX_EN1: 129 if(send_done_sig) begin 130 rx_en <= 1'b1; 131 send_en <= 1'b0; 132 state <= RX_ANSWER_FA; 133 end 134 else 135 state <= RX_EN1; 136 137 RX_ANSWER_FA: //接收鼠标发回的应答数据0xfa 138 if(rx_done_sig) begin 139 dis_data_temp1 <= data_buf; 140 state <= RX_ANSWER_AA;//RX_BYTE1; 141 end 142 else 143 state <= RX_ANSWER_FA; 144 145 RX_ANSWER_AA: //接收鼠标发回的应答数据0xaa 146 if(rx_done_sig) begin 147 dis_data_temp2 <= data_buf; 148 state <= RX_ANSWER_ID; 149 end 150 else 151 state <= RX_ANSWER_AA; 152 153 RX_ANSWER_ID: //接收鼠标发回的应答数据0x00 154 if(rx_done_sig) begin 155 dis_data_temp3 <= data_buf; 156 cnt_en <= 1'b1; 157 rx_en <= 1'b0; 158 state <= SEND_PS2_EN; 159 end 160 else 161 state <= RX_ANSWER_ID; 162 163 SEND_PS2_EN: //发送0xf4 164 if(cnt == T100MS)begin 165 cnt_en <= 1'b0; 166 send_en <= 1'b1; //启动发送 167 send_cmd <= PS2_EN; 168 state <= RX_EN2; 169 end 170 else 171 state <= SEND_PS2_EN; 172 173 RX_EN2: 174 if(send_done_sig) begin 175 rx_en <= 1'b1; //启动接收 176 send_en <= 1'b0; 177 state <= RX_ANSWER2; 178 end 179 else 180 state <= RX_EN2; 181 182 RX_ANSWER2: //第二次应答位 183 if(rx_done_sig) begin 184 dis_data_temp4 <= data_buf; 185 state <= RX_BYTE1; 186 end 187 else 188 state <= RX_ANSWER2; 189 190 RX_BYTE1: 191 if(rx_done_sig) begin 192 if(data_buf[0] == 1'b1)//左键被按下 193 dis_data_btn <= "L"; 194 else if(data_buf[1] == 1'b1) //右键被按下 195 dis_data_btn <= "R"; 196 else if(data_buf[2] == 1'b1) //中键被按下 197 dis_data_btn <= "M"; 198 199 state <= RX_BYTE2; 200 end 201 else 202 state <= RX_BYTE1; 203 204 RX_BYTE2: 205 if(rx_done_sig) begin //接收到第二个字节 206 x_move <= data_buf; 207 state <= RX_BYTE3; 208 end 209 else 210 state <= RX_BYTE2; 211 212 RX_BYTE3: //接收到第三个字节 213 if(rx_done_sig) begin 214 y_move <= data_buf; 215 state <= STOP; 216 cnt_en <= 1'b1; 217 end 218 else 219 state <= RX_BYTE3; 220 221 STOP: 222 if(cnt == T100MS) 223 begin 224 cnt_en <= 1'b0; 225 state <= RX_BYTE1; 226 end 227 else 228 state <= STOP; 229 230 endcase 231 end 232 233 reg [7:0] dis_data_low1; 234 always @(dis_data_temp1[3:0]) 235 case(dis_data_temp1[3:0]) 236 4'h0: dis_data_low1 = "0"; 237 4'h1: dis_data_low1 = "1"; 238 4'h2: dis_data_low1 = "2"; 239 4'h3: dis_data_low1 = "3"; 240 4'h4: dis_data_low1 = "4"; 241 4'h5: dis_data_low1 = "5"; 242 4'h6: dis_data_low1 = "6"; 243 4'h7: dis_data_low1 = "7"; 244 4'h8: dis_data_low1 = "8"; 245 4'h9: dis_data_low1 = "9"; 246 4'ha: dis_data_low1 = "a"; 247 4'hb: dis_data_low1 = "b"; 248 4'hc: dis_data_low1 = "c"; 249 4'hd: dis_data_low1 = "d"; 250 4'he: dis_data_low1 = "e"; 251 4'hf: dis_data_low1 = "f"; 252 endcase 253 254 reg [7:0] dis_data_hig1; 255 always @(dis_data_temp1[7:4]) 256 case(dis_data_temp1[7:4]) 257 4'h0: dis_data_hig1 = "0"; 258 4'h1: dis_data_hig1 = "1"; 259 4'h2: dis_data_hig1 = "2"; 260 4'h3: dis_data_hig1 = "3"; 261 4'h4: dis_data_hig1 = "4"; 262 4'h5: dis_data_hig1 = "5"; 263 4'h6: dis_data_hig1 = "6"; 264 4'h7: dis_data_hig1 = "7"; 265 4'h8: dis_data_hig1 = "8"; 266 4'h9: dis_data_hig1 = "9"; 267 4'ha: dis_data_hig1 = "a"; 268 4'hb: dis_data_hig1 = "b"; 269 4'hc: dis_data_hig1 = "c"; 270 4'hd: dis_data_hig1 = "d"; 271 4'he: dis_data_hig1 = "e"; 272 4'hf: dis_data_hig1 = "f"; 273 endcase 274 275 reg [7:0] dis_data_low2; 276 always @(dis_data_temp2[3:0]) 277 case(dis_data_temp2[3:0]) 278 4'h0: dis_data_low2 = "0"; 279 4'h1: dis_data_low2 = "1"; 280 4'h2: dis_data_low2 = "2"; 281 4'h3: dis_data_low2 = "3"; 282 4'h4: dis_data_low2 = "4"; 283 4'h5: dis_data_low2 = "5"; 284 4'h6: dis_data_low2 = "6"; 285 4'h7: dis_data_low2 = "7"; 286 4'h8: dis_data_low2 = "8"; 287 4'h9: dis_data_low2 = "9"; 288 4'ha: dis_data_low2 = "a"; 289 4'hb: dis_data_low2 = "b"; 290 4'hc: dis_data_low2 = "c"; 291 4'hd: dis_data_low2 = "d"; 292 4'he: dis_data_low2 = "e"; 293 4'hf: dis_data_low2 = "f"; 294 endcase 295 296 reg [7:0] dis_data_hig2; 297 always @(dis_data_temp2[7:4]) 298 case(dis_data_temp2[7:4]) 299 4'h0: dis_data_hig2 = "0"; 300 4'h1: dis_data_hig2 = "1"; 301 4'h2: dis_data_hig2 = "2"; 302 4'h3: dis_data_hig2 = "3"; 303 4'h4: dis_data_hig2 = "4"; 304 4'h5: dis_data_hig2 = "5"; 305 4'h6: dis_data_hig2 = "6"; 306 4'h7: dis_data_hig2 = "7"; 307 4'h8: dis_data_hig2 = "8"; 308 4'h9: dis_data_hig2 = "9"; 309 4'ha: dis_data_hig2 = "a"; 310 4'hb: dis_data_hig2 = "b"; 311 4'hc: dis_data_hig2 = "c"; 312 4'hd: dis_data_hig2 = "d"; 313 4'he: dis_data_hig2 = "e"; 314 4'hf: dis_data_hig2 = "f"; 315 endcase 316 317 reg [7:0] dis_data_low3; 318 always @(dis_data_temp3[3:0]) 319 case(dis_data_temp3[3:0]) 320 4'h0: dis_data_low3 = "0"; 321 4'h1: dis_data_low3 = "1"; 322 4'h2: dis_data_low3 = "2"; 323 4'h3: dis_data_low3 = "3"; 324 4'h4: dis_data_low3 = "4"; 325 4'h5: dis_data_low3 = "5"; 326 4'h6: dis_data_low3 = "6"; 327 4'h7: dis_data_low3 = "7"; 328 4'h8: dis_data_low3 = "8"; 329 4'h9: dis_data_low3 = "9"; 330 4'ha: dis_data_low3 = "a"; 331 4'hb: dis_data_low3 = "b"; 332 4'hc: dis_data_low3 = "c"; 333 4'hd: dis_data_low3 = "d"; 334 4'he: dis_data_low3 = "e"; 335 4'hf: dis_data_low3 = "f"; 336 endcase 337 338 reg [7:0] dis_data_hig3; 339 always @(dis_data_temp3[7:4]) 340 case(dis_data_temp3[7:4]) 341 4'h0: dis_data_hig3 = "0"; 342 4'h1: dis_data_hig3 = "1"; 343 4'h2: dis_data_hig3 = "2"; 344 4'h3: dis_data_hig3 = "3"; 345 4'h4: dis_data_hig3 = "4"; 346 4'h5: dis_data_hig3 = "5"; 347 4'h6: dis_data_hig3 = "6"; 348 4'h7: dis_data_hig3 = "7"; 349 4'h8: dis_data_hig3 = "8"; 350 4'h9: dis_data_hig3 = "9"; 351 4'ha: dis_data_hig3 = "a"; 352 4'hb: dis_data_hig3 = "b"; 353 4'hc: dis_data_hig3 = "c"; 354 4'hd: dis_data_hig3 = "d"; 355 4'he: dis_data_hig3 = "e"; 356 4'hf: dis_data_hig3 = "f"; 357 endcase 358 359 reg [7:0] dis_data_low4; 360 always @(dis_data_temp4[3:0]) 361 case(dis_data_temp4[3:0]) 362 4'h0: dis_data_low4 = "0"; 363 4'h1: dis_data_low4 = "1"; 364 4'h2: dis_data_low4 = "2"; 365 4'h3: dis_data_low4 = "3"; 366 4'h4: dis_data_low4 = "4"; 367 4'h5: dis_data_low4 = "5"; 368 4'h6: dis_data_low4 = "6"; 369 4'h7: dis_data_low4 = "7"; 370 4'h8: dis_data_low4 = "8"; 371 4'h9: dis_data_low4 = "9"; 372 4'ha: dis_data_low4 = "a"; 373 4'hb: dis_data_low4 = "b"; 374 4'hc: dis_data_low4 = "c"; 375 4'hd: dis_data_low4 = "d"; 376 4'he: dis_data_low4 = "e"; 377 4'hf: dis_data_low4 = "f"; 378 endcase 379 380 reg [7:0] dis_data_hig4; 381 always @(dis_data_temp4[7:4]) 382 case(dis_data_temp4[7:4]) 383 4'h0: dis_data_hig4 = "0"; 384 4'h1: dis_data_hig4 = "1"; 385 4'h2: dis_data_hig4 = "2"; 386 4'h3: dis_data_hig4 = "3"; 387 4'h4: dis_data_hig4 = "4"; 388 4'h5: dis_data_hig4 = "5"; 389 4'h6: dis_data_hig4 = "6"; 390 4'h7: dis_data_hig4 = "7"; 391 4'h8: dis_data_hig4 = "8"; 392 4'h9: dis_data_hig4 = "9"; 393 4'ha: dis_data_hig4 = "a"; 394 4'hb: dis_data_hig4 = "b"; 395 4'hc: dis_data_hig4 = "c"; 396 4'hd: dis_data_hig4 = "d"; 397 4'he: dis_data_hig4 = "e"; 398 4'hf: dis_data_hig4 = "f"; 399 endcase 400 //move x 401 reg [7:0] dis_x_low; 402 always @(x_move[3:0]) 403 case(x_move[3:0]) 404 4'h0: dis_x_low = "0"; 405 4'h1: dis_x_low = "1"; 406 4'h2: dis_x_low = "2"; 407 4'h3: dis_x_low = "3"; 408 4'h4: dis_x_low = "4"; 409 4'h5: dis_x_low = "5"; 410 4'h6: dis_x_low = "6"; 411 4'h7: dis_x_low = "7"; 412 4'h8: dis_x_low = "8"; 413 4'h9: dis_x_low = "9"; 414 4'ha: dis_x_low = "a"; 415 4'hb: dis_x_low = "b"; 416 4'hc: dis_x_low = "c"; 417 4'hd: dis_x_low = "d"; 418 4'he: dis_x_low = "e"; 419 4'hf: dis_x_low = "f"; 420 endcase 421 422 reg [7:0] dis_x_hig; 423 always @(x_move[7:4]) 424 case(x_move[7:4]) 425 4'h0: dis_x_hig = "0"; 426 4'h1: dis_x_hig = "1"; 427 4'h2: dis_x_hig = "2"; 428 4'h3: dis_x_hig = "3"; 429 4'h4: dis_x_hig = "4"; 430 4'h5: dis_x_hig = "5"; 431 4'h6: dis_x_hig = "6"; 432 4'h7: dis_x_hig = "7"; 433 4'h8: dis_x_hig = "8"; 434 4'h9: dis_x_hig = "9"; 435 4'ha: dis_x_hig = "a"; 436 4'hb: dis_x_hig = "b"; 437 4'hc: dis_x_hig = "c"; 438 4'hd: dis_x_hig = "d"; 439 4'he: dis_x_hig = "e"; 440 4'hf: dis_x_hig = "f"; 441 endcase 442 //move y 443 reg [7:0] dis_y_low; 444 always @(y_move[3:0]) 445 case(y_move[3:0]) 446 4'h0: dis_y_low = "0"; 447 4'h1: dis_y_low = "1"; 448 4'h2: dis_y_low = "2"; 449 4'h3: dis_y_low = "3"; 450 4'h4: dis_y_low = "4"; 451 4'h5: dis_y_low = "5"; 452 4'h6: dis_y_low = "6"; 453 4'h7: dis_y_low = "7"; 454 4'h8: dis_y_low = "8"; 455 4'h9: dis_y_low = "9"; 456 4'ha: dis_y_low = "a"; 457 4'hb: dis_y_low = "b"; 458 4'hc: dis_y_low = "c"; 459 4'hd: dis_y_low = "d"; 460 4'he: dis_y_low = "e"; 461 4'hf: dis_y_low = "f"; 462 endcase 463 464 reg [7:0] dis_y_hig; 465 always @(y_move[7:4]) 466 case(y_move[7:4]) 467 4'h0: dis_y_hig = "0"; 468 4'h1: dis_y_hig = "1"; 469 4'h2: dis_y_hig = "2"; 470 4'h3: dis_y_hig = "3"; 471 4'h4: dis_y_hig = "4"; 472 4'h5: dis_y_hig = "5"; 473 4'h6: dis_y_hig = "6"; 474 4'h7: dis_y_hig = "7"; 475 4'h8: dis_y_hig = "8"; 476 4'h9: dis_y_hig = "9"; 477 4'ha: dis_y_hig = "a"; 478 4'hb: dis_y_hig = "b"; 479 4'hc: dis_y_hig = "c"; 480 4'hd: dis_y_hig = "d"; 481 4'he: dis_y_hig = "e"; 482 4'hf: dis_y_hig = "f"; 483 endcase 484 endmodule 485
View Code
ps2_send_control.v
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 IDLE = 3'd0, 28 PS2_CLK_SET0 = 3'd1, //时钟拉低 29 PS2_DATA_SET0 = 3'd2, //数据拉低 30 PS2_CLK_SET1 = 3'd3, //释放时钟,拉高 31 SEND_DATA = 3'd4, //发送8bit数据和校验位 32 ACK = 3'd5, //释放数据,拉高 33 STOP = 3'd6, 34 CLEAR = 3'd7; 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_n_1; 60 reg ps2_clk_n_2; 61 always @(posedge sys_clk or negedge rst_n) 62 if(!rst_n) begin 63 ps2_clk_n_1 <= 1'b1; 64 ps2_clk_n_2 <= 1'b1; 65 end 66 else begin 67 ps2_clk_n_1 <= ps2_clk; 68 ps2_clk_n_2 <= ps2_clk_n_1; 69 end 70 71 wire ps2_clk_n; 72 assign ps2_clk_n = ps2_clk_n_2 & (~ps2_clk_n_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 else 119 state <= PS2_DATA_SET0; 120 121 PS2_CLK_SET1: //释放时钟线 122 begin 123 link_clk <= 1'b0; //输入状态 124 ps2_clk_out <= 1'b1; 125 state <= SEND_DATA; 126 end 127 128 SEND_DATA: 129 if(ps2_clk_n) begin //在时钟的下降沿设置数据 130 if(i == 4'd9) begin 131 i <= 4'd0; 132 link_data <= 1'b1; 133 ps2_data_out <= 1'b1; //发送一个停止位 134 state <= ACK; 135 end 136 else begin 137 link_data <= 1'b1; 138 ps2_data_out <= s_data[i]; 139 i <= i + 1'b1; 140 state <= SEND_DATA; 141 end 142 end 143 else 144 state <= SEND_DATA; 145 146 ACK: 147 begin 148 link_data <= 1'b0; //鼠标应答 149 state <= STOP; 150 end 151 152 //鼠标产生数据应答位,同时还会产生最后一个时钟,时钟产生完后,主机发送数据-设备应答 才算完整的结束 153 //如这里不加if(ps2_clk_n)判断条件,接收模块会把真正的起始位采进去,为什么呢,仔细看设备发回的应答数据, 154 //是在时钟为高时,数据拉低,也是相当产生一个起始动作,这是一个伪起始位。 155 //导致后面发送ff命令后,收到的是f4 54 00,发送f4命令后,收到的是f4,按左键显示 R ,右键显示 M ,中键不变化 156 //这里我是通过上面显示数据推断才知道,接收模块会把真正的起始位采进去。 157 STOP: 158 if(ps2_clk_n) begin 159 send_done_sig <= 1'b1; 160 state <= CLEAR; 161 end 162 else 163 state <= STOP; 164 165 CLEAR: 166 begin 167 send_done_sig <= 1'b0; 168 state <= IDLE; 169 end 170 endcase 171 end 172 173 endmodule
View Code
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) 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 53 4'd1,4'd2,4'd3,4'd4,4'd5,4'd6,4'd7,4'd8: //接收8位数据 54 if(ps2_clk_in_n) begin 55 i <= i + 1'b1; 56 data_buf[i- 1] <= ps2_data_in; 57 end 58 59 4'd9: 60 if(ps2_clk_in_n) 61 i <= i + 1'b1; //奇校验位不处理 62 63 4'd10: 64 if(ps2_clk_in_n) 65 i <= i + 1'b1; //停止位不处理 66 67 4'd11: 68 begin 69 rx_done_sig <= 1'b1; //标志着一帧数据接收完 70 i <= i + 1'b1; 71 end 72 73 4'd12: 74 begin 75 rx_done_sig <= 1'b0; //置0,给下次接收做好准备 76 i <= 4'd0; 77 end 78 endcase 79 end 80 81 endmodule 82 83
View Code
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 dis_x_low, 20 dis_x_hig, 21 22 dis_y_low, 23 dis_y_hig, 24 25 //output 26 lcd_rs, 27 lcd_rw, 28 lcd_en, 29 lcd_data, 30 lcd_psb 31 ); 32 input sys_clk;// 50MHZ 33 input rst_n; 34 input [7:0] dis_data_low1; 35 input [7:0] dis_data_hig1; 36 input [7:0] dis_data_low2; 37 input [7:0] dis_data_hig2; 38 input [7:0] dis_data_low3; 39 input [7:0] dis_data_hig3; 40 input [7:0] dis_data_low4; 41 input [7:0] dis_data_hig4; 42 input [7:0] dis_x_low; 43 input [7:0] dis_x_hig; 44 input [7:0] dis_y_low; 45 input [7:0] dis_y_hig; 46 47 input [7:0] dis_data_btn; 48 49 output lcd_rs;//H:data L:command 50 output lcd_rw;//H:read module L:write module 51 output lcd_en;//H active 52 output [7:0] lcd_data; 53 output lcd_psb;//H:parallel module L:SPI module 54 55 /***************************************************/ 56 parameter T3MS = 18'd149_999; 57 parameter IDLE = 5'd0, 58 INIT_FUN_SET1 = 5'd1, 59 INIT_FUN_SET2 = 5'd2, 60 INIT_DISPLAY = 5'd3, 61 INIT_CLEAR = 5'd4, 62 INIT_DOT_SET = 5'd5, 63 SET_DDRAM = 5'd6, 64 WRITE_DATA0 = 5'd7, 65 WRITE_DATA1 = 5'd8, 66 WRITE_DATA2 = 5'd9, 67 WRITE_BLANK1 = 5'd10, 68 WRITE_DATA3 = 5'd11, 69 WRITE_DATA4 = 5'd12, 70 WRITE_BLANK2 = 5'd13, 71 WRITE_DATA5 = 5'd14, 72 WRITE_DATA6 = 5'd15, 73 SET_DDRAM1 = 5'd16, 74 WRITE_DATA7 = 5'd17, 75 WRITE_DATA8 = 5'd18, 76 WRITE_DATA9 = 5'd19, 77 SET_DDRAM2 = 5'd20, 78 WRITE_DATA10 = 5'd21, 79 WRITE_DATA11 = 5'd22, 80 WRITE_BLANK3 = 5'd23, 81 VALUE_X_HIG = 5'd24, 82 VALUE_X_LOW = 5'd25, 83 WRITE_BLANK4 = 5'd26, 84 VALUE_Y_HIG = 5'd27, 85 VALUE_Y_LOW = 5'd28, 86 WRITE_BLANK5 = 5'd29, 87 WRITE_BLANK6 = 5'd30; 88 89 /***************************************************/ 90 //产生周期为6MS的lcd_clk给LCD 91 reg [17:0] cnt; 92 reg lcd_clk; 93 always @(posedge sys_clk or negedge rst_n) 94 if(!rst_n) begin 95 cnt <= 18'd0; 96 lcd_clk <= 1'b0; 97 end 98 else if(cnt == T3MS)begin 99 cnt <= 18'd0; 100 lcd_clk <= ~lcd_clk; 101 end 102 else 103 cnt <= cnt + 1'b1; 104 105 /***************************************************/ 106 reg lcd_rs; 107 always @(posedge lcd_clk or negedge rst_n) 108 if(!rst_n) 109 lcd_rs <= 1'b0; 110 else if( (state == WRITE_DATA1) || (state == WRITE_DATA2) 111 || (state == WRITE_DATA3) || (state == WRITE_DATA4) 112 || (state == WRITE_DATA5) || (state == WRITE_DATA6) 113 || (state == WRITE_DATA7) || (state == WRITE_DATA8) 114 || (state == WRITE_DATA9) || (state == WRITE_DATA10) 115 || (state == WRITE_DATA11) || (state == WRITE_DATA0) 116 || (state == VALUE_X_HIG) || (state == VALUE_X_LOW) 117 || (state == VALUE_Y_HIG) || (state == VALUE_Y_LOW) 118 ||(state == WRITE_BLANK1) || (state == WRITE_BLANK2) 119 ||(state == WRITE_BLANK3) || (state == WRITE_BLANK4) 120 ||(state == WRITE_BLANK5) || (state == WRITE_BLANK6)) 121 lcd_rs <= 1'b1; //写数据模式 122 else 123 lcd_rs <= 1'b0; //写命令模式 124 /***************************************************/ 125 reg [4:0] state; 126 reg [7:0] lcd_data; 127 reg [6:0] num; 128 reg en; 129 reg line_flag; 130 always @(posedge lcd_clk or negedge rst_n) 131 if(!rst_n) begin 132 state <= IDLE; 133 lcd_data <= 8'h00; 134 en <= 1'b1; 135 num <= 6'd0; 136 line_flag <= 1'b0; 137 end 138 else 139 case(state) 140 IDLE: 141 begin 142 state <= INIT_FUN_SET1; 143 lcd_data <= 8'hzz; 144 en <= 1'b1; 145 end 146 147 INIT_FUN_SET1: 148 begin 149 lcd_data <= 8'h30; //功能设定 150 state <= INIT_FUN_SET2; 151 end 152 153 INIT_FUN_SET2: 154 begin 155 lcd_data <= 8'h30; //功能设定 156 state <= INIT_DISPLAY; 157 end 158 159 INIT_DISPLAY: 160 begin 161 lcd_data <= 8'h0c; //显示设定 162 state <= INIT_CLEAR; 163 end 164 165 INIT_CLEAR: 166 begin 167 lcd_data <= 8'h01; //清屏 168 state <= INIT_DOT_SET; 169 end 170 171 INIT_DOT_SET: 172 begin 173 lcd_data <= 8'h06; //进入点设定 174 state <= SET_DDRAM; 175 end 176 177 SET_DDRAM: 178 begin 179 if(!line_flag) begin 180 lcd_data <= 8'h82;//1 line 181 end 182 else begin 183 lcd_data <= 8'h90;//2 line 184 line_flag <= 1'b0; 185 end 186 187 state <= WRITE_DATA0; 188 end 189 190 WRITE_DATA0: ////ff应答:: 191 begin 192 num <= num + 1'b1; 193 lcd_data <= dis_data; 194 if(num == 7'd9) begin 195 line_flag <= 1'b1; 196 state <= SET_DDRAM; 197 end 198 else if(num == 7'd16) 199 state <= WRITE_DATA1; 200 else begin 201 state <= WRITE_DATA0; 202 end 203 end 204 205 WRITE_DATA1: //回应的第一个数据高字节 206 begin 207 lcd_data <= dis_data_hig1; 208 state <= WRITE_DATA2; 209 end 210 211 WRITE_DATA2://回应的第一个数据低字节 212 begin 213 lcd_data <= dis_data_low1; 214 state <= WRITE_BLANK1; 215 end 216 217 WRITE_BLANK1: //写一个空格 218 begin 219 lcd_data <= " "; 220 state <= WRITE_DATA3; 221 end 222 223 WRITE_DATA3: //回应的第二个数据高字节 224 begin 225 lcd_data <= dis_data_hig2; 226 state <= WRITE_DATA4; 227 end 228 229 WRITE_DATA4://回应的第二个数据低字节 230 begin 231 lcd_data <= dis_data_low2; 232 state <= WRITE_BLANK2; 233 end 234 235 WRITE_BLANK2: //写一个空格 236 begin 237 lcd_data <= " "; 238 state <= WRITE_DATA5; 239 end 240 241 WRITE_DATA5: //回应的第三个数据高字节 242 begin 243 lcd_data <= dis_data_hig3; 244 state <= WRITE_DATA6; 245 end 246 247 WRITE_DATA6://回应的第三个数据低字节 248 begin 249 lcd_data <= dis_data_low3; 250 state <= SET_DDRAM1; 251 end 252 253 SET_DDRAM1: 254 begin 255 lcd_data <= 8'h88;//3 line 256 state <= WRITE_DATA7; 257 end 258 259 WRITE_DATA7: //f4应答 260 begin 261 if(num == 7'd24) begin 262 state <= WRITE_DATA8; 263 end 264 else begin 265 num <= num + 1'b1; 266 lcd_data <= dis_data; 267 state <= WRITE_DATA7; 268 end 269 end 270 271 WRITE_DATA8: //第二次回应的高字节 272 begin 273 lcd_data <= dis_data_hig4; 274 state <= WRITE_DATA9; 275 end 276 277 WRITE_DATA9://第二次回应的低字节 278 begin 279 lcd_data <= dis_data_low4; 280 state <= SET_DDRAM2; 281 end 282 283 SET_DDRAM2: 284 begin 285 lcd_data <= 8'h98;//4 line 286 state <= WRITE_DATA10; 287 end 288 289 WRITE_DATA10: 290 begin 291 if(num == 7'd29) begin 292 num <= 7'd0; 293 state <= WRITE_DATA11; 294 end 295 else begin 296 num <= num + 1'b1; 297 lcd_data <= dis_data; 298 state <= WRITE_DATA10; 299 end 300 end 301 302 WRITE_DATA11: 303 begin 304 lcd_data <= dis_data_btn; 305 state <= WRITE_BLANK3; 306 end 307 308 WRITE_BLANK3: 309 begin 310 lcd_data <= " "; 311 state <= WRITE_BLANK4; 312 end 313 314 WRITE_BLANK4: 315 begin 316 lcd_data <= "("; 317 state <= VALUE_X_HIG; 318 end 319 320 VALUE_X_HIG: 321 begin 322 lcd_data <= dis_x_hig; 323 state <= VALUE_X_LOW; 324 end 325 326 VALUE_X_LOW: 327 begin 328 lcd_data <= dis_x_low; 329 state <= WRITE_BLANK5; 330 end 331 332 WRITE_BLANK5: 333 begin 334 lcd_data <= " "; 335 state <= VALUE_Y_HIG; 336 end 337 338 VALUE_Y_HIG: 339 begin 340 lcd_data <= dis_y_hig; 341 state <= VALUE_Y_LOW; 342 end 343 344 VALUE_Y_LOW: 345 begin 346 lcd_data <= dis_y_low; 347 state <= WRITE_BLANK6; 348 end 349 350 WRITE_BLANK6: 351 begin 352 lcd_data <= ")"; 353 state <= SET_DDRAM; 354 end 355 /* STOP: 356 begin 357 en <= 1'b0;//显示完了,lcd_e就一直拉为低 358 state <= STOP; 359 end */ 360 361 default: state <= IDLE; 362 endcase 363 364 reg [7:0] dis_data; 365 always @(posedge sys_clk or negedge rst_n) 366 if(!rst_n) 367 dis_data <= 8'hzz; 368 else 369 case(num) 370 //ps2 Mouse 371 7'd0 : dis_data <= "P"; 372 7'd1 : dis_data <= "S"; 373 7'd2 : dis_data <= "2"; 374 7'd3 : dis_data <= " "; 375 7'd4 : dis_data <= "M"; 376 7'd5 : dis_data <= "o"; 377 7'd6 : dis_data <= "u"; 378 7'd7 : dis_data <= "s"; 379 7'd8 : dis_data <= "e"; 380 7'd9 : dis_data <= " "; 381 //ff应答: 382 7'd10 : dis_data <= "f";//8'h66; 383 7'd11 : dis_data <= "f";//8'h66; 384 7'd12 : dis_data <= 8'hd3; 385 7'd13 : dis_data <= 8'ha6; 386 7'd14 : dis_data <= 8'hb4; 387 7'd15 : dis_data <= 8'hf0; 388 7'd16 : dis_data <= " "; 389 //f4应答: 390 7'd17 : dis_data <= "f"; 391 7'd18 : dis_data <= "4"; 392 7'd19 : dis_data <= 8'hd3; 393 7'd20 : dis_data <= 8'ha6; 394 7'd21 : dis_data <= 8'hb4; 395 7'd22 : dis_data <= 8'hf0; 396 7'd23 : dis_data <= " "; 397 //按键: 398 7'd24 : dis_data <= 8'hb0; 399 7'd25 : dis_data <= 8'hb4; 400 7'd26 : dis_data <= 8'hbc; 401 7'd27 : dis_data <= 8'hfc; 402 7'd28 : dis_data <= " "; 403 default: dis_data <= 8'h00; 404 endcase 405 /***************************************************/ 406 assign lcd_rw = 1'b0;//只有写模式 407 assign lcd_psb = 1'b1;//并口模式 408 assign lcd_en = en ? lcd_clk : 1'b0; 409 /***************************************************/ 410 endmodule
View Code
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 wire [7:0] dis_x_low; 47 wire [7:0] dis_x_hig; 48 wire [7:0] dis_y_low; 49 wire [7:0] dis_y_hig; 50 //控制模块例化 51 ps2_data_control u1_control( 52 //input 53 .sys_clk(sys_clk), 54 .rst_n(rst_n), 55 .send_done_sig(send_done_sig), //发送完标志 56 .rx_done_sig(rx_done_sig), //接收完标志 57 .data_buf(data_buf), //接收到的数据 58 59 //output 60 .rx_en(rx_en), //接收使能 61 .send_en(send_en), //发送使能 62 .send_cmd(send_cmd), //要发送的命令 63 .dis_data_low1(dis_data_low1), //要显示的数据 64 .dis_data_hig1(dis_data_hig1), 65 66 .dis_data_low2(dis_data_low2), //要显示的数据 67 .dis_data_hig2(dis_data_hig2), 68 69 .dis_data_low3(dis_data_low3), //要显示的数据 70 .dis_data_hig3(dis_data_hig3), 71 72 .dis_data_low4(dis_data_low4), //要显示的数据 73 .dis_data_hig4(dis_data_hig4), 74 75 .dis_x_low(dis_x_low), 76 .dis_x_hig(dis_x_hig), 77 78 .dis_y_low(dis_y_low), 79 .dis_y_hig(dis_y_hig), 80 81 .dis_data_btn(dis_data_btn) 82 ); 83 //显示模块例化 84 LCD12864 u2_lcd( 85 //input 86 .sys_clk(sys_clk), 87 .rst_n(rst_n), 88 .dis_data_low1(dis_data_low1), //要显示的数据 89 .dis_data_hig1(dis_data_hig1), 90 91 .dis_data_low2(dis_data_low2), //要显示的数据 92 .dis_data_hig2(dis_data_hig2), 93 94 .dis_data_low3(dis_data_low3), //要显示的数据 95 .dis_data_hig3(dis_data_hig3), 96 97 .dis_data_low4(dis_data_low4), //要显示的数据 98 .dis_data_hig4(dis_data_hig4), 99 100 .dis_x_low(dis_x_low), 101 .dis_x_hig(dis_x_hig), 102 103 .dis_y_low(dis_y_low), 104 .dis_y_hig(dis_y_hig), 105 106 .dis_data_btn(dis_data_btn), 107 108 //output 109 .lcd_rs(lcd_rs), 110 .lcd_rw(lcd_rw), 111 .lcd_en(lcd_en), 112 .lcd_data(lcd_data), 113 // .lcd_psb(lcd_psb) 114 ); 115 //发送模块例化 116 ps2_send_control u3_send( 117 //input 118 .sys_clk(sys_clk), 119 .rst_n(rst_n), 120 .send_en(send_en), //发送使能 121 .send_cmd(send_cmd), //要发送的命令 0xf4 122 123 //output 124 .send_done_sig(send_done_sig),//发送完标志 125 126 //inout 127 .ps2_clk(ps2_clk), //鼠标时钟 128 .ps2_data(ps2_data) //鼠标数据 129 ); 130 //接收模块例化 131 ps2_rx_control u4_rx( 132 //input 133 .sys_clk(sys_clk), 134 .rst_n(rst_n), 135 .ps2_clk_in(ps2_clk), //鼠标时钟 136 .ps2_data_in(ps2_data), //鼠标数据 137 .rx_en(rx_en), //接收模块使能信号 138 139 //output 140 .rx_done_sig(rx_done_sig), //接收完标志信号 141 .data_buf(data_buf) //保存接收到的数据 142 ); 143 endmodule
View Code
总结:
1、上个试验“PS2鼠标+LCD12864实验(调试未成功)”,为什么没有调试成功呢,主要还是细节没注意,要彻底弄清楚每个时钟节拍会做什么动作,尤其是到了一组数据发送完后,一些应答位停止位可以不关心,但一定得知道到它何时产生,在哪变化,只有清楚了每一个细节后,成功才会向你招手。
2、遇到困难时,不要气馁,但反复检查代码时就是没有发现问题,此时应该好好休息一下,因为大脑已经陷入了僵局状态,很难找到问题,且耽误时间,打击自个的信心。
>>>>在ps2_send_control.v中,奇偶校验理解的不对,详细介绍见“奇偶校验位产生器”
转载于:https://www.cnblogs.com/wen2376/p/3389512.html