二、数制与编码:从进制转换到机器码的硬件基石

在数字电路与计算机系统设计中,数制与编码是理解一切硬件行为的基础语言。无论是CPU内部的算术逻辑单元(ALU)执行加法运算,还是存储器中保存的指令与数据,亦或是传感器采集到的模拟信号经ADC转换后的数字量,最终都以二进制比特流的形式存在。本章将系统讲解二进制、八进制、十进制、十六进制之间的转换方法,深入剖析原码、反码、补码的数学本质与硬件实现逻辑,并介绍BCD码、格雷码等工程中广泛应用的编码方案。掌握这些内容,是后续学习组合逻辑电路、时序逻辑电路以及微处理器接口设计的必要前提。

数制与编码核心知识框架 数制转换 二进制 ↔ 八进制 (3位一组) 二进制 ↔ 十六进制 (4位一组) 十进制 → R进制: 除R取余 R进制 → 十进制: 按权展开 常用: 2/8/10/16进制 机器码表示 原码: 符号位+值 反码: 正同原, 负按位取反 补码: 反码+1 (硬件统一) 加减法统一用补码运算 n位补码范围: -2ⁿ⁻¹ ~ 2ⁿ⁻¹-1 常用编码 BCD码: 8421码 (十进制) 格雷码: 相邻码仅1位变化 ASCII码: 字符编码 奇偶校验码: 检错 应用: 编码器/传感器/通信 硬件工程应用映射 ALU运算单元 补码实现加减乘除 溢出判断: 双符号位 ADC/DAC接口 二进制补码输出 满量程对应关系 编码器/传感器 格雷码抗干扰 BCD码用于数码管 存储器/寄存器 地址译码与数据位宽 十六进制查看工具

2.1 数制转换:从二进制到十六进制的工程速算

2.1.1 核心原理:位置计数法与权值

任何R进制数均可表示为各位数字与其权值乘积之和。对于二进制(R=2),权值为2的幂次;十六进制(R=16)权值为16的幂次。硬件工程师之所以偏爱十六进制,是因为一位十六进制数恰好对应四位二进制数,可以极大缩短长二进制数的书写长度。例如32位地址总线用二进制表示需要32个字符,而用十六进制仅需8个字符。

2.1.2 转换方法与操作流程

  • 二进制转十六进制:以小数点为界,整数部分向左、小数部分向右,每4位一组,不足4位补0,每组用对应的十六进制字符(0-9, A-F)替换。
  • 十六进制转二进制:将每位十六进制数展开为4位二进制数,去掉整数部分最高位和小数部分最低位的多余0。
  • 十进制转二进制:整数部分采用“除2取余,逆序排列”;小数部分采用“乘2取整,顺序排列”。
  • 二进制转十进制:按权展开求和,例如 1011.01₂ = 1×2³ + 0×2² + 1×2¹ + 1×2⁰ + 0×2⁻¹ + 1×2⁻² = 11.25₁₀。
工程速算技巧:在调试寄存器或查看内存数据时,建议将二进制与十六进制的对应关系(0000-0, 0001-1, ..., 1111-F)熟记于心。对于8位数据,可直接将高4位和低4位分别转换为十六进制字符,例如 1010 1101₂ = 0xAD。

2.1.3 案例拆解:配置I2C设备地址

假设某传感器I2C从机地址由7位硬件引脚决定,引脚电平组合为 A2=1, A1=0, A0=1,加上固定的基地址 0x40(7位),则完整地址计算如下:

基地址: 100 0000 (0x40)
引脚位: 1 0 1
拼接:   100 0000 1 0 1 → 7位地址 = 1000 0010 1? 实际为 1000 0010 1 取前7位: 1000 0010 1 → 0x41? 重新计算:
7位地址 = 100 0000 (基) + (A2<<2 | A1<<1 | A0) = 0x40 + (1<<2 | 0<<1 | 1) = 0x40 + 5 = 0x45
写地址 = 0x45 << 1 = 0x8A, 读地址 = 0x8B

通过十六进制运算,工程师可以快速确定读写地址,避免逐位二进制转换的繁琐。

2.1.4 常见误区与总结

易错点:小数部分十进制转二进制时,若乘2后整数部分为1,应记录1并将小数部分清零继续;若小数部分始终不为0,则产生循环小数,需根据精度要求截断。例如 0.1₁₀ = 0.0001100110011...₂,在浮点表示中会引入舍入误差。
进制基数数码范围后缀典型应用
二进制20,1B数字电路内部信号
八进制80-7O/Q早期UNIX文件权限
十进制100-9D人机交互显示
十六进制160-9, A-FH/0x地址、寄存器、机器码

2.2 原码、反码与补码:有符号数的硬件实现

2.2.1 核心原理:符号的数字化表示

计算机硬件只能存储0和1,因此必须约定符号位的编码方式。原码是最直观的表示:最高位为符号位(0正1负),其余位为数值值。但原码存在两个问题:一是“正0”(0000)与“负0”(1000)表示冲突;二是加减法运算需要判断符号位,硬件电路复杂。反码通过将负数的数值位按位取反解决减法问题,但仍有双0问题。补码则彻底解决了这些问题:正数的补码等于原码,负数的补码等于反码加1。

2.2.2 补码的数学本质与运算规则

对于n位二进制补码,其数值范围是 -2ⁿ⁻¹ ~ 2ⁿ⁻¹-1。补码的模运算特性使得减法可以转化为加法:A - B = A + (-B的补码)。例如8位系统中计算 5 - 3:

5的补码: 0000 0101
-3的补码: 1111 1101 (3=0000 0011 → 取反1111 1100 → +1 → 1111 1101)
相加: 0000 0101 + 1111 1101 = 1 0000 0010 → 丢弃进位 → 0000 0010 = 2 ✓

硬件ALU只需一个加法器即可完成加减法,大幅简化电路设计。溢出判断可通过最高位进位与次高位进位的异或实现。

2.2.3 案例拆解:8位ADC采样值的符号处理

某温度传感器使用8位ADC,输出格式为二进制补码,满量程对应 -40℃ ~ +125℃。当ADC输出 0x80(即 1000 0000)时,其十进制值为 -128,对应最低温度 -40℃;输出 0x7F(0111 1111)时,值为 +127,对应 +125℃。实际温度计算公式为:

温度 = (ADC值 / 128) × 165 - 40
例如 ADC = 0x00 (0) → 温度 = 0 × 165/128 - 40 = -40℃
ADC = 0x40 (64) → 温度 = 64 × 165/128 - 40 = 82.5 - 40 = 42.5℃

工程师在固件中需先将读取的原始字节强制转换为 int8_t 类型,再进行上述线性换算,否则无符号数会导致负温度计算错误。

2.2.4 常见误区与总结

关键提醒:补码的符号位扩展规则——将8位补码扩展为16位时,正数在高位补0,负数在高位补1。例如 0x80(-128)扩展为16位应为 0xFF80,而非 0x0080。在C语言中,若将 char 赋值给 int,编译器会自动进行符号扩展。
编码方式+5表示-5表示0的表示运算复杂度
原码0000 01011000 01010000 0000 / 1000 0000需判断符号,复杂
反码0000 01011111 10100000 0000 / 1111 1111减法可转加法,仍有双0
补码0000 01011111 10110000 0000加减统一,硬件简单

2.3 BCD码与格雷码:面向显示与抗干扰的编码

2.3.1 BCD码:二进制编码的十进制数

BCD(Binary-Coded Decimal)码用4位二进制数表示1位十进制数,最常用的是8421 BCD码。例如十进制数 39 的BCD码为 0011 1001。BCD码的优点是便于人类阅读和十进制运算,常用于数码管显示、计算器、RTC时钟芯片等场景。但BCD码的存储效率低于纯二进制(4位BCD最大表示9,而4位二进制最大表示15),且运算时需要额外的十进制调整指令(如DAA)。

2.3.2 格雷码:相邻码仅一位变化的循环码

格雷码(Gray Code)的核心特征是任意两个相邻码字之间只有1位二进制位不同。这一特性使其在机械编码器、旋转位置传感器、异步FIFO指针、状态机设计中具有显著优势——当信号在相邻状态间切换时,不会出现多位同时跳变导致的毛刺或竞争冒险。4位格雷码序列为:0000, 0001, 0011, 0010, 0110, 0111, 0101, 0100, 1100, 1101, 1111, 1110, 1010, 1011, 1001, 1000。

2.3.3 案例拆解:旋转编码器的位置检测

工业伺服电机常使用增量式光电编码器,码盘上刻有格雷码图案。假设码盘有12位格雷码,对应360°机械角度。当电机旋转时,光电传感器输出格雷码信号,FPGA或MCU需将格雷码转换为二进制位置值:

// 格雷码转二进制 (C语言实现)
uint16_t gray_to_binary(uint16_t gray) {
    uint16_t bin = gray;
    while (gray >>= 1) {
        bin ^= gray;
    }
    return bin;
}
// 示例: 格雷码 0b1011 → 二进制 0b1101 → 十进制 13

由于格雷码相邻位置仅1位变化,即使码盘在边界处抖动,也不会出现类似二进制码从0111到1000时多位同时变化导致的瞬间错误读数。该设计显著提高了位置反馈的可靠性。

2.3.4 常见误区与总结

易混淆点:BCD码与十六进制数外观相似但含义不同。例如 0x99 作为BCD码表示十进制数99,而作为十六进制数表示十进制数153。在RTC芯片(如DS1302)中,寄存器默认使用BCD格式存储时间,读取后需进行 dec = (bcd & 0x0F) + ((bcd >> 4) * 10) 转换。
编码类型位数表示范围核心优势典型应用
8421 BCD4位/十进制位0-9十进制直观,便于显示数码管、RTC、计算器
格雷码n位0 ~ 2ⁿ-1相邻码仅1位变化,抗干扰编码器、FIFO指针、状态机
ASCII码7位/8位0-127/255字符标准化UART通信、键盘输入
奇偶校验码数据位+1校验位取决于数据位单比特检错UART、存储器校验

2.4 编码在硬件设计中的综合应用与工程复盘

2.4.1 数据链路中的编码选择策略

在实际硬件系统中,不同编码各司其职:CPU内部数据总线使用二进制补码进行算术运算;外部存储器地址使用十六进制表示便于调试;人机交互接口(如数码管)使用BCD码;高速串行通信(如PCIe、USB)使用8b/10b编码保证DC平衡;传感器位置反馈使用格雷码消除毛刺。工程师在设计方案时,应根据信号传输距离、实时性要求、抗干扰需求、调试便利性等因素综合选择编码方式。

2.4.2 案例复盘:混合信号采集板卡的编码设计

背景与约束:某工业数据采集板卡需同时处理8路模拟输入(16位ADC)、4路旋转编码器反馈、以及通过UART与上位机通信。板卡工作环境存在较强电磁干扰,且要求位置数据实时性高。

设计决策过程:

  1. ADC数据:采用二进制补码输出,MCU直接读取16位有符号数,通过查表法进行线性标定,避免浮点运算耗时。
  2. 编码器接口:选用12位格雷码输出型编码器,硬件电路使用异或门阵列将格雷码转换为二进制,转换延迟小于20ns,满足1MHz更新率要求。
  3. UART通信:数据帧采用ASCII码传输十六进制字符串,便于上位机解析和日志记录;每帧附加奇偶校验位,检测传输错误。
  4. 数码管显示:本地面板使用BCD码驱动4位LED数码管,显示当前温度值,MCU通过查表将二进制温度值转换为BCD码。

结果与复盘:该方案在实验室测试中,编码器在3000rpm转速下未出现位置跳变;UART通信在施加2kV ESD干扰时,误码率低于10⁻⁶。复盘经验:格雷码的抗干扰优势在长线传输中尤为明显;BCD码虽然浪费存储空间,但省去了显示驱动芯片的二进制转十进制逻辑,降低了BOM成本。

设计清单:① 明确数据流向与处理环节;② 为每个环节选择最合适的编码;③ 在编码转换边界(如格雷码→二进制、二进制→BCD)增加时序约束;④ 使用仿真工具验证转换逻辑的时序余量;⑤ 在PCB布局时,将编码器信号线远离高频开关电源走线。

数制与编码是连接数学抽象与硬件实现的桥梁。从简单的进制转换到复杂的补码运算,再到面向特定场景的编码方案,每一个知识点都直接关系到硬件系统的正确性、可靠性与可维护性。建议读者在后续学习存储器接口、通信协议和嵌入式系统时,有意识地识别其中使用的编码方式,并思考设计者为何做出如此选择,这将极大提升硬件设计能力。