(1)串口发送模块visio视图:
(2)串口发送模块Verilog代码:
/*
常见波特率: 4800、9600、14400、115200
在系统时钟为50MHz时,对应计数为:
(1/4800) * 10^9 /20 -1 = 10416
(1/9600) * 10^9 /20 -1 = 5207
(1/14400) * 10^9 /20 -1 = 3471
(1/115200) * 10^9 /20 -1 = 433
*/
module rs232_tx
(
input [16:0] baud_set ,
input clk ,
input reset_n ,
input [7:0] tx_data ,
input tx_start ,
output reg tx ,
output reg tx_done
);
reg [15:0] BAUD_MCNT ;
reg [7:0] r_tx_data ;
reg en_baud_cnt ;
reg [15:0] baud_cnt ;
reg [3:0] bit_cnt ;
//波特最大计数设计
always@(posedge clk)
begin
case(baud_set)
17'd4800 :BAUD_MCNT <= 16'd10416;
17'd9600 :BAUD_MCNT <= 16'd5207;
17'd14400 :BAUD_MCNT <= 16'd3471;
17'd115200 :BAUD_MCNT <= 16'd433;
default :BAUD_MCNT <= 16'd5207; //当输入baud_set为其他值时,一律当成9600处理。
endcase
end
//输入信号同步化处理
always@(posedge clk)
if(tx_start)
r_tx_data <= tx_data;
else
r_tx_data <= r_tx_data;
//波特率计数器使能信号设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
en_baud_cnt <= 1'd0;
else if(tx_start)
en_baud_cnt <= 1'd1;
else if((bit_cnt == 4'd9)&&(baud_cnt == BAUD_MCNT))
en_baud_cnt <= 1'd0;
else
en_baud_cnt <= en_baud_cnt;
//波特率计数器模块设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
baud_cnt <= 16'd0;
else if(!en_baud_cnt)
baud_cnt <= 16'd0;
else if(baud_cnt == BAUD_MCNT)
baud_cnt <= 16'd0;
else
baud_cnt <= baud_cnt + 16'd1;
//位计数器模块设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
bit_cnt <= 4'd0;
else if((baud_cnt == BAUD_MCNT) && (bit_cnt == 4'd9))
bit_cnt <= 4'd0;
else if(baud_cnt == BAUD_MCNT)
bit_cnt <= bit_cnt + 4'd1;
else
bit_cnt <= bit_cnt;
//tx输出序列机设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
tx <= 1'd1;
else if(!en_baud_cnt)
tx <= 1'd1;
else if(baud_cnt == 16'd1)begin
case(bit_cnt)
4'd0: tx <= 1'd0;
4'd1: tx <= r_tx_data[0];
4'd2: tx <= r_tx_data[1];
4'd3: tx <= r_tx_data[2];
4'd4: tx <= r_tx_data[3];
4'd5: tx <= r_tx_data[4];
4'd6: tx <= r_tx_data[5];
4'd7: tx <= r_tx_data[6];
4'd8: tx <= r_tx_data[7];
4'd9: tx <= 1'd1;
default:tx <= 1'd1;
endcase
end
else
tx <= tx;
//tx_done信号设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
tx_done <= 1'd0;
else if((baud_cnt == BAUD_MCNT) && (bit_cnt == 4'd9))
tx_done <= 1'd1;
else
tx_done <= 1'd0;
endmodule
(3)串口发送模块仿真代码:
`timescale 1ns / 1ps
module rs232_tx_tb;
reg [16:0] baud_set ;
reg clk ;
reg reset_n ;
reg [7:0] tx_data ;
reg tx_start ;
wire tx ;
wire tx_done ;
initial clk = 1'd1;
always #10 clk = ~clk;
initial begin
baud_set <= 17'd9600;
reset_n <= 1'd0;
tx_data <= 1'd0;
tx_start <= 1'd0;
#21;
reset_n <= 1'd1;
#40;
@(posedge clk);
//输入数据0
tx_data <= 8'd0;
tx_start <= 1'd1;
#20;
tx_start <= 1'd0;
#(5208 * 20 * 10);
//输入数据1
tx_data <= 8'd1;
tx_start <= 1'd1;
#20;
tx_start <= 1'd0;
#(5208 * 20 * 10);
//输入数据2
tx_data <= 8'd2;
tx_start <= 1'd1;
#20;
tx_start <= 1'd0;
#(5208 * 20 * 10);
//输入数据3
tx_data <= 8'd3;
tx_start <= 1'd1;
#20;
tx_start <= 1'd0;
#(5208 * 20 * 10);
//输入数据4
tx_data <= 8'd4;
tx_start <= 1'd1;
#20;
tx_start <= 1'd0;
#(5208 * 20 * 10);
//输入数据5
tx_data <= 8'd5;
tx_start <= 1'd1;
#20;
tx_start <= 1'd0;
#(5208 * 20 * 10);
//输入数据6
tx_data <= 8'd6;
tx_start <= 1'd1;
#20;
tx_start <= 1'd0;
#(5208 * 20 * 10);
//输入数据7
tx_data <= 8'd7;
tx_start <= 1'd1;
#20;
tx_start <= 1'd0;
#(5208 * 20 * 10);
$stop;
end
rs232_tx rs232_tx_inst
(
.baud_set ( baud_set) ,
.clk ( clk ) ,
.reset_n ( reset_n ) ,
.tx_data ( tx_data ) ,
.tx_start ( tx_start) ,
.tx ( tx ) ,
.tx_done ( tx_done )
);
endmodule
(4)仿真波形:
同时,可以看见,tx一开始被赋予了高电平,在波特计数器计数为1,起始位时被拉低。