主要功能分为三个模块,老生常谈的时钟模块,还有一个rx_uart和一个tx_uart模块,rx_uart负责接收来自外界的消息,并将其传给tx_uart模块,而tx_uart负责接收rx_uart的消息并将其解码后根据内部转换机制顺序回复相应的消息。
`timescale 1ns / 1ps
//
// Company: NUAA
// Engineer: Jason Wang
//
// Create Date: 2021/07/05 09:17:07
// Design Name: uart
// Module Name: rs232_uart_clk_rst
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module rs232_uart_clk_rst(
input I_sys_clk_50M,
input I_sys_rst_50M,
output O_clk_96M,
output O_rst_96M
);
wire rst_50M_n;
wire clk;
wire rst;
wire pll_locked;
reg rst_d1;
reg rst_d2;
assign rst_50M_n=~I_sys_rst_50M; // 按下为高电平
assign rst=rst_50M_n | ~pll_locked;
//==============================input register=================================
always@(posedge clk,posedge rst)begin
if(rst)
begin
rst_d1<=1'b1;
rst_d2<=1'b1;
end
else
rst_d1<=rst;
rst_d2<=rst_d1;
end
//==================================assign output=================================
assign O_clk_96M = clk;
assign O_rst_96M = rst_d2;
clk_wiz_0 clk_wiz_0_inst(
.clk_in1(I_sys_clk_50M),
.reset(rst_50M_n),
.locked(pll_locked),
.clk_out1(clk)
);
endmodule
`timescale 1ns / 1ps
//
// Company: NUAA
// Engineer: Jason Wang
//
// Create Date: 2021/07/05 09:17:07
// Design Name: uart
// Module Name: rx_rs232_uart
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module rx_rs232_uart(
input I_clk,
input I_rst,
input I_rx_data,
output [7:0] O_dout,
output O_valid,
output O_rx_clk
);
reg rx_data_d1;
reg rx_data_d2;
reg rx_data_d3;
reg rx_data_d4;
reg[13:0] rx_cnt; //2^14=16384 96MHz /9600bps =10000
reg rx_cnt_en;
reg rx_cnt_cl;
reg[3:0] state;
reg[3:0] n_state;
parameter idle =4'h0,
start=4'h1,
bit0 =4'h2,
bit1 =4'h3,
bit2 =4'h4,
bit3 =4'h5,
bit4 =4'h6,
bit5 =4'h7,
bit6 =4'h8,
bit7 =4'h9,
check=4'ha,
stop =4'hb;
reg [7:0] rx_dout;
reg rx_vld;
reg rx_bsp_flg; //按我的理解这个是开始赋值的标志,在计数到一半的时候开始将值付给dout
//======================input register=================
always@(posedge I_clk)begin
rx_data_d1<=I_rx_data;
rx_data_d2<=rx_data_d1;
rx_data_d3<=rx_data_d2;
rx_data_d4<=rx_data_d3;
end
//======================rx_cnt_cl=======================
always@(posedge I_clk,posedge I_rst)begin
if(I_rst)
rx_cnt_cl<=1'b0;
else if(rx_cnt==14'd9998)
rx_cnt_cl<=1'b1;
else
rx_cnt_cl<=1'b0;
end
//======================rx_cnt_en======================
always@(posedge I_clk,posedge I_rst)begin
if(I_rst)
rx_cnt_en<=1'b0;
else if(state!=idle)
rx_cnt_en<=1'b1;
else
rx_cnt_en<=1'b0;
end
//======================rx_cnt==========================
always@(posedge I_clk,posedge I_rst)begin
if(I_rst)
rx_cnt<=14'd0;
else if(rx_cnt_en==1'b1)
rx_cnt<=rx_cnt+1'b1;
else if(rx_cnt_cl==1'b1)
rx_cnt<=14'd0;
else
rx_cnt<=rx_cnt;
end
//======================rx_bsp_flg====================
always@(posedge I_clk,posedge I_rst)begin
if(I_rst)
rx_bsp_flg<=1'b0;
else if(rx_cnt==14'd5000)
rx_bsp_flg<=1'b1;
else
rx_bsp_flg<=1'b0;
end
//======================fsm===========================
always@(posedge I_clk,posedge I_rst)begin
if(I_rst)
state<=4'h0;
else
state<=n_state;
end
always@(*) begin
case(state)
idle:
begin
if(rx_data_d3==1'b0)
n_state=start;
else
n_state=idle;
end
start:
begin
if(rx_cnt_cl==1'b1)
n_state=bit0;
else
n_state=start;
end
bit0:
begin
if(rx_cnt_cl==1'b1)
n_state=bit1;
else
n_state=bit0;
end
bit1:
begin
if(rx_cnt_cl==1'b1)
n_state=bit2;
else
n_state=bit1;
end
bit2:
begin
if(rx_cnt_cl==1'b1)
n_state=bit3;
else
n_state=bit2;
end
bit3:
begin
if(rx_cnt_cl==1'b1)
n_state=bit4;
else
n_state=bit3;
end
bit4:
begin
if(rx_cnt_cl==1'b1)
n_state=bit5;
else
n_state=bit4;
end
bit5:
begin
if(rx_cnt_cl==1'b1)
n_state=bit6;
else
n_state=bit5;
end
bit6:
begin
if(rx_cnt_cl==1'b1)
n_state=bit7;
else
n_state=bit6;
end
bit7:
begin
if(rx_cnt_cl==1'b1)
n_state=check;
else
n_state=bit7;
end
check:
begin
if(rx_cnt_cl==1'b1)
n_state=stop;
else
n_state=check;
end
stop:
begin
if(rx_cnt_cl==1'b1)
n_state=idle;
else
n_state=stop;
end
default:
n_state=idle;
endcase
end
//==========================assignment=====================
always@(posedge I_clk,posedge I_rst)begin
if(I_rst)
rx_dout<=8'd0;
else if(rx_bsp_flg==1'b1)
case(state)
bit0: rx_dout[0]<=rx_data_d4;
bit1: rx_dout[1]<=rx_data_d4;
bit2: rx_dout[2]<=rx_data_d4;
bit3: rx_dout[3]<=rx_data_d4;
bit4: rx_dout[4]<=rx_data_d4;
bit5: rx_dout[5]<=rx_data_d4;
bit6: rx_dout[6]<=rx_data_d4;
bit7: rx_dout[7]<=rx_data_d4;
default:
rx_dout<=rx_dout;
endcase
else
rx_dout<=rx_dout;
end
//========================assign output==================
always@(posedge I_clk,posedge I_rst)begin
if(I_rst)
rx_vld<=1'b0;
else if(rx_cnt_cl==1'b1 && state==bit7)
rx_vld<=1'b1;
else
rx_vld<=1'b0;
end
assign O_dout = rx_dout;
assign O_vld = rx_vld;
assign O_clk = ~I_clk;
endmodule
`timescale 1ns / 1ps
//
// Company: NUAA
// Engineer: Jason Wang
//
// Create Date: 2021/07/05 09:17:07
// Design Name: uart
// Module Name: tx_rs232_uart
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module tx_rs232_uart(
input I_clk,
input I_rst,
input[7:0] I_data,
input I_valid,
output O_data
);
reg[7:0] I_data_d1;
reg[7:0] I_data_d2;
reg[7:0] I_data_d3;
reg[7:0] I_data_d4;
reg I_valid_d1;
reg I_valid_d2;
reg I_valid_d3;
reg I_valid_d4;
reg[13:0] tx_cnt;
reg tx_cnt_en;
reg tx_cnt_cl;
reg[3:0] state;
reg[3:0] n_state;
parameter idle =4'h0,
start=4'h1,
bit0 =4'h2,
bit1 =4'h3,
bit2 =4'h4,
bit3 =4'h5,
bit4 =4'h6,
bit5 =4'h7,
bit6 =4'h8,
bit7 =4'h9,
check=4'ha,
stop =4'hb;
reg [7:0] data_tem;
reg tx_data;
//===========================input regester==================
always@(posedge I_clk)begin
I_data_d1<=I_data;
I_data_d2<=I_data_d1;
I_data_d3<=I_data_d2;
I_data_d4<=I_data_d3;
end
always@(posedge I_clk)begin
I_valid_d1<=I_valid;
I_valid_d2<=I_valid_d1;
I_valid_d3<=I_valid_d2;
I_valid_d3<=I_valid_d3;
end
//======================tx_cnt_en============================
always@(posedge I_clk,posedge I_rst)begin
if(I_rst)
tx_cnt_en<=1'b0;
else if(state!==idle)
tx_cnt_en<=1'b1;
else
tx_cnt_en<=1'b0;
end
//========================tx_cnt_cl=======================
always@(posedge I_clk,posedge I_rst)begin
if(I_rst)
tx_cnt_cl<=1'b0;
else if(tx_cnt==14'd9998)
tx_cnt_cl<=1'b1;
else
tx_cnt_cl<=1'b0;
end
//===========================tx_cnt==========================
always@(posedge I_clk,posedge I_rst)begin
if(I_rst)
tx_cnt<=14'd0;
else if(tx_cnt_cl==1'b1)
tx_cnt<=14'd0;
else if(tx_cnt_en==1'b1)
tx_cnt<=tx_cnt+1'b1;
else
tx_cnt<=tx_cnt;
end
//============================fsm==============================
always@(posedge I_clk,posedge I_rst)begin
if(I_rst)
state<=idle;
else
state<=n_state;
end
always@(*) begin
case(state)
idle:
begin
if(I_data_d3==1'b0)
n_state=start;
else
n_state=idle;
end
start:
begin
if(tx_cnt_cl==1'b1)
n_state=bit0;
else
n_state=start;
end
bit0:
begin
if(tx_cnt_cl==1'b1)
n_state=bit1;
else
n_state=bit0;
end
bit1:
begin
if(tx_cnt_cl==1'b1)
n_state=bit2;
else
n_state=bit1;
end
bit2:
begin
if(tx_cnt_cl==1'b1)
n_state=bit3;
else
n_state=bit2;
end
bit3:
begin
if(tx_cnt_cl==1'b1)
n_state=bit4;
else
n_state=bit3;
end
bit4:
begin
if(tx_cnt_cl==1'b1)
n_state=bit5;
else
n_state=bit4;
end
bit5:
begin
if(tx_cnt_cl==1'b1)
n_state=bit6;
else
n_state=bit5;
end
bit6:
begin
if(tx_cnt_cl==1'b1)
n_state=bit7;
else
n_state=bit6;
end
bit7:
begin
if(tx_cnt_cl==1'b1)
n_state=check;
else
n_state=bit7;
end
check:
begin
if(tx_cnt_cl==1'b1)
n_state=stop;
else
n_state=check;
end
stop:
begin
if(tx_cnt_cl==1'b1)
n_state=idle;
else
n_state=stop;
end
default:
n_state=idle;
endcase
end
//=====================assignment==============================
always@(posedge I_clk,posedge I_rst)begin
if(I_rst)
data_tem<=8'd0;
else if(I_valid_d2==1'b1)
data_tem<=I_data_d2;
else
data_tem<=data_tem;
end
always@(posedge I_clk,posedge I_rst)begin
if(I_rst)
tx_data<=1'b1;
else
case(state)
idle: tx_data<=1'b1;
start: tx_data<=1'b0;
bit0: tx_data<=data_tem[0];
bit1: tx_data<=data_tem[1];
bit2: tx_data<=data_tem[2];
bit3: tx_data<=data_tem[3];
bit4: tx_data<=data_tem[4];
bit5: tx_data<=data_tem[5];
bit6: tx_data<=data_tem[6];
bit7: tx_data<=data_tem[7];
check: tx_data <= 1'b1;
stop: tx_data <= 1'b1;
default:tx_data <= 1'b1;
endcase
end
assign O_data=tx_data;
endmodule
`timescale 1ns / 1ps
//
// Company: NUAA
// Engineer: Jason Wang
//
// Create Date: 2021/07/05 09:17:07
// Design Name: uart
// Module Name: rs232_uart_top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module rs232_uart_top(
input I_sys_clk_50M,
input I_sys_rst_50M,
input I_rx_data,
output O_tx_data
);
wire clk;
wire rst;
wire [7:0] data;
wire valid;
wire rx_clk;
rs232_uart_clk_rst rs232_uart_clk_rst_inst(
.I_sys_clk_50M (I_sys_clk_50M),
.I_sys_rst_50M (I_sys_rst_50M),
.O_clk_96M (clk),
.O_rst_96M (rst)
);
rx_rs232_uart rx_rs232_uart_inst(
.I_clk (clk),
.I_rst (rst),
.I_rx_data (I_rx_data),
.O_dout (data),
.O_valid (valid),
.O_rx_clk (rx_clk)
);
tx_rs232_uart tx_rs232_uart_inst(
.I_clk (rx_clk),
.I_rst (rst),
.I_data (data),
.I_valid (valid),
.O_data (O_tx_data)
);
endmodule
主要还是状态机的转换。
PS/2这种协议几乎已经不用了,现在的键盘通用的都是USB的接口协议。PS/2通信协议是一种双向同步串行通信协议。通信的两端通过Clock(时钟脚)同步,并通过Data(数据脚)交换数据。任何一方如果想抑制另外一方通信时,只需要把时钟脚拉到低电平。如果是PC和PS/2键盘间的通信,则PC必须做主机,也就是说,PC可以抑制PS/2键盘发送数据,而PS/2键盘则不会抑制PC发送数据。大多数PS/2设备工作在10~20kHz。
由于对于这两个通信协议不是很熟悉,暂时跳过。