FPGA实战:用状态机搞定115200bps的UART通信(含奇校验完整代码)

发布时间:2026/6/8 12:25:24

FPGA实战:用状态机搞定115200bps的UART通信(含奇校验完整代码) FPGA状态机实战115200bps UART通信与奇校验实现精要在嵌入式系统和硬件加速领域UART通信作为最基础的串行通信协议之一其FPGA实现方案一直是工程师的必备技能。本文将深入探讨如何利用状态机设计实现115200bps高速UART通信模块并完整集成奇校验功能。不同于简单的代码展示我们将从工程实践角度剖析状态机设计的核心思维模式帮助FPGA开发者建立系统级的通信模块设计能力。1. UART通信协议与状态机设计基础UARTUniversal Asynchronous Receiver/Transmitter作为一种异步串行通信协议其核心特征是不需要时钟信号线仅通过两根数据线TX和RX即可实现全双工通信。在115200bps的高波特率下每个bit仅持续约8.68μs这对FPGA的时序控制提出了精确要求。经典UART帧结构包含以下几个关键部分起始位1bit低电平标志传输开始数据位通常8bit也可配置为5-9bit从LSB开始传输校验位1bit用于简单的错误检测本文采用奇校验停止位1bit高电平标志传输结束状态机Finite State MachineFSM是FPGA设计中的核心范式特别适合处理UART这类具有明确阶段特征的协议。一个健壮的UART状态机应包含以下基本状态状态功能描述关键判断条件IDLE等待起始位检测RX线下降沿START确认起始位波特率计数器满DATA接收/发送数据位位计数器控制PARITY处理校验位奇偶校验计算STOP确认停止位检测RX线上升沿提示在115200bps高速通信时建议在状态转换中加入半周期采样策略即在每个bit周期的中间点进行数据采样以提高抗干扰能力。2. 接收模块的深度实现接收模块的核心任务是将串行数据流转换为并行数据同时完成时序同步和错误检测。我们采用三段式状态机状态寄存器、次态逻辑、输出逻辑分离实现这一过程确保代码清晰且易于维护。2.1 精确的时钟域处理在50MHz系统时钟下115200bps对应的每个bit周期为434个时钟周期。我们需要构建精确的波特率生成系统parameter CLK_FREQ 50_000_000; parameter BAUD 115200; localparam BAUD_CNT_MAX CLK_FREQ / BAUD; reg [9:0] baud_cnt; wire baud_max (baud_cnt BAUD_CNT_MAX - 1); always (posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) baud_cnt 0; else if(state ! IDLE baud_cnt BAUD_CNT_MAX-1) baud_cnt baud_cnt 1; else baud_cnt 0; end亚稳态处理是接收模块的关键挑战。我们采用三级寄存器链对异步输入信号进行同步reg in_data_reg, in_data_reg1, in_data_reg2; always (posedge sys_clk) begin in_data_reg in_data; in_data_reg1 in_data_reg; in_data_reg2 in_data_reg1; end2.2 奇校验的硬件实现奇校验要求数据位和校验位中1的总数为奇数。在Verilog中可以通过缩减异或运算高效实现wire parity_check ^po_data; // 缩减异或得到偶校验位 wire parity_ok (parity_check ^ in_data_reg2); // 与接收的校验位比较校验时序需要特别注意应当在第9个数据位bit_cnt8且波特率计数器满baud_max时进行校验判断。状态转换逻辑中需要加入校验结果判断always (*) begin case(state) // ...其他状态... DATA: next_state (bit_done baud_max) ? (parity_ok ? PARITY : WAIT) : DATA; PARITY: next_state baud_max ? (stop ? STOP : WAIT) : PARITY; // ...其他状态... endcase end2.3 数据采样与输出策略中点采样技术能显著提高接收稳定性。我们在波特率计数器达到半周期时baud_cntBAUD_CNT_MAX/2采样数据wire sample_point (baud_cnt BAUD_CNT_MAX/2); always (posedge sys_clk) begin if(sample_point state DATA) po_data {in_data_reg2, po_data[7:1]}; // 右移拼接 end数据有效信号po_flag应当在成功通过所有校验包括停止位验证后置位且仅持续一个时钟周期assign po_flag (state STOP baud_max);3. 发送模块的优化设计发送模块需要将并行数据转换为符合UART协议的串行数据流。与接收模块相比其状态机设计更注重输出时序的精确控制。3.1 状态机与数据输出的协同发送状态机省略了WAIT状态但增加了输出数据的组合逻辑always (*) begin case(state) START: out_data 1b0; DATA: out_data pi_data[bit_cnt - 1]; PARITY: out_data ~(^pi_data); STOP: out_data 1b1; default: out_data 1b1; endcase end关键时序点起始位强制拉低1个完整波特率周期数据位按照bit_cnt依次输出pi_data的各个位校验位动态计算奇校验位并输出停止位强制拉高至少1个完整波特率周期3.2 波特率同步与流控制发送模块需要严格遵循115200bps的时序要求。我们使用与接收模块相同的波特率生成逻辑但加入发送使能信号pi_flag的同步处理reg pi_flag_sync; always (posedge sys_clk) begin pi_flag_sync pi_flag; end wire start_trans pi_flag !pi_flag_sync; // 检测上升沿这种边沿检测技术确保每个数据包只触发一次发送过程避免重复发送。4. 系统集成与实战验证将收发模块集成形成完整UART系统时需要特别注意信号互联和测试策略。4.1 顶层模块设计顶层模块应当清晰体现数据流向并预留调试接口module uart_top( input sys_clk, input sys_rst_n, input rx, output tx, output [7:0] debug_data, output debug_valid ); uart_rx_fsm rx_inst( .sys_clk(sys_clk), .sys_rst_n(sys_rst_n), .in_data(rx), .po_data(debug_data), .po_flag(debug_valid) ); uart_tx_fsm tx_inst( .sys_clk(sys_clk), .sys_rst_n(sys_rst_n), .pi_data(debug_data), .pi_flag(debug_valid), .out_data(tx) ); endmodule4.2 功能验证方法针对115200bps高速通信推荐采用以下验证策略回环测试将TX直接连接RX自发自收边界测试发送0x5501010101和0xAA10101010等交替模式压力测试连续发送256个不同字节验证无误码时序验证用逻辑分析仪检查信号时序是否符合115200bps标准常见问题排查表现象可能原因解决方案数据错位波特率不匹配检查时钟频率和分频系数偶发误码亚稳态问题增加同步寄存器级数校验失败采样点偏移调整中点采样位置丢失起始位毛刺干扰添加起始位滤波逻辑在Xilinx Artix-7平台上实测本设计可实现稳定115200bps通信资源占用情况如下LUT约230个寄存器约180个最大频率超过100MHz5. 高级优化技巧对于需要更高性能或更复杂功能的场景可以考虑以下进阶优化时钟恢复技术在高速通信中如1Mbps以上使用过采样和数字锁相环DPLL技术补偿时钟偏差。// 16倍过采样示例 reg [3:0] oversample_cnt; always (posedge sys_clk) begin if(oversample_cnt 15) oversample_cnt 0; else oversample_cnt oversample_cnt 1; end wire sample_enable (oversample_cnt 8); // 在中间点采样错误检测增强增加帧错误FE标志检测无效停止位增加溢出错误OE标志检测新数据覆盖未读取数据添加硬件流控制RTS/CTS信号DMA集成对于大数据量传输可通过AXI Stream接口连接DMA控制器减轻CPU负担axis_fifo #( .DEPTH(256) ) rx_fifo ( .clk(sys_clk), .rst(!sys_rst_n), .s_tdata(po_data), .s_tvalid(po_flag), .s_tready(), .m_tdata(dma_data), .m_tvalid(dma_valid), .m_tready(dma_ready) );在工程实践中我们发现状态机的可配置性非常重要。通过参数化设计可以轻松支持多种波特率和数据格式module uart_rx_fsm #( parameter BAUD 115200, parameter DATA_BITS 8, parameter PARITY_EN 1 )( // 端口定义... );这种设计允许通过简单修改参数即可支持从9600bps到3Mbps的各种波特率以及5-9位数据位配置大大提升了代码的复用价值。

相关新闻