10.1 查表为什么需要专门指令
你要显示数字 0~9,得知道每个数字对应哪 8 段亮。这些数据存在 ROM 里,用 MOVC 取。
MOVC A,@A+DPTR ; 实际操作:A ← ROM[DPTR + A]
一条指令完成「基址 + 偏移」的寻址 —— 这就是变址寻址。
10.2 原理图
10.3 数码管段码表(共阴)
SEG_TAB: DB 3FH, 06H, 5BH, 4FH, 66H, 6DH, 7DH, 07H
DB 7FH, 6FH, 77H, 7CH, 39H, 5EH, 79H, 71H
; 0 1 2 3 4 5 6 7
; 8 9 A B C D E F
| 数字 | 段码 | 亮的段 |
| 0 | 3FH | a b c d e f |
| 1 | 06H | b c |
| 2 | 5BH | a b d e g |
| 8 | 7FH | 全亮 |
共阳要取反:CPL A 一下就行(3FH → C0H)。
10.4 实验:数码管循环显示 0~9
ORG 0000H
LJMP MAIN
ORG 0030H
MAIN: MOV SP,#60H
MOV DPTR,#SEG_TAB ; DPTR 指向表首
MOV R2,#0 ; 要显示的数字
LOOP: MOV A,R2 ; A = 偏移量
MOVC A,@A+DPTR ; 查表 → A = 段码
MOV P0,A ; 送到数码管段码口
LCALL DELAY
INC R2
CJNE R2,#10,LOOP ; 到 10 就归零
MOV R2,#0
SJMP LOOP
DELAY: MOV R5,#100
D1: MOV R6,#250
D2: DJNZ R6,D2
DJNZ R5,D1
RET
SEG_TAB: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H
DB 7FH,6FH,77H,7CH,39H,5EH,79H,71H
END
10.5 关键点追问:DPTR 会被破坏吗
不会。MOVC A,@A+DPTR 只是「读」,不改 DPTR。所以整个循环只需要设一次 DPTR。
但如果表放在 256 字节以外,@A+DPTR 的偏移 A 只有 8 位(最大 255),表长不能超过 256 字节。超过就要分段处理。
10.6 另一种查表:@A+PC
MOV A,R2
MOVC A,@A+PC ; 以 PC 为基址
...
SEG_TAB: DB 3FH,06H,... ; 表必须紧跟在 MOVC 后 256 字节内
@A+PC 不用设 DPTR,但表的位置被「绑死」在指令后面,不灵活。一般用 DPTR 版本。
10.7 易错点
① 忘了 MOV DPTR,#表首址 —— 取到随机数据。
② 用 MOV 而不是 MOVC —— MOV 访问 RAM,读不到 ROM 里的表。
③ 偏移量超过 255 —— 表太长会绕回开头。
④ 表放在 ORG 0030H 之前 —— 会被中断向量区占用。
10.8 今日练习
- 3FH 对应的数字是几?06H 呢?
- 要显示「7」,段码是多少?(只亮 a b c)
- 如果数码管是共阳,3FH 应该改成什么?
📖 参考答案(点击展开)
- 3FH → 0(亮 a b c d e f);06H → 1(亮 b c)。
- 只亮 a b c → bit0、bit1、bit2 置 1 → 07H。
- 共阳要取反:3FH 按位取反 = C0H。可以在代码里加
CPL A 自动转换。