EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
转——PS2键盘
* X- z) C5 @. R# e4 I5 H2 K& x, s( V2 l W3 ~, n
一、老式的电脑都采用PS/2接口协议的键盘。 2 f- Y/ D7 d) |* B- P' g# \* Y
% P- K. y0 U! N7 X+ V3 Q. e
! M# Y8 q9 L l8 q
1 A& ?0 F2 C* D2 Z
PS键盘使用的时序格式和串口UART的格式非常相似,不过它多了一个CLOCK信号,是由键盘给出的,用于定位数据。
, C! k' B* l+ W7 H: S* i3 b; k9 z. s5 \6 R
1 U1 [, A) Q: C% i2 P( A(二)为了正确采集PS/2键盘的数据,首先检测CLOCK的下降沿,并且在每次下降沿把data的数据采集到一个寄存器中,当第11个数据采集到后,比较第一位是否是0(起始位),8位数据位是否校验位和校验位相同。如果满足,则把这一组Data存下来。 具体实现可以使用代码(摘自李亚民老师的<计算机原理与设计:VerilogHDL版>一书),我做了详尽的中文代码注释
6 e( x6 f4 V. S |* z% [, n | $ @7 b" Z$ N' D+ l
`timescale 1ns/1ns module ps2_keyboard (clk,clrn,ps2_clk,ps2_data,rdn,data,ready,oveRFlow,ps2_clk_sync,sampling,buffer,count,w_ptr,r_ptr); input clk, clrn; // 50 MHZ 系统时钟 input ps2_clk; // ps2 时钟信号 input ps2_data; // ps2 数据信号 input rdn; // 外部读信号,有数据时,置低一个周期,便可读一组数据。 output [7:0] data; // 输出数据 output ready; // 如果controller中有数据则Ready为1,表示用户可以置低rdn读数据了 output reg overflow=1'b0; // 如果controller中数据太多没被读,内部fifo满了,overflow=1 output reg [9:0] buffer=10'd0; // 数据buffer,用于暂存ps2_data移位得到的数据。 reg [7:0] fifo[7:0]; // 循环fifo output reg [3:0] count=4'd0; // ps2_data移位次数计数器 output reg [2:0] w_ptr=3'd0; output reg [2:0]r_ptr=3'd0; // fifo 的读写指针 output sampling; output reg [1:0]ps2_clk_sync=2'd00; //下降沿检测,当ps2_clk满足“10”,下降沿时,则sample产生一个脉冲。 always @ (posedge clk) ps2_clk_sync <= {ps2_clk_sync[0],ps2_clk}; assign sampling = ps2_clk_sync[1] & ~ps2_clk_sync[0]; //这个always块主要做的是ps2_data的采集,以及写入fifo和fifo的读操作。 always @ (posedge clk) begin if (!clrn) begin // 同步复位信号 count <= 0; // 清空计数器 w_ptr <= 0; // 清空写指针 r_ptr <= 0; // 清空读指针 overflow <= 0; // 清空溢出信号。 end else if (sampling) begin // 如果进行一次采样, if (count == 4'd10) begin // 如果采集到11个数据了,一帧结束 if ((buffer[0] == 0) && (ps2_data) && (^buffer[9:1])) begin //一帧结束后,判断起始位0,以及结束位为1,奇校验是否正确 if ((w_ptr + 3'b1) != r_ptr) begin//如果这帧数据有效,判断读指针是否碰到写指针,写满 fifo[w_ptr] <= buffer[8:1];//如果没有写满,将数据写入fifo w_ptr <= w_ptr + 3'b1; // 写指针+1 end else begin overflow <= 1; // 若写满,则溢出信号置1 end end count <= 0; // 如果一帧结束,count清0,准备采集下一帧数据 end else begin // buffer[count] <= ps2_data; // 把串行的数据存到buffer的对应位里面 count <= count + 4'b1; // count加1 end end if ((~rdn) && ready) begin //若rdn=0,ready等于1,即在有数据的情况下主机置低rdn r_ptr <= r_ptr + 3'b1; // 读指针加+1,是在下一个时钟的时候才能被采样。故这一拍就可以立即得到fifo[r_ptr]数据了 overflow <= 0; // 清空overflow end end assign ready = (w_ptr != r_ptr); // 如果写指针不等于读指针,则ready置1,表明有数据 assign data = fifo[r_ptr]; // 异步读取。 ) ~1 @$ L1 c* R$ }2 g1 W
endmodule 6 |3 P" d! J7 N4 l' L
9 n" X7 B* ]/ ]' g4 e
(三)仿真波形 testbench部分完全由自己编写,生成类似ps2/键盘产生的时序波形,接入ps2 controller模块,观察写与读的现象。
1 O3 c$ M+ _ x5 r1 x: ]9 R
: t/ _7 M" r$ [9 ]$ V; R* I: a; N X9 y7 x( m) B
" @6 J# V' |0 k7 m |