波特率模块和发送模块都没问题以后,就可以开始编写接收模块的代码了。
其中:
I_clk是系统时钟;
I_rst_n是系统复位;
I_rx_start是开始发送信号,当I_rx_start一直为高电平时,接收模块检测到有数据就会接收;
I_bps_rx_clk是接收模块波特率时钟信号,当检测到I_bps_rx_clk为高的时候就接收1个bit;
I_rs232_rx是串行的bit数据流;
O_para_data[7:0]是并行的8-bit数据;
O_bps_rx_clk_en是发射波特率时钟启动信号,当它为1是波特率产生模块才能产生接收模块的波特率时钟;
O_rx_done是接收1字节数据完成的标志位,当一个字节接收完毕以后,O_rx_done产生一个高脉冲。
接收模块完整代码如下:
module uart_rxd
(
input I_clk ,//系统50MHz时钟
input I_rst_n ,//系统全局复位
input I_rx_start ,//接收使能信号
input I_bps_rx_clk,//接收波特率时钟
input I_rs232_rxd ,//接收的串行数据,硬件上与串口相连
output reg o_bps_rx_clk_en,//波特率时钟使能信号
output reg o_rx_done,//接收完成标志
output reg [7:0] o_para_data//接收到的8 bit并行数据
);
reg R_rs232_rx_reg0 ;
reg R_rs232_rx_reg1 ;
reg R_rs232_rx_reg2 ;
reg R_rs232_rx_reg3 ;
reg R_receiving ;
reg [3:0] R_state ;
reg [7:0] R_para_data_reg;
wire w_rs232_rxd_neg ;
// 功能:把 I_rs232_rxd 打的前两拍,是为了消除亚稳态
// 把 I_rs232_rxd 打的后两拍,是为了产生下降沿标志位
always @(posedge I_clk or negedge I_rst_n)
begin
if(!I_rst_n)
begin
R_rs232_rx_reg0 <= 1'b0;
R_rs232_rx_reg1 <= 1'b0;
R_rs232_rx_reg2 <= 1'b0;
R_rs232_rx_reg3 <= 1'b0;
end
else
begin
R_rs232_rx_reg0 <= I_rs232_rxd ;
R_rs232_rx_reg1 <= R_rs232_rx_reg0;
R_rs232_rx_reg2 <= R_rs232_rx_reg1;
R_rs232_rx_reg3 <= R_rs232_rx_reg2;
end
end
//产生 I_rs232_rxd 信号的下降沿标志位
assign w_rs232_rxd_neg = (~R_rs232_rx_reg2) & R_rs232_rx_reg3;
// 功能:产生发送信号R_receiving
always @(posedge I_clk or negedge I_rst_n)
begin
if(!I_rst_n)
R_receiving <= 1'b0;
else if(o_rx_done)
R_receiving <= 1'b0;
else if(I_rx_start && w_rs232_rxd_neg)
R_receiving <= 1'b1;
end
// 功能:用状态机把串行的输入数据接收,并转化为并行数据输出
always @(posedge I_clk or negedge I_rst_n)
begin
if(!I_rst_n)
begin
o_rx_done <= 1'b0;
R_state <= 4'd0;
R_para_data_reg <= 8'd0;
o_bps_rx_clk_en <= 1'b0;
end
else if(R_receiving)
begin
o_bps_rx_clk_en <= 1'b1 ; // 打开波特率时钟使能信号
if(I_bps_rx_clk)
begin
case(R_state)
4'd0://接收起始位,但不保存
begin
R_para_data_reg <= 8'd0;
o_rx_done <= 1'b0;
R_state <= R_state + 1'b1;
end
4'd1:// 接收第0位,保存到R_para_data_reg[0]
begin
R_para_data_reg[0] <= I_rs232_rxd;
o_rx_done <= 1'b0;
R_state <= R_state + 1'b1;
end
4'd2:// 接收第1位,保存到R_para_data_reg[1]
begin
R_para_data_reg[1] <= I_rs232_rxd;
o_rx_done <= 1'b0;
R_state <= R_state + 1'b1;
end
4'd3:// 接收第2位,保存到R_para_data_reg[2]
begin
R_para_data_reg[2] <= I_rs232_rxd;
o_rx_done <= 1'b0;
R_state <= R_state + 1'b1;
end
4'd4:// 接收第3位,保存到R_para_data_reg[3]
begin
R_para_data_reg[3] <= I_rs232_rxd;
o_rx_done <= 1'b0;
R_state <= R_state + 1'b1;
end
4'd5:// 接收第4位,保存到R_para_data_reg[4]
begin
R_para_data_reg[4] <= I_rs232_rxd;
o_rx_done <= 1'b0;
R_state <= R_state + 1'b1;
end
4'd6:// 接收第5位,保存到R_para_data_reg[5]
begin
R_para_data_reg[5] <= I_rs232_rxd;
o_rx_done <= 1'b0;
R_state <= R_state + 1'b1;
end
4'd7:// 接收第6位,保存到R_para_data_reg[6]
begin
R_para_data_reg[6] <= I_rs232_rxd;
o_rx_done <= 1'b0;
R_state <= R_state + 1'b1;
end
4'd8:// 接收第7位,保存到R_para_data_reg[7]
begin
R_para_data_reg[7] <= I_rs232_rxd;
o_rx_done <= 1'b0;
R_state <= R_state + 1'b1;
end
4'd9:// 接收停止位,但不保存,并把R_para_data_reg给输出
begin
o_para_data <= R_para_data_reg;
o_rx_done <= 1'b1;
R_state <= 4'd0;
end
default :R_state <= 4'd0;
endcase
end
end
else
begin
o_rx_done <= 1'b0 ;
R_state <= 4'd0 ;
R_para_data_reg <= 8'd0 ;
o_bps_rx_clk_en <= 1'b0 ; // 接收完毕以后关闭波特率时钟使能信号
end
end
endmodule
顶层模块的代码如下:
module uart_top
(
input I_clk , // 系统50MHz时钟
input I_rst_n , // 系统全局复位
output [3:0] O_led_out ,
output O_rs232_txd // 发送的串行数据,在硬件上与串口相连
);
wire W_bps_tx_clk ;
wire W_bps_tx_clk_en ;
wire W_bps_rx_clk ;
wire W_bps_rx_clk_en ;
wire W_tx_start ;
wire W_tx_done ;
wire W_rx_done ;
wire [7:0] W_para_data ;
wire [7:0] W_rx_para_data ;
reg [7:0] R_data_reg ;
reg [31:0] R_cnt_1s ;
reg R_tx_start_reg ;
assign W_tx_start = R_tx_start_reg ;
assign W_para_data = R_data_reg ;
assign O_led_out = W_rx_para_data[3:0];
/
// 产生要发送的数据
/
always @(posedge I_clk or negedge I_rst_n)
begin
if(!I_rst_n)
begin
R_cnt_1s <= 31'd0 ;
R_data_reg <= 8'd0 ;
R_tx_start_reg <= 1'b0 ;
end
else if(R_cnt_1s == 31'd5000)
begin
R_cnt_1s <= 31'd0 ;
R_data_reg <= R_data_reg + 1'b1 ;
R_tx_start_reg <= 1'b1 ;
end
else
begin
R_cnt_1s <= R_cnt_1s + 1'b1 ;
R_tx_start_reg <= 1'b0 ;
end
end
uart_txd U_uart_txd
(
.I_clk (I_clk ), // 系统50MHz时钟
.I_rst_n (I_rst_n ), // 系统全局复位
.I_tx_start (W_tx_start ), // 发送使能信号
.I_bps_tx_clk (W_bps_tx_clk ), // 波特率时钟
.I_para_data (W_para_data ), // 要发送的并行数据
.o_rs232_txd (O_rs232_txd ), // 发送的串行数据,在硬件上与串口相连
.o_bps_tx_clk_en (W_bps_tx_clk_en ), // 波特率时钟使能信号
.o_tx_done (W_tx_done ) // 发送完成的标志
);
baudrate_gen U_baudrate_gen
(
.I_clk (I_clk ), // 系统50MHz时钟
.I_rst_n (I_rst_n ), // 系统全局复位
.I_bps_tx_clk_en (W_bps_tx_clk_en ), // 串口发送模块波特率时钟使能信号
.I_bps_rx_clk_en (W_bps_rx_clk_en ), // 串口接收模块波特率时钟使能信号
.O_bps_tx_clk (W_bps_tx_clk ), // 发送模块波特率产生时钟
.O_bps_rx_clk (W_bps_rx_clk ) // 接收模块波特率产生时钟
);
uart_rxd U_uart_rxd
(
.I_clk (I_clk ), // 系统50MHz时钟
.I_rst_n (I_rst_n ), // 系统全局复位
.I_rx_start (1'b1 ), // 接收使能信号
.I_bps_rx_clk (W_bps_rx_clk ), // 接收波特率时钟
.I_rs232_rxd (O_rs232_txd ), // 接收的串行数据,在硬件上与串口相连
.o_bps_rx_clk_en (W_bps_rx_clk_en ), // 波特率时钟使能信号
.o_rx_done (W_rx_done ), // 接收完成标志
.o_para_data (W_rx_para_data ) // 接收到的8-bit并行数据
);
endmodule
testbench文件
`timescale 1ns / 1ps
module tb_uart();
reg I_clk,I_rst_n;
wire [3:0] O_led_out;
wire o_rs232_txd;
initial begin
I_clk =0;
I_rst_n=0;
#200 I_rst_n=1;
end
always #10 I_clk <= ~I_clk;
uart_top tb_uart_top_inst
(
.I_clk (I_clk),
.I_rst_n (I_rst_n),
.O_led_out (O_led_out),
.O_rs232_txd (O_rs232_txd)
);
endmodule
仿真图如图所示