串口系列知识分享:
(1)串口通信实现-串口发送
(2)串口通信发送多字节数据
(3)串口通信实现-串口接收
(4)UART 通信-使用VIO进行板级验证
(5)串口接收-控制LED闪烁
(6)使用串口发送实现ACX720开发板时钟显示
(7)串口发送+RAM+VGA传图
串口通信实现(vivado&verilog版)
前言
此文介绍uart串口协议(串口发送)的verilog实现和testbench的编写,仿真环境为vivado 2018.3。
提示:以下是本篇文章正文内容,下面案例可供参考
一、串口通信协议(uart)
串口作为常用的三大低速总线(UART、SPI、IIC)之一,在设计众多通信接口和调试时占有重要地位。串口(UART)全称通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),主要用于数据间的串行传递,是一种全双工传输模式。它在发送数据时将并行数据转换成串行数据来传输,在接收数据时将接收到的串行数据转换成并行数据。(具体应用可自行百度)
二、串口发送的时序图
UART 在发送或接收过程中的一帧数据由4部分组成,起始位、数据位、奇偶校验位和停止位,如上图所示。其中,起始位标志着一帧数据的开始,停止位标志着一帧数据的结束,数据位是一帧数据中的有效数据。
起始位:起始位标志。低有效。
数据位:一帧数据中的有效数据。注意,串口协议规定了数据位长度只能位 6 7 8 位。要想发多位数据,只能将其切分为多个过程发送。
奇偶校验位:是用来验证数据的正确性。奇偶校验一般不使用,如果 使用,则既可以做奇校验(Odd)也可以做偶校验(Even)。其实就是发的时候如果奇校验位为1,表面数据中1的个数为奇数个,再看接受端的奇校验位是否依旧为1。如果是的话,校验成功。在一定概率上保证了传输的正确性。当然,只是概率上的传输正确。此次试验不同奇偶校验。
停止位:停止位标志着一帧数据的结束,高有效。
空闲时,传输 1 。
波特率设置 : 由于是异步通信,所以没有一个统一的时钟,需要双方约定传输传输速率。常见的波特率有:300, 1200, 2400, 9600, 19200, 115200 等.即一秒发送多少位数据。
所以我们需要实现下面的时序图。当使能信号到来时,发送起始位,数据位,停止位,一帧数据发送结束。
三、uart_byte_tx模块
module uart_byte_tx(
Clk,
Reset_n,
Data,
Send_Go, // 改成单脉冲启动信号 启动一个内部 send_en 信号
Baud_set,
uart_tx,
Tx_done
);
input Clk;
input Reset_n;
input [7:0]Data;
input Send_Go;
input [2:0]Baud_set;
output reg uart_tx;
output reg Tx_done;
//Baud_set = 0 就让波特率 = 9600;
//Baud_set = 1 就让波特率 = 19200
//Baud_set = 2 就让波特率 = 38400;
//Baud_set = 3 就让波特率 = 57600;
//Baud_set = 4 就让波特率 = 115200;
reg [17:0]bps_DR;
always@(*)
case(Baud_set)
0:bps_DR = 1000000000/9600/20;
1:bps_DR = 1000000000/19200/20;
2:bps_DR = 1000000000/38400/20;
3:bps_DR = 1000000000/57600/20;
4:bps_DR = 1000000000/115200/20;
default:bps_DR = 1000000000/9600/20;
endcase
reg Send_en;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Send_en <= 0;
else if(Send_Go)
Send_en <= 1;
else if(Tx_done)
Send_en <= 0;
reg [7:0]r_Data;
always@(posedge Clk) //进行数据寄存,防止当Send_Go脉冲出现时,Data数据发生偏差
if(Send_Go)
r_Data <= Data;
else
r_Data <= r_Data;
wire bps_clk;
assign bps_clk = (div_cnt == 1);
reg [17:0]div_cnt;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
div_cnt <= 0;
else if(Send_en)begin
if(div_cnt == bps_DR - 1)
div_cnt <= 0;
else
div_cnt <= div_cnt + 1'b1;
end
else
div_cnt <= 0;
reg [3:0]bps_cnt;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
bps_cnt <= 0;
else if(Send_en)begin
if(bps_clk)begin
if(bps_cnt == 11)
bps_cnt <= 0;
else
bps_cnt <= bps_cnt + 1'b1;
end
end
else
bps_cnt <= 0;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n) begin
uart_tx <= 1'b1;
end
else begin
case(bps_cnt)
1:uart_tx <= 0;
2:uart_tx <= r_Data[0];
3:uart_tx <= r_Data[1];
4:uart_tx <= r_Data[2];
5:uart_tx <= r_Data[3];
6:uart_tx <= r_Data[4];
7:uart_tx <= r_Data[5];
8:uart_tx <= r_Data[6];
9:uart_tx <= r_Data[7];
10:uart_tx <= 1;
11:begin uart_tx <= 1;end
default:uart_tx <= 1;
endcase
end
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Tx_done <= 0;
else if((bps_clk == 1) && (bps_cnt == 10))
Tx_done <= 1;
else
Tx_done <= 0;
endmodule
四、uart_tx_test模块
此模块用于对uart_byte_tx模块进行测试,将uart_byte_tx模块中的Data输入设为每次发送加1。即第一次发送8’d0,第二次发送8’d1,依次加1发送。
module uart_tx_test(
Clk,
Reset_n,
uart_tx,
);
input Clk;
input Reset_n;
output uart_tx;
reg Send_Go;
reg [7:0]Data;
uart_byte_tx uart_byte_tx(
.Clk(Clk),
.Reset_n(Reset_n),
.Data(Data),
.Send_Go(Send_Go),
.Baud_set(3'd4),
.uart_tx(uart_tx),
.Tx_done(Tx_done)
);
reg [24:0]counter;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
counter <= 0;
else if(counter == 4999999) //每10ms发送一次数据
counter <= 0;
else
counter <= counter + 1;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Send_Go <= 0;
else if(counter == 1)
Send_Go <= 1;
else
Send_Go <= 0;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Data <= 0;
else if(Tx_done)
Data <= Data + 1'b1;
endmodule
五、TB文件
`timescale 1ns / 1ps
module uart_tx_test_tb();
reg Clk;
reg Reset_n;
wire uart_tx;
uart_tx_test uart_tx_test(
.Clk(Clk),
.Reset_n(Reset_n),
.uart_tx(uart_tx)
);
initial Clk = 1;
always#10 Clk = ~Clk;
initial begin
Reset_n = 0;
#201;
Reset_n = 1;
#50000000;
end
endmodule
六、仿真波形展示
【附件:】链接:https://pan.baidu.com/s/1KNI2lWvdekhcJ-VJukWNeg?pwd=78h6
提取码:78h6