本手冊涵蓋 MCS-51 微控制器的全部 111 條指令,分為五大類別,詳細說明每條指令的語法、運作原理、影響旗標、位元組數、機器週期數及使用範例。
目錄
- 基本概念
- 資料傳送指令 (Data Transfer)
- 算術運算指令 (Arithmetic)
- 邏輯運算指令 (Logic)
- 位元操作指令 (Boolean / Bit Manipulation)
- 程式分支指令 (Program Branching)
- 指令速查表
- 附錄:SFR 位址表
1. 基本概念
1.1 定址模式 (Addressing Modes)
| 模式 | 語法 | 說明 | 範例 |
|---|---|---|---|
| 立即定址 (Immediate) | #data |
運算元直接寫在指令中 | MOV A, #30H |
| 直接定址 (Direct) | direct |
指定 RAM 位址 (00H\~FFH) | MOV A, 30H |
| 暫存器定址 (Register) | Rn |
使用 R0\~R7 暫存器 | MOV A, R3 |
| 暫存器間接定址 (Register Indirect) | @Ri |
R0 或 R1 的內容為位址 | MOV A, @R0 |
| 索引定址 (Indexed) | @A+DPTR / @A+PC |
基底+偏移量,用於查表 | MOVC A, @A+DPTR |
| 位元定址 (Bit) | bit |
操作單一位元 | SETB P1.0 |
1.2 暫存器與符號說明
| 符號 | 說明 |
|---|---|
A |
累加器 (Accumulator),8-bit,位址 E0H |
B |
B 暫存器,用於乘除法,位址 F0H |
Rn |
當前暫存器組的 R0\~R7 (n = 0\~7) |
Ri |
R0 或 R1,用於間接定址 (i = 0 或 1) |
direct |
內部 RAM 直接位址 (00H\~7FH) 或 SFR 位址 (80H\~FFH) |
#data |
8-bit 立即值 (00H\~FFH) |
#data16 |
16-bit 立即值 (0000H\~FFFFH) |
addr16 |
16-bit 位址,用於 LJMP/LCALL |
addr11 |
11-bit 位址,用於 AJMP/ACALL |
rel |
8-bit 有號相對偏移量 (-128\~+127) |
bit |
位元位址 (位元定址區 20H\~2FH 或 SFR 的可位元定址位元) |
DPTR |
16-bit 資料指標 (DPH:DPL) |
PC |
程式計數器 (Program Counter) |
SP |
堆疊指標 (Stack Pointer) |
1.3 PSW 旗標位元 (Program Status Word, 位址 D0H)
| 位元 | 符號 | 說明 |
|---|---|---|
| PSW.7 | CY (C) | 進位旗標 (Carry Flag) |
| PSW.6 | AC | 輔助進位旗標 (Auxiliary Carry),BCD 運算用 |
| PSW.5 | F0 | 使用者旗標 0 |
| PSW.4 | RS1 | 暫存器組選擇位元 1 |
| PSW.3 | RS0 | 暫存器組選擇位元 0 |
| PSW.2 | OV | 溢位旗標 (Overflow Flag) |
| PSW.1 | — | 保留 |
| PSW.0 | P | 同位旗標 (Parity Flag),A 中 1 的個數為奇數時 P=1 |
暫存器組選擇:
| RS1 | RS0 | 暫存器組 | RAM 位址 |
|---|---|---|---|
| 0 | 0 | Bank 0 | 00H\~07H |
| 0 | 1 | Bank 1 | 08H\~0FH |
| 1 | 0 | Bank 2 | 10H\~17H |
| 1 | 1 | Bank 3 | 18H\~1FH |
2. 資料傳送指令 (Data Transfer)
資料傳送指令負責在暫存器、記憶體和 I/O 埠之間移動資料。所有資料傳送指令都不影響任何旗標(除了 MOV PSW, ... 直接寫入 PSW 的情況)。
2.1 MOV — 內部資料搬移
MOV 是最常用的指令,用於在內部 RAM、SFR 和暫存器之間搬移 8-bit 資料。
MOV A, \<src> — 搬移到累加器
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
MOV A, Rn |
1 | 1 | A ← Rn |
MOV A, direct |
2 | 1 | A ← (direct) |
MOV A, @Ri |
1 | 1 | A ← ((Ri)) |
MOV A, #data |
2 | 1 | A ← data |
MOV A, R5 ; A = R5 的值
MOV A, 30H ; A = 內部 RAM 位址 30H 的值
MOV A, @R0 ; A = R0 所指向的 RAM 位址的值
MOV A, #0FFH ; A = FFH (立即值 255)
MOV Rn, \<src> — 搬移到暫存器
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
MOV Rn, A |
1 | 1 | Rn ← A |
MOV Rn, direct |
2 | 2 | Rn ← (direct) |
MOV Rn, #data |
2 | 1 | Rn ← data |
MOV R3, A ; R3 = A 的值
MOV R0, 30H ; R0 = RAM 位址 30H 的值
MOV R7, #100 ; R7 = 100 (十進位)
MOV direct, \<src> — 搬移到直接位址
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
MOV direct, A |
2 | 1 | (direct) ← A |
MOV direct, Rn |
2 | 2 | (direct) ← Rn |
MOV direct, direct |
3 | 2 | (direct) ← (direct) |
MOV direct, @Ri |
2 | 2 | (direct) ← ((Ri)) |
MOV direct, #data |
3 | 2 | (direct) ← data |
MOV 30H, A ; RAM 30H = A
MOV 30H, R2 ; RAM 30H = R2
MOV 30H, 40H ; RAM 30H = RAM 40H (記憶體對記憶體搬移!)
MOV P1, #0FFH ; Port 1 = FFH (P1 的 SFR 位址是 90H)
MOV 30H, @R1 ; RAM 30H = R1 所指向的位址的值
重要:
MOV direct, direct是 8051 少數能做「記憶體對記憶體」搬移的指令,不需經過累加器。
MOV @Ri, \<src> — 搬移到間接定址位置
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
MOV @Ri, A |
1 | 1 | ((Ri)) ← A |
MOV @Ri, direct |
2 | 2 | ((Ri)) ← (direct) |
MOV @Ri, #data |
2 | 1 | ((Ri)) ← data |
MOV R0, #30H ; R0 = 30H (設定指標)
MOV @R0, A ; RAM[30H] = A
MOV @R0, #55H ; RAM[30H] = 55H
MOV @R1, P1 ; RAM[R1] = Port 1 的值
MOV DPTR, #data16 — 載入 16-bit 立即值到 DPTR
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
MOV DPTR, #data16 |
3 | 2 | DPTR ← data16 (DPH ← high byte, DPL ← low byte) |
MOV DPTR, #2048H ; DPTR = 2048H,通常用於存取外部記憶體或查表 - #0001H
MOV DPTR, #TABLE ; DPTR 指向 TABLE 標籤的位址
注意: 這是 8051 唯一的 16-bit 資料傳送指令。
2.2 MOVC — 讀取程式記憶體 (Code Memory)
MOVC 用於從 ROM/Flash(程式記憶體)中讀取資料,常用於查表。
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
MOVC A, @A+DPTR |
1 | 2 | A ← Code[(A) + (DPTR)] |
MOVC A, @A+PC |
1 | 2 | A ← Code[(A) + (PC+1)] |
; 範例:查表取得七段顯示器編碼
MOV DPTR, #SEG_TABLE ; DPTR 指向表格起始位址
MOV A, #2 ; 要查第 3 筆資料
MOVC A, @A+DPTR ; A = SEG_TABLE[2]
SEG_TABLE:
DB 3FH, 06H, 5BH, 4FH, 66H ; 0~4 的七段碼
DB 6DH, 7DH, 07H, 7FH, 6FH ; 5~9 的七段碼
; 使用 PC 相對定址的查表
MOV A, R0 ; A = 索引值
MOVC A, @A+PC ; A = Code[A + PC + 1]
; PC+1 指向下一條指令,所以偏移量從下一行開始算
@A+DPTRvs@A+PC: -@A+DPTR:表格可以在 64KB 程式空間的任何位置,較靈活 -@A+PC:表格必須緊接在指令後方,且 A 只能到 255,範圍受限
2.3 MOVX — 存取外部資料記憶體 (External Data Memory)
MOVX 用於讀寫外部 RAM。8051 透過 P0 (資料/位址低位元) 和 P2 (位址高位元) 存取外部記憶體。
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
MOVX A, @DPTR |
1 | 2 | A ← ExtRAM[(DPTR)] |
MOVX A, @Ri |
1 | 2 | A ← ExtRAM[(Ri)](8-bit 位址,需 P2 提供高位元) |
MOVX @DPTR, A |
1 | 2 | ExtRAM[(DPTR)] ← A |
MOVX @Ri, A |
1 | 2 | ExtRAM[(Ri)] ← A |
; 16-bit 定址(可存取 64KB 外部 RAM)4K -> 4096 -> 1000H
MOV DPTR, #8000H
MOVX A, @DPTR ; 讀取外部 RAM 位址 8000H
MOV R3, A
INC DPTR ; increase register + 1
MOV A, R3
MOVX @DPTR, A ; 寫入外部 RAM 位址 8001H
; 8-bit 定址(存取 256 bytes,P2 提供高位元)
MOV P2, #80H ; 高位元位址 = 80H
MOV R0, #00H ; 低位元位址 = 00H
MOVX A, @R0 ; 讀取外部 RAM 位址 8000H
注意: 外部記憶體只能透過 A 存取,不能直接搬移到 Rn 或 direct。
2.4 XCH — 交換資料
XCH 將累加器 A 的內容與指定的運算元交換。
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
XCH A, Rn |
1 | 1 | A ↔ Rn |
XCH A, direct |
2 | 1 | A ↔ (direct) |
XCH A, @Ri |
1 | 1 | A ↔ ((Ri)) |
MOV A, #10H
MOV R0, #20H
XCH A, R0 ; 執行後 A=20H, R0=10H
2.5 XCHD — 交換低半位元組
XCHD 只交換 A 與間接定址位元組的低 4 位元 (Low Nibble),高 4 位元不變。常用於 BCD 運算。
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
XCHD A, @Ri |
1 | 1 | A[3:0] ↔ ((Ri))[3:0],A[7:4] 和 ((Ri))[7:4] 不變 |
MOV A, #36H ; A = 36H (0011 0110)
MOV R0, #40H
MOV @R0, #79H ; RAM[40H] = 79H (0111 1001)
XCHD A, @R0 ; 執行後 A = 39H, RAM[40H] = 76H
; 低半位元組 6 和 9 互換
2.6 PUSH / POP — 堆疊操作
PUSH 將資料壓入堆疊,POP 將資料從堆疊取出。8051 堆疊在內部 RAM 中,向上增長。
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
PUSH direct |
2 | 2 | SP ← SP+1, (SP) ← (direct) |
POP direct |
2 | 2 | (direct) ← (SP), SP ← SP-1 |
; 儲存暫存器到堆疊(ISR 中常見)
PUSH ACC ; 先 SP+1,再把 A 存到 SP 指向的位址
PUSH PSW ; 存 PSW
PUSH 00H ; 存 R0 (Bank 0 的 R0 位址是 00H)
; 從堆疊恢復(順序相反!)
POP 00H ; 恢復 R0
POP PSW ; 恢復 PSW
POP ACC ; 恢復 A
注意: - PUSH/POP 的運算元是 direct 位址,不能寫
PUSH A(要寫PUSH ACC,ACC 是 A 的 SFR 位址 E0H 的別名) - 不能寫PUSH R0,要寫PUSH 00H(R0 在 Bank 0 的 RAM 位址是 00H) - SP 預設值是 07H,第一次 PUSH 會存到 08H
2.7 SWAP — 交換累加器高低半位元組
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
SWAP A |
1 | 1 | A[7:4] ↔ A[3:0] |
MOV A, #3CH ; A = 3CH (0011 1100)
SWAP A ; A = C3H (1100 0011)
; 高 nibble 3 和低 nibble C 互換
應用: BCD 拆解。若 A=59H(BCD 59),
SWAP A得 95H,再ANL A, #0FH得 05H(取得十位數 5)。
3. 算術運算指令 (Arithmetic)
3.1 ADD — 加法 (不含進位)
將運算元加到累加器 A。
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
ADD A, Rn |
1 | 1 | A ← A + Rn |
ADD A, direct |
2 | 1 | A ← A + (direct) |
ADD A, @Ri |
1 | 1 | A ← A + ((Ri)) |
ADD A, #data |
2 | 1 | A ← A + data |
影響旗標: CY, AC, OV, P
MOV A, #C3H ; A = C3H (1100 0011) = 195
ADD A, #AAH ; A = C3H + AAH = 6DH (0110 1101) = 109
; CY=1 (結果超過 FFH,有進位)
; AC=0 (低 nibble 3+A=D,無半進位)
; OV=1 (兩個負數相加得正數,溢位) -- Overflow
旗標運算規則: - CY = bit 7 有進位 → 無號數運算結果超過 255 - AC = bit 3 到 bit 4 有進位 → BCD 加法修正用 - OV = bit 7 進位 ⊕ bit 6 進位 → 有號數運算溢位
3.2 ADDC — 含進位加法
與 ADD 相同,但額外加上 CY 旗標。用於多位元組加法。
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
ADDC A, Rn |
1 | 1 | A ← A + Rn + CY |
ADDC A, direct |
2 | 1 | A ← A + (direct) + CY |
ADDC A, @Ri |
1 | 1 | A ← A + ((Ri)) + CY |
ADDC A, #data |
2 | 1 | A ← A + data + CY |
影響旗標: CY, AC, OV, P
; 16-bit 加法:(R3:R2) = (R1:R0) + (R3:R2)
; R1:R0 = 高:低位元組
MOV A, R0
ADD A, R2 ; 先加低位元組(不含進位)
MOV R2, A
MOV A, R1
ADDC A, R3 ; 再加高位元組(含進位,把低位元組的進位帶上來)
MOV R3, A
3.3 SUBB — 含借位減法
8051 沒有不含借位的 SUB 指令,只有 SUBB。若不需要借位,需先 CLR C。
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
SUBB A, Rn |
1 | 1 | A ← A - Rn - CY |
SUBB A, direct |
2 | 1 | A ← A - (direct) - CY |
SUBB A, @Ri |
1 | 1 | A ← A - ((Ri)) - CY |
SUBB A, #data |
2 | 1 | A ← A - data - CY |
影響旗標: CY, AC, OV, P
; 簡單減法(必須先清除 CY!)
CLR C ; CY = 0
MOV A, #50H
SUBB A, #30H ; A = 50H - 30H - 0 = 20H, CY=0
; 若忘記 CLR C,且之前 CY=1:
; A = 50H - 30H - 1 = 1FH(答案差 1!)
; 16-bit 減法:(R3:R2) = (R1:R0) - (R3:R2)
CLR C
MOV A, R0
SUBB A, R2 ; 低位元組相減
MOV R2, A
MOV A, R1
SUBB A, R3 ; 高位元組相減(含借位)
MOV R3, A
CY 在減法中的意義: CY=1 表示有借位,即被減數 < 減數(無號數比較)。
3.4 INC — 遞增 (+1)
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
INC A |
1 | 1 | A ← A + 1 |
INC Rn |
1 | 1 | Rn ← Rn + 1 |
INC direct |
2 | 1 | (direct) ← (direct) + 1 |
INC @Ri |
1 | 1 | ((Ri)) ← ((Ri)) + 1 |
INC DPTR |
1 | 2 | DPTR ← DPTR + 1 (16-bit 遞增) |
影響旗標: 無(INC 不影響任何旗標!連 CY 也不影響)
MOV A, #0FFH
INC A ; A = 00H(溢位 wrap around),但 CY 不會被設定!
; 若需要偵測溢位,改用 ADD A, #1
INC DPTR ; DPTR = DPTR + 1,16-bit 遞增
; 這是唯一的 16-bit INC 指令
陷阱:
INC不設定 CY。若 A=FFH 做INC A,A 變 00H 但 CY=0。需要判斷溢位時要改用ADD A, #01H。
3.5 DEC — 遞減 (-1)
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
DEC A |
1 | 1 | A ← A - 1 |
DEC Rn |
1 | 1 | Rn ← Rn - 1 |
DEC direct |
2 | 1 | (direct) ← (direct) - 1 |
DEC @Ri |
1 | 1 | ((Ri)) ← ((Ri)) - 1 |
影響旗標: 無
MOV R7, #10
LOOP:
; ... 迴圈主體 ...
DEC R7 ; R7 = R7 - 1
; 注意:DEC 不設定旗標,不能直接用 JNZ 判斷
; 需要搭配 CJNE 或 DJNZ
MOV A, R7
JNZ LOOP ; 若 A ≠ 0 繼續迴圈
注意: 沒有
DEC DPTR!若需要 DPTR-1,必須手動處理:asm ; DEC DPTR 的替代方案 DEC DPL ; 先減低位元組 MOV A, DPL CJNE A, #0FFH, DONE ; 若 DPL 沒有下溢就完成 DEC DPH ; DPL 從 00→FF,需要向高位元借位 DONE:
3.6 MUL — 無號數乘法
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
MUL AB |
1 | 4 | B:A ← A × B (16-bit 結果) |
影響旗標: - CY = 0(永遠清除) - OV = 1 若乘積 > 255(即 B ≠ 0)
MOV A, #50 ; A = 50
MOV B, #10 ; B = 10
MUL AB ; A × B = 500 = 01F4H
; A = F4H (低位元組)
; B = 01H (高位元組)
; OV = 1(乘積 > 255)
; CY = 0(永遠為 0)
限制: 只能做 8×8 = 16 位元的無號數乘法。
3.7 DIV — 無號數除法
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
DIV AB |
1 | 4 | A ← A ÷ B(商),B ← A mod B(餘數) |
影響旗標: - CY = 0(永遠清除) - OV = 1 若除數 B = 0(除以零!結果未定義)
MOV A, #253 ; A = 253
MOV B, #10 ; B = 10
DIV AB ; 253 ÷ 10 = 商 25 餘 3
; A = 25 (商)
; B = 3 (餘數)
; OV = 0, CY = 0
; 將二進位轉 BCD 的應用
MOV A, #0C8H ; A = 200 (十進位)
MOV B, #100
DIV AB ; A = 2 (百位), B = 0 (餘數)
MOV R2, A ; R2 = 百位 = 2
MOV A, B
MOV B, #10
DIV AB ; A = 0 (十位), B = 0 (個位)
MOV R1, A ; R1 = 十位 = 0
MOV R0, B ; R0 = 個位 = 0
3.8 DA — 十進位調整 (Decimal Adjust)
用於 BCD 加法後的修正。必須緊接在 ADD 或 ADDC 之後使用。
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
DA A |
1 | 1 | 將 A 調整為正確的 BCD 結果 |
調整規則: 1. 若 A[3:0] > 9 或 AC=1 → A = A + 06H 2. 若 A[7:4] > 9 或 CY=1 → A = A + 60H
影響旗標: CY(可能被設定,不會被清除)
; BCD 加法:56 + 67 = 123 (BCD)
MOV A, #56H ; A = 56H (BCD 56)
ADD A, #67H ; A = BDH (二進位加法結果)
; AC = 1 (6+7=13, 低 nibble 進位)
DA A ; A = 23H, CY = 1
; 實際結果 = 123 (CY 代表百位的 1)
注意:
DA只對加法有效,不能用於減法後。BCD 減法需要用「十補數」技巧。
4. 邏輯運算指令 (Logic)
4.1 ANL — 位元 AND
逐位元做 AND 運算。常用於清除特定位元(遮罩 Mask)。
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
ANL A, Rn |
1 | 1 | A ← A AND Rn |
ANL A, direct |
2 | 1 | A ← A AND (direct) |
ANL A, @Ri |
1 | 1 | A ← A AND ((Ri)) |
ANL A, #data |
2 | 1 | A ← A AND data |
ANL direct, A |
2 | 1 | (direct) ← (direct) AND A |
ANL direct, #data |
3 | 2 | (direct) ← (direct) AND data |
影響旗標: 無(邏輯指令不影響 CY, AC, OV)
; 清除高 4 位元(保留低 nibble)
MOV A, #3CH ; A = 3CH = 0011 1100
ANL A, #0FH ; A = 0CH = 0000 1100
; 0FH = 0000 1111 作為遮罩
; 清除 Port 的特定位元
ANL P1, #11111100B ; 清除 P1 的 bit 0 和 bit 1,其餘不變
4.2 ORL — 位元 OR
逐位元做 OR 運算。常用於設定特定位元。
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
ORL A, Rn |
1 | 1 | A ← A OR Rn |
ORL A, direct |
2 | 1 | A ← A OR (direct) |
ORL A, @Ri |
1 | 1 | A ← A OR ((Ri)) |
ORL A, #data |
2 | 1 | A ← A OR data |
ORL direct, A |
2 | 1 | (direct) ← (direct) OR A |
ORL direct, #data |
3 | 2 | (direct) ← (direct) OR data |
影響旗標: 無
; 設定高 4 位元(保留低 nibble)
MOV A, #03H ; A = 03H = 0000 0011
ORL A, #0F0H ; A = F3H = 1111 0011
; 設定 Port 的特定位元
ORL P1, #00000011B ; 設定 P1 的 bit 0 和 bit 1,其餘不變
4.3 XRL — 位元 XOR
逐位元做 XOR 運算。常用於翻轉特定位元或比較。
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
XRL A, Rn |
1 | 1 | A ← A XOR Rn |
XRL A, direct |
2 | 1 | A ← A XOR (direct) |
XRL A, @Ri |
1 | 1 | A ← A XOR ((Ri)) |
XRL A, #data |
2 | 1 | A ← A XOR data |
XRL direct, A |
2 | 1 | (direct) ← (direct) XOR A |
XRL direct, #data |
3 | 2 | (direct) ← (direct) XOR data |
影響旗標: 無
; 翻轉特定位元
MOV A, #0F0H ; A = F0H = 1111 0000
XRL A, #0FFH ; A = 0FH = 0000 1111 (全部翻轉 = CPL A)
; Toggle LED
XRL P1, #01H ; P1.0 翻轉(0→1 或 1→0)
; 檢查兩個值是否相等
MOV A, R0
XRL A, R1 ; 若 R0 = R1,A = 0
JZ EQUAL ; A = 0 則跳轉
4.4 CLR A — 清除累加器
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
CLR A |
1 | 1 | A ← 00H |
影響旗標: 無(但 P 旗標會因 A 內容改變而更新)
CLR A ; A = 00H(比 MOV A, #00H 快,且只佔 1 位元組)
效率比較:
CLR A(1 byte, 1 cycle) vsMOV A, #00H(2 bytes, 1 cycle)
4.5 CPL A — 累加器位元反轉
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
CPL A |
1 | 1 | A ← NOT A(每個位元 0↔1) |
影響旗標: 無
MOV A, #55H ; A = 55H = 0101 0101
CPL A ; A = AAH = 1010 1010
應用: 求二補數(有號數取負):
CPL A再INC A(-X = NOT X + 1)
4.6 RL — 向左旋轉
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
RL A |
1 | 1 | A 向左旋轉 1 位元,bit 7 → bit 0 |
影響旗標: 無
旋轉前: [b7][b6][b5][b4][b3][b2][b1][b0]
旋轉後: [b6][b5][b4][b3][b2][b1][b0][b7]
MOV A, #85H ; A = 1000 0101
RL A ; A = 0000 1011 = 0BH
; bit 7 (1) 移到 bit 0
應用: 快速乘以 2(但不處理溢位),或掃描 LED 跑馬燈效果。
4.7 RLC — 含進位向左旋轉
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
RLC A |
1 | 1 | A 和 CY 一起向左旋轉,bit 7 → CY,CY → bit 0 |
影響旗標: CY
旋轉前: CY [b7][b6][b5][b4][b3][b2][b1][b0]
旋轉後: b7 [b6][b5][b4][b3][b2][b1][b0][CY]
CLR C ; CY = 0
MOV A, #85H ; A = 1000 0101
RLC A ; CY = 1, A = 0000 1010 = 0AH
應用: 多位元組左移(乘以 2)。先左移低位元組,進位送入高位元組。
4.8 RR — 向右旋轉
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
RR A |
1 | 1 | A 向右旋轉 1 位元,bit 0 → bit 7 |
影響旗標: 無
旋轉前: [b7][b6][b5][b4][b3][b2][b1][b0]
旋轉後: [b0][b7][b6][b5][b4][b3][b2][b1]
MOV A, #85H ; A = 1000 0101
RR A ; A = 1100 0010 = C2H
; bit 0 (1) 移到 bit 7
4.9 RRC — 含進位向右旋轉
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
RRC A |
1 | 1 | A 和 CY 一起向右旋轉,bit 0 → CY,CY → bit 7 |
影響旗標: CY
旋轉前: [b7][b6][b5][b4][b3][b2][b1][b0] CY
旋轉後: [CY][b7][b6][b5][b4][b3][b2][b1] b0
CLR C ; CY = 0
MOV A, #85H ; A = 1000 0101
RRC A ; CY = 1, A = 0100 0010 = 42H
; bit 0 (1) 移到 CY,CY (0) 移到 bit 7
應用: 無號數除以 2(但 bit 0 進入 CY 作為餘數),或多位元組右移。
5. 位元操作指令 (Boolean / Bit Manipulation)
8051 有一個內建的位元處理器 (Boolean Processor),可以直接操作單一位元。CY 旗標作為位元累加器。
可位元定址的區域: - 內部 RAM 20H\~2FH(共 128 位元,位址 00H\~7FH) - SFR 中位址為 x0H 或 x8H 的暫存器(如 P0, P1, P2, P3, TCON, IE, PSW, ACC 等)
5.1 CLR — 清除位元
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
CLR C |
1 | 1 | CY ← 0 |
CLR bit |
2 | 1 | (bit) ← 0 |
CLR C ; 清除進位旗標
CLR P1.0 ; 清除 P1 的 bit 0(LED ON,Active Low)
CLR ACC.7 ; 清除 A 的 bit 7
CLR 00H ; 清除 bit-addressable RAM 的 bit 0
CLR TR0 ; 停止 Timer 0
5.2 SETB — 設定位元
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
SETB C |
1 | 1 | CY ← 1 |
SETB bit |
2 | 1 | (bit) ← 1 |
SETB C ; 設定進位旗標
SETB P1.0 ; 設定 P1 的 bit 0(LED OFF,Active Low)
SETB EA ; 啟用全域中斷 (IE.7)
SETB TR0 ; 啟動 Timer 0 (TCON.4)
SETB ET0 ; 啟用 Timer 0 中斷 (IE.1)
5.3 CPL — 位元反轉
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
CPL C |
1 | 1 | CY ← NOT CY |
CPL bit |
2 | 1 | (bit) ← NOT (bit) |
CPL C ; CY 翻轉
CPL P1.0 ; P1.0 翻轉(LED Toggle)
5.4 ANL C, bit — 位元 AND
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
ANL C, bit |
2 | 2 | CY ← CY AND (bit) |
ANL C, /bit |
2 | 2 | CY ← CY AND NOT(bit) |
; 檢查 P1.0 和 P1.1 是否同時為 1
MOV C, P1.0 ; CY = P1.0
ANL C, P1.1 ; CY = P1.0 AND P1.1
JC BOTH_HIGH ; 兩個都是 1 才跳轉
; 使用反轉位元
ANL C, /P1.2 ; CY = CY AND (NOT P1.2)
; P1.2=0 時,/P1.2=1
5.5 ORL C, bit — 位元 OR
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
ORL C, bit |
2 | 2 | CY ← CY OR (bit) |
ORL C, /bit |
2 | 2 | CY ← CY OR NOT(bit) |
; 檢查 P1.0 或 P1.1 其中一個為 1
MOV C, P1.0
ORL C, P1.1 ; CY = P1.0 OR P1.1
JC ANY_HIGH ; 任一個為 1 就跳轉
5.6 MOV — 位元搬移
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
MOV C, bit |
2 | 1 | CY ← (bit) |
MOV bit, C |
2 | 2 | (bit) ← CY |
; 把 P3.2 的狀態複製到 P1.0
MOV C, P3.2 ; CY = P3.2 的值
MOV P1.0, C ; P1.0 = CY = P3.2 的值
; 儲存旗標
MOV 00H, C ; 把 CY 存到 bit-addressable RAM bit 0
5.7 JC / JNC — 依進位旗標跳轉
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
JC rel |
2 | 2 | 若 CY=1,PC ← PC + 2 + rel |
JNC rel |
2 | 2 | 若 CY=0,PC ← PC + 2 + rel |
; 無號數比較:若 A < 30H 則跳轉
CLR C
SUBB A, #30H
JC A_LESS_THAN_30 ; CY=1 表示 A < 30H(有借位)
; 位元操作後判斷
MOV C, P1.0
ANL C, P1.1
JC BOTH_SET ; 兩個位元都為 1
JNC NOT_BOTH ; 至少一個為 0
5.8 JB / JNB — 依位元值跳轉
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
JB bit, rel |
3 | 2 | 若 (bit)=1,跳轉 |
JNB bit, rel |
3 | 2 | 若 (bit)=0,跳轉 |
; 等待按鈕按下(P3.2 = 0)
WAIT_PRESS:
JB P3.2, WAIT_PRESS ; P3.2=1(未按),繼續等待
; 等待按鈕放開(P3.2 = 1)
WAIT_RELEASE:
JNB P3.2, WAIT_RELEASE ; P3.2=0(按住),繼續等待
; 檢查 Timer 0 溢位旗標
JB TF0, TIMER_DONE ; TF0=1 表示 Timer 溢位
5.9 JBC — 依位元值跳轉並清除
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
JBC bit, rel |
3 | 2 | 若 (bit)=1,清除 bit 並跳轉 |
; 檢查旗標並自動清除(避免重複處理)
JBC TF0, HANDLE_T0 ; 若 TF0=1,清除 TF0 並跳到 HANDLE_T0
; 若 TF0=0,繼續下一條指令
; 等同於:
JB TF0, $+5 ; 用兩條指令完成同樣的事
SJMP SKIP
CLR TF0
SJMP HANDLE_T0
SKIP:
應用: 適合處理「一次性事件旗標」,讀取後自動清除防止重複觸發。
6. 程式分支指令 (Program Branching)
6.1 無條件跳轉
LJMP — 長跳轉 (Long Jump)
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
LJMP addr16 |
3 | 2 | PC ← addr16 |
LJMP 3000H ; 跳到位址 3000H
LJMP MAIN ; 跳到 MAIN 標籤
可跳轉到 64KB 程式空間的任何位置。
AJMP — 絕對跳轉 (Absolute Jump)
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
AJMP addr11 |
2 | 2 | PC[10:0] ← addr11, PC[15:11] 不變 |
AJMP TARGET ; 跳到 TARGET(必須在同一個 2KB 區塊內)
限制: 目標位址的高 5 位元 (bit 15\~11) 必須與 AJMP 下一條指令的 PC 相同。即只能在同一個 2KB 範圍 (0000\~07FF, 0800\~0FFF, ...) 內跳轉。比 LJMP 省 1 位元組。
SJMP — 短跳轉 (Short Jump)
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
SJMP rel |
2 | 2 | PC ← PC + 2 + rel |
SJMP LOOP ; 相對跳轉(-128 ~ +127 位元組範圍)
; 無窮迴圈的慣用寫法
HERE: SJMP HERE ; 或寫成 SJMP $($ 代表當前位址)
$符號: 代表當前指令的位址。SJMP $= 原地打轉 = 無窮迴圈。
JMP @A+DPTR — 間接跳轉
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
JMP @A+DPTR |
1 | 2 | PC ← A + DPTR |
; 跳轉表 (Switch-Case 實作)
MOV DPTR, #JUMP_TABLE
MOV A, R0 ; R0 = case 編號 (0, 1, 2, ...)
RL A ; A = R0 × 2(因為每個 AJMP 佔 2 bytes)
JMP @A+DPTR
JUMP_TABLE:
AJMP CASE_0 ; case 0
AJMP CASE_1 ; case 1
AJMP CASE_2 ; case 2
AJMP CASE_3 ; case 3
注意: 這是唯一的間接跳轉指令,非常適合實作
switch-case或函數指標陣列。
6.2 副程式呼叫與返回
LCALL — 長呼叫 (Long Call)
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
LCALL addr16 |
3 | 2 | PUSH PC+3 到堆疊,PC ← addr16 |
LCALL DELAY ; 呼叫 DELAY 副程式
; 自動把返回位址壓入堆疊
; SP+1 → 存 PC 低位元組
; SP+1 → 存 PC 高位元組
ACALL — 絕對呼叫 (Absolute Call)
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
ACALL addr11 |
2 | 2 | PUSH PC+2 到堆疊,PC[10:0] ← addr11 |
ACALL NEARBY_FUNC ; 呼叫同一 2KB 區塊內的副程式
與 AJMP 相同的 2KB 範圍限制,比 LCALL 省 1 位元組。
RET — 副程式返回
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
RET |
1 | 2 | POP PC 高位元組,POP PC 低位元組 |
DELAY:
MOV R7, #250
D_LOOP:
DJNZ R7, D_LOOP
RET ; 返回呼叫者,從堆疊取回返回位址
RETI — 中斷服務返回
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
RETI |
1 | 2 | POP PC(同 RET),並恢復中斷優先權邏輯 |
INT0_ISR:
PUSH ACC
PUSH PSW
; ... 處理中斷 ...
POP PSW
POP ACC
RETI ; 中斷返回(不能用 RET!)
RETIvsRET的差異: -RET:只恢復 PC -RETI:恢復 PC 且 告知中斷控制器「此中斷已處理完畢」,允許同優先級的中斷再次觸發 - 在 ISR 中使用RET代替RETI會導致同優先級中斷被永久鎖住!
6.3 條件跳轉
JZ / JNZ — 依累加器值跳轉
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
JZ rel |
2 | 2 | 若 A=0,跳轉 |
JNZ rel |
2 | 2 | 若 A≠0,跳轉 |
MOV A, R0
JZ IS_ZERO ; 若 R0 = 0,跳到 IS_ZERO
JNZ NOT_ZERO ; 若 R0 ≠ 0,跳到 NOT_ZERO
注意: JZ/JNZ 檢查的是 A 的當前值,不是旗標。所以要先把值搬到 A。
CJNE — 比較並跳轉若不相等
CJNE 同時做比較和條件跳轉,是 8051 最強大的條件跳轉指令。
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
CJNE A, direct, rel |
3 | 2 | 若 A ≠ (direct),跳轉 |
CJNE A, #data, rel |
3 | 2 | 若 A ≠ data,跳轉 |
CJNE Rn, #data, rel |
3 | 2 | 若 Rn ≠ data,跳轉 |
CJNE @Ri, #data, rel |
3 | 2 | 若 ((Ri)) ≠ data,跳轉 |
影響旗標: CY - 若 op1 < op2 → CY = 1(無號數比較) - 若 op1 ≥ op2 → CY = 0
; if (A == 'Y') goto MATCH
CJNE A, #'Y', NO_MATCH
SJMP MATCH ; A = 'Y',到這裡表示相等
NO_MATCH:
; A ≠ 'Y'
; 無號數大小比較
CJNE A, #50, NOT_50
SJMP EQUAL_50 ; A = 50
NOT_50:
JC LESS_THAN_50 ; CY=1 → A < 50
; 到這裡是 A > 50
; 等待某個值
WAIT:
MOV A, P1
CJNE A, #55H, WAIT ; 等到 P1 = 55H 才跳出
; 比較 R0 和立即值
CJNE R0, #10, NOT_10 ; R0 ≠ 10 就跳
; R0 = 10
注意: CJNE 不改變運算元的值,只做比較和設定 CY。
DJNZ — 遞減並跳轉若不為零
DJNZ 結合了 DEC 和 JNZ,是最高效的迴圈計數器指令。
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
DJNZ Rn, rel |
2 | 2 | Rn ← Rn - 1,若 Rn ≠ 0 則跳轉 |
DJNZ direct, rel |
3 | 2 | (direct) ← (direct) - 1,若 (direct) ≠ 0 則跳轉 |
影響旗標: 無
; 簡單迴圈:執行 10 次
MOV R7, #10
LOOP:
; ... 迴圈主體 ...
DJNZ R7, LOOP ; R7-1,若 ≠ 0 繼續
; 延遲副程式(巢狀迴圈)
DELAY:
MOV R6, #200 ; 外迴圈 200 次
D_OUTER:
MOV R7, #250 ; 內迴圈 250 次
D_INNER:
DJNZ R7, D_INNER ; 內迴圈
DJNZ R6, D_OUTER ; 外迴圈
RET
; 總共約 200 × 250 × 2 = 100,000 個機器週期
; 使用 direct 位址的 DJNZ
MOV 30H, #5
LP:
; ... 迴圈主體 ...
DJNZ 30H, LP ; 30H 遞減,不為零就繼續
效率:
DJNZ Rn, rel只需 2 bytes,比分開寫DEC R7+MOV A, R7+JNZ LOOP(5 bytes) 高效得多。
6.4 NOP — 無操作
| 指令 | 位元組 | 週期 | 動作 |
|---|---|---|---|
NOP |
1 | 1 | 什麼都不做,PC ← PC + 1 |
; 精確延遲微調
NOP ; 消耗 1 個機器週期
NOP ; 再消耗 1 個機器週期
; 在 12MHz 振盪器下,1 機器週期 = 1μs
; 所以每個 NOP = 1μs 的延遲
應用場景: - 精確時序微調(如串列通訊的 baud rate 校準) - 預留空間供日後修改程式碼 - 對齊位址
7. 指令速查表
7.1 依功能分類
| 類別 | 指令 | 數量 |
|---|---|---|
| 資料傳送 | MOV, MOVC, MOVX, XCH, XCHD, PUSH, POP, SWAP | 28 種組合 |
| 算術運算 | ADD, ADDC, SUBB, INC, DEC, MUL, DIV, DA | 24 種組合 |
| 邏輯運算 | ANL, ORL, XRL, CLR A, CPL A, RL, RLC, RR, RRC | 24 種組合 |
| 位元操作 | CLR bit, SETB, CPL bit, ANL C, ORL C, MOV bit, JC, JNC, JB, JNB, JBC | 17 種組合 |
| 程式分支 | LJMP, AJMP, SJMP, JMP, LCALL, ACALL, RET, RETI, JZ, JNZ, CJNE, DJNZ, NOP | 18 種組合 |
7.2 依位元組數分類
| 位元組數 | 指令範例 |
|---|---|
| 1 byte | MOV A,Rn / MOV Rn,A / INC A / DEC A / CLR A / CPL A / RL / RR / RLC / RRC / SWAP A / MUL AB / DIV AB / NOP / RET / RETI / MOVC / MOVX / XCH A,Rn / JMP @A+DPTR |
| 2 bytes | MOV A,#data / MOV Rn,#data / MOV direct,A / ADD A,#data / SJMP / AJMP / ACALL / JZ / JNZ / JC / JNC / DJNZ Rn / CLR bit / SETB bit / CJNE A,#data / PUSH / POP |
| 3 bytes | MOV direct,direct / MOV direct,#data / MOV DPTR,#data16 / LJMP / LCALL / CJNE A,direct / CJNE Rn,#data / DJNZ direct / JB / JNB / JBC / ANL direct,#data / ORL direct,#data / XRL direct,#data |
7.3 依機器週期分類
| 週期數 | 指令 |
|---|---|
| 1 週期 | 大部分的 MOV, ADD, ADDC, SUBB, INC (非DPTR), DEC, ANL/ORL/XRL (A), CLR, SETB, CPL, RL, RR, RLC, RRC, SWAP, NOP, XCH, XCHD, DA |
| 2 週期 | MOV direct,Rn / MOV Rn,direct / MOV direct,direct / MOV direct,@Ri / MOV direct,#data / MOV DPTR / MOVC / MOVX / PUSH / POP / ANL/ORL/XRL direct / INC DPTR / SJMP / AJMP / LJMP / ACALL / LCALL / RET / RETI / JZ / JNZ / JC / JNC / JB / JNB / JBC / CJNE / DJNZ / JMP @A+DPTR / ANL C / ORL C / MOV C,bit / MOV bit,C |
| 4 週期 | MUL AB / DIV AB |
8. 附錄:SFR 位址表
8.1 完整 SFR 對照表
| 位址 | 符號 | 說明 | 可位元定址 |
|---|---|---|---|
| 80H | P0 | Port 0 | ✓ |
| 81H | SP | Stack Pointer | |
| 82H | DPL | DPTR Low Byte | |
| 83H | DPH | DPTR High Byte | |
| 87H | PCON | Power Control | |
| 88H | TCON | Timer/Counter Control | ✓ |
| 89H | TMOD | Timer/Counter Mode | |
| 8AH | TL0 | Timer 0 Low Byte | |
| 8BH | TL1 | Timer 1 Low Byte | |
| 8CH | TH0 | Timer 0 High Byte | |
| 8DH | TH1 | Timer 1 High Byte | |
| 90H | P1 | Port 1 | ✓ |
| 98H | SCON | Serial Port Control | ✓ |
| 99H | SBUF | Serial Data Buffer | |
| A0H | P2 | Port 2 | ✓ |
| A8H | IE | Interrupt Enable | ✓ |
| B0H | P3 | Port 3 | ✓ |
| B8H | IP | Interrupt Priority | ✓ |
| D0H | PSW | Program Status Word | ✓ |
| E0H | ACC | Accumulator | ✓ |
| F0H | B | B Register | ✓ |
8.2 TCON 位元定義 (88H)
| 位元 | 符號 | 說明 |
|---|---|---|
| TCON.7 | TF1 | Timer 1 溢位旗標 |
| TCON.6 | TR1 | Timer 1 啟動控制 |
| TCON.5 | TF0 | Timer 0 溢位旗標 |
| TCON.4 | TR0 | Timer 0 啟動控制 |
| TCON.3 | IE1 | INT1 邊緣偵測旗標 |
| TCON.2 | IT1 | INT1 觸發模式 (0=Level, 1=Edge) |
| TCON.1 | IE0 | INT0 邊緣偵測旗標 |
| TCON.0 | IT0 | INT0 觸發模式 (0=Level, 1=Edge) |
8.3 IE 位元定義 (A8H)
| 位元 | 符號 | 說明 |
|---|---|---|
| IE.7 | EA | 全域中斷啟用 |
| IE.6 | — | 保留 |
| IE.5 | ET2 | Timer 2 中斷啟用 (8052) |
| IE.4 | ES | 串列埠中斷啟用 |
| IE.3 | ET1 | Timer 1 中斷啟用 |
| IE.2 | EX1 | 外部中斷 1 啟用 |
| IE.1 | ET0 | Timer 0 中斷啟用 |
| IE.0 | EX0 | 外部中斷 0 啟用 |
8.4 P3 替代功能 (B0H)
| 位元 | 符號 | 替代功能 |
|---|---|---|
| P3.0 | RXD | 串列埠接收 |
| P3.1 | TXD | 串列埠傳送 |
| P3.2 | INT0 | 外部中斷 0 |
| P3.3 | INT1 | 外部中斷 1 |
| P3.4 | T0 | Timer 0 外部輸入 |
| P3.5 | T1 | Timer 1 外部輸入 |
| P3.6 | WR | 外部資料記憶體寫入控制 |
| P3.7 | RD | 外部資料記憶體讀取控制 |
8.5 中斷向量表
| 位址 | 中斷源 | 優先權 |
|---|---|---|
| 0003H | 外部中斷 0 (INT0) | 最高 |
| 000BH | Timer 0 溢位 | |
| 0013H | 外部中斷 1 (INT1) | |
| 001BH | Timer 1 溢位 | |
| 0023H | 串列埠 (RI/TI) | 最低 |
8.6 內部 RAM 記憶體映射
┌─────────────────────────────────────┐ FFH
│ │
│ 間接定址專用區 (Upper 128) │ (8052 only)
│ │
├─────────────────────────────────────┤ 80H ←→ SFR (直接定址)
│ │ 7FH
│ 通用 RAM (General Purpose) │
│ 30H ~ 7FH (80 bytes) │
│ │
├─────────────────────────────────────┤ 2FH
│ 位元定址區 (Bit Addressable) │
│ 20H ~ 2FH (16 bytes = 128 bits) │
│ 位元位址 00H ~ 7FH │
├─────────────────────────────────────┤ 1FH
│ Register Bank 3 (18H ~ 1FH) │
│ Register Bank 2 (10H ~ 17H) │
│ Register Bank 1 (08H ~ 0FH) │
│ Register Bank 0 (00H ~ 07H) ← 預設│
└─────────────────────────────────────┘ 00H
版本資訊: 本手冊基於標準 MCS-51 (Intel 8051) 架構。8052 擴充型另有 Timer 2 相關指令與 Upper 128 bytes RAM,未在本文涵蓋。