Veloris.
返回索引
概念基础 2026-02-23

用 1 个 bit 检测传输错误——奇偶校验的原理与 Verilog 实现

5 分钟
1.7k words

用 1 个 bit 检测传输错误——奇偶校验的原理与 Verilog 实现

💡 你通过 UART 从传感器读数据,大部分时候数据正常,但偶尔会收到一个离谱的值——明明温度只有 25°C,却读到了 153°C。问题出在哪里?可能是传输过程中某一位数据被噪声翻转了。

怎么知道收到的数据有没有出错?最简单的方法就是奇偶校验(Parity Check)——只需要多传 1 个 bit,就能检测出任意单 bit 的错误。

这篇文章带你搞清楚:奇偶校验是怎么工作的、怎么用 Verilog 实现、以及什么时候该用更强的校验方案


1. 核心原理:数 1 的个数

奇偶校验的原理简单到只需一句话:发送端和接收端约定好”1 的个数应该是奇数还是偶数”,如果不对就说明数据出错了

1.1 偶校验(Even Parity)

约定:数据位 + 校验位中,1 的总个数为偶数

数据:1 0 1 1 0 0 1(7位,其中有 4 个 1,已经是偶数)
偶校验位 = 0
传输:1 0 1 1 0 0 1 [0]  ← 总共 4 个 1,偶数 ✓
数据:1 0 1 1 0 1 1(7位,其中有 5 个 1,是奇数)
偶校验位 = 1
传输:1 0 1 1 0 1 1 [1]  ← 总共 6 个 1,偶数 ✓

1.2 奇校验(Odd Parity)

约定:数据位 + 校验位中,1 的总个数为奇数。计算方式就是偶校验取反。

💬 你可能会问:奇校验和偶校验该用哪个?

两者的检错能力完全相同,选哪个主要看通信协议的规定。UART 默认常用偶校验,但实际中两者都有使用。有一个小优势:奇校验保证至少有 1 个 1,所以可以检测”全 0 数据”的传输故障(比如线断了)。


2. Verilog 实现:一行代码搞定

奇偶校验的 Verilog 实现非常优雅——异或运算天然就是在”数 1 的个数”

2.1 偶校验生成器

module even_parity_gen (
    input  wire [7:0] data_in,
    output wire       parity_out
);

// 所有位异或:1 的个数为奇数时结果为 1,为偶数时结果为 0
assign parity_out = ^data_in;

endmodule

为什么异或能实现奇偶校验? 因为异或运算的本质就是”模 2 加法”——多个 bit 异或的结果,就是这些 bit 中 1 的个数的奇偶性。1 的个数为奇数 → 结果为 1;1 的个数为偶数 → 结果为 0。

2.2 奇校验生成器

module odd_parity_gen (
    input  wire [7:0] data_in,
    output wire       parity_out
);

assign parity_out = ~(^data_in);  // 偶校验取反

endmodule

2.3 校验检测器

module parity_checker (
    input  wire [7:0] data_in,
    input  wire       parity_in,
    output wire       error        // 1 = 检测到错误
);

// 偶校验检测:数据+校验位全部异或,结果为 1 说明 1 的个数变成了奇数 → 出错
assign error = ^{data_in, parity_in};

endmodule

3. 实战:在 UART 发送模块中集成奇偶校验

光看生成器和检测器还不够——下面是一个在 UART 发送中集成偶校验的实际示例:

// UART 发送模块(含偶校验位)
// 帧结构:[起始位(0)] [8位数据] [校验位] [停止位(1)]
module uart_tx_with_parity (
    input  wire       clk,
    input  wire       rst,
    input  wire       tx_start,     // 发送触发
    input  wire [7:0] tx_data,      // 待发送数据
    output reg        tx_out,       // UART 输出
    output reg        tx_busy       // 发送忙标志
);

// 计算偶校验位
wire parity_bit = ^tx_data;

// 构造完整的发送帧:起始位 + 8位数据 + 校验位 + 停止位
reg [10:0] tx_frame;
reg [3:0]  bit_cnt;

always @(posedge clk) begin
    if (rst) begin
        tx_out  <= 1'b1;  // 空闲状态为高电平
        tx_busy <= 1'b0;
        bit_cnt <= 4'd0;
    end else if (tx_start && !tx_busy) begin
        // 装载发送帧
        tx_frame <= {1'b1, parity_bit, tx_data, 1'b0};  // 停止位 + 校验 + 数据 + 起始位
        tx_busy  <= 1'b1;
        bit_cnt  <= 4'd0;
    end else if (tx_busy) begin
        tx_out <= tx_frame[0];       // LSB first
        tx_frame <= {1'b1, tx_frame[10:1]};  // 右移
        bit_cnt <= bit_cnt + 1'b1;
        if (bit_cnt == 4'd10)        // 11位全部发完
            tx_busy <= 1'b0;
    end
end

endmodule

💡 工程师手记我在一个工业控制项目中用 UART 和温度传感器通信,一开始没有开启奇偶校验。大部分时候数据完全正常,但工厂现场电磁干扰很强,偶尔会收到明显错误的温度值。后来开启了 UART 的偶校验功能,在接收端检测到校验错误时丢弃该帧并请求重传,问题就解决了。虽然奇偶校验只能检测单 bit 错误,但在大多数低速串口场景中,同时出现 2 bit 错误的概率极低,够用了。

(建议替换为你自己的真实经历,读者会更有共鸣)


4. ★ 奇偶校验够用吗?——FPGA 常用校验方案对比

奇偶校验虽然简单,但它的局限性也很明显。下表帮你决定在不同场景下该用哪种校验方案:

方案能检测的错误能纠错吗开销适用场景
奇偶校验1 bit 错误不能极低(1 bit)UART、SPI、低速总线
CRC多 bit 错误、突发错误不能低(8-32 bit)以太网、USB、SD卡、PCIe
汉明码2 bit 错误(检测),1 bit(纠正)能纠 1 bit中等ECC 内存、NAND Flash
RS 码多符号错误能纠多符号光通信、卫星通信

选择原则:

  • 低速、低误码率场景 → 奇偶校验足够
  • 高速、高可靠性场景 → CRC 是最佳平衡
  • 需要纠错能力 → 汉明码 / ECC
  • 噪声极端恶劣(航天、深空通信)→ RS 码或 LDPC

💬 你可能会问:奇偶校验这么简单,为什么不直接用 CRC?

因为 CRC 的硬件实现需要移位寄存器和多项式除法,虽然也不复杂,但比一行异或运算还是大了不少。在一些资源极其紧张或速度要求极高的场景中(比如 FPGA 内部模块间的快速数据传递),奇偶校验的”几乎零开销”就是它的优势。


5. 总结

核心认知内容
原理通过约定 1 的个数奇偶性,用 1 bit 校验位检测单 bit 错误
Verilog 实现偶校验 = ^data,奇校验 = ~(^data),一行搞定
局限性只能检测奇数 bit 错误,无法纠错,无法检测偶数 bit 同时出错
适用场景低速串口通信(UART、SPI)、FPGA 内部低开销校验
更强方案CRC(检多 bit 错)→ 汉明码(能纠错)→ RS 码(纠多符号错)

系列回顾:

到这里,你已经学完了 FPGA 数字设计的 6 个基础专题:

  1. 组合逻辑 vs 时序逻辑
  2. 竞争与冒险
  3. 同步 vs 异步设计
  4. 亚稳态与跨时钟域
  5. 阻塞赋值 vs 非阻塞赋值
  6. 奇偶校验

这些是 FPGA 设计中最基础、最重要的概念。掌握了它们,你就有了扎实的理论基础,可以开始挑战更复杂的设计了——比如状态机设计、FIFO 架构、信号处理流水线等。


常见问题

💬 如果同时有 2 位出错,奇偶校验能检测到吗?

不能。2 位同时翻转后,1 的个数奇偶性不变,校验位仍然”正确”——这就是奇偶校验最大的盲区。好消息是,在大多数低误码率的通信场景中,同时出现 2 bit 错误的概率极低(概率大约是单 bit 错误概率的平方)。

💬 UART 的奇偶校验位是自动处理的还是需要手动实现?

取决于你的实现方式。如果你使用 FPGA 厂商提供的 UART IP 核,通常可以通过参数配置自动生成和检测校验位。如果你自己写 UART 模块,就需要手动在发送端生成校验位、在接收端检测校验位。

💬 奇偶校验在 FPGA 内部模块间通信中有用吗?

FPGA 内部的数据传输通常不会出现 bit 翻转(没有外部噪声),所以一般不需要校验。但在一些高可靠性场景中(如航天 FPGA),会对 BRAM 的存储内容加 ECC 保护,防止单粒子翻转(SEU)导致的数据错误。


参考资料

  1. Xilinx/AMD, UG953: Vivado Design Suite 7 Series FPGA and Zynq-7000 SoC Libraries Guide(XPM_MEMORY ECC 配置)
  2. IEEE 802.3: Ethernet Standard(CRC-32 校验)
  3. Richard Hamming, Error Detecting and Error Correcting Codes, Bell System Technical Journal, 1950

系列导航:本文是「FPGA 入门系列」第 17 篇。

如果这篇文章对你有帮助,欢迎点赞、收藏,也欢迎在评论区聊聊你在项目中用过的错误检测方案——奇偶校验、CRC 还是 ECC?

End of file.