串口接收模块——verilog实现
1、设计想法
原理与之前的串口发送模块一样,1位的起始位和8位的数据位再加上1位的停止位。唯一不同的是在接收的时候要考虑到有干扰的情况下,为了避免干扰,我们对每位数据进行多次采样,按出现概率大的值为该数据位的值。
如果按照通常想法在每bits位中间取值的话,bit3位出现图中的干扰很有可能会读出错误的值。所以需要对每位进行多次抽样进行判断。
每位要抽8次的话,那需要将每个波特段分成9等分。
2、状态机设定
3、模块代码
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer: Lclone
//
// Create Date: 2022/12/16 15:37:44
// Design Name: uart_byte_rx
// Module Name: uart_byte_rx
// Project Name: uart_byte_rx
// Target Devices:
// Tool Versions:
// Description: 8位串口接收模块
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module uart_byte_rx
# (
parameter RX_BAUD = 9600, //波特率
parameter CLK_FQC = 50_000_000, //模块时钟频率
parameter BAUD_CNT = CLK_FQC/RX_BAUD) //模块每波特需要计数的次数(设置此端口方便仿真用)
(
input Clk, //时钟频率接口
input Rst_n, //复位接口
input Uart_rx, //串口接收接口
output reg [7:0] Data, //接收到的数据接口
output reg Rx_done //接收完成信号
);
reg uart_rx_r; //延一拍
reg uart_rx_rr; //延两拍
reg uart_rx_rrr; //延三拍,减少亚稳态出现的概率
reg receiv_begin; //接收开始信号
reg receiv_flag; //接收状态信号
reg [ 3:0] state; //状态机寄存器
reg [15:0] baud_cnt; //波及计数器
reg [ 3:0] sampel_cnt; //采样计数器
reg sampel_en; //采样使能
reg sampel_ref; //样本寄存器
reg [ 3:0] acc; //累加寄存器
reg [ 3:0] bit_cnt; //数据位寄存器
always @(posedge Clk) begin //延两拍为下降沿捕获
uart_rx_r <= Uart_rx;
uart_rx_rr <= uart_rx_r;
uart_rx_rrr <= uart_rx_rr;
end
always @(posedge Clk or negedge Rst_n) begin //接收信号发生
if(Rst_n == 0)
receiv_begin <= 0;
else if(state == 0 & uart_rx_rrr & ~uart_rx_rr)
receiv_begin <= 1'b1;
else
receiv_begin <= 0;
end
always @(posedge Clk or negedge Rst_n) begin //状态机
if(Rst_n == 0) begin
state <= 0;
sampel_ref <= 8'b0;
acc <= 8'b0;
Data <= 8'b0;
end
else case(state)
0: //空闲状态
if(receiv_begin == 1)
state <= 3'd1;
else
state <= 0;
1: begin //抽样状态
if(sampel_en == 1) begin
sampel_ref <= Uart_rx;
state <= 3'd2;
end
else
state <= 3'b1;
end
2: begin //数据判断状态
acc <= acc + sampel_ref;
if(sampel_cnt == 7) begin
if(acc >= 4)
begin Data[7] <= 1'b1; state <= 3'd3;acc <= 8'b0; end
else
begin Data[7] <= 0; state <= 3'd3;acc <= 8'b0; end
end
else
state <= 3'd1;
end
3: begin //数据移位状态
if(bit_cnt < 8) begin
Data <= Data >> 1;
state <= 3'd1;
end
else
state <= 0;
end
default:;
endcase
end
always @(posedge Clk or negedge Rst_n) begin //接收进行标志
if(Rst_n == 0)
receiv_flag <= 0;
else if(receiv_begin == 1)
receiv_flag <= 1'b1;
else if(bit_cnt == 9 & baud_cnt == BAUD_CNT/9*8) //这里设置为记到BAUD_CNT/9*8是为了让Rx_done信号提前一点产生,
receiv_flag <= 1'b0; //避免因为Rx_done出现过晚,导致错过下一个起始位的下降沿。
end //后面和其相同的条件判断,也是因为相同原因设置的。
always @(posedge Clk or negedge Rst_n) begin //波特计数
if(Rst_n == 0)
baud_cnt <= 0;
else if(receiv_flag == 1) begin
if(baud_cnt == BAUD_CNT - 1)
baud_cnt <= 0;
else
baud_cnt <= baud_cnt + 1'b1;
end
else
baud_cnt <= 0;
end
always @(posedge Clk or negedge Rst_n) begin //采样计数
if(Rst_n == 0) begin
sampel_cnt <= 0;
sampel_en <= 0;
end
else if(receiv_flag == 1) begin
case(baud_cnt)
BAUD_CNT/9*1-1 : begin sampel_cnt <= 0; sampel_en <=1; end
BAUD_CNT/9*2-1 : begin sampel_cnt <= 1; sampel_en <=1; end
BAUD_CNT/9*3-1 : begin sampel_cnt <= 2; sampel_en <=1; end
BAUD_CNT/9*4-1 : begin sampel_cnt <= 3; sampel_en <=1; end
BAUD_CNT/9*5-1 : begin sampel_cnt <= 4; sampel_en <=1; end
BAUD_CNT/9*6-1 : begin sampel_cnt <= 5; sampel_en <=1; end
BAUD_CNT/9*7-1 : begin sampel_cnt <= 6; sampel_en <=1; end
BAUD_CNT/9*8-1 : begin sampel_cnt <= 7; sampel_en <=1; end
BAUD_CNT/9*9-1 : sampel_cnt <= 0;
default:sampel_en <=0;
endcase
end
end
always @(posedge Clk or negedge Rst_n) begin //数据位计数
if(Rst_n == 0)
bit_cnt <= 0;
else if(bit_cnt == 9 & baud_cnt == BAUD_CNT/9*8)
bit_cnt <= 0;
else if(baud_cnt == BAUD_CNT - 1)
bit_cnt <= bit_cnt + 1'b1;
end
always @(posedge Clk or negedge Rst_n) begin //接收完成信号产生
if(Rst_n == 0)
Rx_done <= 0;
else if(bit_cnt == 9 & baud_cnt == BAUD_CNT/9*8)
Rx_done <= 1'b1;
else
Rx_done <= 0;
end
endmodule
4、仿真验证
(1)仿真激励文件
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2022/12/16 21:36:04
// Design Name:
// Module Name: uart_byte_rx_tb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module uart_byte_rx_tb();
reg CLK_50M;
reg RST_N;
wire [7:0] Data;
reg Uart_rx;
reg [7:0] test_data;
wire RX_DONE;
uart_byte_rx
# (
.RX_BAUD (9600),
.CLK_FQC (50_000_000),
.BAUD_CNT (50))
uart_byte_rx_inst
(
.Clk (CLK_50M),
.Rst_n (RST_N),
.Uart_rx (Uart_rx),
.Data (Data),
.Rx_done (Rx_done)
);
always #10 CLK_50M <= ~CLK_50M;
initial begin
CLK_50M <= 1'b0;
RST_N <= 1'b0;
Uart_rx <= 1'b1;
test_data <= 8'h0;
#100
RST_N <= 1'b1;
#20
test_data <= 8'haf;
#1000
Uart_rx <= 1'b0;
#1000
Uart_rx <= test_data[0];
#1000
Uart_rx <= test_data[1];
#1000
Uart_rx <= test_data[2];
#1000
Uart_rx <= test_data[3];
#1000
Uart_rx <= test_data[4];
#1000
Uart_rx <= test_data[5];
#1000
Uart_rx <= test_data[6];
#1000
Uart_rx <= test_data[7];
#1000
Uart_rx <= 1'b1;
test_data <= 8'h56;
#1000
Uart_rx <= 1'b0;
#1000
Uart_rx <= test_data[0];
#1000
Uart_rx <= test_data[1];
#1000
Uart_rx <= test_data[2];
#1000
Uart_rx <= test_data[3];
#1000
Uart_rx <= test_data[4];
#1000
Uart_rx <= test_data[5];
#1000
Uart_rx <= test_data[6];
#1000
Uart_rx <= test_data[7];
#1000
Uart_rx <= 1'b1;
#2000
$stop;
end
endmodule