Chương III: LẬP TRÌNH HỢP NGỮ TRÊN VI ĐIỀU KHIỂN MCS-51
3. Nhóm lệnh chuyển điều khiển
Nhóm lệnh chuyển điều khiển bao gồm các lệnh nhảy, các lệnh liên quan đến chương trình con, mô tả như sau:
Bảng 3.6 – Các lệnh chuyển điều khiển
Lệnh Hoạt động Chu kỳ thực thi
JMP addr Nhảy tới nhãn addr 2
JMP @A+DPTR Nhảy tới địa chỉ A + DPTR 2
CALL addr Gọi chương trình con tại địa chỉ addr 2
RET Trở về từ chương trình con 2
RETI Trở về từ chương trình con phục vụ ngắt 2
NOP Không làm gì cả 1
JMP: Jump RET: Return
RETI: Return from Interrupt NOP: No Operation
Lệnh Hoạt động Chế độ địa chỉ Chu kỳ
thực thi Tức thời Trực tiếp Gián tiếp Thanh ghi
JZ rel Nhảy đến nhãn rel nếu A = 0 Chỉ dùng cho thanh ghi A 2 JNZ rel Nhảy đến nhãn rel nếu A ≠ 0 Chỉ dùng cho thanh ghi A 2
DJNZ (byte),rel (byte) = (byte) - 1 Nếu (byte) ≠ 0 thì nhảy đến nhãn
rel x x 2
CJNE A,(byte),rel Nhảy đến nhãn rel nếu A ≠ (byte) x x 2
CJNE (byte),
#data8,rel Nhảy đến nhãn rel nếu (byte) ≠
data8 x x 2
JZ: Jump if Zero; JNZ: Jump if Not Zero DJNZ: Decrement and Jump if Not Zero CJNE: Compare and Jump if Not Equal
Lệnh JMP (Jump):
Lệnh JMP bao gồm 3 lệnh: LJMP (Long jump), AJMP (Absolute jump) và SJMP (Short jump) cho phép nhảy đến một vị trí bất kỳ trong chương trình.
Lệnh LJMP có kích thước 3 byte trong đó 1 byte mã lệnh và 2 byte chứa địa chỉ nhãn nên phạm vi biểu diễn địa chỉ là 64K (2 byte = 16 bit -> phạm vi biểu diễn 216 = 26 x 210 = 64K). Do đó lệnh LJMP có thể thực hiện nhảy đến bất kỳ vị trí nào trong chương trình và địa chỉ sử dụng trong lệnh LJMP là địa chỉ tuyệt đối.
Lệnh SJMP có kích thước 2 byte trong đó có 1 byte mã lệnh và 1 byte địa chỉ nên phạm vi biểu diễn địa chỉ là 256 byte. Trong lệnh này, địa chỉ sử dụng không phải là địa chỉ tuyệt đối mà là địa chỉ tương đối (khoảng nhảy tính từ vị trí bắt đầu lệnh). Do byte địa chỉ sử dụng phương pháp bù 2 nên phạm vi biểu diễn từ -128 ÷ + 127, nghĩa là phạm vi nhảy của lệnh SJMP chỉ trong phạm vi từ - 128 đến 127 byte. Phạm vi thực hiện mô tả như hình vẽ.
Hình 3.1 – Phạm vi thực hiện của lệnh SJMP
Lệnh AJMP có kích thước 2 byte trong đó địa chỉ chứa trong 11 bit nên phạm vi biểu diễn địa chỉ là 211 (2K). Trong khi đó, vùng địa chỉ tối đa của MCS-51 là 64K nên khi thực hiện lệnh AJMP, 64K chương trình phải chia thành từng vùng 2K (tổng cộng 32 vùng) và lệnh AJMP chỉ có thể thực hiện trong một vùng.
Tuy nhiên, khi lập trình cho MCS-51, thông thường các chương trình dịch đều cho phép sử dụng lệnh JMP thay thế cho 3 lệnh trên. Khi biên dịch, chương trình dịch sẽ tự động thay thế bằng các lệnh thích hợp.
Hình 3.2 – Phạm vi thực hiện của lệnh AJMP
Lệnh JMP @A + DPTR cho phép chọn các vị trí nhảy khác nhau tuỳ theo giá trị trong thanh ghi A. Địa chỉ nhảy đến chính là tổng giá trị của thanh ghi A và DPTR.
Ví dụ:
MOV DPTR, # JUMP_TABLE ; Địa chỉ bảng nhảy MOV A, INDEX_NUMBER ; Vị trí nhảy MOV B, #3 ; x3 do lệnh LJMP MUL AB ; có kích thước 3 JMP @ A + DPTR
………
JUMP_TABLE:
LJMP LABEL0 ; Vị trí nhảy 0 LJMP LABEL1 ; Vị trí nhảy 1 LJMP LABEL2 ; Vị trí nhảy 2 LJMP LABEL3 ; Vị trí nhảy 3 LJMP LABEL4 ; Vị trí nhảy 4
Lệnh CALL, RET, RETI
Lệnh CALL dùng để gọi chương trình con, bao gồm 2 lệnh: ACALL (Absolute Call) và LCALL (Long Call). Vị trí có thể gọi lệnh CALL giống như đã xét trong lệnh JMP. Khi lập trình, thông thường các chương trình dịch cũng cho phép thay thế duy nhất bằng lệnh CALL và khi biên dịch, lệnh CALL sẽ được thay thế bằng lệnh ACALL hay LCALL tuỳ theo vị trí gọi lệnh. Lưu ý rằng khi thực hiện lệnh CALL thì trong chương trình con phải kết thúc bằng lệnh RET.
Ngoài ra, khi sử dụng các chương trình con phục vụ ngắt, khi kết thúc phải dùng lệnh RETI. Lệnh RETI và lệnh RET chỉ khác nhau ở chỗ lệnh RETI báo cho hệ thống điều khiển ngắt biết rằng quá trình xử lý ngắt đã thực hiện xong.
Lệnh JZ, JNZ
Lệnh JZ và JNZ dùng để kiểm tra nội dung của thanh ghi A. Lệnh JZ nhảy khi A = 0 và JNZ nhảy khi A ≠ 0. Lưu ý rằng phạm vi nhảy chỉ cho phép trong khoảng từ -128 ÷ 127 byte (giống như khi sử dụng lệnh SJMP).
Lệnh DJNZ:
Lệnh DJNZ thường được dùng để tạo vòng lặp. Số lần lặp được chuyển vào thanh ghi đếm ở đầu vòng lặp (thanh ghi đếm có thể dùng bất kỳ thanh ghi nào hay là bộ nhớ).
Ví dụ:
MOV R7, #10 ; Lặp 10 lần LOOP:
……
……
DJNZ R7, LOOP
Lệnh CJNE:
Lệnh CJNE dùng để so sánh 2 giá trị với nhau, khi 2 giá trị này khác nhau thì sẽ thực hiện lệnh nhảy. Lưu ý rằng trong tập lệnh của MCS-51 không có lệnh lớn hơn hay nhỏ hơn nên chỉ có thể thực hiện các lệnh này bằng cách kết hợp lệnh CJNE và nội dung của cờ Carry.
Trong lệnh CJNE, nếu byte đầu tiên nhỏ hơn byte thứ hai thì CF = 1. Ngược lại (byte đầu tiên lớn hơn hay bằng byte thứ hai) thì CF = 0.
Ví dụ: Kiểm tra nội dung của thanh ghi A, nếu A nhỏ hơn 10 thì xuất giá trị trong thanh ghi A ra Port 1. Ngược lại thì xuất giá trị 10 ra Port 1.
CJNE A,#10,Khacnhau ; So sánh A với 10
JMP Xuat10 ; Nếu A = 10 thì xuất giá trị 10 Khacnhau:
JC XuatA ; Nếu CF = 1 (A < 10) thì xuất nội Xuat10: ; dung trong A ra P1
MOV P1,#10 SJMP Tiep XuatA:
MOV P1,A Tiep: