Tải bản đầy đủ (.pdf) (104 trang)

Giáo trình hợp ngữ - Lập trình PIC 16F877A

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (848.62 KB, 104 trang )

T
T
r
r


n
n


T
T
h
h
á
á
i
i


A
A
n
n
h
h


Â
Â
u


u






K
K
h
h
o
o
a
a


Đ
Đ
i
i


n
n









Đ
Đ


i
i


h
h


c
c


B
B
á
á
c
c
h
h


K

K
h
h
o
o
a
a


-
-


Đ
Đ


i
i


h
h


c
c


Đ

Đ
à
à


N
N


n
n
g
g


1

CHƯƠNG 1: CẤU TRÚC VI ĐIỀU KHIỂN PIC 16F
1. Cấu trúc chung:

Hình 1: Cấu trúc chung của vi điều khiển
Cấu tạo của vi điều khiển có thể chia làm 2 phần cơ bản như sau:
- Phần lõi: gồm bộ điều khiển trung tâm có chức năng chạy chương trình
(gồm các câu lệnh) đã được nạp vào trong bộ nhớ chương trình (program
memory) trước đó.
- Phần ngoại vi: gồm có các timer, bộ biến đổi tương tự số ADC và các
modun khác
T
T
r

r


n
n


T
T
h
h
á
á
i
i


A
A
n
n
h
h


Â
Â
u
u







K
K
h
h
o
o
a
a


Đ
Đ
i
i


n
n









Đ
Đ


i
i


h
h


c
c


B
B
á
á
c
c
h
h


K
K
h

h
o
o
a
a


-
-


Đ
Đ


i
i


h
h


c
c


Đ
Đ
à

à


N
N


n
n
g
g


2

Phần lõi của vi điều khiển chịu trách nhiệm chạy chương trình trong vi điều khiển
và quản lý toàn bộ các hoạt động khác bao gồm hoạt động của ngoại vi.
Vi điều khiển chạy chương trình gồm các lệnh trong bộ nhớ chương trình, địa chỉ
của lệnh nằm trong thanh ghi bộ đếm chương trình PC, lúc khởi động PC=0, sau
khi thực hiện một lệnh PC=PC+1 do đó vi điều khiển chạy lệnh kế tiếp trong
chương trình. Lệnh vi điều khiển trong bộ nhớ thực ra đã được mã hóa mỗi lệnh
thành 14 bit. Quá trình thực hiện một lệnh gồm các bước:
- Lệnh trong bộ nhớ chương trình được đưa vào thanh ghi lệnh (địa chỉ của lệnh
nằm trong thanh ghi PC). Sau đó lệnh đưa vào bộ giải mã và điều khiển để giải mã
lệnh. Trên cơ sở đó, vi điều khiển biết lệnh đó là lệnh gì, thao tác với dữ liệu nào,
phép thao tác v.v.v Trên cơ sở đó, nếu lệnh thao tác với dữ liệu chứa trong các
thanh ghi trong RAM, bộ điều khiển điều khiển đọc dữ liệu trong RAM đưa vào
bộ xử lý số học và logic ALU, các phép toán sẽ được thực hiện qua trung gian là
thanh ghi làm việc W, quá trình sẽ kết thúc khi kết quả trả dữ liệu về cho chương
trình, tiếp theo PC tăng lên 1 đơn vị, vi điều khiển nhảy đến lệnh kế tiếp, tiếp tục 1

chu kì thực hiện lệnh













T
T
r
r


n
n


T
T
h
h
á
á

i
i


A
A
n
n
h
h


Â
Â
u
u






K
K
h
h
o
o
a
a



Đ
Đ
i
i


n
n








Đ
Đ


i
i


h
h



c
c


B
B
á
á
c
c
h
h


K
K
h
h
o
o
a
a


-
-


Đ
Đ



i
i


h
h


c
c


Đ
Đ
à
à


N
N


n
n
g
g



3

CHƯƠNG 2: BỘ NHỚ VI ĐIỀU KHIỂN PIC 16F877A
Bộ nhớ vi điều khiển PIC chia làm 3 phần:
- Bộ nhớ chương trình-FLASH: chứa nội dung của chương trình chạy trong
vi điều khiển. Bộ đếm chương trình PC (Program counter) sẽ thực hiện các
lệnh chứa trong bộ nhớ chương trình này theo thứ tự từ trên xuống.
- Bộ nhớ dữ liệu tạm thời- RAM : Gồm 2 phần: các thanh ghi đặc biệt-SFR
(Special Function Register) - đây là các thanh ghi chức năng thể hiện hoặc
trạng thái, điều khiển của các khối bên trong vi điều khiển PIC (các thanh
ghi trạng thái các chân vi điều khiển như PORTA v.v, Các thanh ghi Status
v.vv, TMR0 cho timer v.v ). Các thanh ghi mục đích chung GPR (general
purpose register) là nơi lưu các giá trị tạm thời, nơi mà các biến chương
trình nằm đây
- Bộ nhớ dữ liệu không mất nội dung- EEPROM cho phép chứa các dữ liệu
và dữ liệu này không mất nội dung khi mất điện (phần này xem như thiết bị
ngoại vi)
2.1 Bộ nhớ chương trình:
Bộ nhớ chương trình là nơi chứa các lệnh đã được mã hóa. Quá trình mã hóa đã
được thực hiện trong khâu dịch chương trình trên máy tính ra file hex và nạp
chương trình vào bộ nhớ chương trình.
Mỗi một lệnh đã được mã hóa được chứa trong 1 thanh ghi 14 bit trong bộ nhớ
chương trình
Như vậy khi hình dung về bộ nhớ chương trình ta có hình ảnh sau:

Bit
13
Bit
12
Bit

11
Bit
10
Bit
9
Bit
8
Bit
7
Bit
6
Bit
5
Bit
4
Bit
3
Bit
2
Bit
1
Bit
0
0 0 0 1 1 1 0 1 0 1 1 0 1 0
0 0 0 1 0 1 1 0 1 1 1 1 1 0

T
T
r
r



n
n


T
T
h
h
á
á
i
i


A
A
n
n
h
h


Â
Â
u
u







K
K
h
h
o
o
a
a


Đ
Đ
i
i


n
n









Đ
Đ


i
i


h
h


c
c


B
B
á
á
c
c
h
h


K
K
h
h

o
o
a
a


-
-


Đ
Đ


i
i


h
h


c
c


Đ
Đ
à
à



N
N


n
n
g
g


4


-
1 1 1 1 1 1 0 0 1 1 1 0 1 1
0 1 1 1 0 1 0 1 0 1 0 1 0 1

Chương trình của vi điều khiển chạy theo thứ tự từ địa chỉ thấp đến địa chỉ cao, địa
chỉ lệnh là nội dung của thanh ghi bộ đếm chương trình PC (Program Counter).
Đối với pic16f877a, thanh ghi PC có độ dài 13 bit.
Nếu dùng 2 bit địa chỉ ta phân biệt được 4 địa chỉ: 00,01,10,11
Nếu dùng 3 bit địa chỉ ta phân biệt được 8 địa chỉ:
000,001,010,011,100,101,110,111

Suy ra, PC dùng 13 bit địa chỉ ta phân biệt được 2^13= 2^3 x 2^10=8K địa chỉ
Khi bật nguồn cho vi điều khiển (hay ấn nút reset chương trình), PC được xóa về 0
Sau khi thực hiện xong 1 lệnh nội dung của PC tăng lên 1 đơn vị: PC=PC+1 (trừ 1
số lệnh đặc biệt như gọi chương trình con, goto v.v.v)

Do vi điều khiển sẽ thực hiện lệnh tại địa chỉ chứa trong thanh ghi PC nên theo
phân tích trên có thể nói, vi điều khiển thực hiện lệnh tuần tự từ địa chỉ thấp đến
địa chỉ cao
2.1.1 Mã hóa và giải mã lệnh:
Như đã nói ở trên, khi chương trình đã nằm trong bộ nhớ (tức là đã được nạp vào),
các lệnh đã được mã hóa thành số nhị phân 14 bit chứa trong các thanh ghi của bộ
nhớ chương trình.
Việc mã hóa này phải tuân theo qui luật của từng loại vi điều khiển mà cụ thể đối
với PIC16F877a thì việc mã hóa phải tuân theo qui luật của nhà sản xuất
microchip qui định để trong quá trình thực hiện 1 lệnh, bộ điều khiển bên trong
của vi điều khiển PIC có thể giải mã (để hiểu) và thực thi lệnh đó được.
Để tiện cho việc theo dõi, ta đưa ra bảng tổng hợp các lệnh vi điều khiển 16f877a
như sau:
T
T
r
r


n
n


T
T
h
h
á
á
i

i


A
A
n
n
h
h


Â
Â
u
u






K
K
h
h
o
o
a
a



Đ
Đ
i
i


n
n








Đ
Đ


i
i


h
h


c

c


B
B
á
á
c
c
h
h


K
K
h
h
o
o
a
a


-
-


Đ
Đ



i
i


h
h


c
c


Đ
Đ
à
à


N
N


n
n
g
g


5



Bảng 1: Tập hợp tấc cả các lệnh
Toàn bộ tập lệnh chia làm 3 dạng:
- Lệnh thao tác theo từng byte (Byte-Oriented)
- Lệnh thao tác theo từng bit (Bit-Oriented)
- Lệnh thao tác với hằng số
Trong vi điều khiển pic16f877a không có lệnh thực hiện tương tác giữa 2 thanh
ghi, hay giữa thanh ghi và một số (chú ý ở đây, thanh ghi là thanh ghi nằm
trong bộ nhớ RAM, ví dụ như PORTA hoặc thanh ghi có địa chỉ 0x21 )
Để giải quyết vấn đề trên, trong vi điều khiển pic 16f877a có thanh ghi đặc biệt
làm chức năng trung gian cho các thao tác trên gọi là thanh ghi làm việc W
(work register)
Để dễ hiểu:
T
T
r
r


n
n


T
T
h
h
á
á

i
i


A
A
n
n
h
h


Â
Â
u
u






K
K
h
h
o
o
a
a



Đ
Đ
i
i


n
n








Đ
Đ


i
i


h
h



c
c


B
B
á
á
c
c
h
h


K
K
h
h
o
o
a
a


-
-


Đ
Đ



i
i


h
h


c
c


Đ
Đ
à
à


N
N


n
n
g
g



6

Giả sử ta có 2 biến a,b (tất nhiên là được khai báo và cấp phát trong bộ nhớ
RAM)
Ta muốn thực hiện phép toán:
a=a+b
Trong PIC không có lệnh thực hiện giữa 2 thanh ghi a và b. Để thực hiện lệnh
này ta phải qua các bước:
W=0
W= w+b (sau lệnh này w=b)
a=w+a (sau lện này a=w+a=b+a)
Các lệnh thực hiện chuỗi phép toán trên như sau:
CLRW
ADDWF b,0
ADDWF a,1
Phần cụ thể về lệnh sẽ được giới thiệu sau, ta trở lại vấn đề mã hóa lệnh
Cấu trúc một lệnh:
Cấu trúc một lệnh phụ thuộc vào 3 dạng thao tác theo byte, theo bit , thao tác
với hằng số
- Các lệnh thao tác theo byte
Cấu trúc lệnh:
o Mã lệnh thanhghi,d
Đây là các tác động giữa thanh ghi trong RAM và thanh ghi làm việc W, d
chỉ hướng kết quả được lưu trữ. d=0 kết quả chứa trong w, d=1 kết quả chứa trong
thanh ghi
Ví dụ: cộng thanh ghi a với w, kết quả chứa trong a
ADDWF a,1
cộng thanh ghi a với w, kết quả chứa trong w
ADDWF a,0
T

T
r
r


n
n


T
T
h
h
á
á
i
i


A
A
n
n
h
h


Â
Â
u

u






K
K
h
h
o
o
a
a


Đ
Đ
i
i


n
n









Đ
Đ


i
i


h
h


c
c


B
B
á
á
c
c
h
h


K

K
h
h
o
o
a
a


-
-


Đ
Đ


i
i


h
h


c
c


Đ

Đ
à
à


N
N


n
n
g
g


7

Câu hỏi đặt ra là khi vi điều khiển đọc mã lệnh trong bộ nhớ gồm các con số
nhị phân làm sao nó xác định được đâu là lệnh cộng (ADDWF) đâu là lệnh
AND (ANDWF) ?
Câu trả lời là trong lúc mã hóa lệnh một số bit đầu tiên của chuỗi 14 bit lệnh
dành để phân biệt các lệnh với nhau hay còn gọi là mã toán tử hay theo tiếng
anh là opcode
Đối với lệnh theo tác theo byte, vi điều khiển dùng 6 bit để mã hóa opcode
Để phân biệt khi nào kết quả chứa trong thanh ghi, khi nào thì chứa trong w, vi
điều khiển dành 1 bít hướng d: d=0 kết quả chứa trong thanh ghi w, d=1 kết
quả chứa trong thanh ghi.
7 bit còn lại trong để phân biệt lệnh tác động với thanh ghi nào trong bộ nhớ
RAM
13 8 7 6 0

OPCODE (toán tử) d(hướng)

FILE (địa chỉ thanh ghi)

Ví dụ: ADDWF a, 0
Giải sử a địa chỉ là 0x30= 0b00110000
Mã lệnh sẽ là:
OPCODE (toán tử) d(hướng)

FILE (địa chỉ thanh ghi)
00 0111 0 0110000

- Các lệnh thao tác theo bit
Cấu trúc lệnh gồm 3 phần:
o Mã lệnh thanh ghi, bit
Các lệnh bao gồm lệnh set 1 bit nào đó của một thanh ghi nào đó lên mức 1 hoặc
xóa bít đó về 0, hoặc kiểm tra 1 bit nào đó của một thanh ghi nào đó bằng 0 hoặc
bằng 1 v.v
Từ đây, ta có thể thấy, cần một số bit trong 14 bit của 1 lệnh dành để phân biệt các
lệnh với nhau, cụ thể ở đây là 4 bit, cần 3 bít để xác định vị trí bít nào trong thanh
T
T
r
r


n
n



T
T
h
h
á
á
i
i


A
A
n
n
h
h


Â
Â
u
u






K
K

h
h
o
o
a
a


Đ
Đ
i
i


n
n








Đ
Đ


i
i



h
h


c
c


B
B
á
á
c
c
h
h


K
K
h
h
o
o
a
a



-
-


Đ
Đ


i
i


h
h


c
c


Đ
Đ
à
à


N
N



n
n
g
g


8

ghi bị tác động (vì vị trí bít là 0-7), còn lại 7 bít để xác định thanh ghi nào trong
các thanh ghi bộ nhớ RAM bị tác động
13 10 9 7 6 0
OPCODE (toán tử) Vị trí bít FILE (địa chỉ thanh ghi)

Ví dụ: BCF a,3
Xóa bít 3=011 của thanh ghi a (giả sử a được khai báo trước và có địa chỉ
0x24=0b0010 0100 trong bộ nhớ RAM)
13 10 9 7 6 0
OPCODE (toán tử) Vị trí bít FILE (địa chỉ thanh ghi)
01 00 011 010 0100

- Các lệnh thao tác với hằng số và điều khiển rẽ nhánh chương trình:
Cấu trúc lệnh:
o Mã lệnh hằng số k
Các lệnh thông thường:
13 8 7 0
OPCODE (toán tử) Hằng số k

Trừ 2 lệnh Call k và goto k
13 11 10 0
OPCODE (toán tử) Hằng số k


Ví dụ: ADDLW 233
Miêu tả: cộng 233 vào thanh ghi w
13 8 7 0
OPCODE (toán tử) Hằng số k
11 111 1110 1001
T
T
r
r


n
n


T
T
h
h
á
á
i
i


A
A
n
n

h
h


Â
Â
u
u






K
K
h
h
o
o
a
a


Đ
Đ
i
i



n
n








Đ
Đ


i
i


h
h


c
c


B
B
á
á

c
c
h
h


K
K
h
h
o
o
a
a


-
-


Đ
Đ


i
i


h
h



c
c


Đ
Đ
à
à


N
N


n
n
g
g


9


Sau khi phân tích như trên, nhìn lại bảng 1: tập hợp tất cả các lệnh của vi điều
khiển pic16f877a ta đưa ra nhận xét sau:
- 2 bit đầu của 14 bit mã hóa lệnh xác định 3 dạng lệnh: thao tác theo byte
(00), thao tác theo bit (01), thao tác với hằng số (11 hoặc 10 hoặc 00)
- Có tấc cả 18 lệnh thao tác byte, như đã nêu ở trên, để mã hóa mã lệnh

(opcode-toán tử) dùng hết 6 bít: 2 bít phân biệt dạng thao tác theo byte (00)
vậy còn 4 bit để phân biệt 18 lệnh thao tác byte. Như ta biết với 4 bit chỉ
phân biệt được 2^4 =16 lệnh, làm sao phân biệt được 18 lệnh.
Thực ra vi điều khiển dùng 14 mã lệnh cho 14 lệnh, 2 mã lệnh còn lại, cụ
thể là 00 0001 cùng cho 2 lệnh CLRF (xóa nội dung thanh ghi) CLRW (xóa
nội dung thanh ghi W) và mã 00 0000 cùng cho 2 lệnh MOVWF (chuyển
nội dung của thanh ghi w sang thanh ghi F (có địa chỉ cụ thể trong ram) )
và lệnh NOP (lệnh không thực hiện nhiệm vụ gì). Thế làm sao phân biệt
được CLRF và CLRW? Đơn giản là khi
gặp mã lệnh 00 0001 vi điều khiển kiểm tra tiếp bit hướng d: rõ ràng nếu
d=0 (kết quả chứa trong w) thì đây là lệnh CLRW, nếu d=1 (kết quả chứa
trong thanh ghi f) thì đây là lệnh CLRF
Khi gặp mã 00 0000, vi điều khiển kiểm tra tiếp bit hướng d, d =1 thì đây
là lệnh MOVWF, d=0 là lệnh NOP
- Có 4 lệnh thao tác theo bit. 2 bit mã thao tác theo bit là 01, 2 bit còn lại
trong OPCODE (xem bên trên) để mã hóa 4 lệnh
- Có 13 lệnh thao tác với hằng số và điều khiển: một số lệnh có 2 bit mã thao
tác là 11 hoặc 10 hoặc 00. Kiểm tra các bit còn lại ta thấy đều có cách để vi
điều khiển thực hiện phân biệt được các lệnh với nhau
2.1.2 Cấu trúc bộ nhớ và stack:
T
T
r
r


n
n



T
T
h
h
á
á
i
i


A
A
n
n
h
h


Â
Â
u
u






K
K

h
h
o
o
a
a


Đ
Đ
i
i


n
n








Đ
Đ


i
i



h
h


c
c


B
B
á
á
c
c
h
h


K
K
h
h
o
o
a
a



-
-


Đ
Đ


i
i


h
h


c
c


Đ
Đ
à
à


N
N



n
n
g
g


10


Hình 2: Tổ chức bộ nhớ chương trình và Stack
2.1.2.1 Thanh ghi bộ đếm chương trình:
Tại mỗi thời điểm, vi điều khiển thực hiện 1 lệnh trong bộ nhớ chương trình có địa
chỉ cho bởi thanh ghi bộ đếm chương trình PC (Program Counter) gồm 13 bit.
Nhắc lại là với độ dài 13 bit, thanh ghi PC có thể phân biệt được tối đa 2^13=8K
địa chỉ.
Cấu trúc thanh ghi PC gồm 2 phần: phần thấp PCL (Program Counter Low) 8 bit
0-7, phần cao PCH (Program Counter High) 5 bit 8-12
12 11 10 9 8 7 6 5 4 3 2 1 0
PCH PCL

T
T
r
r


n
n



T
T
h
h
á
á
i
i


A
A
n
n
h
h


Â
Â
u
u






K
K

h
h
o
o
a
a


Đ
Đ
i
i


n
n








Đ
Đ


i
i



h
h


c
c


B
B
á
á
c
c
h
h


K
K
h
h
o
o
a
a



-
-


Đ
Đ


i
i


h
h


c
c


Đ
Đ
à
à


N
N



n
n
g
g


11

Trong đó các bit trong PCL là các bit có thể đọc ghi được
Các bit trong PCH<12-8> không thể đọc ghi và được cập nhật thông qua thanh ghi
PCLATCH<4-0>. Nghĩa là mỗi một lần tác động thay đổi 4 bit PCLATCH sẽ dẫn
đến thay đổi nội dung PCH.
Nhìn vào tổ chức bộ nhớ chương trình của vi điều khiển ta thấy rằng bộ nhớ
chương trình gồm 8 K chia thành 4 bank nhớ, mỗi bank có dung lượng 2 K từ
nhớ:
- Bank 0: 0000h-07FFh
- Bank 1: 0800h-0FFFh
- Bank 2: 1000h-17FFh
- Bank 3: 1800h-1FFFh
2 bit cao PCLATCH<4-3> sẽ qui định vi điều khiển đang truy cập bank nhớ nào
trong 4 bank nêu trên.
Khi bàn đến các lệnh CALL, GOTO, các lệnh trở về từ chương trình con, chương
trình ngắt ta sẽ quay lại vấn đề này
2.1.2.2 Reset vector:
Mỗi khi chương trình vi điều khiển bị reset lại (tắt nguồn, ấn nút reset), thanh ghi
PC bị xóa về 0, vậy vi điều khiển bắt đầu thực hiện lệnh chứa tại địa chỉ 0000h.
Do đó địa chỉ này gọi là địa chỉ vector reset
2.1.2.3 Stack:
Trong khi thực hiện chương trình, sẽ có những đoạn chương trình được thực hiện
nhiều lần, người lập trình để đơn giản chương trình sẽ đưa đoạn chương trình đó

thành chương trình con, mỗi lần cần thực hiện đoạn chương trình thì đơn giản là
gọi chương trình con đó.
Ví dụ chương trình con hay dùng nhất là chương trình delay ví dụ như các chương
trình con delay 100ms dưới đây
;************* 1msec Timer Subroutine
*****************
T
T
r
r


n
n


T
T
h
h
á
á
i
i


A
A
n
n

h
h


Â
Â
u
u






K
K
h
h
o
o
a
a


Đ
Đ
i
i



n
n








Đ
Đ


i
i


h
h


c
c


B
B
á
á

c
c
h
h


K
K
h
h
o
o
a
a


-
-


Đ
Đ


i
i


h
h



c
c


Đ
Đ
à
à


N
N


n
n
g
g


12

t1m movlw d'2' ;(1) Set loop
cnt1
movwf cnt1m ;(1) Save loop
cnt1
tm1lp1 movlw d'249' ;(1)*2 Set loop
cnt2

movwf cnt500u ;(1)*2 Save loop
cnt2
tm1lp2 nop ;(1)*249*2 Time adjust
nop ;(1)*249*2 Time adjust
decfsz cnt500u,f ;(1)*249*2 cnt500u-1=0
?
goto tm1lp2 ;(2)*248*2 No, continue
decfsz cnt1m,f ;(1)*2 cnt1m-1=0 ?
goto tm1lp1 ;(2) No. Continue
return ;(2) Yes. Cnt end
;Total
2501*0.4usec=1msec

;************* 100msec Timer Subroutine
***************
t100m movlw d'100' ;Set loop counter
movwf cnt100m ;Save loop counter
tm2lp call t1m ;1msec subroutine
decfsz cnt100m,f ;cnt100m - 1 = 0 ?
goto tm2lp ;No. Continue
return ;Yes. Count end


T
T
r
r


n

n


T
T
h
h
á
á
i
i


A
A
n
n
h
h


Â
Â
u
u







K
K
h
h
o
o
a
a


Đ
Đ
i
i


n
n








Đ
Đ



i
i


h
h


c
c


B
B
á
á
c
c
h
h


K
K
h
h
o
o
a

a


-
-


Đ
Đ


i
i


h
h


c
c


Đ
Đ
à
à


N

N


n
n
g
g


13

;************* 500msec Timer Subroutine
***************
t500m movlw d'5' ;Set loop counter
movwf cnt500m ;Save loop counter
tm3lp call t100m ;100msec subroutine
decfsz cnt500m,f ;cnt500m - 1 = 0 ?
goto tm3lp ;No. Continue
return ;Yes. Count end


chương trình chính:


bcf a,3
call t1m
bsf a,3


Như vậy sau khi thực hiện lệnh bcf a,3, gặp lệnh call t1m, thanh ghi PC được load

địa chỉ bắt đầu của chương trình t1m, sau khi gặp lệnh return vi điều khiển trở về
chương trình chính thực hiện lệnh bsf a,3. Câu hỏi đặt ra là làm sao vi điều khiển
nhớ được địa chỉ trở về? thực ra khi gặp lệnh CALL t1m, nội dung thanh ghi PC
tăng lên 1 đơn vị và giá trị này được lưu vào stack, sau đó PC được load địa chỉ
của lệnh đầu tiên trong chương trình con t1m và do đó vi điều khiển sẽ thực hiện
lệnh của chương trình con t100m, cho đến khi gặp lệnh return, PC load được chỉ
đã lưu trước đó ở stack ra, và do đó thực hiện tiếp lệnh bsf a,3
Qua ví dụ nói trên ta đã hình dung được nhiệm vụ của stack là lưu địa chỉ trở về từ
chương trình con, chương trình ngắt (sẽ đề cập sau)
T
T
r
r


n
n


T
T
h
h
á
á
i
i


A

A
n
n
h
h


Â
Â
u
u






K
K
h
h
o
o
a
a


Đ
Đ
i

i


n
n








Đ
Đ


i
i


h
h


c
c


B

B
á
á
c
c
h
h


K
K
h
h
o
o
a
a


-
-


Đ
Đ


i
i



h
h


c
c


Đ
Đ
à
à


N
N


n
n
g
g


14

Stack của vi điều khiển pic16f877a có thể quản lý đến 8 mức stack. Nếu sử dụng
đến mức stack thì 9 thì mức stack 9 này sẽ viết đè lên mức 1.


2.1.2.4 Vector ngắt:
Chưa bàn đến ngắt, nhưng chúng ta hình dung như thế này: mặc định vi điều khiển
thực hiện chương trình chính, khi có sự kiện ngắt xảy ra, nếu ngắt đó được cài đặt
trước trong chương trình thì vi điều khiển sẽ dừng thực hiện chạy chương trình
chính và nhảy vào địa chỉ 0004h, tại đó phần xử lý ngắt này do người lập trình viết
chương trình thực hiện
Và địa chỉ 0004h trong bộ nhớ chương trình được gọi là vector ngắt.
2.2 Tập lệnh vi điều khiển PIC:
2.2.1 Thời gian thực hiện 1 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 lệnh
Mỗi bước tương ứng với 1 chu kì xung của vi điều khiển.
T
T
r
r


n
n


T
T
h

h
á
á
i
i


A
A
n
n
h
h


Â
Â
u
u






K
K
h
h
o

o
a
a


Đ
Đ
i
i


n
n








Đ
Đ


i
i


h

h


c
c


B
B
á
á
c
c
h
h


K
K
h
h
o
o
a
a


-
-



Đ
Đ


i
i


h
h


c
c


Đ
Đ
à
à


N
N


n
n
g

g


15

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
2.2.2 Tập lệnh:
Xem theo datasheet






















T
T
r
r


n
n


T
T
h
h
á
á
i
i


A
A
n
n
h
h



Â
Â
u
u






K
K
h
h
o
o
a
a


Đ
Đ
i
i


n
n









Đ
Đ


i
i


h
h


c
c


B
B
á
á
c
c

h
h


K
K
h
h
o
o
a
a


-
-


Đ
Đ


i
i


h
h



c
c


Đ
Đ
à
à


N
N


n
n
g
g


16

2.3 Bộ nhớ dữ liệu tạm thời:
2.3.1 Tổ chức bộ nhớ:

Bộ nhớ dữ liệu tạm thời (RAM) của vi điều khiển gồm 2 phần chính, chia thành 4
bank nhớ:
- Các thanh ghi chức năng đặc biệt SFR (Special Function Register) điều
khiển quá trình hoạt động của các bộ phận chức năng trong vi điều khiển
cũng như các thiết bị ngoại vi được tích hợp trong vi điều khiển. Nhìn vào

hình vẽ tổ chức bộ nhớ như trên ta thấy, các thanh ghi SFR phân bố từ địa
T
T
r
r


n
n


T
T
h
h
á
á
i
i


A
A
n
n
h
h


Â

Â
u
u






K
K
h
h
o
o
a
a


Đ
Đ
i
i


n
n









Đ
Đ


i
i


h
h


c
c


B
B
á
á
c
c
h
h



K
K
h
h
o
o
a
a


-
-


Đ
Đ


i
i


h
h


c
c



Đ
Đ
à
à


N
N


n
n
g
g


17

chỉ 00h - 1Fh trong bank 0, phân bố rải rác từ 80F- 9Fh trong bank 1, từ
100h đến 11Fh trong bank 2, từ 180h-19Fh trong bank 3
- Các thanh ghi mục đích chung GPR (General Purpose Register) dùng để
chứa dữ liệu (dùng để đặt biến) từ 20h-7Fh trong bank 0, từ A0h-EFh trong
bank 1, từ 120h-16Fh trong bank 2, từ 1A0h-1F0h trong bank 3
Một số điểm chú ý khác là:
Khi truy cập các địa chỉ từ F0h-FFh trong bank 1, 170h-17Fh trong bank 2 và
1F0h-1FFh trong bank 3 tức là truy cập đến 70h-7Fh trong bank 0
Các vị trí màu xám không sử dụng.
Tại mỗi thời điểm, vi điều khiển làm việc trên một bank nhớ , việc lựa chọn
làm việc bank nhớ phụ thuộc 2 bit RP1, RP0 của thanh ghi STATUS<6-5>


Chú ý:
Trong chương trình viết cho vi điều khiển PIC, nếu sau ki thực hiện lệnh đối
với 1 thanh ghi (thanh ghi SFR hoặc GPR) ở bank i, muốn thực hiện l lệnh đối
với 1 thanh ghi khác ở bank j (j#i) ta phải chọn lại bank nhớ, tức là phải có
lệnh can thiệp đến 2 bit RP1 và RP0, nếu không lệnh sau sẽ không tác dụng:
Ví dụ: ta có chương trình như sau:
BCF TRISA,2
ADDWF PORTA,1
Lệnh thứ 2 sẽ không có tác dụng, vì lệnh đầu tiên thao tác với thanh ghi TRISA
nằm trên bank 1, trong khi lệnh thứ 2 tác động đến PORTA nằm trên bank 0
Chương trình đúng là
BSF STATUS,5 ; ĐƯA GIÁ TRỊ RP0 LÊN MỨC 1 CHỌN BANK 1
BCF TRISA,2
BCF STATUS,5 ; ĐƯA GIÁ TRỊ RP0 XUỐNG MỨC 0 CHỌN BANK 0
T
T
r
r


n
n


T
T
h
h
á

á
i
i


A
A
n
n
h
h


Â
Â
u
u






K
K
h
h
o
o
a

a


Đ
Đ
i
i


n
n








Đ
Đ


i
i


h
h



c
c


B
B
á
á
c
c
h
h


K
K
h
h
o
o
a
a


-
-


Đ

Đ


i
i


h
h


c
c


Đ
Đ
à
à


N
N


n
n
g
g



18

ADDWF PORTA,1
Lí do của việc phải chọn bank nhớ giải thích như sau:
Chúng ta xem lại bảng tổng hợp tất cả các lệnh của vi điều khiển PIC và để ý rằng
trong các lệnh thao tác với các thanh ghi (các thanh ghi nằm trong bộ nhớ RAM),
mỗi thanh ghi được mã hóa bằng 7 bit (tức là đánh số từ 00-7Fh)
Ví dụ:
Lệnh ADDWF f,d mã hóa lệnh như sau:
00 111 d fffffff
Như vậy: ADDWF PORTA,0 có mã lệnh: 00 111 0 000 0100 (do địa chỉ của
PORTA=0x05=000 0100)
ADDWF TRISA, 0 không thể viết bằng được vì địa chỉ TRISA=0x85=1000 0100
gồm 8 bit không thể mã hóa được bằng 7 bit như trong luật mã hóa lệnh
Để giải quyết vấn đề này, để mã hóa lệnh ADDWF TRISA,0 vi điều khiển mã
hóa thanh ghi TRISA bằng 7 bit như PORTA, việc phân biệt PORTA và TRISA
phụ thuộc vào các bit chọn bank nhớ RP1 và RP0.
Giải thích này cũng tương tự cho các lệnh thao tác trên thanh ghi của bank 1, bank
2 và bank 3.
Do đó, nếu khi thực hiện lệnh tiếp theo có thao tác với thanh ghi thuộc bank nhớ
khác với bank nhớ đang được tác động hiện tại cần phải có lệnh chọn lại bank nhớ
2.3.2 Địa chỉ gián tiếp:
Để hiểu về địa chỉ gián tiếp ta xem địa chỉ trực tiếp như thế nào
Để dễ hiểu ta cho ví dụ:
CLRF 0x30
Câu lệnh này thực hiện việc xóa thanh ghi có địa chỉ 30h trong bộ nhớ Ram. Rõ
ràng là địa chỉ ở đây là lấy trực tiếp trong RAM, địa chỉ được ghi trực tiếp trong
lệnh
Trong một số trường hợp ta dùng đến địa chỉ gián tiếp, cụ thể là: thanh ghi FSR

(File Select Register) chứa địa chỉ của thanh ghi trong RAM và thanh ghi INDF sẽ
T
T
r
r


n
n


T
T
h
h
á
á
i
i


A
A
n
n
h
h


Â

Â
u
u






K
K
h
h
o
o
a
a


Đ
Đ
i
i


n
n









Đ
Đ


i
i


h
h


c
c


B
B
á
á
c
c
h
h



K
K
h
h
o
o
a
a


-
-


Đ
Đ


i
i


h
h


c
c



Đ
Đ
à
à


N
N


n
n
g
g


19

ánh xạ vào thanh ghi RAM có địa chỉ là nội dung của FSR, mọi thao tác trên
INDF xem như là thao tác trên thanh ghi của RAM nêu trên
Ví dụ:
MOVLW 0x30
MOVWF FSR ; sau lệnh này FSR chứa 0x30 tức là chỉ đến thanh ghi có
địa chỉ 0x30 trong RAM
CLRF INDF; xóa INDF tức là xóa nội dụng của thanh ghi địa chỉ
0x30


Hình vẽ trên cho ta cách mà vi điều khiển xác định thanh ghi nào trong Ram được

thực hiện.
Trở lại ví dụ trên:
CLRF 0x30 lệnh này mã hóa như sau: 00 0001 1 fff ffff
Trong đó fff ffff= mã thanh ghi = 011 0000
Khi đó RP1=0, RP0=0 bank nhớ 0 được chọn
Rõ ràng là thông qua 7 byte thấp của opcode và giá trị RP1, RP0 vi điều khiển xác
định được thanh ghi trong bộ nhớ RAM
Đối với lệnh gián tiếp:
T
T
r
r


n
n


T
T
h
h
á
á
i
i


A
A

n
n
h
h


Â
Â
u
u






K
K
h
h
o
o
a
a


Đ
Đ
i
i



n
n








Đ
Đ


i
i


h
h


c
c


B
B

á
á
c
c
h
h


K
K
h
h
o
o
a
a


-
-


Đ
Đ


i
i



h
h


c
c


Đ
Đ
à
à


N
N


n
n
g
g


20

MOVLW 0x30
MOVWF FSR
CLRF INDF;
Vi điều khiển dựa vào bit IRP (là bít 7 của thanh ghi STATUS) và bít 7 của FSR

để xác định bank nhớ nơi chứa thanh ghi. 7 bít còn lại FSR<6-0> xác định chính
xác vị trí của thanh ghi đó


IRP FSR<7> Bank
0 0 0
0 1 1
1 0 2
1 1 3
















T
T
r
r



n
n


T
T
h
h
á
á
i
i


A
A
n
n
h
h


Â
Â
u
u







K
K
h
h
o
o
a
a


Đ
Đ
i
i


n
n








Đ

Đ


i
i


h
h


c
c


B
B
á
á
c
c
h
h


K
K
h
h
o

o
a
a


-
-


Đ
Đ


i
i


h
h


c
c


Đ
Đ
à
à



N
N


n
n
g
g


21

CHƯƠNG 3: LẬP TRÌNH HỢP NGỮ
3.1 Dạng số trong chương trình hợp ngữ:
Các dạng số dùng trong chương trình hợp ngữ và cách viết trong hợp ngữ như
sau:

Dạng Cách viết
Ví dụ
DECIMAL D’Số’
. ‘Số’
D’100’
HEXADECIMAL H ‘Số’
0xSố
H’20’
0x20
OCTAL O ‘Số’ O’10’
BINARY B’Số’ B’00011000’
ASCII A’kí tự’

‘kí tự’

A’X’
‘X’

3.2 Chú thích:
Chú thích nằm sau dấu chấm phẩy “;”
Ví dụ:
Movlw 0x20 ; đây là phần chú thích
3.3 Khai báo biến,hằng số:
Có một số phương pháp đặt biến, hằng số như sau:
- Dùng chỉ dẫn equ:
Tên hằng, biến equ giá trị
Ví dụ: count equ 0x20
- Dùng chỉ dẫn set:
Tên hằng, biến set giá trị
Ví dụ: count1 set 0x20
- Dùng chỉ dẫn variable:
T
T
r
r


n
n


T
T

h
h
á
á
i
i


A
A
n
n
h
h


Â
Â
u
u






K
K
h
h

o
o
a
a


Đ
Đ
i
i


n
n








Đ
Đ


i
i



h
h


c
c


B
B
á
á
c
c
h
h


K
K
h
h
o
o
a
a


-
-



Đ
Đ


i
i


h
h


c
c


Đ
Đ
à
à


N
N


n
n

g
g


22

Variable Tên hằng, biến = [biểu thức hoặc số]
Ví dụ: Variable count3=0x20
Hoặc Variable count3
- Dùng chỉ dẫn cblock:
Cblock địa chỉ
Biến1, biến 2,
Endc

Ví dụ: cblock 0x20
Count1, count2, count3
Endc

Khai báo cả một vùng các biến 1, 2 bắt đầu từ địa chỉ

Một số chú ý:
- Khi đặt biến hằng bằng equ ta không thể định nghĩa lại
Ví dụ: viết như thế này là bị lỗi
Count equ 0x20


Count equ 0x23
Nhưng có thể đặt lại giá trị với set
Ví dụ: Viết như thế này không bị lỗi
Count set 0x20



Count set 0x23
- Biến hằng đi kèm với set và equ phải được khởi tạo giá trị (gán giá trị)
nhưng với variable thì không cần thiết
T
T
r
r


n
n


T
T
h
h
á
á
i
i


A
A
n
n
h

h


Â
Â
u
u






K
K
h
h
o
o
a
a


Đ
Đ
i
i


n

n








Đ
Đ


i
i


h
h


c
c


B
B
á
á
c

c
h
h


K
K
h
h
o
o
a
a


-
-


Đ
Đ


i
i


h
h



c
c


Đ
Đ
à
à


N
N


n
n
g
g


23

Ví dụ: Chương trình dịch sẽ báo lỗi:
Count equ
Count set
Nhưng thế này thì không báo lỗi
Variable count;
- Thực ra khi sử dụng set, variable, equ là ta khai báo hằng Chỉ có sử dụng
cblock thì đây mới thực sự là biến và được cấp phát bộ nhớ cho biến đó

Để hiểu rõ điều này ta cùng xem 2 ví dụ sau:
Ví dụ 1:
Count equ 0x21 ; khai báo hằng số count có giá trị 0x21

Movlw d’5 ; đưa giá trị 5 vào thanh ghi w: w=5
Movwf count ; chuyển giá trị w cho thanh ghi có địa chỉ bằng count tức
thanh
; ghi có địa chỉ 0x21 trong bộ nhớ RAM
Như vậy count đây xem như là một hằng số 0x21

Ví dụ 2:

CBLOCK 0x21
Count1, count2

Endc

Movlw d’5 ; đưa giá trị 5 vào thanh ghi w: w=5
Movwf count1 ; đưa giá trị w vào thanh ghi count1, tức thanh ghi có địa
chỉ
; 0x21 như đã khai báo
T
T
r
r


n
n



T
T
h
h
á
á
i
i


A
A
n
n
h
h


Â
Â
u
u






K

K
h
h
o
o
a
a


Đ
Đ
i
i


n
n








Đ
Đ


i

i


h
h


c
c


B
B
á
á
c
c
h
h


K
K
h
h
o
o
a
a



-
-


Đ
Đ


i
i


h
h


c
c


Đ
Đ
à
à


N
N



n
n
g
g


24

Rõ ràng trong trường hợp này count1 là biến, giá trị đưa vào trong lệnh là
địa chỉ của count1 không phải là giá trị của count1

- Khi khai báo các biến và hằng này, ta chú ý giá trị khởi tạo. Vì thực ra các
biến hằng này được sử dụng trong các lệnh như là địa chỉ các thanh ghi
nằm trong vùng nhớ RAM. Như ta biết địa chỉ dành cho các biến phải ở
trong vùng các thanh ghi mục đích chung:
Trong bank 0: 0x20->0x7f
Bank 1: 0xA0->0xEF
Bank 2: 0x120->0x16F
Bank 3: 0x1A0-0x1EF
Do đó giá trị khởi tạo cho các biến hằng khi khai báo cũng phải nằm trong
vùng này
- Khi làm việc với các biến hằng cần phải nhớ địa chỉ của thanh ghi trong
lệnh. Nếu đang thao tác với thanh ghi thuộc bank nhớ i (i=0-3) chuyển sang
lệnh tiếp theo làm việc với một thanh ghi khác thuộc bank nhớ j (j=0-3 và
j#i) cần phải có lệnh chuyển bank nhớ như trong chương 2 đã giới thiệu
3.4 Chỉ dẫn biên dịch chương trình ORG:
Cách thức:
ORG địa chỉ 1
Lệnh 1

Lệnh 2

Lệnh n
ORG địa chỉ 2
Lệnh m
Lệnh m+1

T
T
r
r


n
n


T
T
h
h
á
á
i
i


A
A
n

n
h
h


Â
Â
u
u






K
K
h
h
o
o
a
a


Đ
Đ
i
i



n
n








Đ
Đ


i
i


h
h


c
c


B
B
á

á
c
c
h
h


K
K
h
h
o
o
a
a


-
-


Đ
Đ


i
i


h

h


c
c


Đ
Đ
à
à


N
N


n
n
g
g


25

Miêu tả: chỉ dẫn biên dịch này để điều khiển chương trình dịch MPLAB phân
bố các lệnh nằm sau ORG (ở đây là lệnh 1, lệnh 2, lệnh n) và trước một chỉ
dẫn ORG tiếp theo (ORG địa chỉ 2) vào bộ nhớ chương trình từ địa chỉ bắt đầu
là địa chỉ 1
3.5 Nhãn:

Nhãn-label: là chuỗi kí tự do người lập trình đánh vào để đánh dấu một chuỗi thao
tác lệnh nào đó hoặc 1 chương trình con nào đó. Nhãn còn được dùng trong các
câu lệnh goto và call:
GOTO nhãn
CALL nhãn
Ví dụ 1: goto capnhat
Movf bien1,1
Movlw d’10
Movwf bien2
Capnhat:
Addlw d’2
Ví dụ 2:
Call ct1
Movf bien1,1
Movlw d’10
Movwf bien2
Ct1
Addlw d’2
Movwf bien2
Return
Qui định nhãn:
Nhãn có thể tập hợp các kí tự (số kí tự không giới hạn) và không được rơi vào một
số trường hợp sau:
- Bắt đầu bằng 2 kí tự gạch dưới (ví dụ: __abc là sai)

×