欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-06-23 17:19:45
...

我的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学习笔记--串口接收模块
串口时序如图,包括一个起始位,8个数据位和1个停止位,期中起始位为0,停止位为1,中间的八个位为数据位,期中低拉在前,高位在后。
计数时间说明:
波特率指的是1s内发送接收了多少比特的数据,若波特率为9600b/s,则1s可以传输9600bit,那么传输1bit的时间为:1/9600 s。
输出说明:
我的FPGA学习笔记--串口接收模块
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学习笔记--串口接收模块
2020/1/19学习笔记