嵌入式系統 - 指令
程式的流程以順序方式進行,從一條指令到下一條指令,除非執行控制轉移指令。組合語言中各種型別的控制轉移指令包括條件或無條件跳轉和呼叫指令。
迴圈和跳轉指令
8051 中的迴圈
重複執行一系列指令一定次數的操作稱為迴圈。指令DJNZ reg, label用於執行迴圈操作。在此指令中,暫存器遞減 1;如果它不為零,則 8051 跳轉到標籤所引用的目標地址。
在迴圈開始之前,暫存器載入計數器以表示重複次數。在此指令中,暫存器遞減和跳轉決策組合成單個指令。暫存器可以是 R0-R7 中的任何一個。計數器也可以是 RAM 位置。
示例
使用重複加法的方法將 25 乘以 10。
解答 - 乘法可以透過重複新增被乘數來實現,次數與乘數相同。例如:
25 * 10 = 250(FAH)
25 + 25 + 25 + 25 + 25 + 25 + 25 + 25 + 25 + 25 = 250
MOV A,#0 ;A = 0,clean ACC MOV R2,#10 ; the multiplier is replaced in R2 Add A,#25 ;add the multiplicand to the ACC AGAIN:DJNZ R2, AGAIN:repeat until R2 = 0 (10 times) MOV R5 , A ;save A in R5 ;R5 (FAH)
8051 的缺點 - 使用指令DJNZ Reg label的迴圈操作僅限於 256 次迭代。如果不進行條件跳轉,則執行跳轉後的指令。
迴圈內的迴圈
當我們在另一個迴圈內使用迴圈時,這稱為巢狀迴圈。當最大計數限制為 256 時,使用兩個暫存器來儲存計數。因此,我們使用此方法來重複比 256 次更多的操作。
示例
編寫一個程式 -
- 將累加器載入為值 55H。
- 將 ACC 反碼 700 次。
解答 - 由於 700 大於 255(任何暫存器的最大容量),因此使用兩個暫存器來儲存計數。以下程式碼顯示瞭如何使用兩個暫存器 R2 和 R3 來進行計數。
MOV A,#55H ;A = 55H NEXT: MOV R3,#10 ;R3 the outer loop counter AGAIN:MOV R2,#70 ;R2 the inner loop counter CPL A ;complement
其他條件跳轉
下表列出了在 8051 中使用的條件跳轉 -
| 指令 | 動作 |
|---|---|
| JZ | 如果 A = 0 則跳轉 |
| JNZ | 如果 A ≠ 0 則跳轉 |
| DJNZ | 遞減並跳轉如果暫存器 ≠ 0 |
| CJNE A, data | 如果 A ≠ data 則跳轉 |
| CJNE reg, #data | 如果位元組 ≠ data 則跳轉 |
| JC | 如果 CY = 1 則跳轉 |
| JNC | 如果 CY ≠ 1 則跳轉 |
| JB | 如果位 = 1 則跳轉 |
| JNB | 如果位 = 0 則跳轉 |
| JBC | 如果位 = 1 則跳轉並清除位 |
JZ(如果 A = 0 則跳轉) - 在此指令中,檢查累加器的內容。如果為零,則 8051 跳轉到目標地址。JZ 指令僅適用於累加器,不適用於任何其他暫存器。
JNZ(如果 A 不等於 0 則跳轉) - 在此指令中,檢查累加器的內容是否非零。如果它不為零,則 8051 跳轉到目標地址。
JNC(如果無進位,則跳轉如果 CY = 0) - 標誌(或 PSW)暫存器中的進位標誌位用於決定是否跳轉“JNC 標籤”。CPU 檢視進位標誌以檢視是否已置位 (CY = 1)。如果未置位,則 CPU 開始從標籤地址獲取並執行指令。如果 CY = 1,它不會跳轉,而是會執行 JNC 下面的下一條指令。
JC(如果進位,則跳轉如果 CY = 1) - 如果 CY = 1,則跳轉到目標地址。
JB(如果位高則跳轉)
JNB(如果位低則跳轉)
注意 - 必須注意,所有條件跳轉都是短跳轉,即目標地址必須在程式計數器內容的 –128 到 +127 位元組以內。
無條件跳轉指令
8051 中有兩個無條件跳轉 -
LJMP(長跳轉) - LJMP 是 3 位元組指令,其中第一個位元組表示操作碼,第二個和第三個位元組表示目標位置的 16 位地址。2 位元組目標地址是為了允許從 0000 到 FFFFH 的任何記憶體位置跳轉。
SJMP(短跳轉) - 它是一個 2 位元組指令,其中第一個位元組是操作碼,第二個位元組是目標位置的相對地址。相對地址範圍為 00H 到 FFH,分為向前和向後跳轉;也就是說,相對於當前 PC(程式計數器)地址的記憶體空間在 –128 到 +127 位元組內。對於向前跳轉,目標地址可以在距當前 PC 127 位元組的空間內。對於向後跳轉,目標地址可以在距當前 PC –128 位元組的空間內。
計算短跳轉地址
所有條件跳轉(JNC、JZ 和 DJNZ)都是短跳轉,因為它們是 2 位元組指令。在這些指令中,第一個位元組表示操作碼,第二個位元組表示相對地址。目標地址始終相對於程式計數器的值。要計算目標地址,將第二個位元組新增到跳轉指令正下方的指令的 PC。請檢視下面給出的程式 -
Line PC Op-code Mnemonic Operand 1 0000 ORG 0000 2 0000 7800 MOV R0,#003 3 0002 7455 MOV A,#55H0 4 0004 6003 JZ NEXT 5 0006 08 INC R0 6 0007 04 AGAIN: INC A 7 0008 04 INC A 8 0009 2477 NEXT: ADD A, #77h 9 000B 5005 JNC OVER 10 000D E4 CLR A 11 000E F8 MOV R0, A 12 000F F9 MOV R1, A 13 0010 FA MOV R2, A 14 0011 FB MOV R3, A 15 0012 2B OVER: ADD A, R3 16 0013 50F2 JNC AGAIN 17 0015 80FE HERE: SJMP HERE 18 0017 END
向後跳轉目標地址計算
對於向前跳轉,位移值是 0 到 127(十六進位制為 00 到 7F)之間的正數。但是,對於向後跳轉,位移是 0 到 –128 的負值。
CALL 指令
CALL 用於呼叫子程式或方法。子程式用於執行需要頻繁執行的操作或任務。這使程式更結構化並節省記憶體空間。有兩條指令 - LCALL 和 ACALL。
LCALL(長呼叫)
LCALL 是一條 3 位元組指令,其中第一個位元組表示操作碼,第二個和第三個位元組用於提供目標子程式的地址。LCALL 可用於呼叫在 8051 的 64K 位元組地址空間內可用的子程式。
為了成功返回到呼叫子程式執行後的點,CPU 將 LCALL 下方指令的地址儲存到堆疊中。因此,當呼叫子程式時,控制將轉移到該子程式,處理器將 PC(程式計數器)儲存在堆疊中,並開始從新位置獲取指令。指令 RET(返回)在完成子程式執行後將控制轉移回呼叫方。每個子程式都使用 RET 作為最後一條指令。
ACALL(絕對呼叫)
與 LCALL 為 3 位元組相比,ACALL 是一條 2 位元組指令。子程式的目標地址必須在 2K 位元組內,因為只有 2 位元組的 11 位用於定址。ACALL 和 LCALL 之間的區別在於 LCALL 的目標地址可以在 8051 的 64K 位元組地址空間中的任何位置,而 CALL 的目標地址在 2K 位元組範圍內。