FPGA Verilog串口控制器设计与实现

1. Verilog串口控制器设计背景与需求

在工业自动化和物联网设备中,串口通信因其简单可靠的特性,仍然是设备间数据交互的主流方式之一。我最近完成的一个工业传感器项目就遇到了这样的需求:需要在FPGA上实现一个稳定可靠的串口控制器,用于与上位机进行数据通信。经过多次迭代,最终设计出了一个无奇偶校验、支持115200bps波特率的通用串口控制器。

这个设计有几个关键特点:首先,它完全采用Verilog HDL实现,不依赖任何第三方IP核,具有很好的可移植性;其次,通过了-40℃到85℃的高低温测试,在恶劣环境下依然能稳定工作;最后,整个设计包含完整的仿真测试环境和实际硬件验证方案。

需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。

2. 串口控制器整体架构设计

2.1 系统框图与接口定义

整个串口控制器的架构可以分为三个主要模块:

  1. 波特率发生器:根据系统时钟和设定的波特率参数,生成符合时序要求的采样时钟
  2. 发送模块:实现并串转换,按照串口协议规范发送数据
  3. 接收模块:完成串并转换,正确采样和解析输入数据

接口信号定义如下:

verilog复制module uart_controller (
    input wire clk,        // 系统时钟(50MHz)
    input wire rst_n,      // 低电平复位
    input wire rx,         // 串行接收数据线
    output wire tx,        // 串行发送数据线
    input wire [7:0] din,  // 并行输入数据
    input wire wr,         // 写使能信号
    output wire [7:0] dout,// 并行输出数据
    output wire rx_ready,  // 接收数据就绪
    output wire tx_busy    // 发送忙标志
);

2.2 波特率计算与实现

对于50MHz的系统时钟,要实现115200bps的波特率,需要计算分频系数:

code复制分频系数 = 系统时钟频率 / (16 × 波特率) 
          = 50,000,000 / (16 × 115200) 
          ≈ 27.1267

实际实现时取整数值27,这样产生的实际波特率为:

code复制实际波特率 = 50,000,000 / (16 × 27) ≈ 115740bps

误差率为(115740-115200)/115200 ≈ 0.47%,在RS-232标准允许的范围内。

波特率生成器的Verilog实现:

verilog复制reg [15:0] baud_counter;
reg baud_tick;

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        baud_counter <= 0;
        baud_tick <= 0;
    end else begin
        if (baud_counter == 16'd26) begin
            baud_counter <= 0;
            baud_tick <= 1;
        end else begin
            baud_counter <= baud_counter + 1;
            baud_tick <= 0;
        end
    end
end

3. 发送模块详细实现

3.1 发送状态机设计

发送模块采用有限状态机(FSM)实现,包含以下状态:

  1. IDLE:空闲状态,等待发送请求
  2. START:发送起始位(0)
  3. DATA:依次发送8位数据
  4. STOP:发送停止位(1)
  5. CLEANUP:完成发送,返回空闲状态

状态转移图如下:

code复制        +-------+
        | IDLE  |
        +---+---+
            | wr有效
            v
        +-------+
        | START |
        +---+---+
            | 1个波特周期
            v
        +-------+
        | DATA  |---> 依次发送8位
        +---+---+
            | 最后1位完成
            v
        +-------+
        | STOP  |
        +---+---+
            | 1个波特周期
            v
        +-------+
        |CLEANUP|
        +---+---+
            |
            v
        返回IDLE

3.2 发送模块Verilog实现

verilog复制localparam [2:0]
    IDLE     = 3'b000,
    START    

内容推荐

已经到底了哦
已经到底了哦