自己借鉴网上写的,自我觉得这种方法挺好,每个信号分给一个时序描述。分享给大家
串口通信一般呢,两种方式:同步和异步。
同步:通信双方在同一时钟的控制下,同步传输数据;
异步:通信双方使用各自的时钟控制数据的发送和接受;

串口通信的速率用波特率表示,表示每秒传输比特位的位数,单位bps,常用有9600、115200;在设置好数据格式及传输速率之后,UART 负责完成数据的串并转换,而信号的传输则由外部驱动电 路实现。电信号的传输过程有着不同的电平标准和接口规范,针对异步串行通信的接口标准有 RS232、 RS422、RS485 等,它们定义了接口不同的电气特性,如 RS-232 是单端输入输出,而 RS-422/485 为差分输入输出等。
我们选用9600,50MHZ时钟,根据这些我们可以得到发送一比特位需要5208个计数,为了便于仿真,我们这才用28个计数。
简单介绍这些,下来我们根据时序图来写uart协议。
首先我们来写一下发送端口的协议。
module uart(
input clk,
input rst_n,
input start, //起始信号
input [7:0] data, //传输的数据
output reg rs232_tx, //串口传输端口
output reg done //结束信号
);
reg state; //传送状态
reg [7:0] r_data; //寄存器保存数据,防止数据变化引起不必要的错误
reg [12:0] baud_cnt;//一比特计数
reg bit_flag; //一比特计数发送标志
reg [3:0] bit_cnt; //发送的第几比特位
//=============data===============//
//功能:寄存器保存所要发送的数据
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
r_data <= 8'b0;
else if(start)
r_data <= data;
else
r_data <= r_data;
end
//============state==============//
//功能:发送状态的变化
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
state <= 1'b0;
else if(start)
state <= 1'b1;
else if(done)
state <= 1'b0;
else
state<=state;
end
//=============baud_cnt=========//
//发送一比特计数器
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
baud_cnt <= 1'b0;
else if(state)begin
if(baud_cnt == 13'd28)
baud_cnt <= 13'd0;
else
baud_cnt <= baud_cnt + 1'b1;
end
else
baud_cnt <= 13'd0;
end
//===============bit_flag=======//发送比特标志位
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
bit_flag <= 1'b0;
else if(baud_cnt == 13'd1)
bit_flag <= 1'b1;
else
bit_flag <= 1'b0;
end
//===============bit_cnt========//发送的第几个比特
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
bit_cnt <= 4'b0;
else if(bit_flag)begin
if(bit_cnt == 4'd10)
bit_cnt <= 4'd0;
else
bit_cnt <= bit_cnt + 1'b1;
end
else
bit_cnt <= bit_cnt;
end
//==============rs232_tx=======//
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
rs232_tx <= 1'b1;
else if(state)begin
if(bit_flag)begin
case(bit_cnt)
4'd0:rs232_tx <= 4'd0;
4'd1:rs232_tx <= r_data[0];
4'd2:rs232_tx <= r_data[1];
4'd3:rs232_tx <= r_data[2];
4'd4:rs232_tx <= r_data[3];
4'd5:rs232_tx <= r_data[4];
4'd6:rs232_tx <= r_data[5];
4'd7:rs232_tx <= r_data[6];
4'd8:rs232_tx <= r_data[7];
4'd9:rs232_tx <= 4'd1;
default:rs232_tx <= 4'd1;
endcase
end
else ;
end
else rs232_tx <= 4'd1;
end
//=============done=========//
//功能:发送结束信号
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
done <= 1'b0;
else if(bit_flag && bit_cnt == 4'd10)
done <= 1'd1;
else
done <= 1'd0;
end
endmodule
然后接收端口的协议
module uart_rx(
input clk,
input rst_n,
input rs232, //接受端口
output reg [7:0]rx_data, //接受的数据
output reg done
);
reg rs232_t,rs232_t1,rs232_t2;
reg [12:0] baud_cnt;
reg [3:0] bit_cnt;
reg state;
reg bit_flag;
wire en_flag;
assign en_flag=(!rs232_t1)&&(rs232_t2);
//==============消除亚稳态==============
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
rs232_t <= 1'b1;
rs232_t1 <= 1'b1;
rs232_t2 <= 1'b1;
end
else begin
rs232_t <= rs232;
rs232_t1 <= rs232_t;
rs232_t2 <= rs232_t1;
end
end
//==============state==============
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
state <= 1'b0;
else if(en_flag)
state <= 1'b1;
else if(done)
state <= 1'b0;
else
state <= state;
end
//=============baud_cnt=========//
//接受一比特计数器
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
baud_cnt <= 1'b0;
else if(state)begin
if(baud_cnt == 13'd28)
baud_cnt <= 13'd0;
else
baud_cnt <= baud_cnt + 1'b1;
end
else
baud_cnt <= 13'd0;
end
//===============bit_flag=======//接受比特标志位
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
bit_flag <= 1'b0;
else if(baud_cnt == 13'd14)
bit_flag <= 1'b1;
else
bit_flag <= 1'b0;
end
//===============bit_cnt========//接受的第几个比特
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
bit_cnt <= 4'b0;
else if(bit_flag)begin
if(bit_cnt == 4'd10)
bit_cnt <= 4'd0;
else
bit_cnt <= bit_cnt + 1'b1;
end
else
bit_cnt <= bit_cnt;
end
//==============rs232_tx=======//
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
rx_data <= 1'b0;
else if(state)begin
if(bit_flag)begin
case(bit_cnt)
4'd1:rx_data[0] <= rs232_t2;
4'd2:rx_data[1] <= rs232_t2;
4'd3:rx_data[2] <= rs232_t2;
4'd4:rx_data[3] <= rs232_t2;
4'd5:rx_data[4] <= rs232_t2;
4'd6:rx_data[5] <= rs232_t2;
4'd7:rx_data[6] <= rs232_t2;
4'd8:rx_data[7] <= rs232_t2;
default:rx_data <= rx_data;
endcase
end
else ;
end
else rx_data <= 'd0;
end
//=============done=========//
//功能:接受结束信号
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
done <= 1'b0;
else if(bit_flag && bit_cnt == 4'd10)
done <= 1'd1;
else
done <= 1'd0;
end
endmodule
最后的仿真代码;
`timescale 1ns/1ps
module tb_uart();
reg clk;
reg rst_n;
reg start;
reg [7:0]data;
wire rs232_tx;
wire done;
wire [7:0] rx_data;
uart t_uart(
.clk(clk),
.rst_n(rst_n),
.start(start), //????
.data(data), //?????
.rs232_tx(rs232_tx), //??????
.done() //??????
);
uart_rx t_uart_rx(
.clk(clk),
.rst_n(rst_n),
.rs232(rs232_tx), //接受端口
.rx_data(rx_data), //接受的数据
.done()
);
initial clk = 1'b1;
always #10 clk = ~clk;
initial begin
rst_n = 1'b0;
start = 1'b0;
data = 8'd0;
#100;
rst_n = 1'b1;
#200;
data = 8'h55;
#20;
start = 1'd1;
#20;
start = 1'b0;
#20000;
data = 8'h58;
#20;
start = 1'd1;
#20;
start = 1'b0;
#20000;
data = 8'h66;
#20;
start = 1'd1;
#20;
start = 1'b0;
#20000;
$stop;
end
endmodule