FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
登录
首页-技术文章/快讯-技术分享-正文

FPGA实战指南:基于UART的通信协议设计与实现

二牛学FPGA二牛学FPGA
技术分享
1小时前
0
0
3

Quick Start

  • 步骤一:搭建开发环境。安装Vivado(推荐2020.1及以上版本)并确保板卡驱动正常。
  • 步骤二:新建Vivado工程,选择目标器件(如Xilinx Artix-7 XC7A35T)。
  • 步骤三:创建顶层模块,例化UART收发器IP(或自行编写RTL)。
  • 步骤四:编写UART发送模块(tx),支持8位数据、1位停止位、无校验。
  • 步骤五:编写UART接收模块(rx),同步采样并恢复数据。
  • 步骤六:连接顶层模块,将发送与接收对接,形成回环测试。
  • 步骤七:编写testbench仿真,验证发送与接收波形正确。
  • 步骤八:综合、实现并生成比特流,下载到FPGA板卡。
  • 步骤九:使用串口调试助手(如Putty)发送0x55,观察回显数据是否一致。
  • 步骤十:验收:发送0x00~0xFF所有字节,回显无误即为成功。

前置条件与环境

项目推荐值说明替代方案
器件/板卡Xilinx Artix-7 XC7A35T(如Nexys A7)低成本、资源充足,适合UART实验Intel Cyclone IV / Lattice iCE40
EDA版本Vivado 2020.1稳定,支持IP集成Vivado 2019.1 / 2022.1
仿真器Vivado Simulator内置于Vivado,无需额外安装ModelSim / Questa
时钟/复位50MHz系统时钟,低电平异步复位板载晶振,复位按键100MHz时钟(需调整波特率分频)
接口依赖USB-UART(FT232)板载或外接,用于PC通信RS232电平转换器
约束文件XDC约束:时钟周期、引脚分配必须指定UART TX/RX引脚自动引脚分配(仅仿真)

目标与验收标准

  • 功能点:实现UART发送与接收,支持波特率9600/115200可配,8位数据、1位停止位、无校验。
  • 性能指标:发送与接收无误码率,连续传输1000字节无丢包。
  • 资源占用:LUT ≤ 200,FF ≤ 150,BRAM 0(纯逻辑实现)。
  • Fmax:≥ 200MHz(基于Artix-7速度等级-1)。
  • 验收方式:上板后,串口调试助手发送0x55,回显0x55;发送0x00~0xFF循环,回显一致。

实施步骤

工程结构

project/
├── src/
│   ├── uart_top.v        // 顶层模块(例化tx和rx)
│   ├── uart_tx.v         // 发送模块
│   ├── uart_rx.v         // 接收模块
│   └── baud_gen.v        // 波特率发生器
├── sim/
│   └── tb_uart.v         // 测试平台
├── constr/
│   └── uart.xdc          // 时序与引脚约束
└── ip/                   // 可选IP(如FIFO)

关键模块:波特率发生器

波特率发生器是一个计数器,根据系统时钟和波特率计算分频值。例如,50MHz时钟,波特率115200时,分频系数 = 50_000_000 / 115200 ≈ 434。实际使用中需考虑采样点位置,通常使用16倍过采样(即分频系数 = 时钟频率 / (波特率 × 16))。

// baud_gen.v
module baud_gen #(
    parameter CLK_FREQ = 50_000_000,
    parameter BAUD_RATE = 115200
)(
    input wire clk,
    input wire rst_n,
    output reg baud_tick  // 每个数据位宽度内产生16个脉冲
);

localparam DIV = CLK_FREQ / (BAUD_RATE * 16);
reg [15:0] cnt;

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt <= 0;
        baud_tick <= 0;
    end else if (cnt < DIV - 1) begin
        cnt <= cnt + 1;
        baud_tick <= 0;
    end else begin
        cnt <= 0;
        baud_tick <= 1;
    end
end

endmodule

关键模块:UART发送模块

UART发送模块负责将并行数据转换为串行比特流,并按照起始位、数据位、停止位的格式输出。核心机制:当检测到发送使能信号时,模块拉低TX线作为起始位,随后依次输出8位数据(LSB first),最后拉高TX线作为停止位。每次状态切换由波特率时钟(baud_tick)同步。

// uart_tx.v
module uart_tx #(
    parameter DATA_BITS = 8,
    parameter STOP_BITS = 1
)(
    input wire clk,
    input wire rst_n,
    input wire [DATA_BITS-1:0] data_in,
    input wire tx_start,
    output reg tx,
    output reg tx_busy
);

localparam IDLE = 0, START = 1, DATA = 2, STOP = 3;
reg [1:0] state;
reg [3:0] bit_cnt;

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        state <= IDLE;
        tx <= 1;
        tx_busy <= 0;
        bit_cnt <= 0;
    end else case (state)
        IDLE: begin
            tx <= 1;
            tx_busy <= 0;
            if (tx_start) begin
                state <= START;
                tx_busy <= 1;
            end
        end
        START: begin
            tx <= 0;
            state <= DATA;
            bit_cnt <= 0;
        end
        DATA: begin
            tx <= data_in[bit_cnt];
            if (bit_cnt == DATA_BITS-1) begin
                state <= STOP;
            end else begin
                bit_cnt <= bit_cnt + 1;
            end
        end
        STOP: begin
            tx <= 1;
            state <= IDLE;
            tx_busy <= 0;
        end
    endcase
end

endmodule

关键模块:UART接收模块

UART接收模块通过过采样(16倍)检测起始位下降沿,并在数据位中点采样以恢复数据。核心机制:空闲时RX线为高,检测到下降沿后启动接收状态机,在每个数据位的中间点(第8个baud_tick脉冲)采样RX值,最终组合成并行数据输出。

// uart_rx.v
module uart_rx #(
    parameter DATA_BITS = 8,
    parameter STOP_BITS = 1
)(
    input wire clk,
    input wire rst_n,
    input wire rx,
    output reg [DATA_BITS-1:0] data_out,
    output reg data_valid
);

localparam IDLE = 0, START = 1, DATA = 2, STOP = 3;
reg [1:0] state;
reg [3:0] bit_cnt;
reg [3:0] sample_cnt;

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        state <= IDLE;
        data_out <= 0;
        data_valid <= 0;
        bit_cnt <= 0;
        sample_cnt <= 0;
    end else case (state)
        IDLE: begin
            data_valid <= 0;
            if (rx == 0) begin
                state <= START;
                sample_cnt <= 0;
            end
        end
        START: begin
            if (sample_cnt == 7) begin  // 采样中点
                state <= DATA;
                bit_cnt <= 0;
                sample_cnt <= 0;
            end else begin
                sample_cnt <= sample_cnt + 1;
            end
        end
        DATA: begin
            if (sample_cnt == 15) begin
                data_out[bit_cnt] <= rx;
                if (bit_cnt == DATA_BITS-1) begin
                    state <= STOP;
                    sample_cnt <= 0;
                end else begin
                    bit_cnt <= bit_cnt + 1;
                    sample_cnt <= 0;
                end
            end else begin
                sample_cnt <= sample_cnt + 1;
            end
        end
        STOP: begin
            if (sample_cnt == 15) begin
                state <= IDLE;
                data_valid <= 1;
            end else begin
                sample_cnt <= sample_cnt + 1;
            end
        end
    endcase
end

endmodule

顶层模块与回环测试

顶层模块例化发送和接收模块,并将接收到的数据直接反馈到发送输入端,形成回环。这样,PC发送的字节会立即被回显,便于验证通信链路完整性。

// uart_top.v
module uart_top (
    input wire clk,
    input wire rst_n,
    input wire rx,
    output wire tx
);

wire [7:0] rx_data;
wire rx_valid;
wire tx_busy;
reg [7:0] tx_data;
reg tx_start;

uart_rx u_rx (
    .clk(clk),
    .rst_n(rst_n),
    .rx(rx),
    .data_out(rx_data),
    .data_valid(rx_valid)
);

uart_tx u_tx (
    .clk(clk),
    .rst_n(rst_n),
    .data_in(tx_data),
    .tx_start(tx_start),
    .tx(tx),
    .tx_busy(tx_busy)
);

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        tx_data <= 0;
        tx_start <= 0;
    end else if (rx_valid && !tx_busy) begin
        tx_data <= rx_data;
        tx_start <= 1;
    end else begin
        tx_start <= 0;
    end
end

endmodule

验证结果

仿真波形应显示:发送模块在tx_start脉冲后依次输出起始位(低)、8位数据(LSB first)、停止位(高);接收模块在检测到起始位后,在每个数据位中点采样,输出并行数据并置位data_valid。上板测试时,串口调试助手发送0x55(二进制01010101),应回显相同字节。连续发送0x00~0xFF循环,回显一致即表示验证通过。

排障指南

  • 问题:回显数据错误或乱码。原因:波特率不匹配或时钟分频计算错误。解决:核对分频系数,确保PC端波特率与FPGA一致。
  • 问题:无回显。原因:引脚约束错误或硬件连接问题。解决:检查XDC文件中TX/RX引脚分配,确认USB-UART驱动正常。
  • 问题:仿真波形异常。原因:状态机逻辑错误或复位时序问题。解决:检查状态转移条件,确保复位信号低电平有效。

扩展建议

  • 增加FIFO缓冲:使用Block RAM实现FIFO,支持连续数据流传输,避免数据丢失。
  • 支持多波特率:通过寄存器配置分频系数,实现运行时切换波特率。
  • 集成CRC校验:在数据包末尾添加CRC字段,增强通信可靠性。

参考

  • Xilinx UG949:Vivado Design Suite用户指南
  • UART协议标准:EIA RS-232规范
  • FPGA设计实战:UART通信模块实现(相关技术博客)

附录

附录A:完整工程代码包(含约束文件、测试平台)可在项目仓库获取。附录B:常见问题FAQ持续更新中。

标签:
本文原创,作者:二牛学FPGA,其版权均为FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训所有。
如需转载,请注明出处:https://z.shaonianxue.cn/39229.html
二牛学FPGA

二牛学FPGA

初级工程师
这家伙真懒,几个字都不愿写!
79618.18W3.96W3.67W
分享:
成电国芯FPGA赛事课即将上线
跨时钟域同步:FIFO深度计算与设计案例
跨时钟域同步:FIFO深度计算与设计案例上一篇
基于UART的通信协议实现:FPGA实战指南下一篇
基于UART的通信协议实现:FPGA实战指南
相关文章
总数:822
基于FPGA的实时目标检测系统设计:从算法到硬件实现的实践指南

基于FPGA的实时目标检测系统设计:从算法到硬件实现的实践指南

QuickStart(快速上手)本指南面向具备FPGA基础开发经验、希…
技术分享
4天前
0
0
18
0
Verilog中函数与任务的使用:代码复用与仿真加速

Verilog中函数与任务的使用:代码复用与仿真加速

QuickStart步骤1:在工程目录下新建utils.v文件,…
技术分享
2天前
0
0
13
0
FPGA基础及CPLD与FPGA核心差异解析

FPGA基础及CPLD与FPGA核心差异解析

一、FPGA是什么FPGA是可编程逻辑门阵列(Field-Pro…
技术分享, 行业资讯
3个月前
0
0
172
0
评论表单游客 您好,欢迎参与讨论。
加载中…
评论列表
总数:0
FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
没有相关内容