FPGA即插即用Verilog驱动系列——UART串口接收

发布于:2025-08-16 ⋅ 阅读:(23) ⋅ 点赞:(0)

实现功能:

  1. FPGA实现串口接收,波特率可修改
  2. 按字节接收,有完成标志位输出
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
//
//                      模块 1: UART 字节接收器 (修正版)
//
// 文件名: Uart_Rec.v
// 描述:
//   - 用户提供的UART接收模块。
//   - **FIXED**: 将系统时钟参数 CLK_FREQ 修改为 50MHz,以匹配顶层设计,
//     确保波特率计算正确。
//
//////////////////////////////////////////////////////////////////////////////////
module Uart_Rec(
    input                 sys_clk,     //系统时钟
    input                 sys_rst_n,   //系统复位,低电平有效
    
    input                 uart_rxd,    //UART接收端口
    output reg            uart_done,   //接收一帧数据完成标志
    output reg [7:0]      uart_data    //接收的数据
);
    
    //parameter define
    parameter  CLK_FREQ = 50000000; // **FIXED**: 系统时钟频率为50MHz
    parameter  UART_BPS = 115200;   // 串口波特率
    localparam BPS_CNT  = CLK_FREQ/UART_BPS; // 计算每个比特位的时钟周期数

    //reg define
    reg        uart_rxd_d0;
    reg        uart_rxd_d1;
    reg [15:0] clk_cnt;
    reg [3:0]  rx_cnt;
    reg [7:0]  rxdata;
    reg        rx_flag;

    //wire define
    wire       start_flag;

    assign start_flag = uart_rxd_d1 & (~uart_rxd_d0);

    always @(posedge sys_clk or negedge sys_rst_n) begin
        if (!sys_rst_n) begin
            uart_rxd_d0 <= 1'b1;
            uart_rxd_d1 <= 1'b1;
        end
        else begin
            uart_rxd_d0 <= uart_rxd;
            uart_rxd_d1 <= uart_rxd_d0;
        end
    end

    always @(posedge sys_clk or negedge sys_rst_n) begin
        if (!sys_rst_n)
            rx_flag <= 1'b0;
        else begin
            if(start_flag)
                rx_flag <= 1'b1;
            else if((rx_cnt == 4'd9) && (clk_cnt == BPS_CNT/2))
                rx_flag <= 1'b0;
        end
    end

    always @(posedge sys_clk or negedge sys_rst_n) begin
        if (!sys_rst_n)
            clk_cnt <= 16'd0;
        else if (rx_flag) begin
            if (clk_cnt < BPS_CNT - 1)
                clk_cnt <= clk_cnt + 1'b1;
            else
                clk_cnt <= 16'd0;
        end
        else
            clk_cnt <= 16'd0;
    end

    always @(posedge sys_clk or negedge sys_rst_n) begin
        if (!sys_rst_n)
            rx_cnt  <= 4'd0;
        else if (rx_flag) begin
            if (clk_cnt == BPS_CNT - 1)
                rx_cnt <= rx_cnt + 1'b1;
        end
        else
            rx_cnt  <= 4'd0;
    end

    always @(posedge sys_clk or negedge sys_rst_n) begin
        if (!sys_rst_n)
            rxdata <= 8'd0;
        else if(rx_flag)
            if (clk_cnt == BPS_CNT/2) begin
                case (rx_cnt)
                    4'd1 : rxdata[0] <= uart_rxd_d1;
                    4'd2 : rxdata[1] <= uart_rxd_d1;
                    4'd3 : rxdata[2] <= uart_rxd_d1;
                    4'd4 : rxdata[3] <= uart_rxd_d1;
                    4'd5 : rxdata[4] <= uart_rxd_d1;
                    4'd6 : rxdata[5] <= uart_rxd_d1;
                    4'd7 : rxdata[6] <= uart_rxd_d1;
                    4'd8 : rxdata[7] <= uart_rxd_d1;
                    default:;
                endcase
            end
    end

    always @(posedge sys_clk or negedge sys_rst_n) begin
        if (!sys_rst_n) begin
            uart_data <= 8'd0;
            uart_done <= 1'b0;
        end
        else if(rx_cnt == 4'd9 && clk_cnt == BPS_CNT/2) begin
            uart_data <= rxdata;
            uart_done <= 1'b1;
        end
        else begin
            uart_done <= 1'b0;
        end
    end
endmodule


网站公告

今日签到

点亮在社区的每一天
去签到