本手冊涵蓋 MCS-51 微控制器的全部 111 條指令,分為五大類別,詳細說明每條指令的語法、運作原理、影響旗標、位元組數、機器週期數及使用範例。


目錄

  1. 基本概念
  2. 資料傳送指令 (Data Transfer)
  3. 算術運算指令 (Arithmetic)
  4. 邏輯運算指令 (Logic)
  5. 位元操作指令 (Boolean / Bit Manipulation)
  6. 程式分支指令 (Program Branching)
  7. 指令速查表
  8. 附錄: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+DPTR vs @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) vs MOV 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 AINC 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!)

RETI vs RET 的差異: - 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 結合了 DECJNZ,是最高效的迴圈計數器指令。

指令 位元組 週期 動作
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,未在本文涵蓋。