Giao Trinh Hop Ngu PIC - t.au

104
Trn Thái Anh Âu – Khoa Đin – Đại hc Bách Khoa - Đại hc Đà Nng 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

Transcript of Giao Trinh Hop Ngu PIC - t.au

Page 1: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

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

Page 2: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

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

Page 3: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

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

--- --- -- -- -- -- -- -- -- -- -- -- -- --

Page 4: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

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:

Page 5: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

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:

Page 6: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

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

Page 7: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

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

Page 8: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

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

Page 9: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

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:

Page 10: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

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

Page 11: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

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

*****************

Page 12: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

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

Page 13: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

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)

Page 14: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

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.

Page 15: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

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

Page 16: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

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

Page 17: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

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

Page 18: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

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ẽ

Page 19: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

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:

Page 20: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

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

Page 21: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

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:

Page 22: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

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

Page 23: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

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

Page 24: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

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

-------

Page 25: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

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)

Page 26: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

26

- Không được bắt đầu bằng các con số 0-9, *, & , giữa các kí tự không có các

kí tự đặc biệt

- Không được giống các từ đặc biệt của chương trình như ORG, các lệnh v.v

3.6 Cấu trúc của một chương trình hợp ngữ:

Cấu trúc cơ bản gồm các phần như sau:

; DUA FILE LIET KE VAO

#include p16f877a.inc ; chỉ dẫn bao gồm file định nghĩa chip vi điều khiển

; KHAI BAO CAU HINH

__CONFIG _HS_OSC & _WDT_OFF &_LVP_OFF

; KHAI BAO BIEN O DAY

; DIA CHI BIEN O VUNG NHO BIEN BANK0

cblock 0x21

vong1, vong2, vong3

endc

variable giatricong=0x25

;CHUONG TRINH VI DIEU KHIEN CHAY TAI DAY

org 0x000; CHI DAN BIEN DICH

; NHAY TOI CHUONG TRINH CHINH

goto main

; chi dan bien dich

; CHUONG TRINH CHINH BAT DAU TU DAY

org 0x005

main

; CHON BANK NHO CHUA THANH GHI TRISB

banksel trisb

; XOA THANH GHI TRISB, CHO PHEP CAC CHAN PORTB LA DAU RA

clrf trisb

; CHON BANK NHO CO THANH GHI PORTB

banksel PORTB

Page 27: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

27

; BAT DAU XU LY

start:

; XOA BIT CO C

bcf status,c

; DUA GIA TRI 1 VAO BIEN GIATRICONG: GIATRICONG=0000 0001

movlw d'1

movwf giatricong

; DUA DU LIEU GIATRICONG VAO THANH GHI TRUNG GIAN W

loop1

movf giatricong,w

; CHUYEN GIA TRI CHO THANH GHI PORTB

movwf portb

; GOI CHUONG TRINH TAO TRE 200MS

call delay

; KIEM TRA BIT 7 CUA BIEN GIATRICONG: GIATRICONG=1000 0000?

btfss giatricong,7

; NEU SAI NHAY TOI UPDATE DE DICH BIT SANG TRAI

goto update

; NEU DUNG TRO LAI START BAT DAU LAI

goto start

; DOAN DICH BIT:

update: rlf giatricong,1

; XU LY TIEP

goto loop1

abc1234567890123456789012345678111111: movlw d'2

; CHUONG TRINH CON DELAY 200MS

DELAY:

nop

nop

Page 28: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

28

movlw d'185

movwf vong1

movlw d'4

movwf vong2

movlw d'2

movwf vong3

decfsz vong1,f

goto $-1

decfsz vong2,f

goto $-3

decfsz vong3,f

goto $-5

; THOAT KHOI CHUONG TRINH CON

return

; KET THUC MOI CHUONG TRINH

End

- Phần thứ nhất, bắt buộc phải có là phần khai báo bao hàm file định nghĩa

vi điều

khiển, đây là phần bắt buộc

#include p16f877a.inc

Thực ra chỉ dẫn này ra lệnh cho MPLAB copy toàn bộ nội dung của file

“C:\Program Files\Microchip\MPASM Suite\p16f877a.inc” vào phần đầu

của chương trình vi điều khiển.

Nội dung của file này thực ra là định nghĩa các thanh ghi và các cài đặt trong

chương trình.

Chúng ta xem lệnh trong vi điều khiển như sau:

MOVLW B’00001111

MOVWF PORTA,1

Page 29: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

29

Vi điều khiển không biết từ “PORTA” là gì cả, nó chỉ biết rằng thanh ghi đặc

biệt có địa chỉ 0x05 trong bộ nhớ RAM là nơi lưu trữ trạng thái và điều khiển

của các chân trên PORTA.

Như vậy để can thiệp đến các chân này người lập trình phải gửi lệnh

MOVLW B’00001111

MOVWF 0x05,1

Tuy nhiên, có rất nhiều thanh ghi đặc biệt trong vi điều khiển, người sử dụng

không thể nhớ được địa chỉ của nó để mà viết lệnh. Để tiện cho người lập trình,

chương trình biên dịch MPLAB chuẩn bị sẵn file định nghĩa p16f877a.inc

trong đó định nghĩa:

PORTA equ h’00005

Và người lập trình chỉ việc đưa dòng: #include p16f877a.inc

Toàn bộ nội dung của file trên sẽ được đưa vào chương trình và khi đó người

dùng viết các dòng lệnh có PORTA thì trình dịch sẽ tự động hiểu là 0x05 (vì

PORTA đã định nghĩa bằng 5)

Khi ta dùng vi điều khiển khác ví dụ như pic 18f4431 ta đơn giản thay đổi

dòng bao hàm bằng: #include p18f4431inc

- Phần thứ hai, khai báo cấu hình cho vi điều khiển

__CONFIG _HS_OSC & _WDT_OFF &_LVP_OFF

Mục đích của khai báo cấu hình là cài đặt một số chế độ hoạt động của vi điều

khiển như chọn nguồn xung dao động, tắt đồng hồ watchdog timer v.v

Các tham số cài đặt cho config xem ở file header

- Phần thứ ba, khai báo biến, sử dụng các phương pháp khai báo như đã giới

thiệu ở các mục trước

- Phần thứ tư, chương trình, kết thúc bởi nhãn END

- Các chương trình con phải đặt trước END, kết thúc chương trình con có

lệnh return

- Trong chương trình có sử dụng các chỉ dẫn biên dịch ORG để phân bố bộ

nhớ cho chương trình như đã đề cập trước đây

Page 30: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

30

3.7 Dạng thức của 1 lệnh:

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ố

3.7.1 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.7.2 Lệnh thao tác với bit:

Dạng lệnh: lệnh f,b

Page 31: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

31

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

3.7.3 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.8 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.8.1 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

Page 32: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

32

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.8.2 Lệnh tăng giảm đồng thời kiểm tra thanh ghi:

Có 2 lệnh: DECFSZ, INCFSZ

- Dạng lệnh:

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.8.3 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

Page 33: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

33

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

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

Page 34: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

34

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 đề!!!

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

Page 35: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

35

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

Đ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.8.4 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

Page 36: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

36

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.8.5 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:

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

Page 37: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

37

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

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.9 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

Page 38: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

38

- Q3: thời gian thực thi dữ liệu

- Q4: thời gian viết dữ liệu

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

Page 39: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

39

3.10 Chương trình con tạo thời gian trễ:

Trong thực tế viết chương trình điều khiển cho một số thiết bị ta hay tạo một

khoảng thời gian trễ.

Ví dụ: sự kiện 1

Chờ một khoảng thời gian

sự kiện 2

Vì vậy đòi hỏi ta phải có một chương trình con để tạo thời gian trễ này.

Ý tưởng để có một chương trình con tạo thời gian trễ là:

Muốn tạo ra một khoảng thời gian trễ n (micro giây) ta tạo một chương trình mà

thời gian để thực hiện xong nó là n (micro giây)

Ta đã biết: một lệnh thực hiện trong 1 chu kì lệnh (trừ một số lệnh đặc biệt), một

chu kì lệnh tính theo đơn vị micro giây.

Ví dụ: nếu dùng bộ dao động ngoài sử dụng thạch anh có tần số fosc=4Mhz

Suy ra, chu kì lệnh= 4*chu kì xung= 4/tần số xung= 4/4Mhz=1 mico giây

Như vậy để tạo ra khoảng thời gian n micro giây đơn giản ta tạo ra một chương

trình mà thời gian thực hiện nó là n chu kì lệnh

Ví dụ: để tạo thời gian trễ 20 mico giây

Ta dùng 20 lệnh NOP:

NOP

NOP

-------

NOP

Tuy nhiên cách làm đó thì hơi thủ công, và ta cũng không có thời gian để mà đánh

n dòng NOP như vậy (ví dụ: n=200.000!!!!)

Ta phải dùng các lệnh khác với thuật toán phức tạp hơn. Ta đi vào từng bước khảo

sát phương pháp này.

3.10.1 Vòng 1:

Ta có các câu lệnh sau:

Page 40: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

40

decfsz vong1,F

goto $-1

Trong đó vong1 là biến đã được tạo ra trước đó

Ta tính thử thời gian thực hiện 2 lệnh trên:

Như đã bàn ở các mục trước lệnh goto mất 2 chu kì lệnh, lệnh DECFSZ f,z mất 1

chu kì lệnh khi f #0 và mất 2 chu kì lệnh khi f=0

Giả sử ban đầu:

Vong1=2.

Lần 1: decfsz vong1,f -> vong1=1 -> vong1#0 (mất 1 chu kì lệnh)

Goto $-1 (mất 2 chu kì lệnh)

Lần 2: dectsz vong1, f -> vong1=0 chương trình bỏ qua lệnh goto -> thoát (mất 2

chu kì lệnh)

Như vậy mất tổng cộng: (1+2)+2= 5 chu kì lệnh

Giả sử ban đầu:

Vòng 1=3:

Lần 1: decfsz vong1,f -> vong1=2 -> vong1#0 (mất 1 chu kì lệnh)

Goto $-1 (mất 2 chu kì lệnh)

Số chu kì lệnh mất= 3 chu kì lệnh

Lần 2: decfsz vong1,f -> vong1=1 -> vong1#0 (mất 1 chu kì lệnh)

Vong1=vong1-1

Vong1=0?

Thoát

YES

NO

Page 41: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

41

Goto $-1 (mất 2 chu kì lệnh)

Số chu kì lệnh mất = 3 chu kì lệnh

Lần 2: dectsz vong1, f -> vong1=0 chương trình bỏ qua lệnh goto -> thoát

Số chu kì lệnh mất = 2 chu kì lệnh

Tổng số chu kì lệnh mất = 3*2 +2

Cứ như vậy thì có thể qui nạp lệnh

Số chu kì lệnh mất tổng cộng với một giá trị của biến vong1 là:

3* (vong1-1) +2 =3*vong1-1 (1)

(3 chu kì lệnh cho (vong1-1) lần đầu và 2 chu kì lệnh cho lần cuối)

Số chu kì lệnh tối thiểu và tối đa tạo trễ được.

- Khi vong1=1: số chu kì lệnh= 2

- Khi vong1=0: số chu kì lệnh= 3*256-1= 767

3.10.2 Vòng 2:

Ta có đoạn lệnh sau:

decfsz vong1,F

goto $-1

decfsz vong2,F

goto $-3

Thuật toán:

Page 42: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

42

Giả sử ban đầu:

Vong1=3, vong2=3

Như đã phân tích trong mục 3.10.1, số chu kì lệnh mất cho đến khi chương trình

bắt đầu xử lý vong2 (tương đương với số chu kì lệnh mất cho đến khi nhảy đến

thoát trong mục 3.10.1) là: 3*vong1 -1 chu kì lệnh

Đến đây vong1=0, xử lý tiếp vong2

Lần 1: decfsz vong2,f : vong2=vong2-1=3-1=2, vong2#0 nhảy đến goto $-3 (mất

1 chu kì lệnh)

Goto $-3 nhảy đến lệnh decfsz vong1,f (mất 2 chu kì lệnh)

Tổng chu kì lệnh mất = 3 chu kì lệnh

Tới lệnh: decfsz vong1,f (vong1 bây giờ đang =0)

Xem như đây là chu trình giống mục 3.10.1 với vong1=0

Suy ra cho đến khi gặp lại decfsz vong2,f mất: 3*256-1=767 chu kì lệnh

Như vậy tổng số chu kì lệnh cho lần 1 là 767+3= 770 chu kì lệnh

Vong1=vong1-1

Vong1=0?

Thoát

YES

NO Vong1=0?

Vong2=0?

Vong2=vong2-1

NO

YES

Page 43: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

43

Lần 2: decfsz vong2,f : vong2=vong2-1=2-1=1, vong2#0 nhảy đến goto $-3

Tương tự như trên:

tổng số chu kì lệnh cho lần 2 là 767+3= 770 chu kì lệnh

Lần 3: decfsz vong2,f : vong2=vong2-1=1-1=0, vong2=0 nhảy đến thoát (mất 2

chu kì lệnh)

Như vậy tổng chu kì lệnh mất đi là:

3*vong1-1 + 770*2 +2

Qui nạp lên:

3*vong1-1 + 770*(vong2-1) +2= 3*vong1 +770*vong2 -769

Vậy số chu kì lệnh = 3*vong1 +770*vong2 -769 (2)

3.10.3 Vòng 3:

Ta có đoạn lệnh sau:

decfsz vong1,F

goto $-1

decfsz vong2,F

goto $-3

decfsz vong3,F

goto $-5

Thuật toán:

Vong1=vong1-1

Vong1=0?

Thoát

YES

NO Vong1=0?

Vong2=0?

Vong2=vong2-1

NO

YES

Vong3=vong3-1

Vong3=0?

YES

NO

Page 44: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

44

Tính toán tương tự như trên, ta có công thức:

Số chu kì lệnh= 3*vong1+ 770*vong2 + 197122*vong3 - 197889 (3)

Ta cũng cần chú ý ở đây nữa là để nạp giá trị đầu cho biến vong1 ta mất 2 chu kì

lệnh cho 2 lệnh sau:

Movlw d’ giá trị đầu (ví dụ: movlw d’100)

Movwf vong1

Tương tự như vậy nếu dùng vòng 2 ta sẽ mất thêm 2 lệnh cho việc khởi tạo giá trị

đầu biến vong2 như vậy mất 4 chu kì lệnh

Tương tự như vậy nếu dùng vòng 3 ta sẽ mất thêm 2 lệnh cho việc khởi tạo giá trị

đầu biến vong3 như vậy mất 6 chu kì lệnh

Ta phải gọi chương trình con tạo thời gian trễ: call delay mất thêm 2 chu kì lệnh

Trong chương trình con delay có lệnh trở về return mất thêm 2 chu kì lệnh.

Như vậy công thức tổng quát cuối cùng là:

- Nếu chỉ sử dụng vòng 1:

Số chu kì lệnh = 3*vong1-1+2 (cho khởi tạo biến vong1) +2 (cho lệnh

call delay) +2 (cho lệnh return)

Số chu kì lệnh= 3*vong1+5 (4)

- Nếu sử dụng vòng 1 và vòng 2:

Số chu kì lệnh = 3*vong1 +770*vong2 -769 +4 (cho khởi tạo biến

vong1, vong2) +2 (cho lệnh call delay) +2 (cho lệnh return)

Số chu kì lệnh= 3*vong1+770*vong2-761 (5)

- Nếu sử dụng cả 3 vòng 1, vòng 2 và vòng 3:

Số chu kì lệnh = 3*vong1+ 770*vong2 + 197122*vong3 - 197889 +6

(cho khởi tạo biến vong1, vong2, vong3) +2 (cho lệnh call delay) +2 (cho lệnh

return)

Số chu kì lệnh= 3*vong1+ 770*vong2 + 197122*vong3 -197879 (6)

Tính toán:

Page 45: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

45

Giả sử ta dùng bộ dao động thạch anh f=4Mhz, cho chân rb0 lên mức 1, tạo thời

gian trễ 200ms, cho chân rb0 xuống mức 0.

Thời gian trễ ở đây là 200ms.

Giả sử ta áp dụng thuật toán 3 vòng.

200ms= 200.000 micro giây= 200.000 chu kì lệnh

Áp dụng công thức (6) ta có:

3*vong1+ 770*vong2 + 197122*vong3 -197879 = 200.000

Suy ra:

3*vong1+ 770*vong2 + 197122*vong3 = 397897

Vong3= 397897/197122= 2

3*vong1+770*vong2= 397897-197122*vong3= 397897-197122*2=3653

Suy ra:

Vong2= 3653/770=4

3*vong1=3643-770*vong2=563

Suy ra: vong1=563/3=187

Số dư= 563-3*187=2

Như vậy:

200.000= 3*187 +770*4+197122*2 +2

Số 2 dư ra ta dùng 2 lệnh NOP

Chương trình chính và chương trình con delay sẽ như sau:

; DUA FILE LIET KE VAO

#include p16f877a.inc

; KHAI BAO CAU HINH

__CONFIG _HS_OSC & _WDT_OFF &_LVP_OFF

; KHAI BAO BIEN O DAY

; DIA CHI BIEN O VUNG NHO BIEN BANK0

cblock 0x21

vong1, vong2, vong3

Page 46: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

46

endc

variable giatricong=0x25

;CHUONG TRINH VI DIEU KHIEN CHAY TAI DAY

org 0x000; CHI DAN BIEN DICH

; NHAY TOI CHUONG TRINH CHINH

goto main

; chi dan bien dich

; CHUONG TRINH CHINH BAT DAU TU DAY

org 0x005

main

banksel trisb

clrf trisb

banksel PORTB

START:

BSF PORTB,0

CALL DELAY

BCF PORTB,0

CALL DELAY

GOTO START

DELAY:

nop

nop

movlw d'187

movwf vong1

movlw d'4

movwf vong2

movlw d'2

movwf vong3

decfsz vong1,f

Page 47: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

47

goto $-1

decfsz vong2,f

goto $-3

decfsz vong3,f

goto $-5

; THOAT KHOI CHUONG TRINH CON

return

; KET THUC MOI CHUONG TRINH

end

Page 48: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

48

CHƯƠNG 4: CÁC PHƯƠNG PHÁP HIỂN THỊ TRONG CÁC THIẾT BỊ

DÙNG VI ĐIỀU KHIỂN

PHẦN LÝ THUYẾT:

Hiện nay, trong hầu hết các thiết bị nhúng đều có sử dụng các khối hiển thị. Mục

đích cho người dùng giám sát, cài đặt và hiển thị các thông số của thiết bị cũng

như đối tượng cần giám sát điều khiển.

Có rất nhiều phương pháp hiển thị, có thể kể ra như sau:

- Hiển thị cảnh báo, báo lỗi: thông thường dùng led đơn. Có thể hiển thị theo

kiểu dùng nhiều màu khác nhau hoặc bật tắt v.v

- Hiển thị số liệu: dùng led 7 đoạn, LCD hoặc LCD đồ họa v.v

- Hiển thị trên máy tính: dùng các phần mềm điều khiển giám sát, kết nối

thiết bị và máy tính thông qua chuẩn RS232 hoặc các chuẩn mạng (giám sát

từ xa)

Trong bài này sẽ giới thiệu 2 cách hiển thị đầu, phần hiển thị bằng máy tính sẽ

được đề cập trong bài học về chuẩn giao tiếp RS232.

4.1 Hiển thị bằng led đơn:

Đây là cách hiển thị đơn giản nhất.

Thông thường cách hiển thị này dùng để báo một trạng thái nào đấy của thiết bị

như trạng thái làm việc của nguồn (lỗi hoặc không lỗi), cũng như các khối chức

năng khác.

Có rất nhiều loại led đơn dùng để hiển thị. Phương pháp đơn giản như sau:

Page 49: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

49

Hình 2.1: Hiển thị led đơn

Các led này sáng khi được cấp áp cỡ 2 V, dòng 10-20mA.

Nếu dùng một chân ra từ vi điều khiển để bật tắt led, phải dùng thêm điện trở hạn

dòng,hạn áp.

Tính toán như sau:

Muốn bật đèn, ta cho chân ra vi điều khiển lên mức cao nối với đầu vào của mạch

trên. Như ta biết, chân ra vi điều khiển ở mức logic cao có điện áp 5V.

Cho điện áp rơi trên led là 2V, dòng qua là 15mA.

Suy ra, điện áp rơi trên trở là 3V. Dòng qua led chính là dòng qua điện trở và bằng

15mA.

Suy ra, điện trở dùng: R=3/15mA=200 ohm.

Chọn điện trở tiêu chuẩn 220 ohm

(Điện trở tiêu chuẩn: 10, 11, 12, 13, 15, 16, 18, 20, 22, 24, 27, 30, 33, 36, 39, 43,

47, 51, 56, 62, 68, 72, 82, 91 và các bội số)

4.2 Hiển thị bằng led bảy đoạn- 7 segment led:

4.2.1 Cấu tạo của led 7 đoạn:

Hình 2.2: Led 7 đoạn

Một led 7 đoạn thực ra là gồm 7 led đơn nối với nhau (8 led đơn nêu có thêm dấu

chấm-dp).

Có 2 loại:

Page 50: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

50

- Chung catod: các đầu catod (cực âm) được nối chung với nhau và nối với

đất, các đầu anod a,b,c,d,e,f,g,h được đưa ra ngoài (các chân) nhận tín hiệu

điều khiển. Khi cấp điện áp 5v cho mỗi đầu anod, led tương ứng với đầu đó

sẽ sáng

- Chung anod: các đầu anod (cực âm) được nối chung với nhau và nối với

nguồn, các đầu catod a,b,c,d,e,f,g,h được đưa ra ngoài (các chân) nhận tín

hiệu điều khiển. Muốn led đơn nào sáng chỉ việc đưa chân catod của led

tương ứng xuống mức 0V.

Hình 2.3: Cấu tạo của 2 loại led 7 đoạn

4.2.2 Hiển thị 1 led 7 đoạn dùng vi điều khiển:

Page 51: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

51

Như đã giới thiệu ở phần trên, thực chất led 7 đoạn gồm 8 hoặc 7 led đơn nối với

nhau. Vì vậy để điều khiển thanh led đơn sáng, cách thực hiện phần cứng như hình

2.1.

Cụ thể hơn, như dùng led chung anod như hình vẽ trên. Mỗi đầu vào a,b,c,d,e,f,g,h

được nối với một chân của vi điều khiển, tương ứng là RB0, RB1, ..RB7, thông

qua các điện trở phân áp 200 ohm, đầu anod chung được nối với nguồn. Để led

đơn sáng đơn giản ta đưa chân vi điều khiển nối với led đó xuống mức thấp.

Như trên hình 2.4 trên, để led 7 đoạn hiển thị số 2 thì các led a,b,d,e,g sáng; các

led c, f tắt. Giá trị sáng tương ứng chân vi điều khiển nối vào ở mức 0, giá trị tắt

tương ứng với chân vi điều khiển nối với ở mức 1.

Do đó nội dung của thanh ghi PORTB là:

0 0 1 0 0 1 0 0

Đây là mã led 7 đoạn của số 2

Như vậy, chúng ta lưu ý một điều rằng, dữ liệu xuất ra led 7 đoạn là mã led

tương ứng với số cần xuất

Mã led tương ứng với các số từ 0 đến 9 là:

0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90

Cách điều khiển led 7 đoạn chung catod thì ngược lại.

Page 52: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

52

4.2.2.1 Chương trình điều khiển hiển thị 1 led 7 đoạn:

Xem theo file đính kèm

4.2.3 Hiển thị nhiều led 7 đoạn dùng vi điều khiển:

Trong thực tế, ta phải dùng nhiều led 7 đoạn để hiển thị.

Vậy giải quyết việc hiển thị nhiều led như thế nào?

Ví dụ: để hiển thị số 35 bằng 2 led 7 đoạn.

Đối chiếu với cách hiển thị 1 led 7 đoạn, ta nghĩ đơn giản chỉ là dùng 1 cổng hiển

thị số 3, 1 cổng khác hiển thị số 5.

Như vậy ta mất 2 cổng. Hiển thị 4 led thì mất 4 cổng => toàn bộ chân trên vi điều

khiển dùng cho việc hiển thị led…Không còn chân để giao tiếp với các thiết bị

khác như bàn phím, đầu vào số khác v.v Không khả thi!

Ta có phương pháp tiết kiệm chân hơn để giải quyết:

Hình 2.5: Hiển thị 2 led 7 đoạn

Các chân dữ liệu (chân sẽ nhận mã led từ vi điều khiển) được nối tương ứng với

nhau và nối vào 1 cổng của vi điều khiển, chẳng hạn như cổng B

Chân nguồn của 2 led được điều khiển bởi 2 chân trên vi điều khiển, chằng hạn

chân RA4 và RA5 như trên hình, thông qua cực B của 2 transistor pnp.

Page 53: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

53

Quá trình hiển thị con số 35 trên 2 led sẽ như sau:

- Cho chân RA4 (chân nối với led hàng chục) xuống mức thấp, transistor thứ

nhất mở do tiếp giáp BE thuận, chân RA5 lên mức cao (chân nối với led

hàng đơn vị), transistor thứ hai không mở. Vậy chỉ có led hàng chục được

cấp nguồn.

- Cho cổng B xuất dữ liệu mã led của số 3. Chỉ có led hàng chục được cấp

nguồn nên chỉ có led này sáng

- Tạo thời gian trễ 10-20ms

- Điều khiển tương tự cho led hàng đơn vị được cấp nguồn, led hàng chục

không cấp nguồn, xuất dữ liệu mã led số 5 ra cổng B. Led đơn vị hiển thị số

5.

- Tạo thời gian trễ 10-20ms

- Quay lại bước thứ nhất

Như vậy, số 3 hiển thị 10ms, số 5 hiển thị 10ms và quay vòng như vậy. Thời gian

này rất nhanh, do hiệu ứng của mắt, ta cảm giác như số 35 hiển thị cùng lúc. Bài

toán được giải quyết, ta chỉ mất có 10 chân để điều khiển 2 led.

Cách hiển thị nhiều led cũng tương tự như vậy.

Cũng giải thích thêm lí do dùng transistor nối vào RA4, RA5. Do chân vi điều

khiển có dòng khoảng vài chục mA, đây là chân cấp nguồn cho led 7 đoạn, mỗi

led đơn trong Led 7 đoạn mất 20mA vây cả led 7 đoạn mất trên 100mA. Vì vậy ta

phải dùng transistor để khuếch đại dòng.

4.2.3.1 Chương trình điều khiển hiển thị 2 led 7 đoạn:

Xem theo file đính kèm

4.3 Hiển thị dùng LCD:

Page 54: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

54

D7

14D

613

D5

12D

411

D3

10D

29

D1

8D

07

E6

RW5

RS

4

VSS

1

VD

D2

VEE

3

LM016L

Hình 2.6: Các chân LCD

4.3.1 Các chân cơ bản của LCD 2 dòng 16 kí tự:

• VSS: Chân đất

• VCC: Chân nguồn

• VEE: Chân hiệu chỉnh độ sáng của LCD

• RS:

– =0: LCD sẽ nhận lệnh từ vi điều khiển

– =1: LCD sẽ nhận kí tự từ vi điều khiển để hiển thị

• R/W:

– =1: Vi điều khiển đọc dữ liệu từ LCD

– =0: Vi điều khiển ghi dữ liệu lên LCD

Thông thường Vi điều khiển chủ yếu ghi dữ liệu lên LCD nên chân này thường

nối đất

Page 55: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

55

• E: Chân cho phép (Enable). Sau khi lệnh hoặc dữ liệu đã được chuẩn bị trên

đường dữ liệu, tạo xung mức cao-mức thấp sẽ bắt đầu quá trình LCD nhận

dữ liệu hoặc lệnh từ vi điều khiển.

• D0-D7: các chân dữ liệu, nơi vi điều khiển truyền lệnh hoặc dữ liệu lên

LCD.

4.3.2 Khởi tạo LCD:

LCD có nhiều độ làm việc, có thể kể ra như sau:

- Chế độ 1 dòng hay 2 dòng

- Chế độ giao tiếp 4 bit hay 8 bit

- Chế độ font 5*8 hoặc 5*10

- Ngoài ra còn có thể thay đổi vị trí hiển thị kí tự v.v

Vì vậy, trước khi bắt đầu quá trình hiển thị một chuỗi kí tự nào đó, ta cần quá trình

khởi tạo để

cài đặt các chế độ này. Vi điều khiển thực hiện quá trình khởi tạo này bắt cách ghi

đến LCD một chuỗi các lệnh.

Căn cứ vào chức năng của các chân vi điều khiển được giới thiệu ở trên, ta đưa ra

qui trình của việc gửi một lệnh từ Vi điều khiển đến LCD:

- Cho chân R/W=0 để xác định đây là ghi xuống LCD (thông thường chân

này được nối đất, nên mặc định chân này ở mức 0, ta không cần quan tâm

đến nữa)

- Cho chân RS=0 để xác định đây là lệnh mà vi điều khiển gửi xuống LCD

(phân biệt với RS=1, gửi kí tự hiển thị)

- Gửi mã lệnh xuống LCD theo các đường dữ liệu (RD0-RD7 nếu dùng chế

độ 8 bit, R4-R7 nếu dùng chế độ 4 bit)

- Đưa chân E (chân cho phép- Enable) lên mức cao, mức 1

- Tạo trễ vài chu kì lệnh

- Đưa chân E xuống mức thấp, mức 0

Page 56: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

56

Mã lệnh như đã giới thiệu trong phần trên tùy thuộc vào từng lệnh, ở đấy giới

thiệu một số lệnh cơ bản như sau:

. Lệnh cài đặt chế độ làm việc:

0 0 1 DL N F - -

• DL:

– = 1: 8 bit

– = 0: 4 bit

• N:

– = 1: 2 dòng

– = 0 1 dòng

• F:

– = 1: font 5x10 dot

– = 0: font 5x8 dot

. Lệnh đặt chế độ tăng giảm địa chỉ:

0 0 0 0 0 1 I/D S

• I/D:

– = 1 tăng địa chỉ

– = 0 giảm địa chỉ

• S:

– =1: Cài đặt di chuyển cùng địa chỉ

. Lệnh đặt chế độ hiển thị:

0 0 0 0 1 D C B

Page 57: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

57

• D: Cho phép hiển thị

• C: cài đặt hiển thị con trỏ

• B: nhấp nháy vị trí kí tự

. Lệnh đặt vị trí hiển thị của kí tự:

1 ĐC ĐC ĐC ĐC ĐC ĐC ĐC

• Địa chỉ dòng 1: 00- 0F

• Địa chỉ dòng 2: 40-4F

Vì vậy, muốn hiển thị đầu dòng thứ nhất, mã lệnh sẽ là 0x80

muốn hiển thị đầu dòng thứ hai, mã lệnh sẽ là 0xC0

. Lệnh xóa màn hình: mã lệnh 0x01

. Lệnh trở về đầu dòng thứ nhất: mã lệnh 0x02

Chi tiết có thề xem datasheet đi kèm

4.3.2 Ghi kí tự lên LCD để hiển thị:

Sau khi thực hiện quá trình khởi tạo để gửi các lệnh cài đặt chế độ làm việc cùa

LCD, kí tự sẽ được hiển thị lên LCD bất kì khi nào vi điều khiển muốn gửi.

Quá trình gửi kí tự gồm các bước sau:

- Cho chân R/W=0 để xác định đây là ghi xuống LCD (thông thường chân

này được nối đất, nên mặc định chân này ở mức 0, ta không cần quan tâm

đến nữa)

- Cho chân RS=1 để xác định đây là kí tự mà vi điều khiển gửi xuống LCD

(phân biệt với RS=0, gửi lệnh)

- Gửi mã ascii của kí tự cần hiển thị xuống LCD theo các đường dữ liệu

(RD0-RD7 nếu dùng chế độ 8 bit, R4-R7 nếu dùng chế độ 4 bit)

- Đưa chân E (chân cho phép- Enable) lên mức cao, mức 1

Page 58: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

58

- Tạo trễ vài chu kì lệnh

- Đưa chân E xuống mức thấp, mức 0

Câu hỏi 1: Lý do vì sao chúng ta lại dùng transistor trong cách nối vi điều

khiển với 2 led 7 đoạn và cách tính toán mạch như thế nào?:

Nếu chúng ta không dùng transistor. Sơ đồ như sau:

Trong đó các chân a,b,c,d,e,f,g,h của cả 2 led 7 đoạn sẽ nối tương ứng với nhau

cùng nối vào rb0,rb1..rb7 thông qua điện trở 220 ohm

Như ta đã biết, 1 led 7 đoạn gồm 8 led đơn bên trong. Với loại led chung anod

như trên ta vẽ lại sơ đồ điện của từng led 7 đoạn như sau:

Page 59: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

59

Như vậy dòng đi từ chân RA0 lớn nhất khi tấc cả các led đơn a,b,...g,h của led

7 đoạn đều sáng.

Khi đó các chân a,b,c...g,h nối đất

Page 60: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

60

Ta tính dòng chảy ra từ RA0:

Giả sử điện áp đổ trên mỗi led là 1.5 V. RA0 mức 1 tương ứng 5 V

Suy ra áp đổ trên R1 là : U(R1)=5-1.5=3.5V

Suy ra dòng chảy qua R1 và led là: I (led)= U(R1)/R1=3.5/220=15.9mA

Dòng chảy ra từ chân RA0:

I(RA0)= 8 I(led)=8*15.9= 127mA

Điều này không thể được vì mỗi chân của vi điều khiển pic16f877a cho dòng

ra tối đa cho phép là vài chục mA.

Để giải quyết vấn đề này, ta phải dùng transistor để khuếch đại, khi đó tín hiệu

ra từ RA0 chỉ là tín hiệu điều khiển. Dòng đổ đến led sẽ do nguồn trực tiếp

cấp

Sơ đồ như sau:

Sơ đồ chi tiết sẽ như sau:

Page 61: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

61

Như vậy khi RA0 ở mức 0 (0V) transistor dẫn. Dòng đổ từ nguồn 5 V đi vào

led qua trở xuống chân a,b,c,...e,f,g của led 7 đoạn (các chân này nối với

RB0,RB1..RB6,RB7)

Muốn led tương ứng sáng ta cho các chân a,b...g,h (tức là

RB0,RB1,...RB6,RB7) xuống mức 0.

Khi RA0 ở mức 1 (5V), transistor không dẫn, không có dòng đổ vào các led

nên các led không sáng (dù cho các chân a,b,...g,h) có ở mức 0 hay không

Như vậy sơ đồ mạch như hình trên là thõa mãn.

Vấn đề là đi tìm giá trị của các điện trở ở ngõ ra của từng led nối với các chân

a,b,c...

Và điện trở phân cực tại RA0- nối với cực B của transistor.

Để các led trong led 7 đoạn sáng đều nhau rõ ràng các điện trở ở ngõ ra của

từng led phải bằng nhau. R1=R2=...=R7

Page 62: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

62

Ta cũng biết là mỗi led có sáng hay không phụ thuộc vào dữ liệu ở các chân

a,b,..g,h tức là các chân RB0,RB1,...RB6,RB7 ở mức 0 hay mức 1 (5V)

Trong các ứng dụng của ta dùng led 7 đoạn hiển thị các con số từ 0-9. như vậy

số lượng led sáng là thây đổi

Trường hợp có số lượng led sáng ít nhất là khi hiển thị số 1, có 2 led đơn sáng

Trường hợp số lượng led sáng nhiều nhất khi hiển thị số 8. (số 8 có dấu chấm)

Ta cũng muốn rằng dù là hiển thị bất cứ số nào trong các số từ 0-9 thì đòi hỏi

led phải sáng đều và mức sáng là như nhau khi thể hiện các số khác nhau

Suy ra là điện áp ở cực C của transistor là không đổi đối với tải khác nhau (do

mỗi led sáng thì số lượng led là khác nhau)

Trường hợp này chỉ xẩy ra khi transistor nếu như mở thì phải mở bão hòa trong

tấc cả các trường hợp hiển thị các số khác nhau.

Khi đó Vc=Ve-0.1=5V-0.1V=4.9V.

Từ đó ta tính ra điện trở của R1=R2=..=R7 theo cách tính của led đơn đã đề

cập trong chương 4 (phần 4.1)

Ở đây ta chọn: R1=R2=..=R7=220 ohm

Giả sử điện áp đổ trên mỗi led là 1.5V. Ta tính được dòng điện đổ qua mỗi led

khi sáng:

Iled=(4.9V-1.5)/220= 15.5 mA

Như đã đề cập như trên, ta phải chọn R10- điện áp phân cực cho cực B của

transistor để transistor mở bão hòa khi led 7 đoạn hiển thị bất kì số gì từ 0-9.

Trường hợp số led sáng ít nhất khi led 7 đoạn hiển thị số 1, tức led b và c sáng,

tấc cả các led khác tắt, ta có hình sau:

Page 63: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

63

Trường hợp số led sáng nhiều nhất khi led 7 đoạn hiển thị số 8 có chấm, tức tấc

cả các led đều sáng, ta có hình sau:

Khi đó: Ic = 8 Iled = 8*15.4 = 123 mA

Vì transistor bão hòa nên: Ic=Icbaohoa=123mA

Điều kiện để transistor bão hòa là:

Page 64: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

64

Ib>Icbaohoa/k

K là hệ số khuếch đại 1 chiều. Giả sử ở đây: K=100

Suy ra: Ib > Icbaohoa/100

=> Vb/R10 > Icbaohoa/100

Vb=Ve-Veb=5-0.7=4.3 V

Suy ra:

4.3/R10>123/100

Suy ra: R10<(100*4.3)/123= 3.5K

Rõ ràng là với giá trị này thì transistor luôn mở bão hòa cho tấc cả các trường

hợp hiển thị số từ 0-9 của led 7 đoạn

R10 < 3.5K

Câu hỏi 2: Thuật toán của chương trình hiển thị 1 led 7 đoạn (xem lại

chương trình đã được up lên)?

Start

Chọn bank nhớ chứa TRISB Xóa thanh ghi TRISB

(Cho phép các chân PORTB đầu ra)

Chọn bank nhớ 0 chứa PORTB

Gán: W=9

Gọi chương trình con Bảng mã led 7 đoạn

Gọi chương trình con Delay 200ms

Gán: W=0

Gọi chương trình con Bảng mã led 7 đoạn

Gọi chương trình con Delay 200ms

Page 65: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

65

Trong chương trình này phần quan trọng là gọi chương trình con bảng mã

led 7 đoạn.Ta cùng khảo sát chương trình này.

Với sơ đồ kết nối 8 chân a,b,c..g,h của led 7 đoạn với 8 chân

RB0,RB1,..RB6,RB7 của vi điều khiển, đầu anod chung của led 7 đoạn nối với

nguồn . Quay lại sơ đồ chân của led 7 đoạn để dễ hình dung:

Ta biết rằng: Muốn hiển thị số 1 ta phải đưa ra PORTB mã led 7 đoạn của số

1 (chỉ có b và c sáng, còn lại tắt):

RB7 RB6 RB5 RB4 RB3 RB2 RB1 RB0

1 1 1 1 1 0 0 1

(nhớ rằng: để led sáng thì chân RB phải ở mức 0)

Vậy mã led 7 đoạn của số 1 là: 0xF9

Như vậy để led 7 đoạn hiển thị số 1, đơn giản ta dùng lệnh:

MOVLW 0xF9

MOVWF PORTB

Đối với 10 số từ 0-9 sẽ có 10 mã led tương ứng:

0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90

Vấn đề ở đây là: trong các ứng dụng thông thường con số cần hiển thị là ngẫu

nhiên do một quá trình mang đến

Ví dụ: ta dùng led 7 đoạn để hiển thị số lần tác động của phím bấm.

Page 66: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

66

Nếu phím chưa bấm thì led hiển thị số 0

Nếu bấm 3 lần thì hiển thị số 3

Vậy con số này là không xác định

Như vậy chương trình sẽ không thể biết là 1 hay 9 lần để mà hiển thị xuất mã led

0xf9 hay 0x90 ra cổng PORTB để hiển thị

Ta phải giải quyết vấn đề này 1 cách tự động. Sử dụng kĩ thuật bảng:

Trước khi đi vào ta giới thiệu lại lệnh RETLW:

Chương trình con có 2 loại:

- loại không trả về giá trị - kết thúc bằng RETURN

- Loại trả về giá trị- kết thúc bằng RETLW (trả giá trị về cho thanh ghi W)

(Cũng giống như Procedure và Function trong ngôn ngữ C)

Cách gọi chương trình như sau:

MOVLW D’số

CALL BANGMA

MOVWF PORTB

Ta xem chương trình con bảng mã led 7 đoạn như sau:

BANGMA

ADDWF PCL,F

RETLW 0XC0

RETLW 0XF9

RETLW 0XA4

RETLW 0XB0

RETLW 0X99

RETLW 0X92

RETLW 0X82

RETLW 0XF8

RETLW 0X80

RETLW 0X90

Giả sử ta cần hiển thị số 1:

Page 67: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

67

MOVLW D’1

CALL BANGMA

MOVWF PORTB

Ta xem chương trình chạy như thế nào:

Sau lệnh: MOVLW D’1: W=1

Sau lệnh: CALL BANGMA: nhảy đến chương trình con BANGMA

Sau lệnh: ADDWF PCL,F : PCL=PCL +W=PCL+1

Và sau 1 lệnh thì PCL=PCL+1 nên sau lệnh ADDWF PCL,F ta có: PCL=PCL+2

Do chương trình vi điều khiển chạy theo PC tức PCL nên con trỏ chương trình

nhảy đến địa chỉ lệnh RETLW 0XC0 (2 lệnh kể từ lệnh ADDWF PCL,F)

Khi đó W=0xC0 là mã led 7 đoạn của số 1

Vậy nếu đưa W=1 và gọi chương trình con BANGMA ta có W=mã led 7 đoạn của

số 1

Tương tự như vậy đối với W=0-9

Rõ ràng với cách dùng KĨ THUẬT BẢNG cho phép ta tự động lấy giá trị của mã

led

Ví dụ: giả sử muốn hiển thị số lần phím được bấm ta dùng biến solanbam, giả sử

solanbam đã được xử lý bằng đoạn chương trình xử lý phím bấm phía trước.

Để hiển thị ta dùng đoạn chương trình sau:

MOVF solanbam,f

CALL BANGMA

MOVWF PORTB

Rõ ràng với đoạn chương trình trên thì không cần biết solanbam là bao nhiêu

chương trình cũng tự động cập nhật được

Câu hỏi 3: Hạn chế của chương trình con bảng mã led 7 đoạn:

Ta xem lại chương trình đã được listting với cột đầu tiên là địa chỉ của lệnh trong

bộ nhớ chương trình với thay đổi nhỏ là bangma được bắt đầu ở địa chỉ 0x100:

Page 68: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

68

--- E:\ADP\TEACHER\VIDIEUKHIEN\BAITAP\LED7DOAN0\test.asm --------

-------------------------------

1: ; DUA FILE LIET KE VAO

2: #include p16f877a.inc

3: ; KHAI BAO CAU HINH

4: __CONFIG _HS_OSC & _WDT_OFF

&_LVP_OFF

5: ; KHAI BAO BIEN O DAY

6: ; DIA CHI BIEN O VUNG NHO BIEN

BANK0

7: cblock 0x20

8: vong1,

9: vong2,

10: vong3

11: endc

12:

13: ;

14: ;CHUONG TRINH VI DIEU KHIEN CHAY

TAI DAY

15: org 0x000; CHI DAN BIEN DICH

16: ; NHAY TOI CHUONG TRINH CHINH

0000 2805 GOTO 0x5 17: goto main

18:

19: ; chi dan bien dich

20: ; CHUONG TRINH CHINH BAT DAU TU

DAY

21: org 0x005

22:

23: main

Page 69: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

69

24: ; CHON BANK NHO CHUA THANH GHI

TRISB

0005 1683 BSF 0x3, 0x5 25: banksel trisb

0006 1303 BCF 0x3, 0x6

26: ; XOA THANH GHI TRISB CHO PHEP

CAC CHAN PORTB LA DAU RA

0007 0186 CLRF 0x6 27: clrf trisb

28: ; CHON BANK NHO CO THANH GHI

PORTB

0008 1283 BCF 0x3, 0x5 29: banksel PORTB

0009 1303 BCF 0x3, 0x6

30:

31: ; BAT DAU XU LY

32: start:

33: LOOP:

000A 3009 MOVLW 0x9 34: movlw d'9

000B 2100 CALL 0x100 35: CALL BANGMA

36:

000C 0086 MOVWF 0x6 37: MOVWF PORTB

38:

000D 2015 CALL 0x15 39: CALL DELAY

40:

000E 3000 MOVLW 0 41: movlw d'0

000F 2100 CALL 0x100 42: CALL BANGMA

43:

0010 0086 MOVWF 0x6 44: MOVWF PORTB

0011 3000 MOVLW 0 45: movlw high (DELAY)

0012 008A MOVWF 0xa 46: movwf pclath

0013 2015 CALL 0x15 47: CALL DELAY

Page 70: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

70

0014 280A GOTO 0xa 48: GOTO LOOP

49: ; DUA DU LIEU GIATRICONG VAO

THANH GHI TRUNG GIAN W

50:

51:

52: ; CHUONG TRINH CON DELAY 200MS

53: DELAY:

54:

0015 0000 NOP 55: nop

0016 0000 NOP 56: nop

0017 30B9 MOVLW 0xb9 57: movlw d'185

0018 00A0 MOVWF 0x20 58: movwf vong1

0019 3004 MOVLW 0x4 59: movlw d'4

001A 00A1 MOVWF 0x21 60: movwf vong2

001B 3002 MOVLW 0x2 61: movlw d'2

001C 00A2 MOVWF 0x22 62: movwf vong3

001D 0BA0 DECFSZ 0x20, F 63: decfsz vong1,f

001E 281D GOTO 0x1d 64: goto $-1

001F 0BA1 DECFSZ 0x21, F 65: decfsz vong2,f

0020 281D GOTO 0x1d 66: goto $-3

0021 0BA2 DECFSZ 0x22, F 67: decfsz vong3,f

0022 281D GOTO 0x1d 68: goto $-5

0023 0008 RETURN 69: return

70:

71:

72: ORG 0X100

73: BANGMA

0100 0782 ADDWF 0x2, F 74: ADDWF PCL,F

0101 34C0 RETLW 0xc0 75: RETLW 0XC0

Page 71: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

71

0102 34F9 RETLW 0xf9 76: RETLW 0XF9

0103 34A4 RETLW 0xa4 77: RETLW 0XA4

0104 34B0 RETLW 0xb0 78: RETLW 0XB0

0105 3499 RETLW 0x99 79: RETLW 0X99

0106 3492 RETLW 0x92 80: RETLW 0X92

0107 3482 RETLW 0x82 81: RETLW 0X82

0108 34F8 RETLW 0xf8 82: RETLW 0XF8

0109 3480 RETLW 0x80 83: RETLW 0X80

010A 3490 RETLW 0x90 84: RETLW 0X90

85:

2007 3490 RETLW 0x90 86: end

Trước khi đi vào phân tích các khả năng có thể xảy ra, ta xem kĩ lại nguyên lý làm

việc của thanh ghi PC.

Thanh ghi PC có độ dài 13 bit chia làm 2 thanh ghi PCL (tức 8 bit thấp của thanh

ghi PC PC<7:0>) và PCH (5 bit cao của thanh ghi PC- PC<12-8>):

PCH PCL

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

Trong đó thanh ghi PCL có thể đọc /ghi được

Thanh ghi PCH không thể đọc ghi được. Tuy nhiên có thể ghi được thông qua

thanh ghi PCLATH.

Nghĩa là 5 bit cao của thanh ghi PC, PC<12:8> có thể cập nhật được bằng cách

viết vào 5 bit thấp của thanh ghi PCLATH.

Khi chương trình được reset lại từ đầu, các bit PC<12:8> được xóa về 0

Có điều chú ý là:

Nếu có lệnh can thiệp vào thanh ghi PCL thì lập tức các bit cao của thanh ghi PC

sẽ được cập nhật từ thanh ghi PCLATH

Page 72: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

72

Như vậy, các bit cao của thanh ghi PC được cập nhật khi xẩy ra 1 trong 2

điều kiện:

- Cập nhật PCL

- Cập nhật PCLATH

Ví dụ 1: khi thực hiện lệnh CALL nhãn

Nếu sau nhãn là lệnh ở địa chỉ k (0<k<2047)

Lệnh trên được phân giải dưới dạng CALL k

Khi thực hiện lệnh này:

11 bit cao của PC được cập nhật: PC<10:0> =k

Lập tức 2 bit còn lại của PC cũng được cập nhật qua PCLATH:

PC<12:11>=PCLATH<4:3>

Ví dụ 2: khi thực hiện lệnh ADDWF PCL,F

Lập tức PCL=PCL+W

Do PCL được cập nhật nên các bit cao của PC cũng được cập nhật qua PCLATH:

PCH=PC<12:8>=PCLATH<4:0>

Từ đây trở lại chương trình hiển thị led 7 đoạn sử dụng kĩ thuật bảng.

Để ý đoạn chương trình con BANGMA được khai báo sử dụng bộ nhớ từ địa chỉ

0x100 (ORG 0x100). Xét lệnh ở dòng 34 và 35:

000A 3009 MOVLW 0x9 34: movlw d'9

000B 2100 CALL 0x100 35: CALL BANGMA

Khi thực hiện lệnh ở dòng 34, W=9

Trước thực hiện lệnh ở dòng 35, PCL=PC<7:0>=0x0B, PCLATH=0x00,

PCH=PC<12:8>=00000

Nhãn BANGMA ở địa chỉ 0x100

Như vậy lệnh trên phân giải như sau: CALL 0x100

Khi thực hiện lệnh này, 11 bit thấp của PC, PC<10:0>=0x100= 01 0000 0000

2 bit cao của PC, PC<12:11>=PCLATH<43>=00

Vậy PC= 0001 0000 0000=0x100

Và chương trình nhảy đến thực hiện lệnh ở địa chỉ 0x100

Page 73: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

73

0100 0782 ADDWF 0x2, F 74: ADDWF PCL,F

Khi thực hiện lệnh này PCL=PCL+W=0x00 +0x09=0x09=1001

Do PCL được cập nhật nên PCH cũng được cập nhật qua PCLATH

PCH=PC<12:8>=PCLATH<4:0>=00000

Vậy PC=0000 0000 1001=0x09

Sau khi thực hiện 1 lệnh PC=PC+1=0x0A

Chương trình nhảy đến thực hiện lệnh có địa chỉ 0x0A:

000A 3009 MOVLW 0x9 34: movlw d'9

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Như vậy là không đúng ý đồ của ta, chương trình chạy sai!!!!!!!!!!!!!!

Nhìn lại quá trình phân tích như trên, ta thấy mấu chốt của vấn đề là:

Chương trình con bảng mã bắt đầu từ địa chỉ >0xff

Do đó lệnh CALL làm PC thây đổi nội dung các bit cao

Khi gặp lệnh tác động đến thanh ghi PCL: ADDWF PCL,F

Thì đồng thời PCH cũng được cập nhật qua PCLATH

Tuy nhiên PCLATH lại không được cập nhật trước đó như vậy địa chỉ PC bây giờ

<0xff

Để giải quyết vấn đề trên ta thấy chỉ cần cập nhật PCLATH bằng các bit cao của

địa chỉ của lệnh đầu tiên trong chương trình con bảng mã

; DUA FILE LIET KE VAO

#include p16f877a.inc

; KHAI BAO CAU HINH

__CONFIG _HS_OSC & _WDT_OFF &_LVP_OFF

; KHAI BAO BIEN O DAY

; DIA CHI BIEN O VUNG NHO BIEN BANK0

cblock 0x20

vong1,

vong2,

vong3

Page 74: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

74

endc

;

;CHUONG TRINH VI DIEU KHIEN CHAY TAI DAY

org 0x000; CHI DAN BIEN DICH

; NHAY TOI CHUONG TRINH CHINH

goto main

; chi dan bien dich

; CHUONG TRINH CHINH BAT DAU TU DAY

org 0x005

main

; CHON BANK NHO CHUA THANH GHI TRISB

banksel trisb

; XOA THANH GHI TRISB CHO PHEP CAC CHAN PORTB LA DAU RA

clrf trisb

; CHON BANK NHO CO THANH GHI PORTB

banksel PORTB

; BAT DAU XU LY

start:

LOOP:

movlw high (BANGMA)

movwf pclath

movlw d'9

CALL BANGMA

MOVWF PORTB

movlw high (DELAY)

Page 75: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

75

movwf pclath

CALL DELAY

movlw high (BANGMA)

movwf pclath

movlw d'0

CALL BANGMA

MOVWF PORTB

movlw high (DELAY)

movwf pclath

CALL DELAY

GOTO LOOP

; DUA DU LIEU GIATRICONG VAO THANH GHI TRUNG GIAN W

; CHUONG TRINH CON DELAY 200MS

DELAY:

nop

nop

movlw d'185

movwf vong1

movlw d'4

movwf vong2

movlw d'2

movwf vong3

decfsz vong1,f

goto $-1

decfsz vong2,f

goto $-3

decfsz vong3,f

Page 76: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

76

goto $-5

return

ORG 0X100

BANGMA

ADDWF PCL,F

RETLW 0XC0

RETLW 0XF9

RETLW 0XA4

RETLW 0XB0

RETLW 0X99

RETLW 0X92

RETLW 0X82

RETLW 0XF8

RETLW 0X80

RETLW 0X90

end

Câu hỏi 4: Thuật toán chương trình chia cho 10?

Trong chương trình hiển thị số có 2 chữ số bằng led 7 đoạn ta có dùng thuật toán

chia 10 để xác định con số hàng chục và con số hàng đơn vị, sau đó hiển thị từng

con số này bởi 1 led 7 đoạn.

Thuật toán:

Page 77: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

77

Cho con số ví dụ để hiểu thuật toán:

Số =35

Bước 1: W=số=35

Hangdonvi=W=35

Bước 2: W=10

Số = số -W=Số - 10= 25

Bước 3: Số >0, nhảy theo nhánh No

Hangchuc=hangchuc+1=1

Bước 4: hangdonvi=số=25

Bước 5: W=10

Số = số -W=Số - 10= 15

Bước 6: Số >0, nhảy theo nhánh No

Hangchuc=hangchuc+1=1+1=2

START

W=SỐ Hangdonvi=W

W=10 SỐ=SỐ-W=SỐ-10

Số<0

Hangchuc= hangchuc+1

Yes

Thoát

No

Page 78: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

78

Bước 7: hangdonvi=số=15

Bước 8: W=10

Số = số -W=Số - 10= 15-10=5

Bước 9: Số >0, nhảy theo nhánh No

Hangchuc=hangchuc+1=2+1=3

Bước 10: hangdonvi=số=5

Bước 11: W=10

Số = số -W=Số - 10= 5-10=-

Bước 12: Số <, nhảy theo nhánh Yes thoát

Rõ ràng lúc này hangchuc=3 và hangdonvi=5 đúng yêu cầu

Trong thuật toán trên chỉ có một khúc mắc nho nhỏ là làm sao để kiểm tra số<0

hay chưa

Ta sử dụng cờ nhớ C của thanh ghi status

C phản ánh trạng thái dương hay âm của phép toán

Nếu kết quả phép toán là dương (>=0) thì cờ C=1

Nếu kết quả phép toán là âm (<0) thì cờ C=0

Do đó lệnh sử dụng ở đây là:

MOVLW D'10

subwf so,f

btfsc status,c

goto No

goto Yes

CHƯƠNG 5: BỘ ĐỊNH THỜI - TIMER

5.1 Giới thiệu:

Định thời là tạo một khoảng thời gian giữa 2 sự kiện

Trong các ứng dụng của vi điều khiển trong thực tế, việc định thời là việc thường

xuyên xảy ra.

Để thực hiện việc này, ta có 2 cách:

Page 79: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

79

- Dùng các lệnh thực hiện các vòng lặp để tạo ra khoảng thời gian. Nguyên

tắc tạo ra khoảng thời gian này đơn giản như sau: nếu vi điều khiển mất

một khoảng thời gian x để thực hiện một lệnh, việc lặp lại một lệnh n lần sẽ

mất n*x thời gian.

Trong chương trình, cách này được dùng nhiều với thể hiện là các chương

trình con Delay. Giải thích và thuật toán làm việc của chương trình con

delay đã được trình bày khá kĩ ở các chương trước

- Dùng các bộ định thời Timer để tạo ra khoảng thời gian trễ.

Trong bài này, ta sẽ đi vào nguyên cứu các bộ timer.

Một chế độ quan trọng nữa của Timer là khi ta cài đặt cho nó hoạt động như bộ

đếm. Trong ứng dụng này, timer hoạt động như một bộ đếm, có nhiệm vụ đếm số

các xung đi vào một chân cụ thể trên vi điều khiển (Đối với timer0 chân đầu vào

của tín hiệu xung là RA4, với timer1 là RC0). Chế độ bộ đếm này có nhiều ứng

dụng trong thực tế như đếm số vòng quay của động cơ (phản hồi từ bộ đo tốc độ

động cơ- encoder), đếm số sản phẩm trên một dây chuyền v.v.

Vi điều khiển PIC16F877A có 3 bộ Timer:

- Timer0: 8 bit (số đếm tối đa của nó là 255), hoạt động ở 2 chế độ định thời

và bộ đếm.

- Timer1: 16 bit (số đếm tối đa của nó là 65535), hoạt động ở 2 chế độ định

thời và bộ đếm.

- Timer2: 8 bit, hoạt động phục vụ chức năng PWM (Pulse Width

Modulation- Điều chế độ rộng xung)

Trong bài này ta đi vào khảo sát 2 bộ Timer0 và Timer1, Timer2 sẽ được khảo sát

trong bài về PWM.

Để tiện cho việc khảo sát, ta đi vào nguyên lý hoạt động cơ bản của các bộ timer ở

hai chế độ: định thời và bộ đếm.

5.2 Nguyên lý hoạt động cơ bản của một bộ Timer:

5.2.1 Chế độ định thời:

Page 80: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

80

Mỗi bộ timer có một hoặc nhiều thanh ghi chứa giá trị đếm của nó (tùy thuộc vào

độ dài của timer), ta giả sử tên thanh ghi là TMR có độ dài là n byte (n=1 với

timer0, n=2 với timer1), hay giá trị đếm tối đa là 0 (Chuyển từ 128 n về 0). Khi

giá trị của TMR đạt đến giá trị này, vi điều khiển sẽ set bit cờ của bộ timer đó lên

mức 1. Người dùng sẽ biết được thời điểm này bằng cách kiểm tra bit cờ.

Khi được cài đặt hoạt động trong chế độ định thời:

- Giá trị của thanh ghi TMR sẽ tự động tăng lên 1 đơn vị sau mỗi chu kì

lệnh của vi điều khiển: TMR=TMR+1

- Khi giá trị của TMR đạt đến giá trị tối đa (Đối với timer0: từ 255 cộng

thêm 1 chuyển về 0, đối với timer1: từ 65535 cộng 1 chuyển về 0) , bit cờ

của Timer (Đối với Timer0, tên bit cờ là TMR0IF, vị trí là bit số 2 của

thanh ghi INTCON; Đối với Timer1, tên bit cờ là TMR1IF, vị trí là bit số 0

của thanh ghi PIR1) sẽ được set lên mức 1

Giả sử vi điều khiển dùng thạch anh tần số 4MHz, như vậy:

Chu kỳ lệnh= 4 chu kì thạch anh= =1µs

Vậy TMR sẽ tự động tăng lên 1 đơn vị sau một chu kì lệnh tức sau 1µs.

Nếu ban đầu ta gán cho TMR= x. Thì sau khoảng thời gian xn 82 (µs) giá trị

TMR sẽ đạt giá trị tối đa của nó là 0 (chuyển từ 255+1->0) . Thời điểm này được

xác định thông qua trạng thái của bit cờ.

Ngược lại, ta muốn thực hiện định thời khoảng thời gian t sau một sự kiện 1 như

sau:

- Sự kiện 1

- Tạo khoảng thời gian trễ t

- Sự kiện 2

Ta làm các bước:

- Sự kiện 1

- Gán giá trị ban đầu cho TMR = tn 82

- Kiểm tra bit cờ

Page 81: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

81

- Khi bit cờ = 1, thực hiện sự kiện 2.

Thật vậy, sau 1 (µs) TMR tăng lên 1 đơn vị

Để tăng giá trị cho TMR từ tn 82 đến giá trị 0 (chuyển từ 255 +1 về 0) (khi bit

cờ được set lên 1) mất )2(2 88 tnn = t (µs)

Vậy khoảng thời gian từ sau sự kiện 1 (khi TMR bắt đầu được gán) đến sự kiện 2

(ngay sau khi bit cờ được set) là t (µs) đúng như yêu cầu của ta.

Ví dụ: Để định thời 200 (µs) dùng Timer0 (8 bit; n=1; giá trị tối đa là 255) ta cho

TMR0= 256-200=56

Như vậy:

Sau 1 µs đầu tiên. TMR0=TMR0+1=57

Sau 2 µs . TMR0=TMR0+1=58

-------

Sau 200 µs, TMR0=TMR0+1= 255+1= 0 (TMR0 có giá trị lớn nhất là 255)

5.2.2 Chế độ bộ đếm:

Khi được cài đặt trong chế độ này, một chân chức năng trên vi điều khiển sẽ trở

thành chân đầu vào xung của bộ đếm. Ví dụ: chân RA4 đối với Timer0 và RC0

đối với Timer1. Hoạt động của nó có nét giống với chế độ định thời.

Khi được cài đặt hoạt động trong chế độ bộ đếm, Giá trị của thanh ghi TMR sẽ tự

động tăng lên 1 đơn vị khi và chỉ khi có một xung đi vào chân đầu vào xung

của timer đó. Khi giá trị của TMR0 đạt đến giá trị tối đa (chuyển về 0 do

255+1=256 ), bit cờ của Timer sẽ được set lên mức 1 và TMR bị xóa, TMR=0.

Như vậy, về cách hoạt động trong chế độ này chỉ khác với chế độ định thời ở chỗ,

thay vì TMR tự động tăng lên sau mỗi chu kì lệnh, thì TMR tăng lên khi có một

xung đi vào chân đầu vào xung của Timer đó.

Dạng xung được xác định là sườn âm (từ mức cao -> mức thấp) hay sườn dương

(mức thấp->mức cao) phụ thuộc vào việc cài đặt bit chọn dạng xung tương ứng .

Đối với Timer0: Để chọn dạng xung dung bit T0SE – bít số 4 của thanh ghi

OPTION_REG

T0IE=0: Chọn dạng xung dương (L->H)

Page 82: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

82

T0IE=1: Chọn dạng xung âm (H->L)

Đối với Timer1: chỉ có dạng xung đầu vào là xung dương

Nguyên lý hoạt động định thời và bộ đếm này cũng đúng với các bộ vi điều khiển,

vi xử lý khác.

Ta đi vào khảo sát cụ thể 2 Timer0 và Timer1 của vi điều khiển PIC.

5.3 Timer 0:

5.3.1 Đặc điểm:

- Thanh ghi chứa giá trị đếm là TMR0 có độ dài 8 bit (số đếm tối đa là 255).

- Nội dung của thanh ghi TMR0 có thể đọc và ghi được

- Hoạt động ở 2 chế độ: bộ định thời và bộ đếm

- Trong chế độ bộ đếm: dạng xung đầu vào có thể lựa chọn (sườn dương

hoặc sườn âm)

- Có bộ chia tần số có thể thay đổi tỉ lệ chia bằng chương trình

5.3.2 Các bit điều khiển:

a. Bit chọn chế độ:

Timer0 hoạt động ở 2 chế độ: bộ định thời và bộ đếm

Để lựa chọn chế độ làm việc, ta gán giá trị cho bit T0CS (Timer0 Clock Select bit-

Bit lựa chọn nguồn xung cho Timer), vị trí của bit này là bit 5 của thanh ghi

OPTION_REG:

T0CS=1: Timer0 hoạt động ở chế độ bộ đếm (nguồn xung là xung đầu đi vào chân

RA4)

T0CS=0: Timer0 hoạt động ở chế độ định thời (nguồn xung là dao động thạch anh,

tần số=Fosc/4)

b. Bit chọn dạng xung đầu vào:

Khi hoạt động ở chế độ bộ đếm, thanh ghi TMR0=TMR0+1 mỗi lần có 1 xung đi

vào chân RA4

Vấn đề là dạng xung là xung sườn lên hay sườn xuống

Để cài đặt dạng xung ta gán giá trị cho bit T0SE (Timer0 Edge Select Bit- Bít

chọn dạng sườn xung), vị trí của bit là bít 4 của thanh ghi OPTION_REG:

Page 83: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

83

T0SE=1: TMR0=TMR0+1 Khi có đổi trạng thái từ cao xuống thấp trên chân RA4

(sườn âm)

T0SE=0: TMR0=TMR0+1 Khi có đổi trạng thái từ thấp lên cao trên chân RA4

(sườn dương)

c. Các bít cài đặt tỉ lệ chia tần số:

Như trong phần a đã khảo sát, nguồn xung tác động có thể xung đi vào chân RA4

(trong chế độ bộ đếm)

Hoặc nguồn xung từ dao động thạch anh (đã được chia 4- trong chế độ bộ định

thời)

Trong thực tế, dao động từ nguồn xung trên phải đi qua bộ chia tần số trước khi đi

vào tác động đến

Timer0.

Bộ chia tần số này có thể cài đặt tỉ lệ chia tần số

Cụ thể ta hiểu đơn giản như sau:

Trong chế độ bộ đếm, TMR0=TMR0+1 sau mỗi xung của tín hiệu đi vào chân

RA4

Vậy tần số cập nhật của TMR0 là bằng tần số xung

Bây giờ do tín hiệu xung từ chân RA4 đi qua bộ chia tần số trước khi tác động

thay đổi TMR0

Giả sử tỉ lệ chia là 1:2 nghĩa là tần số của xung đầu ra của bộ chia bằng ½ tần số

của xung vào RA4

Mỗi xung đầu ra của bộ chia làm cho TMR0=TMR0+1

Vậy tần số xung của RA4=2 tần số cập nhật TMR0

Do đó, sau khi có 2 tác động vào RA4 thì TMR0=TMR0+1

Tương tự, đối với chế độ bộ định thời

Sau 2 chu kì lệnh, TMR0=TMR0+1

Điều đặc biệt là tỉ lệ chia này có thể thay đổi được bằng cách gán giá trị cho các

bit PS2,PS1,PS0- Vị trí các bít là bit 2,1,0 của thanh ghi OPTION_REG

Cụ thể tỉ lệ chia tương ứng với giá trị của PS2,PS1,PS0 như sau:

Page 84: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

84

PS2 PS1

PS0

Tỉ lệ chia

000 1:2

001 1:4

010 1:8

011 1:16

100 1:32

101 1:64

110 1:128

111 1:256

d. Bít chọn bộ chia tần số cho TIMER0:

Thực ra bộ chia tần số có thể được lựa chọn làm bộ chia cho Timer0 hoặc Watch

Dog Timer

Vì vậy, để cài đặt bộ chia tần số làm việc với Timer0 ta có gán giá trị cho bít PSA

, vị trí bit là bít số 3 của thanh ghi OPTION_REG.

PSA=0, bộ chia làm việc cho TIMER0

PSA=1, bộ chia làm việc cho Watch Dog Timer

e. Bít cờ trạng thái:

Do độ dài của thanh ghi TMR0 là 8 bit, như vậy tốt đa viết được 255

Nếu như TMR0=255, nếu tiếp tục có xung vào (từ nguồn dao động thạch anh

trong chế độ định thời hoặc từ chân RA4 trong chế độ bộ đếm), TMR0 = 255+1 =

256 bị tràn và TMR0=0

Mỗi lần TMR0 bị tràn, bit cờ trạng thái sẽ tự động set lên 1 để báo trạng thái tràn

đó

Bit cờ này có tên là TMR0IF (Timer0 Interrupt Flag- Bít cờ ngắt), vị trí bit là

bít 2 của thanh ghi INTCON.

Chú ý là khi có tràn giá trị của thanh ghi TMR0, TMR0IF=1, TMR0=0

Ta phải xóa TMR0IF bằng chương trình.

Page 85: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

85

Toàn bộ hoạt động của timer0 có thể tổng kết theo sơ đồ sau:

5.3.3 Các thanh ghi liên quan:

Thanh ghi TMR0 (Địa chỉ 01h):

Chứa giá trị đếm hiện tại của Timer 0

Thanh ghi Option_Reg (Địa chỉ 81h):

T0CS: Bit chọn chế độ

= 0: TMR0 hoạt động chế độ định thời

= 1: TMR0 hoạt động chế độ bộ đếm

T0SE: Bit chọn dạng xung cho chế độ bộ đếm

= 0: Xung sườn lên

= 1: Xung sườn xuống

PSA: Bit chọn chế độ cho bộ chia tần số PresCale là WatchDog_Timer hay Timer

0.

= 0: Bộ chia tần số dành cho Timer 0

= 1: Bộ chia tần số dành cho Watch_Dog Timer

PS2-PS0: 3 bit chọn tỉ lệ chia tần số như đã giới thiệu ở phần trên

Thanh ghi INTCON (0Bh):

Page 86: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

86

Bit TMR0IE: Bit này bằng 1 cho phép ngắt Timer 0. Sự kiện ngắt xảy ra khi có sự

tràn TMR0 từ 255 xuống 0.

Bit TMR0IF: Bit cờ xác nhận giá trị TMR0 đã bị tràn từ 255 về 0

Page 87: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

87

BÀI 6: NGẮT

6.1 Ngắt là gì:

Ngắt hiểu theo nghĩa đơn giản là các sự kiện ngẫu nhiên làm gián đoạn quá trình

đang xảy ra. Để có thể dễ hiểu khái niệm mới này ta cùng đưa ra một ví dụ trong

thực tế như sau:

Ví dụ: Trong giờ học trên lớp, ta đang học bài, có chuông điện thoại hoặc có bạn

gọi, ta phải dừng hoạt động học bài lại để trả lời điện thoại hoặc ra gặp bạn. Sự

kiện điện thoại reo chuông, hay bạn bè gọi được gọi là sự kiện ngắt, việc ta trả lời

điện thoại hay ra gặp bạn là chương trình phục vụ ngắt. Việc đang học bài được

xem là chương trình chính.

Ngắt được thực hiện khi và chỉ khi cho phép nó. Như trong ví dụ trên, nếu sự kiện

ngắt- điện thoại reo xảy ra, nếu giáo viên và bản thân ta cho phép mình trả lời điện

thoại khi đang học bài thì khi có điện thoại ta mới nghe.

Vi điều khiển cũng có ngắt. Cách xử lý của nó cũng tương tự như ví dụ trên.

Cụ thể hoạt động của vi điều khiển khi có sự kiện ngắt xảy ra và ngắt đó đã được

cho phép:

- Thực hiện nốt lệnh đang thực hiện

- Dừng chương trình đang thực hiện

- Lưu lại địa chỉ của lệnh kế tiếp trong chương trình đang thực hiện vào bộ

nhớ stack

- Nhảy tới địa chỉ 0x04 trong bộ nhớ chương trình

- Tại đây, vi điều khiển sẽ thực hiện chương trình con phục vụ ngắt do người

lập trình đã lập trình từ trước.

Page 88: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

88

- Sau khi thực hiện xong chương trình con phục vụ ngắt, vi điều khiển lấy lại

địa chỉ của lệnh kế tiếp đã được lưu và thực hiện tiếp chương trình đang

thực hiện dở lúc chưa có ngắt

Như vậy, cách phản ứng của vi điều khiển là khá tương đồng với cách xử lý của

con người trong thực tế. Như trong ví dụ trên, khi ta đang học bài, khi có ngắt, tức

có điện thoại-sự kiện ngắt, ta đọc nốt từ cuối cùng, nhớ dòng đang đọc ở trang thứ

mấy, đánh dấu, trả lời điện thoại (chương trình con phục vụ ngắt), trả lời xong ta

trở lại học bài ở dòng, trang đã được đánh dấu.

Tới đây ta tổng hợp lại các thuật ngữ dùng cho xử lý ngắt trong vi điều khiển:

- Nguồn ngắt: nguồn ngắt là nguyên nhân gây ra ngắt. Như trong ví dụ trên,

nguồn ngắt có thể

Là điện thoại gọi hoặc bạn gọi

- Sự kiện ngắt: khi nguồn ngắt xảy ra

- Chương trình con phục vụ ngắt: là chương trình vi điều khiển xử lý khi

có sự kiện ngắt xảy ra do người lập trình lập trình ra

Ví dụ như ta trả lời hoặc chạy ra khỏi phòng gặp bạn

- Vecto ngắt: tức địa chỉ 0x04 nơi vi điều khiển chạy tới sau khi lưu địa chỉ

trả về

- Bit cho phép ngắt: tức việc cho phép vi điều khiển chạy chương trình con

phục vụ ngắt khi có sự kiện ngắt xảy ra. Trong vi điều khiển PIC, mỗi ngắt

có bit cho phép của nó. Bit này tận cùng bằng chữ E (enable), nằm trong

các thanh ghi chuyên dụng. Muốn cho phép ngắt đó, ta phải đưa bit cho

phép ngắt tương ứng lên giá trị 1. Ngắt chỉ thực sự được cho phép ngắt khi

ta cho bit cho phép ngắt toàn cục GIE (Global Interrupt Enable) lên mức 1.

Ta hình dùng như sau: khi có sự kiện ngắt- điện thoại gọi, nếu ta cho phép

mình nghe điên thoại (tức bit cho phép ngắt của ngắt đó được set lên 1)

Page 89: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

89

đồng thời thầy giáo cho phép (bit cho phép ngắt toàn cục GIE được lên mức

1) thì ta mới nghe điện thoại (cho chương trình con phục vụ ngắt hoạt

động).

Một số các ngắt khác, như các ngắt ngoại vi bao gồm ADC, PWM v.v

Muốn cho phép nó còn phải đưa bit cho phép ngắt ngoại vi lên mức 1.

- Cờ ngắt: là bit phản ánh trạng thái của sự kiện ngắt. Mỗi ngắt có một bit

cờ. Khi bit cờ này bằng 1 nghĩa là sự kiện ngắt tương ứng với cờ đó xảy ra.

Ta hình dung như tiếng chuông của điện thoại là cờ ngắt, chuông rung báo

có sự kiện ngắt- có điện thoại xảy ra. Các bit này tận cùng bằng từ F (Flag-

cờ). Lưu ý là dù một ngắt có được cho phép hay không thì cờ ngắt vẫn được

set lên 1 khi có sự kiện ngắt xảy ra. (Dù ta có được phép nghe điện thoại

hay không thì chuông điện thoại vẫn cứ reo).

6.2 Các ngắt trong vi điều khiển PIC16F877A:

Vi điều khiển PIC16F877A có 15 nguồn ngắt. Được chia làm 2 lớp ngắt:

- Lớp ngắt cơ bản: bao gồm các ngắt cơ bản như ngắt tràn timer 0, ngắt

ngoài, ngắt thay đổi trạng thái của các chân PortB (RB4-RB7). Bit cho

phép ngắt và bit cờ tương ứng là TMR0IE,TMR0IF; INTE, INTF; RBIE và

RBIF. Để ý là để cho phép ngắt thực sự xảy ra phải có bit cho phép ngắt

toàn cục GIE.

- Lớp ngắt ngoại vi: bao gồm các ngắt ngoại vi như ngắt tràn timer 1

(TMR1IE, TMR1IF), ngắt tràn Timer 2(TMR2IE, TMR2IF), ngắt hoàn

thành việc chuyển đổi ADC (ADCIE, ADCIF), ngắt hoàn thành việc nhận

kí tự trong truyền thông RS232 (RCIE, RCIF), ngắt hoàn thành việc truyền

kí tự trong truyền thông RS232 (TXIE, TXIF) v.v Để ý là muốn thực sự

cho phép các ngắt này ngoài bit cho phép ngắt toàn cục được set phải set cả

bỉt cho phép ngắt ngoại vi PEIE.

Page 90: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

90

6.3 Cấu trúc một chương trình hợp ngữ có xử lý ngắt:

6.3.1 Cấu trúc chương trình:

; DUA FILE LIET KE VAO

#INCLUDE P16F877A.INC

; KHAI BAO CAU HINH

__CONFIG _HS_OSC & _WDT_OFF &_LVP_OFF

Page 91: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

91

; KHAI BAO BIEN O DAY

; DIA CHI BIEN O VUNG NHO BIEN BANK0

CBLOCK 0x20

ENDC

;CHUONG TRINH VI DIEU KHIEN CHAY TAI DAY

ORG 0x000; CHI DAN BIEN DICH

; NHAY TOI CHUONG TRINH CHINH

GOTO MAIN

; DIA CHI VECTOR NGAT

ORG 0x004

; THUC HIEN LENH NHAY DEN CHUONG TRINH CON

GOTO INTERRUPT_SUB

; CHUONG TRINH CHINH BAT DAU TU DAY

ORG 0x005

MAIN

Page 92: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

92

; CAC LENH CUA CHUONG TRINH CHINH VIET O DAY

; Dùng ngắt nào thì phải cài đặt và cho phép ngắt đó

; CHUONG TRINH CON PHUC VU NGAT

INTERRUPT_SUB

; CÁC LỆNH VIẾT Ở ĐÂY

; KET THUC CHUONG TRINH CON PHUC VU NGAT

RETFIE

END

6.3.2 Các điểm chú ý trong chương trình có sử dụng ngắt:

ORG 0x000; CHI DAN BIEN DICH

; NHAY TOI CHUONG TRINH CHINH

GOTO MAIN

; DIA CHI VECTOR NGAT

ORG 0x004

; THUC HIEN LENH NHAY DEN CHUONG TRINH CON

Page 93: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

93

GOTO INTERRUPT_SUB

; CHUONG TRINH CHINH BAT DAU TU DAY

ORG 0x005

MAIN

; CAC LENH CUA CHUONG TRINH CHINH VIET O DAY

Như đã phân tích ở các mục bên trên, địa chỉ 0x004 trong bộ nhớ chương trình là

vector ngắt của vi điều khiển, nghĩa là khi có một ngắt nào đó xảy ra (với điều

kiện là ngắt đó và ngắt toàn cục đã được cho phép) thì cờ ngắt cho ngắt đó được

set lên 1, vi điều khiển lập tức nhảy tới địa chỉ 0x004, tại đây người lập trình đưa

ra các lệnh xử lý ngắt đó.

Như vậy, các lệnh của phần xử lý ngắt này phải bắt đầu từ địa chỉ 0x004. Tuy

nhiên, thông thường để cho tiện quản lý và theo dõi ngắt, phần chương trình xử lý

ngắt được bố trí ở một nơi khác. Ví dụ ở đây là chương trình con phục vụ ngắt:

INTERRUPT_SUB

; KET THUC CHUONG TRINH CON PHUC VU NGAT

RETFIE

Và tại địa chỉ 0x004 ta có lệnh nhảy đến chương trình con này:

ORG 0x004

; THUC HIEN LENH NHAY DEN CHUONG TRINH CON

Page 94: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

94

GOTO INTERRUPT_SUB

Ở đây cũng lưu ý thêm 1 điều là chương trình chính phải bố trí bắt đầu ít

nhất là từ địa chỉ 0x005 trở đi. Vì rõ ràng nếu nằm trong khoảng từ 0x000 đến

0x0004 thì các lệnh của chương trình chính sẽ nằm đè lên chương trình con phục

vụ ngắt mà cụ thể ở đây là lệnh GOTO INTERRUPT_SUB

6.3.3 Chương trình con phục vụ ngắt:

Cấu trúc:

Tên chương trình con

RETFIE

Khi có ngắt xảy ra, vi điều khiển lưu địa chỉ của lệnh tiếp theo sẽ được thực hiện ở

chương trình chính vào stack, sau đó nhảy đến địa chỉ 0x004, tại đây có lệnh nhảy

đến chương trình con phục vụ ngắt. Chương trình con phục vụ ngắt được thực hiện

cho đến khi gặp lệnh RETFIE, vi điều khiển lấy địa chỉ trong stack đưa vào PC để

có lệnh trở về chương trình chính, và bit cờ GIE được set lên 1.

Trong thực tế, trước khi nhảy vào phần thực hiện các xử lý ngắt trong chương

trình con phục vụ ngắt ta cần lưu lại giá trị thanh ghi W và thanh ghi STATUS tại

thời điểm khi xảy ra ngắt để khi xử lý xong ta trở về thực hiện tiếp chương trình

chính.

Để thực hiện điều này, chương trình con phục vụ ngắt có cấu trúc như sau:

Tên chương trình con

MOVWF W_TEMP

Page 95: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

95

SWAPF STATUS,W

MOVWF STATUS_TEMP

; các lệnh xử lý ngắt ở đây

SWAPF STATUS_TEMP,W

MOVWF STATUS

SWAPF W_TEMP,F

SWAPF W_TEMP,W

RETFIE

Về cơ bản ở đây là trước khi xử lý ngắt cần đưa nội dung của thanh ghi W, thanh

ghi STATUS vào các thanh ghi tạm thời trong RAM: W_TEMP, STATUS_TEMP

Và sau khi xử lý xong thì đưa các giá trị này về thanh ghi W và STATUS

Chỉ chú ý một điều là thay vì dùng các lệnh movf để xử lý ở đây sử dụng các lệnh

swapf vì lệnh này khác lệnh movf ở chỗ là nó không làm ảnh hưởng đến thanh ghi

STATUS.

6.4 Ngắt ngoài:

6.4.1 Hoạt động:

- Nguồn ngắt: là xung đi vào chân RB0 của vi điều khiển PIC

Page 96: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

96

- Sự kiện ngắt: sự kiện ngắt xảy ra khi có xung đi vào chân RB0 của vi điều

khiển. Xung là xung sườn dương hay sườn âm phụ thuộc bit cài đặt chọn

dạng xung, bit INTEDG ( bit 6 của thanh ghi OPTION_REG) là 1 hay 0.

- Bit cho phép ngắt: Để cho phép ngắt ngoài, bit cho phép ngắt ngoài INTIE

(bit 4 của thanh ghi INTCON) phải được set lên 1. Ngoài ra, bit cho phép

ngắt toàn cục GIE (bit 7 của thanh ghi INTCON) cũng phải được set lên 1.

- Cờ ngắt: bit cờ ngắt ngoài là bit INTIF (bit 1 của thanh ghi INTCON) được

tự động set lên 1 khi có sự kiện ngắt ngoài xảy ra. Cờ này phải được xóa

bằng chương trình (cụ thể là trong chương trình con phục vụ ngắt) để vi

điều khiển quản lý chính xác các lần ngắt kế tiếp.

6.4.2 Quản lý ngắt ngoài trong chương trình hợp ngữ:

;CHUONG TRINH VI DIEU KHIEN CHAY TAI DAY

ORG 0x000; CHI DAN BIEN DICH

; NHAY TOI CHUONG TRINH CHINH

GOTO MAIN

; DIA CHI VECTOR NGAT

ORG 0x004

; THUC HIEN LENH NHAY DEN CHUONG TRINH CON

GOTO INTERRUPT_SUB

; CHUONG TRINH CHINH BAT DAU TU DAY

ORG 0x005

Page 97: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

97

MAIN

; CAC LENH CUA CHUONG TRINH CHINH VIET O DAY

; CAI DAT DANG XUNG SUONG AM HAY SUON DUONG

BCF OPTION_REG,6 ; CHON SUON AM

; CHO PHEP NGAT

BSF INTCON,4; CHO PHEP NGAT NGOAI

BSF INTCON,7; CHO PHEP NGAT TOAN CUC

; PHAN CHUONG TRINH CHINH O DAY

; CHUONG TRINH NGAT

INTERRUPT_SUB

MOVWF W_TEMP

SWAPF STATUS,W

MOVWF STATUS_TEMP

BANKSEL INTCON

BCF INTCON,1 ; XOA CO NGAT NGOAI

; PHAN XU LY NGAT O DAY

Page 98: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

98

; PHAN KET THUC NGAT O DAY

SWAPF STATUS_TEMP,W

MOVWF STATUS

SWAPF W_TEMP,F

SWAPF W_TEMP,W

; KET THUC CHUONG TRINH CON PHUC VU NGAT

RETFIE

Xem thêm chương trình xử lý ngắt ngoài trong file đính kèm

6.5 Ngắt Timer 0:

6.5.1 Hoạt động:

- Nguồn ngắt: là trạng thái tràn của thanh ghi bộ đếm timer 0 - TMR0 của vi

điều khiển PIC

- Sự kiện ngắt: sự kiện ngắt xảy ra khi có sự tràn của TMR0, tức là khi

TMR0=255 +1 và bị xóa

- Bit cho phép ngắt: Để cho phép ngắt này, bit cho phép ngắt TMR0IE (bit 5

của thanh ghi INTCON) phải được set lên 1. Ngoài ra, bit cho phép ngắt

toàn cục GIE (bit 7 của thanh ghi INTCON) cũng phải được set lên 1.

- Cờ ngắt: bit cờ ngắt ngoài là bit TMR0IF (bit 2 của thanh ghi INTCON)

được tự động set lên 1 khi có sự kiện ngắt ngoài xảy ra. Cờ này phải được

xóa bằng chương trình (cụ thể là trong chương trình con phục vụ ngắt) để vi

điều khiển quản lý chính xác các lần ngắt kế tiếp.

6.5.2 Quản lý ngắt Timer 0 trong chương trình hợp ngữ:

Page 99: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

99

Trong chương trình chính, cài đặt ngắt:

- Cài đặt chế độ cho Timer0

- Gán giá trị ban đầu cho thanh ghi TMR0, tùy thuộc vào thời gian mà người

lập trình đưa ra theo yêu cầu

- Cho phép ngắt timer 0: TMR0IE=1 (bít thứ 5 của thanh ghi INTCON)

- Cho phép ngắt toàn cục: GIE=1 (bít thứ 5 của thanh ghi INTCON)

Trong chương trình con phục vụ ngắt:

- Nhớ xóa cờ ngắt timer0: TMR0IF=0 (bít thứ 2 của thanh ghi INTCON)

; DUA FILE LIET KE VAO

#INCLUDE P16F877A.INC

; KHAI BAO CAU HINH

__CONFIG _HS_OSC & _WDT_OFF &_LVP_OFF

; KHAI BAO BIEN O DAY

; DIA CHI BIEN O VUNG NHO BIEN BANK0

CBLOCK 0x20

vong1,

vong2,

vong3,

so,SOLANNGAT

hangchuc,hangdonvi,trunggian, STATUS_TEMP,W_TEMP

ENDC

;CHUONG TRINH VI DIEU KHIEN CHAY TAI DAY

ORG 0x000; CHI DAN BIEN DICH

; NHAY TOI CHUONG TRINH CHINH

GOTO MAIN

; DIA CHI VECTOR NGAT

Page 100: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

100

ORG 0x004

; THUC HIEN LENH NHAY DEN CHUONG TRINH CON

GOTO INTERRUPT_SUB

; CHUONG TRINH CHINH BAT DAU TU DAY

ORG 0x005

MAIN

; CAC LENH CUA CHUONG TRINH CHINH VIET O DAY

; CAI DAT DANG XUNG SUONG AM HAY SUON DUONG

; CHO PHEP NGAT

BANKSEL OPTION_REG

MOVLW B'00000111'; CHON CHE DO BO DINH THOI, TI LE

BO CHIA TAN SO LA 1:256

MOVWF OPTION_REG

BANKSEL TMR0

MOVLW D'237'; CAI DAT DE KHI TMR0 BI TRAN VUA DU

5MS

MOVWF TMR0

BANKSEL INTCON

BSF INTCON,5; CHO PHEP NGAT TIMER0

BSF INTCON,7; CHO PHEP NGAT TOAN CUC

BANKSEL TRISB

; XOA THANH GHI TRISB, CHO PHEP CAC CHAN PORTB LA DAU

RA

CLRF TRISD

CLRF TRISA

Page 101: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

101

MOVLW B'00000001'

MOVWF TRISB

BANKSEL ADCON1

MOVLW 0X06

MOVWF ADCON1

; CHON BANK NHO CO THANH GHI PORTB

; BAT DAU XU LY

start:

banksel PORTB

clrf porta

movlw d'12

MOVWF SO

clrf hangchuc

clrf hangdonvi

call chia10

MOVLW D'2

MOVWF SOLANNGAT

GOTO $

; DUA DU LIEU GIATRICONG VAO THANH GHI TRUNG GIAN W

; CHUONG TRINH CON PHUC VU NGAT

INTERRUPT_SUB

MOVWF W_TEMP

Page 102: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

102

SWAPF STATUS,W

MOVWF STATUS_TEMP

; XOA CO NGAT NGOAI

BCF INTCON,2

DECFSZ SOLANNGAT,F

GOTO BATLED1

GOTO BATLED2

BATLED1:

bcf porta,1

bsf porta,0

movF HANGCHUC,W

CALL BANGMA

MOVWF PORTD

GOTO THOAT

BATLED2:

MOVLW D'2

MOVWF SOLANNGAT

bcf porta,0

bsf porta,1

MOVF HANGDONVI,W

CALL BANGMA

MOVWF PORTD

Page 103: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

103

THOAT:

SWAPF STATUS_TEMP,W

MOVWF STATUS

SWAPF W_TEMP,F

SWAPF W_TEMP,W

; KET THUC CHUONG TRINH CON PHUC VU NGAT

RETFIE

chia10:

;tru cho 10

BANKSEL SO

MOVF SO,W

MOVWF HANGDONVI

MOVLW D'10

subwf so,f

btfsc status,c

goto capnhat

; dua gia tri ve cho hang donvi

goto EXIT

capnhat:

incf hangchuc,f

goto chia10

EXIT:

return

BANGMA

Page 104: Giao Trinh Hop Ngu PIC - t.au

TTrrầầnn TThhááii AAnnhh ÂÂuu –– KKhhooaa ĐĐiiệệnn –– ĐĐạạii hhọọcc BBáácchh KKhhooaa -- ĐĐạạii hhọọcc ĐĐàà NNẵẵnngg

104

ADDWF PCL,F

RETLW 0XC0

RETLW 0XF9

RETLW 0XA4

RETLW 0XB0

RETLW 0X99

RETLW 0X92

RETLW 0X82

RETLW 0XF8

RETLW 0X80

RETLW 0X90

END