我的FPGA学习笔记--串口接收模块

我的FPGA学习笔记–串口接收模块

1.模块接口信号

信号名 位宽 I/O 功能
clk 1 I 工作时钟,时钟频率为50M
rst_n 1 I 复位信号,低电平有效
din 1 I Uart 输入数据(RX)
dout 8 O 输出数据信号
dout_vld 1 O 数据有效指示信号,高电平有效

2.功能说明

该模块的功能:负责接收串口的数据,将串行数据转化为并行数据。串口波特率9600,无奇偶校验位。

串口时序说明:
我的FPGA学习笔记--串口接收模块_第1张图片
串口时序如图,包括一个起始位,8个数据位和1个停止位,期中起始位为0,停止位为1,中间的八个位为数据位,期中低拉在前,高位在后。
计数时间说明:
波特率指的是1s内发送接收了多少比特的数据,若波特率为9600b/s,则1s可以传输9600bit,那么传输1bit的时间为:1/9600 s。
输出说明:
我的FPGA学习笔记--串口接收模块_第2张图片
dout :din波形如上图所示,din的第一个下降沿表示开始传输数据,din依次为0、{1、0、1、1、0、1、1、0、}1,根据串口协议,当din输出停止位的同时,dout_vld= 1,且dout=8’b0110_1101(8’h6d) 。

3.verilog代码实现

module uart_rx(
    clk     ,
    rst_n   ,
    rx ,
    dout_vld  ,
    dout
);

input        clk     ;
input        rst_n   ;
input        rx      ;
output       dout_vld;
output[7:0]  dout    ;

reg          dout_vld;
reg   [7:0]  dout    ;

reg   [12:0] cnt0    ;
wire         add_cnt0;
wire         end_cnt0;
reg   [3:0]  cnt1    ;
wire         add_cnt1;
wire         end_cnt1;

reg          rx_ff0  ;
reg          rx_ff1  ;
reg          rx_ff2  ;
reg          flag_add;

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        cnt0 <= 0;
    end
    else if(add_cnt0)begin
        if(end_cnt0)
            cnt0 <= 0;
        else
            cnt0 <= cnt0 + 1;
    end
end

assign add_cnt0 = flag_add == 1;
assign end_cnt0 = add_cnt0 && cnt0== 5208-1;

always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        cnt1 <= 0;
    end
    else if(add_cnt1)begin
        if(end_cnt1)
            cnt1 <= 0;
        else
            cnt1 <= cnt1 + 1;
    end
end

assign add_cnt1 = end_cnt0;
assign end_cnt1 = add_cnt1 && cnt1== 9-1;

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        dout_vld <= 0;
    end
    else if(end_cnt1)begin
        dout_vld <= 1;
    end
    else begin
        dout_vld <= 0;
    end
end

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        dout <= 0;
    end
    else if(add_cnt0 && cnt0==2604-1 cnt1!=0) begin
        dout[cnt1-1] <= rx;
    end
end


always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        rx_ff0 <= 1;
        rx_ff1 <= 1;
        rx_ff2 <= 1;
    end
    else begin

        rx_ff0 <= rx;
        rx_ff1 <= rx_ff0;
        rx_ff2 <= rx_ff1;
    end
end


always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        flag_add <= 0;
    end
    else if(flag_add == 0 && rx_ff1==0 && rx_ff2==1)begin
        flag_add <= 1;
    end
    else if(end_cnt1)begin
        flag_add <= 0;
    end
end



4.注意事项

由于din是异步信号,按规范需要2拍才能保证正确接收。
因此增加如下代码:
我的FPGA学习笔记--串口接收模块_第3张图片
2020/1/19学习笔记

你可能感兴趣的:(FPGA学习笔记,fpga,串口通信,verilog)