单片机实训平台MCU Lab

首页/图文文章

为什么汇编里要写成 0F H —— 从一根地址线说起

本文的结论可以在 进制转换与寄存器实训 里逐题验证,再回来看推导会更快。

单片机的引脚只有两种状态:高电平或者低电平。既然机器只认 0 和 1,为什么我们写代码时几乎离不开十六进制?

答案藏在一根线上。

一根线 = 一个二进制位

拿 8051 的 P1 口来说,它一共有 8 根引脚,也就是 8 个二进制位。假设现在要把 P1.3 拉到高电平、其余保持低电平,写成二进制是这样:

P1 = 0b00001000;

这一串 00001000 从左到右对应 P1.7 到 P1.0。数一下是能数出来的,但引脚一多就会出事——如果同时要控制 12 个引脚,你得对着屏幕一位一位地数,数错一位就调半天。

换成十六进制:

P1 = 0x08;

清爽了。秘诀在于:一位十六进制,正好等于四位二进制。

四根线一组

为什么是四?因为 2 的 4 次方等于 16——四位二进制能表示的组合数,恰好是一位十六进制能表示的数字个数。这不是巧合,是这个进制被发明的理由。

二进制 十六进制 十进制
0000 0 0
0001 1 1
1000 8 8
1010 A 10
1111 F 15

所以从二进制转十六进制,不用算,从右往左每四位切一刀,每刀查一次表就行:

1010 0110
  A    6      →  0xA6

反过来也一样。这就是为什么十六进制在嵌入式里这么好用:它保留了二进制的"位感",但短了四倍。

十六进制不是给机器看的,是给人看的。机器眼里只有 0 和 1,而一个十六进制位永远对应四根线,数位和引脚一一对得上——这才是它真正的价值。

为什么有人写 0FH,有人写 0x0F

同一个值 15,在不同场合有不同写法,仅仅是为了让编译器知道这是几进制:

写法 用在哪 含义
0FH 汇编(Keil A51) 后缀 H 表示十六进制
0x0F C51 / C 语言 前缀 0x 表示十六进制
0b00001111 部分编译器扩展 前缀 0b 表示二进制
15 任何地方 十进制

汇编里写 0FH 时必须以数字开头。要表示十六进制的 A~F 开头的值,前面得补个 0——写 AH 会被当成符号名,正确的是 0AH。这个坑几乎是每个人第一次写汇编都会踩的。

落到代码里

真正常用的其实就三类操作。以下面这段 CC2530 的代码为例:

// 1. 直接赋值:整个口的 8 根线一起定
P1 = 0xA6;              // 1010 0110

// 2. 位或:只把某几位置 1,其余不动
P1 |= (1 << 3);         // 把 P1.3 拉高 → 1010 1110

// 3. 位与取反:只把某几位清 0,其余不动
P1 &= ~(1 << 4);        // 把 P1.4 拉低 → 1010 0110

三个写法的区别值得单独说清楚——直接赋值会覆盖整个寄存器,而位或、位与只动目标位。什么时候该用哪个,见 改寄存器的三个层次。

一句话总结

  • 一位十六进制 = 四位二进制 = 四根线
  • 二进制转十六进制:从右往左四位一切,查表
  • 汇编用后缀 H,C 语言用前缀 0x
  • 汇编里 0AH 不能写成 AH

想练手的话,进制转换与寄存器实训 里有一整套 16/2 进制互转和位运算的题目,答对自动出下一题。