uart介绍
UART (Universal Asynchronous Receiver/Transmitter) 是一种常用的串行通讯协议,用于数据在电子设备之间的传输和通讯。它是一种异步数据传输协议,在通讯时不需要发送方和接收方之间的时钟信号同步。
uart的工作过程
UART 协议通常使用两条线路进行通讯,一条用于数据传输(TX),一条用于数据接收(RX)。uart的传输格式如下:(TX跟RX均为一位)
空闲状态:空闲状态时,uart传输位始终保持高电平状态
起始位:uart传输位拉低一个低电平并且持续一个周期,传输开始
数据传输状态:uart实际要传输的数据位数,可以是 5、6、7 或 8 位。
奇偶校验状态:是可选的,可以选择奇校验还是偶校验,用于数据的验证,通常为 0 (即不使用奇偶校验)或 1 位。
奇校验:数据1个数为奇时,校验为0,反之为1;
偶校验:数据0个数为奇时,校验为0,反之为1;
停止位状态:用于标识数据传输的结束位置,通常为 1 或 2 位。uart传输位恢复高电平
uart的verilog实现
本次的实验代码使用的数据传输位数为8位,奇偶校验位数为1位,停止位为1位
uart_tx模块
uart_tx模块主要是负责将要传输的八位数据进行并串转化,输出八个单bit数据,优先输出高位uart的发送端模块分为空闲状态,开始状态,传输数据状态,奇偶校验状态和停止模块。状态图如下:
verilog代码如下:
module uart_tx(
input sysclk ,
input rst_n ,
input [7:0] tx_data,
input tx_en ,
output reg tx ,
output reg tx_done
);
parameter CLK_FREQ = 50000000 ; //
parameter UART_BPS = 9600 ;
localparam BPS_CNT = CLK_FREQ/UART_BPS;//每个数据位占用的周期
parameter EVEN_ODD_CHECK = 1 ;
parameter IDLE =5'b00001;
parameter START=5'b00010;
parameter DATA =5'b00100;
parameter CHECK=5'b01000;
parameter DONE =5'b10000;
reg [4:0] state ;
reg tx_flag ;//数据正在传输
reg [3:0] tx_cnt ;//数据传输位计数器,
reg [15:0] data_cnt ;
reg check_flag;
always@(posedge sysclk or negedge rst_n) begin
if(rst_n==1'b0)
data_cnt<=16'd0 ;
else if(data_cnt==BPS_CNT)
data_cnt<=16'd0 ;
else if(tx_en==1'b1)
data_cnt<=data_cnt+1'b1;
else
data_cnt<=data_cnt ;
end
always@(posedge sysclk or negedge rst_n) begin
if(rst_n==1'b0)
tx_cnt<=4'd0 ;
else if(tx_cnt==4'd11)
tx_cnt<=4'd0 ;
else if ((tx_en==1'b1)&&(data_cnt==BPS_CNT))
tx_cnt<=tx_cnt+1'b1;
else
tx_cnt<=tx_cnt ;
end
always @(posedge sysclk or negedge rst_n )
if(rst_n==1'b0) begin
state<=IDLE;
end
else
case (state)
IDLE: begin
if((tx_en==1'b1)&&(tx_cnt==4'd1))
state<=START;
else
state<=IDLE;
end
START :begin
if(tx_cnt==4'd2)
state<=DATA;
else
state<=START;
end
DATA:begin
if(tx_cnt==4'd10)
state<=CHECK;
else
state<=DATA;
end
CHECK:begin
if(check_flag)
state<=DONE;
else
state<=CHECK;
end
DONE:begin
if(tx_done==1'b1)
state<=IDLE;
else
state<=DONE;
end
default begin
state<=IDLE;
end
endcase
always @(posedge sysclk or negedge rst_n) begin
if(rst_n==1'b0)
tx_flag<=1'b0;
else if (state==DATA)
tx_flag<=1'b1;
else
tx_flag<=tx_flag;
end
always@(posedge sysclk or negedge rst_n) begin
if (rst_n==1'b0)
tx_done<=1'b0;
else if ((state==DONE)&&(data_cnt==BPS_CNT))
tx_done<=1'b1;
else
tx_done<=1'b0;
end
reg [7:0] data;
reg [2:0] cnt;
reg check;
always@(posedge sysclk or negedge rst_n) begin
if(rst_n==1'b0)
tx<=1'b1;
else if(state==IDLE)
tx<=1'b1;
else if(state==START)
tx<=1'b0;
else if(state==DATA)
tx<=data[7-cnt];
else if(state==CHECK)
tx<=check;
else if(state==DONE)
tx<=1'b1;
else
tx<=tx;
end
always@(posedge sysclk or negedge rst_n) begin
if(rst_n==1'b0)
data<=8'd0;
else if (state==START)
data<=tx_data;
else
data<=data;
end
always@(posedge sysclk or negedge rst_n) begin
if(rst_n==1'b0)
cnt<=3'd0;
else
case(tx_cnt)
4'd0:cnt<=3'd0;
4'd1:cnt<=3'd0;
4'd2:cnt<=3'd1;
4'd3:cnt<=3'd2;
4'd4:cnt<=3'd3;
4'd5:cnt<=3'd4;
4'd6:cnt<=3'd5;
4'd7:cnt<=3'd6;
4'd8:cnt<=3'd7;
4'd9:cnt<=3'd0;
4'd10:cnt<=3'd0;
default begin
cnt<=cnt;
end
endcase
end
always@(posedge sysclk or negedge rst_n) begin
if(rst_n==1'b0)
check_flag<=1'b0;
else if ((data_cnt==BPS_CNT)&&(state==CHECK))
check_flag<=1'b1;
else
check_flag<=1'b0;
end
reg even_check;
reg odd_check;
always@(posedge sysclk or negedge rst_n)
if(rst_n==1'b0) begin
even_check<=1'b0;
odd_check <=1'b0;
end
else if(tx==1'b1) begin
even_check<=^tx_data;
odd_check<=~^tx_data;
end
else begin
even_check<=even_check;
odd_check<=odd_check;
end
always@(posedge sysclk or negedge rst_n) begin
if(rst_n==1'b0)
check<=1'b0;
else if(tx_en==1'b1&&EVEN_ODD_CHECK==1'b1)
check<=even_check;
else if(tx_en==1'b1&&EVEN_ODD_CHECK==1'b0)
check<=odd_check;
else
check<=check;
end
endmodule
uart_rx模块
uart接收模块负责将接收到的单bit数据进行串并转化,输出一个8位的数据,先传输过来的数据放在高位。uart的发送端模块分为空闲状态,开始状态,传输数据状态,奇偶校验状态和停止模块。状态图如下:
verilog代码如下:
module uart_rx(
input sysclk ,
input rst_n ,
input tx ,
input tx_done,
output reg[7:0] rx_data,
output reg error ,
output reg rx_done
);
parameter CLK_FREQ = 50000000 ; //
parameter UART_BPS = 9600 ;
localparam BPS_CNT = CLK_FREQ/UART_BPS;//每个数据位占用的周期
parameter EVEN_ODD_CHECK = 1 ;
parameter IDLE =5'b00001;
parameter START=5'b00010;
parameter DATA =5'b00100;//接收数据
parameter CHECK=5'b01000;
parameter DONE =5'b10000;
reg [4:0]state;
reg [15:0] data_cnt ;//计数到BPS_CNT
always@(posedge sysclk or negedge rst_n) begin
if(rst_n==1'b0)
data_cnt<=16'd0 ;
else if(data_cnt>BPS_CNT)
data_cnt<=16'd0 ;
else if(data_cnt<BPS_CNT)
data_cnt<=data_cnt+1'b1;
else
data_cnt<=data_cnt ;
end
reg [3:0] rx_cnt;//每到bps_cnt计数
always@(posedge sysclk or negedge rst_n)begin
if(rst_n==1'b0)
rx_cnt<=4'd0 ;
else if(rx_cnt==4'd11)
rx_cnt<=4'd0 ;
else if (data_cnt==BPS_CNT)
rx_cnt<=rx_cnt+1'b1;
else
rx_cnt<=rx_cnt ;
end
reg start_end;
always@(posedge sysclk or negedge rst_n) begin
if(rst_n==1'b0)
start_end<=1'b0;
else if((state==START)&&(data_cnt==BPS_CNT))
start_end<=1'b1;
else
start_end<=start_end;
end
reg check_flag;
always@(posedge sysclk or negedge rst_n) begin
if(rst_n==1'b0)
check_flag<=1'b0;
else if ((data_cnt==BPS_CNT)&&(state==CHECK))
check_flag<=1'b1;
else
check_flag<=1'b0;
end
reg [2:0]cnt;
always@(posedge sysclk or negedge rst_n) begin
if(rst_n==1'b0)
cnt<=3'd0;
else
case(rx_cnt)
4'd0:cnt<=3'd0;
4'd1:cnt<=3'd0;
4'd2:cnt<=3'd1;
4'd3:cnt<=3'd2;
4'd4:cnt<=3'd3;
4'd5:cnt<=3'd4;
4'd6:cnt<=3'd5;
4'd7:cnt<=3'd6;
4'd8:cnt<=3'd7;
4'd9:cnt<=3'd0;
4'd10:cnt<=3'd0;
default begin
cnt<=cnt;
end
endcase
end
reg data_done;//当state==data,cnt=7时拉�?
always@(posedge sysclk or negedge rst_n) begin
if(rst_n==1'b0)
data_done<=1'b0;
else if (cnt==3'd7&&state==DATA)
data_done<=1'b1;
else
data_done<=1'b0;
end
//state
reg check;
always @(posedge sysclk or negedge rst_n )
if(rst_n==1'b0) begin
state<=IDLE;
end
else
case (state)
IDLE: begin
if(tx_done)
state<=START;
else
state<=IDLE;
end
START :begin
if(start_end)
state<=DATA;
else
state<=START;
end
DATA:begin
if(data_done)
state<=CHECK;
else
state<=DATA;
end
CHECK:begin
if(check_flag)
state<=DONE;
else
state<=CHECK;
end
DONE:begin
if(rx_done==1'b1)
state<=IDLE;
else
state<=DONE;
end
default begin
state<=IDLE;
end
endcase
reg [7:0]shift_reg;
always@(posedge sysclk or negedge rst_n) begin
if(rst_n==1'b0)
shift_reg<=8'd0;
else if((state==DATA)&&(data_cnt==BPS_CNT))
shift_reg<={tx,shift_reg[7:1]};
else
shift_reg<=shift_reg;
end
always@(posedge sysclk or negedge rst_n)
if(rst_n==1'b0) begin
rx_data<=8'd0;
rx_done<=1'b0;
end
else if(state==DATA&&rx_cnt==3'd7) begin
rx_data<=shift_reg;
rx_done<=1'b1;
end
else begin
rx_data<=rx_data;
rx_done<=rx_done;
end
reg even_check;
reg odd_check;
always@(posedge sysclk or negedge rst_n)
if(rst_n==1'b0) begin
even_check<=1'b0;
odd_check <=1'b0;
end
else if(tx==1'b1) begin
even_check<=^rx_data;
odd_check<=~^rx_data;
end
else begin
even_check<=even_check;
odd_check<=odd_check;
end
always@(posedge sysclk or negedge rst_n) begin
if(rst_n==1'b0)
check<=1'b0;
else if(EVEN_ODD_CHECK==1'b1)
check<=even_check;
else if(EVEN_ODD_CHECK==1'b0)
check<=odd_check;
else
check<=check;
end
always@(posedge sysclk or negedge rst_n) begin
if(rst_n==1'b0)
error<=1'b0;
else if((state==CHECK)&&(tx==check))
error<=1'b0;
else if(state==CHECK&&tx!=check)
error<=1'b1;
else
error<=error;
end
endmodule
uart的top模块
module uart_top(
input sysclk ,
input rst_n ,
input [7:0] tx_data,
input tx_en ,
output [7:0] rx_data,
output error ,
output rx_done
);
wire tx_done;
wire tx ;
uart_tx uart_tx_u(
.sysclk (sysclk ),
.rst_n (rst_n ),
.tx_data(tx_data),
.tx_en (tx_en ),
.tx (tx ),
.tx_done(tx_done)
);
uart_rx uart_rx_u(
.sysclk (sysclk ),
.rst_n (rst_n ),
.tx (tx ),
.tx_done(tx_done),
.rx_data(rx_data),
.error (error ),
.rx_done(rx_done)
);
endmodule
uart的tb模块
module uart_tb();
reg sysclk ;
reg rst_n ;
reg [7:0] tx_data;
reg tx_en ;
wire [7:0] rx_data;
wire error ;
wire rx_done;
uart_top uart_top_u(
.sysclk (sysclk ),
.rst_n (rst_n ),
.tx_data(tx_data),
.tx_en (tx_en ),
.rx_data(rx_data),
.error (error ),
.rx_done(rx_done)
);
initial begin
sysclk <=1'b0 ;
rst_n <=1'b0 ;
tx_data<=8'd0 ;
tx_en <=1'b0 ;
#10;
rst_n <=1'b1 ;
tx_en <=1'b1 ;
#15;
tx_data<=8'd36;
end
always #10sysclk=!sysclk;
endmodule
uart仿真原理图
可以看出,uart_tx模块跟uart_rx模块仅使用两条线路进行通讯