实现功能:
1.接收uart串行数据,输出并行数据(1byte)。
2.输入并行数据(1byte),输出uart串行数据。
3.完成uart传输的1次环回。
uart协议的1帧数据传输
uart_test系统框图
Verilog代码实现
1.uart接收模块:接收串行数据,输出并行数据和其有效标志。
module uart_rx#(
parameter UART_BPS='d9600 , //波特率:1s传输9600个bit
parameter CLK_FREQ='d50_000_000 //时钟频率:50MHz
)(
input wire clk ,
input wire rst_n ,
input wire rx , //接收的串行数据
output reg [7:0] po_data , //输出并行数据
output reg po_flag //输出有效并行数据的标志信号
);
首先对rx进行时钟同步,消除亚稳态,以及打拍处理提取下降沿;
always@(posedge clk or negedge rst_n)
if(!rst_n) begin
rx_d1<=1'b1;
rx_d2<=1'b1;
rx_d3<=1'b1;
end
else begin
rx_d1<=rx; //时钟同步,消除亚稳态
rx_d2<=rx_d1; //时钟同步,消除亚稳态
rx_d3<=rx_d2; //打拍处理
end
assign rx_fall = ~rx_d2 & rx_d3 ; //提取rx下降沿
然后需要数据帧的有效信号,以便知道什么时候计数;
always@(posedge clk or negedge rst_n)
if(!rst_n) frame_val<=1'b0;
else if((bit_cnt==BIT_CNT_MAX-1'b1) && bit_flag) //接收完1帧数据
frame_val<=1'b0;
else if(rx_fall)
frame_val<=1'b1;
else
frame_val<=frame_val;
1码元符号(1bit)所需的计数器;
always@(posedge clk or negedge rst_n)
if(!rst_n) baud_cnt<=16'd0;
else if(frame_val==1'b0) //数据帧无效
baud_cnt<=16'd0;
else if(baud_cnt==BAUD_CNT_MAX-1'b1)
baud_cnt<=16'd0;
else
baud_cnt<=baud_cnt+1'b1;
1bit稳定数据的采样标志信号;
always@(posedge clk or negedge rst_n)
if(!rst_n) bit_flag<=1'b0;
else if(baud_cnt==BAUD_CNT_MAX_HALF-1'b1) //采样需要在中间数据才稳定
bit_flag<=1'b1;
else
bit_flag<=1'b0;
对采样到的bit数据进行计数;
always@(posedge clk or negedge rst_n)
if(!rst_n) bit_cnt<=4'd0;
else if((bit_cnt==BIT_CNT_MAX-1'b1) && bit_flag) //10bit数据采样完毕
bit_cnt<=4'd0;
else if(bit_flag) //采样到1bit数据
bit_cnt<=bit_cnt+1'b1;
else
bit_cnt<=bit_cnt;
将接收到的串行数据rx转化为并行数据po_data_t;
always@(posedge clk or negedge rst_n)
if(!rst_n) po_data_t<=8'b0;
else if((bit_cnt>=4'd1) && (bit_cnt<BIT_CNT_MAX-1'b1) && bit_flag) //8bit数据
po_data_t<={rx_d3,po_data_t[7:1]}; //起始位后接的是低位
else
po_data_t<=po_data_t;
并行数据全部拼接完成的标志信号;
always@(posedge clk or negedge rst_n)
if(!rst_n) po_flag_t<=1'b0;
else if((bit_cnt==BIT_CNT_MAX-1'b1) && bit_flag)
po_flag_t<=1'b1;
else
po_flag_t<=1'b0;
输出并行数据和输出有效并行数据的标志信号。
always@(posedge clk or negedge rst_n)
if(!rst_n) po_data<=8'b0;
else if(po_flag_t)
po_data<=po_data_t;
else
po_data<=po_data;
//po_flag_t延迟1拍与po_data同步
always@(posedge clk or negedge rst_n)
if(!rst_n) po_flag<=1'b0;
else
po_flag<=po_flag_t;
仿真结果:
2.uart发送模块:接收并行数据,发送串行数据。
module uart_tx#(
parameter UART_BPS='d9600 , //波特率:1s传输9600个bit
parameter CLK_FREQ='d50_000_000 //时钟频率:50MHz
)(
input wire clk ,
input wire rst_n ,
input wire pi_flag , //输入并行数据
input wire [7:0] pi_data , //输入有效并行数据的标志信号
output reg tx //输出串行数据
);
首先同样是uart 1帧数据的有效信号;
always@(posedge clk or negedge rst_n)
if(!rst_n) frame_val<=1'b0;
else if((bit_cnt==BIT_CNT_MAX-1'b1) && bit_flag) //发送完1帧数据
frame_val<=1'b0;
else if(pi_flag) //接收到有效的并行数据
frame_val<=1'b1;
else
frame_val<=frame_val;
1码元符号(1bit)所需的计数器;
always@(posedge clk or negedge rst_n)
if(!rst_n) baud_cnt<=16'd0;
else if(frame_val==1'b0) //数据帧无效
baud_cnt<=16'd0;
else if(baud_cnt==BAUD_CNT_MAX-1'b1)
baud_cnt<=16'd0;
else
baud_cnt<=baud_cnt+1'b1;
1bit数据的发送标志信号;
always@(posedge clk or negedge rst_n)
if(!rst_n) bit_flag<=1'b0;
else if(frame_val && !baud_cnt)
bit_flag<=1'b1;
else
bit_flag<=1'b0;
对bit数据的发送进行计数;
always@(posedge clk or negedge rst_n)
if(!rst_n) bit_cnt<=4'd0;
else if((bit_cnt==BIT_CNT_MAX-1'b1) && bit_flag) //10bit数据计数完毕
bit_cnt<=4'd0;
else if(bit_flag) //发送完1bit数据
bit_cnt<=bit_cnt+1'b1;
else
bit_cnt<=bit_cnt;
输出串行数据。
always@(posedge clk or negedge rst_n)
if(rst_n==1'b0) tx<=1'b1; //空闲
else if(bit_flag)
case(bit_cnt)
4'd0: tx<=1'b0; //起始位
4'd1: tx<=pi_data[0]; //最低位数据
4'd2: tx<=pi_data[1];
4'd3: tx<=pi_data[2];
4'd4: tx<=pi_data[3];
4'd5: tx<=pi_data[4];
4'd6: tx<=pi_data[5];
4'd7: tx<=pi_data[6];
4'd8: tx<=pi_data[7]; //最高位数据
4'd9: tx<=1'b1; //结束位
default:tx<=1'b1;
endcase
仿真结果:
3.uart环回测试。
module uart_test#(
parameter UART_BPS='d9600 , //波特率:1s传输9600个bit
parameter CLK_FREQ='d50_000_000 //时钟频率:50MHz
)(
input wire clk ,
input wire rst_n ,
input wire rx , //接收的串行数据
output wire tx //发送的串行数据
);
wire [7:0] data ;
wire data_flag ;
uart_rx#(
.UART_BPS(UART_BPS),
.CLK_FREQ(CLK_FREQ)
)u_uart_rx(
.clk (clk ),
.rst_n (rst_n ),
.rx (rx ),
.po_data(data),
.po_flag(data_flag)
);
uart_tx#(
.UART_BPS(UART_BPS),
.CLK_FREQ(CLK_FREQ)
)u_uart_tx(
.clk (clk ),
.rst_n (rst_n ),
.pi_data(data),
.pi_flag(data_flag),
.tx(tx)
);
endmodule
仿真验证:
`timescale 1ns/1ns
module tb_uart_test();
parameter UART_BPS='d9600 ; //波特率:1s传输9600个bit
parameter CLK_FREQ='d50_000_000 ; //时钟频率:50MHz
reg clk;
reg rst_n;
reg rx;
wire tx;
initial
begin
clk=1'b0;
rst_n<=1'b0;
rx<=1'b1;
#20
rst_n<=1'b1;
end
always #10 clk=~clk;
initial
begin
#200 //空闲状态
rx_test();
#(5208*10*20*3)
#200
$stop;
end
//输出uart数据帧(10-13)
task rx_test(); //任务函数,类似C语言
integer j;
for(j=10;j<13;j=j+1)
rx_8bit(j);
endtask
//输入8bit并行数据,输出uart数据帧
task rx_8bit(
input [7:0] data
);
integer i;
for(i=0;i<10;i=i+1)
begin
case(i)
0:rx<=1'b0; //1帧数据
1:rx<=data[0];
2:rx<=data[1];
3:rx<=data[2];
4:rx<=data[3];
5:rx<=data[4];
6:rx<=data[5];
7:rx<=data[6];
8:rx<=data[7];
9:rx<=1'b1;
endcase
#(5208*20); //9600波特率
end
endtask
uart_test#(
.UART_BPS(UART_BPS),
.CLK_FREQ(CLK_FREQ)
)u_uart_test(
.clk (clk ),
.rst_n (rst_n ),
.rx (rx ),
.tx(tx)
);
endmodule