前面发了个发送模块,这次补齐,完整。
串口计数器,波特率适配
uart_clk.v
module uart_clk(input wire clk,input wire rst_n,input wire tx_clk_en,input wire rx_clk_en,input wire[1:0] baud_sel,output wire tx_clk,output wire rx_clk
);
localparam OSC = 50_000_000;
reg[16:0] bauds[0:3] ;reg[16:0] tx_cnt;
reg[16:0] rx_cnt;initial beginbauds[0] <= OSC/19200 - 1;bauds[1] <= OSC/38400 - 1;bauds[2] <= OSC/57600 - 1;bauds[3] <= OSC/115200 - 1;
endalways @(posedge clk or negedge rst_n ) beginif (!rst_n )tx_cnt <= 0;else if (!tx_clk_en || tx_cnt === bauds[baud_sel])tx_cnt <= 0;elsetx_cnt <= tx_cnt + 1;
endassign tx_clk = (tx_cnt === bauds[baud_sel]) ? 1'b1 : 1'b0;always @(posedge clk or negedge rst_n) beginif (!rst_n)rx_cnt <= 0;else if (!rx_clk_en || rx_cnt === bauds[baud_sel])rx_cnt <= 0;elserx_cnt <= rx_cnt + 1;
endassign rx_clk = (rx_cnt === (bauds[baud_sel] >>1)) ? 1'b1 : 1'b0;endmodule
发送模块
tx.v
module tx (input wire clk,input wire rst_n,input wire tx_en,input wire tx_clk,input wire[7:0] tx_data,output reg tx_clk_en,output reg txd,output reg busy,output reg done
);reg [1:0] stage;
reg [2:0] curbit;
reg [7:0] tx_rdata;always @(posedge clk or negedge rst_n) beginif (!rst_n) beginbusy <= 1'b0;end else if (tx_en && !busy) beginbusy <= 1'b1;tx_rdata <= tx_data;end else if (done)busy <= 1'b0;
endalways @(busy) beginif(busy)tx_clk_en <= 1'b1;else tx_clk_en <= 1'b0;
endalways @(posedge clk or negedge rst_n) beginif (!rst_n) begintxd <= 1'b1;done <= 1'b0;stage <= 2'd0;end else if (busy) beginif (tx_clk) beginif(stage === 2'd0) begintxd <= 1'b0;done <= 1'b0;curbit <= 3'd0;stage <= 2'b1;end else if (stage === 2'b1) begintxd <= tx_rdata[curbit];if(curbit == 3'd7)stage <= 2'd2;elsecurbit <= curbit + 1;end else if (stage == 2'd2) begintxd <= 1'b1;stage <= stage + 1;end else if (stage == 2'd3) begintxd <= 1'b1;done <= 1'b1;stage <= 2'd0;endendend else begintxd <= 1'b1;done <= 1'b0;stage <= 2'd0;end
endendmodule
接收模块
rx.v
module rx (input wire clk,input wire rst_n,input wire rx_en,input wire rx_clk,input wire rxd,output reg rx_clk_en,output reg[7:0] rx_data,output reg busy,output reg done
);reg[7:0] tmp;
reg[3:0] tmpres;reg [ 1:0] stage;
reg [2:0] curbit;
reg [7:0] rx_rdata;wire rxd_negedge;
always @(posedge clk or negedge rst_n) beginif (!rst_n)tmp <= 8'b0;elsetmp <= (tmp << 1) | rxd;tmpres <= {tmp[7:6], tmp[1:0]};
end
assign rxd_negedge = ( tmpres === 4'b1100) ? 1'b1 : 1'b0;always @(posedge clk or negedge rst_n) beginif (!rst_n) beginbusy <= 1'b0;end else if (rx_en && rxd_negedge && !busy) beginbusy <= 1'b1;end else if (done)busy <= 1'b0;
endalways @(busy) beginif (busy)rx_clk_en <= 1'b1;elserx_clk_en <= 1'b0;
endalways @(posedge clk or negedge rst_n) beginif (!rst_n) begindone <= 1'b0;stage <= 2'd0;rx_rdata <= 8'd0;end else if (busy) beginif (rx_clk) beginif (stage === 2'd0) beginrx_rdata <= 8'd0;done <= 1'b0;curbit <= 3'd0;stage <= 2'b1;end else if (stage === 2'b1) beginrx_rdata[curbit] <= rxd;if (curbit == 3'd7)stage <= 2'd2;elsecurbit <= curbit + 1;end else if (stage === 2'd2) beginrx_data <= rx_rdata;done <= 1'b1;stage <= 2'd0;end elsestage <= 2'd0;endend else beginrx_rdata <= 8'd0;done <= 1'b0;stage <= 2'd0;end
endendmodule
组合
uart.v
module uart(input wire clk,input wire rst_n,input wire rx_en,input wire rxd,input wire tx_en,output wire[7:0] rx_data,input wire[7:0] tx_data,input wire[1:0] baud_sel,output wire txd,output wire rbusy,output wire rdone,output wire tbusy,output wire tdone
);wire rx_clk,rx_clk_en;
wire tx_clk, tx_clk_en;uart_clk uclk1(clk,rst_n,tx_clk_en,rx_clk_en,baud_sel,tx_clk,rx_clk);
tx tx1(clk,rst_n,tx_en,tx_clk,tx_data,tx_clk_en,txd,tbusy,tdone);
rx rx1(clk,rst_n,rx_en,rx_clk,rxd,rx_clk_en,rx_data,rbusy,rdone);endmodule
测试
uart_test.v
module uart_test (input wire clk,input wire rst_n,input wire rxd,output wire txd
);
reg rx_en = 1;
reg tx_en;
wire rbusy,tbusy;
wire rdone,tdone;
reg[7:0] tx_data = 0;
wire[7:0] rx_data ;
// reg received = 1'b0;
reg sent = 1'b0;
reg[1:0] baud_sel = 0;always @(posedge clk or negedge rst_n) beginif (!rst_n) beginrx_en = 0;tx_en = 0;end else if(!tbusy && !rbusy && !sent) begintx_data <= tx_data+1 ;tx_en <= 1'b1;sent <= 1;$display("sent %d",tx_data);end else if (rdone) beginsent <= 0;$display("received %d",rx_data);end else begintx_en <= 1'b0;rx_en <= 1'b1;end
enduart uart1(clk, rst_n, rx_en,rxd,tx_en,rx_data, tx_data,baud_sel,txd,rbusy,rdone,tbusy,tdone);endmodule
testbench
module test;reg rst_n=1 ;initial begin$dumpfile("test.vcd");$dumpvars(0, test);#10 rst_n = !rst_n;#30 rst_n = !rst_n;#500000 $finish;
endreg clk = 0;
always #1 clk = !clk;wire txd;
wire rxd;
uart_test uart1(clk,rst_n,rxd,txd);
// always @(posedge clk)
// rxd <= txd;
assign rxd = txd;endmodule
gtkwave 波形
方便模拟测试,发送转接收,对比结果。