除了顶层模块,三个底层模块分别为PS/2传输处理模块、串口传输模块以及串口波特率选择模块(下面只给出顶层模块和PS/2传输处理模块的Verilog代码)。
Module Ps2_key(Clk,Rst_n,Ps2k_clk,Ps2k_data,Rs232_tx);
Input Clk; //50M时钟信号
Input Rst_n; //复位信号
Input Ps2k_clk; //PS2接口时钟信号
Input Ps2k_data; //PS2接口数据信号
Output Rs232_tx; // RS232发送数据信号
Wire[7:0] Ps2_byte; // 1byte键值
Wire Ps2_state; //按键状态标志位
Wire Bps_start; //接收到数据后,波特率时钟启动信号置位
Wire Clk_bps; // Clk_bps的高电平为接收或者发送数据位的中间采样点
Ps2scan Ps2scan( .Clk(Clk), //按键扫描模块
.Rst_n(Rst_n),
.Ps2k_clk(Ps2k_clk),
.Ps2k_data(Ps2k_data),
.Ps2_byte(Ps2_byte),
.Ps2_state(Ps2_state)
);
Speed_select Speed_select( .Clk(Clk),
.Rst_n(Rst_n),
.Bps_start(Bps_start),
.Clk_bps(Clk_bps)
);
My_uart_tx My_uart_tx( .Clk(Clk),
.Rst_n(Rst_n),
.Clk_bps(Clk_bps),
.Rx_data(Ps2_byte),
.Rx_int(Ps2_state),
.Rs232_tx(Rs232_tx),
.Bps_start(Bps_start)
);
Endmodule
Module Ps2scan(Clk,Rst_n,Ps2k_clk,Ps2k_data,Ps2_byte,Ps2_state);
Input Clk; //50M时钟信号
Input Rst_n; //复位信号
Input Ps2k_clk; //PS2接口时钟信号
Input Ps2k_data; //PS2接口数据信号
Output[7:0] Ps2_byte; // 1byte键值,只做简单的按键扫描
Output Ps2_state; //键盘当前状态,Ps2_state=1表示有键被按下
//------------------------------------------
Reg Ps2k_clk_r0,Ps2k_clk_r1,Ps2k_clk_r2; //Ps2k_clk状态寄存器
//Wire Pos_ps2k_clk; // Ps2k_clk上升沿标志位
Wire Neg_ps2k_clk; // Ps2k_clk下降沿标志位
Always @ (Posedge Clk Or Negedge Rst_n) Begin
If(!Rst_n) Begin
Ps2k_clk_r0 <= 1''B0;
Ps2k_clk_r1 <= 1''B0;
Ps2k_clk_r2 <= 1''B0;
End
Else Begin //锁存状态,进行滤波
Ps2k_clk_r0 <= Ps2k_clk;
Ps2k_clk_r1 <= Ps2k_clk_r0;
Ps2k_clk_r2 <= Ps2k_clk_r1;
End
End
Assign Neg_ps2k_clk = ~Ps2k_clk_r1 & Ps2k_clk_r2; //下降沿
//------------------------------------------
Reg[7:0] Ps2_byte_r; //PC接收来自PS2的一个字节数据存储器
Reg[7:0] Temp_data; //当前接收数据寄存器
Reg[3:0] Num; //计数寄存器
Always @ (Posedge Clk Or Negedge Rst_n) Begin
If(!Rst_n) Begin
Num <= 4''D0;
Temp_data <= 8''D0;
End
Else If(Neg_ps2k_clk) Begin //检测到Ps2k_clk的下降沿
Case (Num)
4''D0: Num <= Num+1''B1;
4''D1: Begin
Num <= Num+1''B1;
Temp_data[0] <= Ps2k_data; //Bit0
End
4''D2: Begin
Num <= Num+1''B1;
Temp_data[1] <= Ps2k_data; //Bit1
End
4''D3: Begin
Num <= Num+1''B1;
Temp_data[2] <= Ps2k_data; //Bit2
End
4''D4: Begin
Num <= Num+1''B1;
Temp_data[3] <= Ps2k_data; //Bit3
End
4''D5: Begin
Num <= Num+1''B1;
Temp_data[4] <= Ps2k_data; //Bit4
End
4''D6: Begin
Num <= Num+1''B1;
Temp_data[5] <= Ps2k_data; //Bit5
End
4''D7: Begin
Num <= Num+1''B1;
Temp_data[6] <= Ps2k_data; //Bit6
End
4''D8: Begin
Num <= Num+1''B1;
Temp_data[7] <= Ps2k_data; //Bit7
End
4''D9: Begin
Num <= Num+1''B1; //奇偶校验位,不做处理
End
4''D10: Begin
Num <= 4''D0; // Num清零
End
Default: ;
Endcase
End
End
Reg Key_f0; //松键标志位,置1表示接收到数据8''Hf0,再接收到下一个数据后清零
Reg Ps2_state_r; //键盘当前状态,Ps2_state_r=1表示有键被按下
Always @ (Posedge Clk Or Negedge Rst_n) Begin //接收数据的相应处理,这里只对1byte的键值进行处理
If(!Rst_n) Begin
Key_f0 <= 1''B0;
Ps2_state_r <= 1''B0;
End
Else If(Num==4''D10) Begin //刚传送完一个字节数据
If(Temp_data == 8''Hf0) Key_f0 <= 1''B1;
Else Begin
If(!Key_f0) Begin //说明有键按下
Ps2_state_r <= 1''B1;
Ps2_byte_r <= Temp_data; //锁存当前键值
End
Else Begin
Ps2_state_r <= 1''B0;
Key_f0 <= 1''B0;
End
End
End
End
Reg[7:0] Ps2_asci; //接收数据的相应ASCII码
Always @ (Ps2_byte_r) Begin
Case (Ps2_byte_r) //键值转换为ASCII码,这里做的比较简单,只处理字母
8''H15: Ps2_asci <= 8''H51; //Q
8''H1d: Ps2_asci <= 8''H57; //W
8''H24: Ps2_asci <= 8''H45; //E
8''H2d: Ps2_asci <= 8''H52; //R
8''H2c: Ps2_asci <= 8''H54; //T
8''H35: Ps2_asci <= 8''H59; //Y
8''H3c: Ps2_asci <= 8''H55; //U
8''H43: Ps2_asci <= 8''H49; //I
8''H44: Ps2_asci <= 8''H4f; //O
8''H4d: Ps2_asci <= 8''H50; //P
8''H1c: Ps2_asci <= 8''H41; //A
8''H1b: Ps2_asci <= 8''H53; //S
8''H23: Ps2_asci <= 8''H44; //D
8''H2b: Ps2_asci <= 8''H46; //F
8''H34: Ps2_asci <= 8''H47; //G
8''H33: Ps2_asci <= 8''H48; //H
8''H3b: Ps2_asci <= 8''H4a; //J
8''H42: Ps2_asci <= 8''H4b; //K
8''H4b: Ps2_asci <= 8''H4c; //L
8''H1z: Ps2_asci <= 8''H5a; //Z
8''H22: Ps2_asci <= 8''H58; //X
8''H21: Ps2_asci <= 8''H43; //C
8''H2a: Ps2_asci <= 8''H56; //V
8''H32: Ps2_asci <= 8''H42; //B
8''H31: Ps2_asci <= 8''H4e; //N
8''H3a: Ps2_asci <= 8''H4d; //M
Default: ;