抱着“不气馁、不放弃、誓不罢休、搞不定你我还能搞其他玩意吗”的心态,调试许久的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