串口系列知识分享:
(1)串口通信实现-串口发送
(2)串口通信发送多字节数据
(3)串口通信实现-串口接收
(4)UART 通信-使用VIO进行板级验证
(5)串口接收-控制LED闪烁
(6)使用串口发送实现ACX720开发板时钟显示
(7)串口发送+RAM+VGA传图
前言
此文介绍uart串口协议(串口接收)的verilog实现和testbench的编写,仿真环境为vivado 2018.3。
一、串口的通信协议
要进行模块的设计,首先要了解该部分功能的原理。这就涉及到串口的通信协议。
从这个图中可以看到,在RX信号线中,空闲状态是高电平。也就是说在不传输信息的时候,信号线置高。拉低的信号就是起始信号,也就是要开始传输数据的信号。第一位是起始位,紧跟后面的是数据位,随后有校验位和停止位。
【设计思路】:
- 空闲状态: 高电平
- 起始位: 拉低并且持续一位的时间,也就是持续 1/bps 的时间
- 数据位: 从这位开始就是数据位,数据位的长度从5 到 8 不等。最常见的是8位数据位。
- 校验位: 作为数据的校验位。
- 停止位: 拉高持续0.5,1 或者 2个时钟,只要接收双方协议好即可。
这就是一帧数据中包含的信息量,其中对接收方来说最重要的自然是数据位。需要准确的从中提取出数据位,来进行下一步的处理。
其中校验位的设计又有多种选择,校验方法有奇校验(odd)、偶校验(even)、0校验(space)、1校验(mark)及无校验(noparity)。常见的就是无校验,或者奇偶校验。
无校验位:就是不设置校验位,直接跟上停止位。
奇偶校验位根据数据位中1 的个数来设计。
奇校验位:如果数据位中1 的个数为奇数个,则该位为0。如果数据位中1 的个数为偶数个,则该位为1。也就是要求数据位与校验位中 1 的个数为奇数。
偶校验位:和奇校验位相反。如果数据位中1 的个数为奇数个,则该位为1。如果数据位中1 的个数为偶数个,则该位为0。也就是要求数据位与校验位中 1 的个数为偶数。
————————————————
二、分模块设计
这次模块的设计让我也是重新的认识到 Verilog 语言设计新的一种格式。先设计好每一个相应的模块,在合理的将每个模块联系起来,形成需要的模块。这种方式使得整体的进程可以进行的比较有条理。下面我们先来进行第一步,分模块的设计。
1.检测模块
首先第一个是检测模块。该模块的功能是检测信号线的下降沿,也就是起始位的开始。那么只要做一个下降沿来的时候,产生一个时钟的高脉冲即可。
reg [1:0]uart_rx_r;
always@(posedge Clk)begin //uart_rx为输入数据
uart_rx_r[0] <= uart_rx;
uart_rx_r[1] <= uart_rx_r[0] ;
end
wire nedge_uart_rx;
//assign nedge_uart_rx = ((uart_rx_r[1] == 1) && (uart_rx_r[0] == 0));
assign nedge_uart_rx = (uart_rx_r == 2'b10); //下降沿检测
根据上图知在uart_rx出现下降沿时,nedge_uart_rx会在下一个时钟上升沿出现高电平信号。
2.波特率设置
代码如下(示例):
reg [8:0] Bps_DR; //波特率设置
always@(*)
case(Baud_Set)
0:Bps_DR = 1000000000/9600/16/20 - 1;
1:Bps_DR = 1000000000/19200/16/20 - 1;
2:Bps_DR = 1000000000/38400/16/20 - 1;
3:Bps_DR = 1000000000/57600/16/20 - 1;
4:Bps_DR = 1000000000/115200/16/20 - 1;
default:Bps_DR = 1000000000/9600/16/20 - 1;
endcase
此处为防止信号传输过程中产生干扰,将每一位信号分为16进行判断,舍去前5段,后五段,留中间5段进行判断。
reg [8:0]div_cnt;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
div_cnt <= 0;
else if(RX_EN)begin
if(div_cnt == Bps_DR)
div_cnt <= 0;
else
div_cnt <= div_cnt + 1'b1;
end
else
div_cnt <= 0;
wire bps_clk_16x; //取每个信号的中点值
assign bps_clk_16x = (div_cnt == Bps_DR / 2);
reg [7:0]bps_cnt;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
bps_cnt <= 0;
else if(RX_EN)begin
if(bps_clk_16x)begin
if(bps_cnt == 160)
bps_cnt <= 0;
else
bps_cnt <= bps_cnt + 1'b1;
end
else
bps_cnt <= bps_cnt;
end
else
bps_cnt <= 0;
3.判断过程
//reg width name number/depth
reg[2:0]r_data[7:0];
reg [2:0]sta_bit;
reg [2:0]sto_bit;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n) begin
sta_bit <= 0;
sto_bit <= 0;
r_data[0] <= 0;
r_data[1] <= 0;
r_data[2] <= 0;
r_data[3] <= 0;
r_data[4] <= 0;
r_data[5] <= 0;
r_data[6] <= 0;
r_data[7] <= 0;
end
else if(bps_clk_16x)begin
case(bps_cnt)
0:begin
sta_bit <= 0;
sto_bit <= 0;
r_data[0] <= 0;
r_data[1] <= 0;
r_data[2] <= 0;
r_data[3] <= 0;
r_data[4] <= 0;
r_data[5] <= 0;
r_data[6] <= 0;
r_data[7] <= 0;
end
5,6,7,8,9,10,11:sta_bit <= sta_bit + uart_rx;
21,22,23,24,25,26,27: r_data[0] <= r_data[0] + uart_rx;
37,38,39,40,41,42,43: r_data[1] <= r_data[1] + uart_rx;
53,54,55,56,57,58,59: r_data[2] <= r_data[2] + uart_rx;
69,70,71,72,73,74,75: r_data[3] <= r_data[3] + uart_rx;
85,86,87,88,89,90,91: r_data[4] <= r_data[4] + uart_rx;
101,102,103,104,105,106,107: r_data[5] <= r_data[5] + uart_rx;
117,118,119,120,121,122,123: r_data[6] <= r_data[6] + uart_rx;
133,134,135,136,137,138,139: r_data[7] <= r_data[7] + uart_rx;
149,150,151,152,153,154,155: sto_bit <= sto_bit + uart_rx;
default:;
endcase
end
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Data <= 0;
else if(bps_clk_16x && (bps_cnt == 159))begin
Data[0] <= (r_data[0] >= 4)?1'b1:1'b0;
Data[1] <= (r_data[1] >= 4)?1'b1:1'b0;
Data[2] <= (r_data[2] >= 4)?1'b1:1'b0;
Data[3] <= (r_data[3] >= 4)?1'b1:1'b0;
Data[4] <= (r_data[4] >= 4)?1'b1:1'b0;
Data[5] <= (r_data[5] >= 4)?1'b1:1'b0;
Data[6] <= (r_data[6] >= 4)?1'b1:1'b0;
Data[7] <= (r_data[7] >= 4)?1'b1:1'b0;
end
三、完整代码展示
module uart_byte_rx(
Clk,
Reset_n,
Baud_Set,
uart_rx,
Data,
Rx_Done,
);
input Clk;
input Reset_n;
input [2:0]Baud_Set;
input uart_rx;
output reg[7:0]Data;
output reg Rx_Done;
reg [1:0]uart_rx_r;
always@(posedge Clk)begin
uart_rx_r[0] <= uart_rx;
uart_rx_r[1] <= uart_rx_r[0] ;
end
wire pedge_uart_rx;
// assign pedge_uart_rx = ((uart_rx_r[1] == 0) && (uart_rx_r[0] == 1));
assign pedge_uart_rx = (uart_rx_r == 2'b01);
wire nedge_uart_rx;
// assign nedge_uart_rx = ((uart_rx_r[1] == 1) && (uart_rx_r[0] == 0));
assign nedge_uart_rx = (uart_rx_r == 2'b10); //下降沿检测
reg [8:0] Bps_DR; //波特率设置
always@(*)
case(Baud_Set)
0:Bps_DR = 1000000000/9600/16/20 - 1;
1:Bps_DR = 1000000000/19200/16/20 - 1;
2:Bps_DR = 1000000000/38400/16/20 - 1;
3:Bps_DR = 1000000000/57600/16/20 - 1;
4:Bps_DR = 1000000000/115200/16/20 - 1;
default:Bps_DR = 1000000000/9600/16/20 - 1;
endcase
wire bps_clk_16x; //取每个信号的中点值
assign bps_clk_16x = (div_cnt == Bps_DR / 2);
reg RX_EN;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
RX_EN <= 0;
else if(nedge_uart_rx)
RX_EN <= 1;
else if(Rx_Done || (sta_bit >= 4))
RX_EN <= 0;
reg [8:0]div_cnt;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
div_cnt <= 0;
else if(RX_EN)begin
if(div_cnt == Bps_DR)
div_cnt <= 0;
else
div_cnt <= div_cnt + 1'b1;
end
else
div_cnt <= 0;
reg [7:0]bps_cnt;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
bps_cnt <= 0;
else if(RX_EN)begin
if(bps_clk_16x)begin
if(bps_cnt == 160)
bps_cnt <= 0;
else
bps_cnt <= bps_cnt + 1'b1;
end
else
bps_cnt <= bps_cnt;
end
else
bps_cnt <= 0;
//reg width name number/depth
reg[2:0]r_data[7:0];
reg [2:0]sta_bit;
reg [2:0]sto_bit;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n) begin
sta_bit <= 0;
sto_bit <= 0;
r_data[0] <= 0;
r_data[1] <= 0;
r_data[2] <= 0;
r_data[3] <= 0;
r_data[4] <= 0;
r_data[5] <= 0;
r_data[6] <= 0;
r_data[7] <= 0;
end
else if(bps_clk_16x)begin
case(bps_cnt)
0:begin
sta_bit <= 0;
sto_bit <= 0;
r_data[0] <= 0;
r_data[1] <= 0;
r_data[2] <= 0;
r_data[3] <= 0;
r_data[4] <= 0;
r_data[5] <= 0;
r_data[6] <= 0;
r_data[7] <= 0;
end
5,6,7,8,9,10,11:sta_bit <= sta_bit + uart_rx;
21,22,23,24,25,26,27: r_data[0] <= r_data[0] + uart_rx;
37,38,39,40,41,42,43: r_data[1] <= r_data[1] + uart_rx;
53,54,55,56,57,58,59: r_data[2] <= r_data[2] + uart_rx;
69,70,71,72,73,74,75: r_data[3] <= r_data[3] + uart_rx;
85,86,87,88,89,90,91: r_data[4] <= r_data[4] + uart_rx;
101,102,103,104,105,106,107: r_data[5] <= r_data[5] + uart_rx;
117,118,119,120,121,122,123: r_data[6] <= r_data[6] + uart_rx;
133,134,135,136,137,138,139: r_data[7] <= r_data[7] + uart_rx;
149,150,151,152,153,154,155: sto_bit <= sto_bit + uart_rx;
default:;
endcase
end
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Data <= 0;
else if(bps_clk_16x && (bps_cnt == 159))begin
Data[0] <= (r_data[0] >= 4)?1'b1:1'b0;
Data[1] <= (r_data[1] >= 4)?1'b1:1'b0;
Data[2] <= (r_data[2] >= 4)?1'b1:1'b0;
Data[3] <= (r_data[3] >= 4)?1'b1:1'b0;
Data[4] <= (r_data[4] >= 4)?1'b1:1'b0;
Data[5] <= (r_data[5] >= 4)?1'b1:1'b0;
Data[6] <= (r_data[6] >= 4)?1'b1:1'b0;
Data[7] <= (r_data[7] >= 4)?1'b1:1'b0;
end
// always@(posedge Clk or negedge Reset_n)
// if(!Reset_n)
// Data <= 0;
// else if(bps_clk_16x && (bps_cnt == 159))begin
// Data[0] <= r_data[0][2];
// Data[1] <= r_data[1][2];
// Data[2] <= r_data[2][2];
// Data[3] <= r_data[3][2];
// Data[4] <= r_data[4][2];
// Data[5] <= r_data[5][2];
// Data[6] <= r_data[6][2];
// Data[7] <= r_data[7][2];
// end
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Rx_Done <= 0;
else if((div_cnt == Bps_DR/2) && (bps_cnt == 160))
Rx_Done <= 1;
else
Rx_Done <= 0;
endmodule
四、TB文件
`timescale 1ns / 1ps
module uart_byte_rx_tb();
reg Clk;
reg Reset_n;
wire [2:0]Baud_Set;
reg uart_rx;
wire [7:0]Data;
wire Rx_Done;
assign Baud_Set = 4;
uart_byte_rx uart_byte_rx(
Clk,
Reset_n,
Baud_Set,
uart_rx,
Data,
Rx_Done,
);
initial Clk = 1;
always#10 Clk = ~Clk;
initial begin
Reset_n = 0;
uart_rx = 1;
#201;
Reset_n = 1;
#200;
uart_tx_byte(8'h5a);
#90000;
uart_tx_byte(8'ha5);
#90000;
uart_tx_byte(8'h86);
#90000;
$stop;
end
task uart_tx_byte;
input [7:0]tx_data;
begin
uart_rx = 1;
#20;
uart_rx = 0;
#8680;
uart_rx = tx_data[0];
#8680;
uart_rx = tx_data[1];
#8680;
uart_rx = tx_data[2];
#8680;
uart_rx = tx_data[3];
#8680;
uart_rx = tx_data[4];
#8680;
uart_rx = tx_data[5];
#8680;
uart_rx = tx_data[6];
#8680;
uart_rx = tx_data[7];
#8680;
uart_rx = 1;
#8680;
end
endtask
endmodule
五、仿真展示
【附件:】链接:https://pan.baidu.com/s/1UcO93C8R2Ab3M9OTqssEKw?pwd=84i9
提取码:84i9