一、Uart 发送模块编写和测试
`timescale 1ns / 1ps
module uart_tx(
clk ,
rst ,
baud_set ,
send_go ,
data ,
uart_tx ,
tx_done
);
input clk ;
input rst ;
input[2:0] baud_set ;
input send_go ;
input[7:0] data ;
output uart_tx ;
output tx_done ;
reg r_uart_tx ;
reg r_tx_done ;
reg[17:0] baud_cnt ;
reg[17:0] baud_counter ;
reg[3:0] counter1 ;
reg bps_clk ;
reg send_en ;
reg[7:0 ] r_data ;
assign uart_tx = r_uart_tx ;
assign tx_done = r_tx_done ;
always@(*)begin //波特率选择
case (baud_set)
3'd0: baud_cnt <= 1_000_000_000 / 4800 /20 ;
3'd1: baud_cnt <= 1_000_000_000 / 9600 /20 ;
3'd2: baud_cnt <= 1_000_000_000 / 14400 /20 ;
3'd3: baud_cnt <= 1_000_000_000 / 19200 /20 ;
3'd4: baud_cnt <= 1_000_000_000 / 38400 /20 ;
3'd5: baud_cnt <= 1_000_000_000 / 56000 /20 ;
3'd6: baud_cnt <= 1_000_000_000 / 57600 /20 ;
3'd7: baud_cnt <= 1_000_000_000 / 115200 /20 ;
default: baud_cnt <= 1_000_000_000 / 4800 /20 ;
endcase
end
always@(posedge clk,negedge rst)begin
if(!rst)
send_en <= 0;
else if(send_go)
send_en <= 1;
else if(tx_done)
send_en <= 0;
else
send_en <= send_en;
end
always@(posedge clk ,negedge rst)begin //波特率计数器,最小计时单位
if(!rst)
baud_counter <= 0;
else if(send_en)begin
if(baud_counter == baud_cnt - 1)
baud_counter <= 0;
else
baud_counter <= baud_counter + 1;
end
else
baud_counter <= 0;
end
always@(posedge clk ,negedge rst)begin //波特率时钟生成
if(!rst)
bps_clk <= 0;
else if(baud_counter == 1)
bps_clk <= 1;
else
bps_clk <= 0;
end
always@(posedge clk ,negedge rst)begin
if(!rst)
counter1 <= 0;
else if(send_en) begin
if(counter1 == 11 && baud_counter == 1)
counter1 <= 0;
else if(baud_counter == 1)
counter1 <= counter1 + 1;
else
counter1 <= counter1;
end
else
counter1 <= 0;
end
always@(posedge clk ,negedge rst)begin
if(!rst)
r_data <= 0;
else if(send_go)
r_data <= data;
else
r_data <= r_data;
end
always@(posedge clk ,negedge rst)begin
if(!rst)
r_uart_tx <= 1;
else begin
case (counter1)
4'd1: r_uart_tx <= 0;
4'd2: r_uart_tx <= r_data[0];
4'd3: r_uart_tx <= r_data[1];
4'd4: r_uart_tx <= r_data[2];
4'd5: r_uart_tx <= r_data[3];
4'd6: r_uart_tx <= r_data[4];
4'd7: r_uart_tx <= r_data[5];
4'd8: r_uart_tx <= r_data[6];
4'd9: r_uart_tx <= r_data[7];
4'd10: r_uart_tx <= 1;
4'd11: r_uart_tx <= 1;
default:r_uart_tx <= 1;
endcase
end
end
always@(posedge clk ,negedge rst)begin
if(!rst)
r_tx_done <= 0;
else if(bps_clk==1 && counter1 == 11)
r_tx_done <= 1;
else
r_tx_done <= 0;
end
endmodule
PS: 1.在编写代码是,counter1从1开始传输起始位,是为了避免ounter1==0时与空闲状态重合。
2.baud_counter == 1是为了缩小起始位的到达时间,这样就可以很快的进入到counter1== 1 的状态,从而实现起始位的传输。
二、利用uart发送模块设计一个数据发送器
测试实现每10ms以115200的波特率发送一次数据,发送的数据每次+1
uart_tx_tset 的顶层调用
`timescale 1ns / 1ps
module uart_tx_test(
clk ,
rst ,
uart_tx
);
input clk ;
input rst ;
output uart_tx ;
reg[19:0] counter;
reg send_go;
reg[7:0] data ;
wire tx_done;
uart_tx uart_tx_u0(
.clk ( clk ) ,
.rst ( rst ) ,
.baud_set ( 7 ) ,
.send_go (send_go ) ,
.data (data ) ,
.uart_tx (uart_tx ) ,
.tx_done (tx_done )
);
always@(posedge clk,negedge rst)begin
if(!rst)
counter <= 0;
else if(counter == 499_999)
counter <= 0;
else
counter <= counter + 1;
end
always@(posedge clk,negedge rst)begin
if(!rst)
send_go <= 0;
else if(counter == 1)
send_go <= 1;
else
send_go <=0;
end
always@(posedge clk,negedge rst)begin
if(!rst)
data <= 8'd0;
else if(counter == 499_999)
data <= data + 1;
else
data <= data;
end
endmodule
TB文件
`timescale 1ns / 1ps
module uart_tx_test_tb();
reg clk ;
reg rst ;
wire uart_tx ;
uart_tx_test uart_tx_test_u0(
.clk (clk ) ,
.rst (rst ) ,
.uart_tx (uart_tx )
);
initial clk = 0;
always #10 clk =~clk;
initial begin
rst = 0;
#201;
rst = 1;
#50_000_000;
end
endmodule
测试波形
三、实现多字节的传输
利用一个字节的传输子模块,发送5字节的数据
利用状态机(只需关注输入,输出)
`timescale 1ns / 1ps
module uart_tx_5byte(
clk ,
rst ,
Data40 ,
Trans_go,
uart_tx ,
Trans_done
);
input clk ;
input rst ;
input[39:0] Data40 ;
input Trans_go;
output uart_tx ;
output Trans_done;
reg[7:0] data ;
reg send_go ;
wire tx_done ;
reg Trans_done;
reg[2:0] state;
uart_tx uart_tx_u0(
.clk (clk ) ,
.rst (rst ) ,
.baud_set ( 7 ) ,
.send_go (send_go) ,
.data (data ) ,
.uart_tx (uart_tx) ,
.tx_done (tx_done)
);
always@(posedge clk , negedge rst)begin
if(!rst)begin
state <= 0;
data <= 0;
send_go <= 0;
Trans_done <= 0;
end
else
case (state)
0: if(Trans_go)begin
data <= Data40[7:0];
send_go <= 1;
state <= 1;
end
else begin
data <= 0;
send_go <= 0;
state <= 0;
Trans_done <= 0;
end
1: if(tx_done)begin
data <= Data40[15:8];
send_go <= 1;
state <= 2;
end
else begin
data <= data;
send_go <= 0;
state <= 1;
end
2: if(tx_done)begin
data <= Data40[23:16];
send_go <= 1;
state <= 3;
end
else begin
data <= data;
send_go <= 0;
state <= 2;
end
3: if(tx_done)begin
data <= Data40[31:24];
send_go <= 1;
state <= 4;
end
else begin
data <= data;
send_go <= 0;
state <= 3;
end
4: if(tx_done)begin
data <= Data40[39:32];
send_go <= 1;
state <= 5;
end
else begin
data <= data;
send_go <= 0;
state <= 4;
end
5: if(tx_done)begin
data <= 0;
send_go <= 0;
state <= 0;
Trans_done <= 1;
end
else begin
data <= data;
send_go <= 0;
state <= 5;
end
default: begin
state <= 0;
data <= 0;
send_go <= 0;
Trans_done <= 0;
end
endcase
end
endmodule
TB文件
`timescale 1ns / 1ps
module uart_tx_5byte_tb();
reg clk ;
reg rst ;
reg[39:0] Data40 ;
reg Trans_go;
wire uart_tx ;
wire Trans_done;
uart_tx_5byte uart_tx_5byte_u0(
.clk (clk ),
.rst (rst ),
.Data40 (Data40 ),
.Trans_go (Trans_go),
.uart_tx (uart_tx ),
.Trans_done (Trans_done)
);
initial clk = 0;
always #10 clk =~clk;
initial begin
rst = 0;
Data40 = 0;
Trans_go = 0;
#201;
rst = 1;
#200;
Data40 = 40'h123456789a;
Trans_go = 1;
#20;
Trans_go = 0;
@(posedge Trans_done);
#20000;
Data40 = 40'ha987654321;
Trans_go = 1;
#20;
Trans_go = 0;
@(posedge Trans_done);
#20000;
$stop;
end
endmodule
仿真结果
always@(posedge clk,negedge rst)begin
if(!rst)
s_counter <= 0;
else if(s_counter == 5)
s_counter <= 0;
else if(tx_done)
s_counter <= s_counter + 1;
else
s_counter <= s_counter;
end
always@(posedge clk,negedge rst)begin
if(!rst)
r_Data40 <= 0;
else if(Trans_go)
r_Data40 <= Data40;
else if(tx_done)
r_Data40 <= r_Data40 >> 8;
else
r_Data40 <= r_Data40;
end
always@(posedge clk ,negedge rst)begin
if(!rst)
state <= 0;
else
state <= n_state;
end
always@(*)begin
case (state)
0: if(Trans_go)
n_state <= 1;
else
n_state <= 0;
1: if(s_counter == 5)
n_state <= 0;
else
n_state <= 1;
default: n_state <= 2'bxx;
endcase
end
always@(posedge clk ,negedge rst)begin
if(!rst)
data <= 0;
else if(state == 0)
data <= Data40[7:0];
else if(state == 1 && tx_done == 1)
data <= r_Data40[15:8];
else
data <= data;
end
always@(posedge clk ,negedge rst)begin
if(!rst)
send_go <= 0;
else if(s_counter == 4 && tx_done)
send_go <= 0;
else if((state ==1 && tx_done == 1)||Trans_go)
send_go <= 1;
else
send_go <= 0;
end
always@(posedge clk ,negedge rst)begin
if(!rst)
Trans_done <= 0;
else if(s_counter == 4 && tx_done)
Trans_done <= 1;
else
Trans_done <= 0;
end