CHƯƠNG 3. LẬP TRÌNH HỢP NGỮ VỚI VI ĐIỀU KHIỂN PIC
3.4 Tập lệnh hợp ngữ của vi điều khiển PIC
Có 3 loại lệnh:
- Lệnh thao tác với byte - Lênh thao tác với bit - Lệnh thao tác với số
32
3.4.2 Lệnh thao tác với byte Dạng lệnh: lệnh f,d
Trừ các lệnh: CLRW ( xóa thanh ghi W) CLRF f (xóa thanh ghi f)
NOP (lệnh không làm gì) Trong đó:
- Lệnh là từ gợi nhớ về phép toán thực hiện. Ví dụ: ADDWF là cộng thanh ghi W và thanh ghi F
- F: là địa chỉ của thanh ghi (trong bộ nhớ RAM) đƣợc thao tác trong lệnh.
Ví dụ: ADDWF PORTA,1 ADDWF 0x05,1
Cả hai lệnh trên là giống nhau: Cộng thanh ghi w và thanh ghi có địa chỉ 0x05 trong bộ nhớ RAM. Vi điều khiển chỉ biết địa chỉ 0x05 không biết PORTA là gì - d: chỉ ra kết quả của lệnh chứa ở đâu.
o Nếu d=0: kết quả chứa trong w
o Nếu d=1: kết quả chứa trong thanh ghi f o Mặc định: d=1, kết quả chứa trong thanh ghi f Ví dụ: ADDWF 0x05,0
W=W+thanh ghi có địa chỉ 0x05 ADDWF 0x05,1
Thanh ghi có địa chỉ 0x05=W+ Thanh ghi có địa chỉ 0x05 3.4.3 Lệnh thao tác với bit
Dạng lệnh: lệnh f,b Trong đó:
- Lệnh là từ gợi nhớ về phép toán thực hiện - f: địa chỉ thanh ghi
- b: vị trí của bit 0-7 Ví dụ: BSF 0x23,3
33
3.4.4 Lệnh thao tác với số Dạng lệnh: lệnh số
Trong đó:
- Lệnh là từ gợi nhớ về phép toán thực hiện - Số là tham số trong phép toán
Ví dụ: ADDLW 0x30 3.4.5 Một số lệnh đặc biệt
Tập lệnh của vi điều khiển PIC gồm 35 lệnh. Dạng lệnh và miêu tả dễ dàng hiểu đƣợc qua datasheet. Ở đây chỉ giới thiệu một số lệnh đặc biệt
3.4.6 Lệnh kiểm tra trạng thái của bit Có 2 lệnh: BTFSS và BTFSC
- Dạng lệnh:
BTFSS địa chỉ thanh ghi, vị trí bít Lệnh 1
Lệnh 2
Miêu tả: kiểm tra bít ở vị trí bít trên thanh ghi, nếu bít đó bằng 1 bỏ qua lệnh 1 thực hiện lệnh 2, nếu bít đó bằng 0 thực hiện lệnh 1 (theo kiểu tuần tự)
Chú ý là khi bit =1, lệnh này mất 2 chu kì lệnh, khi bit =0 lệnh này mất 1 chu kì lệnh - Dạng lệnh:
BTFSC địa chỉ thanh ghi, vị trí bít Lệnh 1
Lệnh 2
Miêu tả: kiểm tra bít ở vị trí bít trên thanh ghi, nếu bít đó bằng 0 bỏ qua lệnh 1 thực hiện lệnh 2, nếu bít đó bằng 1 thực hiện lệnh 1 (theo kiểu tuần tự)
Chú ý là khi bit =0, lệnh này mất 2 chu kì lệnh, khi bit =1 lệnh này mất 1 chu kì lệnh 3.4.7 Lệnh tăng giảm đồng thời kiểm tra thanh ghi
Có 2 lệnh: DECFSZ, INCFSZ - Dạng lệnh:
34
DECFSZ địa chỉ thanh ghi,hướng Lệnh 1
Lệnh 2
Miêu tả: Lệnh này trước hết tự động giảm giá trị của thanh ghi đi 1 đơn vị và sau đo kiểm tra nếu thanh ghi đó bằng 0 bỏ qua lệnh 1 thực hiện lệnh 2, nếu khác 0 thực hiện lệnh 1 (theo kiểu tuần tự như bình thường)
Chú ý là khi thanhghi =1, lệnh này mất 2 chu kì lệnh, khi thanhghi#1 lệnh này mất 1 chu kì lệnh
- Dạng lệnh:
INCFSZ địa chỉ thanh ghi,hướng Lệnh 1
Lệnh 2
Miêu tả: Lệnh này trước hết tự động tăng giá trị của thanh ghi đi 1 đơn vị và sau đo kiểm tra nếu thanh ghi đó bằng 0 bỏ qua lệnh 1 thực hiện lệnh 2, nếu khác 0 thực hiện lệnh 1 (theo kiểu tuần tự như bình thường)
3.4.8 Lệnh nhảy không điều kiện GOTO Dạng lệnh: GOTO nhãn
Miêu tả: nhảy đến đoạn chương trình bắt đầu bởi nhãn Để hiểu rõ đoạn chương trình trên ta có ví dụ sau:
START:
BSF PORTB,1 CALL DELAY BCF PORB,1 CALL DELAY
GOTO START
Khi gặp lệnh GOTO START, vi điều khiển lập tức nhảy đến đoạn chương trình bắt đầu bởi START tức là sẽ nhảy đến lệnh BSF PORTB,1
Thực ra, đằng sau lệnh GOTO START, vi điều khiển tính ra địa chỉ của lệnh bắt đầu sau START giả sử đó là k, và câu lệnh thực sự là GOTO k
35
Chúng ta xem dạng dissampling của đoạn lệnh trên sẽ rõ:
29: ; BAT DAU XU LY 30: START:
000A 1486 BSF 0x6, 0x1 31: BSF PORTB,1 000B 200F CALL 0xf 32: CALL DELAY 000C 1086 BCF 0x6, 0x1 33: BCF PORTB,1 000D 200F CALL 0xf 34: CALL DELAY 000E 280A GOTO 0xa 35: GOTO START
Cột thứ nhất chứa địa chỉ của lệnh. Cột thứ 3 là lệnh thực sự đã đƣợc phân giải. Ta thấy lệnh nằm ngay sau nhãn là BSF PORTB,1 có địa chỉ là 0x0a trong bộ nhớ chương trình Vì vậy trong cột 3, ta có lệnh GOTO 0xa
Nhƣ vậy dạng lệnh thực sự là GOTO k
Khi gặp lệnh này: PC<10:0>=k; PC<12:11>=PCLATCH<4:3>
Tóm lại có thể giải thích lại nhƣ sau:
Khi gặp lệnh: goto nhãn
Trong trường hợp trên là goto start
MPLAB tính ra địa chỉ của lệnh nằm ngay sau nhãn start, giả sử đó là k Trong trường hợp trên là lệnh BSF PORTB,1 có địa chỉ k=0x0a
MPLAB điều khiển đƣa giá trị k vào thanh ghi PC: PC=k Do đó chương trình vi điều khiển sẽ chạy lệnh BSF PORTB,1 Mã hóa lệnh: 10 1kkk kkkk kkkk
Nhìn vào mã hóa lệnh ta thấy địa chỉ k gồm 11 bit kkk kkkk kkkk Nhƣ vậy thực ra chỉ 11 bit đầu của thanh ghi PC là chứa giá trị k:
PC<10:0>=kkk kkkk kkkk
2 bit cao của thanh ghi PC lấy từ thanh ghi PCLATCH PC<12:11>=PCLATCH<4:3>
Điều này sẽ dẫn đến một vấn đề!!!
36
Giả sử ta có đoạn chương trình sau:
org 0x005 main
banksel trisb clrf trisb
banksel PORTB START:
BSF PORTB,1 CALL DELAY BCF PORTB,1 CALL DELAY GOTO UPDATE ORG 0x800
UPDATE:
MOVLW 0xFF MOVWF PORTB
Nhƣ vậy lệnh GOTO UPDATE nằm ở địa chỉ 0x0E
Nhƣ vậy khi gặp lệnh này, 2 bit của thanh ghi PCLATCH<4:3>=00
Lệnh nằm sau nhãn UPDATE là MOVLW 0xFF nằm ở địa chỉ 0x800 (do có chỉ dẫn biên dịch ORG 0x800)
Suy ra địa chỉ là: 0x800=1000 0000 0000
Nhƣ vậy khi gặp lệnh GOTO UPDATE, thanh ghi PC đƣợc nạp giá trị:
PC<10:0> = 000 0000 0000
PCLATCH vẫn không đổi: PCLATCH<4:3>=00 Suy ra, PC<12:11>=PC<4:3>=00
Suy ra: PC=0 0000 0000 0000 =0x00
Vậy chương trình nhảy đến địa chỉ 0x00!!!!!
Chắc chắn là chương trình sẽ không chạy được đoạn lệnh nằm sau UPDATE Để chạy đúng, đơn giản là ta phải dùng lệnh cho PCLATCH<4:3>=01
37
Đoạn chương trình đúng sẽ như sau:
org 0x005 main
banksel trisb clrf trisb
banksel PORTB START:
BSF PORTB,1 CALL DELAY BCF PORTB,1 CALL DELAY
PAGESEL UPDATE GOTO UPDATE ORG 0x800
UPDATE:
MOVLW 0xFF MOVWF PORTB
3.4.9 Lệnh gọi chương trình con CALL Dạng lệnh: CALL nhãn
Cách làm việc của lệnh này tương tự như lệnh goto chỉ khác là trước khi nhảy đến địa chỉ nhãn, vi điều khiển lưu lại địa chỉ của lệnh kế tiếp sau lệnh CALL tức PC+1 vào ngăn xếp để sau khi thực hiện đoạn chương trình con, vi điều khiển chạy về chương trình chính và thực hiện lệnh kế tiếp đó.
3.4.10 Các toán tử
Các kí hiệu +,-,*, / v.v.v gọi là các toán tử.
Chương trình hợp ngữ MPLAB qui định một tập các toán tử như sau:
38
Bảng 3.2: Các toán tử
Qua bảng trên ta dễ dàng hiểu đƣợc chức năng của từng toán tử.
Ở đây chỉ lưu ý một số toán tử đặc biệt như sau:
- Toán tử $: thường đi kèm với lệnh goto Goto $
Sau khi thực hiện lệnh này, thanh ghi PC giữ giá trị không đổi: PC=PC
(Thông thường sau khi thực hiện 1 lệnh, PC=PC+1, vi điều khiển thực hiện lệnh tiếp theo)
Goto $-n
39
Sau khi thực hiện các lệnh này, PC=PC-$, nhƣ vậy sau khi thực hiện lệnh này, vi điều khiển sẽ nhảy đến thực hiện lệnh trước lệnh hiện tại n lệnh
Tương tự với:
Goto $+n Ví dụ:
decfsz bien1,F goto $-1 decfsz bien2,F goto $-3
Như vậy khi gặp lệnh goto $-1, vi điều khiển nhảy về thực hiện lệnh trước đó nằm cách 1 lệnh decfsz bien1,f, khi gặp lệnh goto $-3, vi điều khiển nhảy về thực hiện lệnh trướ đó nằm cách 3 lệnh tức là sẽ thực hiện lệnh decfsz bien1,f
- Toán tử !: hay đƣợc dùng trong câu điều kiện If(!(a= =b)) nghĩa là nếu a!=b
3.4.11 Chu kì lệnh:
Hình 3.1: Chu kỳ lệnh Chu kì thực hiện 1 lệnh gồm 4 bước, kí hiệu là Qi, i=1-4:
- Q1: thời gian giải mã lệnh - Q2: thời gian đọc lệnh
- Q3: thời gian thực thi dữ liệu - Q4: thời gian viết dữ liệu
40
Mỗi bước tương ứng với 1 chu kì xung của vi điều khiển. Xung dao động của vi điều khiển đƣợc tạo ra từ mạch dao động bên ngoài nhƣ thạch anh, mạch RC hoặc mạch dao động bên trong (Phần cấu hình cho dao động sẽ đƣợc đề cập ở mục khác).
Nếu dùng bộ dao động xung thạch anh có tần số f=4MHZ Chu kì xung =1/tần số xung=1/4MHz
Chu kì lệnh = 4 * chu kì xung= 4/4MHZ= 1us (micro giây)
Hầu nhƣ tất cả các lệnh trong 35 lệnh của vi điều khiển PIC16F thực hiện trong 1 chu kì lệnh trừ 1 số lệnh đặc biệt nhƣ lệnh CALL, GOTO, RETURN, RETFI,RETLW mất 2 chu kì lệnh. Ngoài ra còn có một số lệnh khi thì thực hiện trong 1 chu kì lệnh khi thì 2.
Đó là các lệnh DECFSZ, INCFSZ, BTFSZ, BTFSC. (Xem tập lệnh trang 158-datasheet 16f877a)
Ta lấy lệnh DECFSZ để giải thích cho dễ hiểu:
Ví dụ: DECFSZ bien,1
GOTO nhan1 GOTO nhan2
Lệnh đầu tiên DECFSZ giảm thanh ghi bien đi 1 đơn 1: bien=bien-1 Sau đó lệnh này kiểm tra bien:
Nếu bien=0 nhảy qua 1 lệnh, tức là nhảy đến và thực hiện lệnh GOTO nhan2 Nếu bien#0 thì không nhảy tức là thực hiện lệnh GOTO nhan2
Như vậy nếu bien#0 (tức là trước khi gặp lệnh này bien #1)thì vi điều khiển mất một chu kì lệnh để thực hiện lệnh(để thực hiện thao tác trừ)
Nếu bien=0 (tức là trước khi gặp lệnh này bien=1) thì vi điều khiển mất 2 chu kì lệnh để thực hiện lệnh(1 chu kì lệnh để thao tác trừ + 1 chu kì lệnh để nhảy)
Thời gian thực hiện lệnh INCFSZ, BTFSC,BTFSS cũng tương tự như vậy