Tổng quan về vi điều khiển PIC - Pdf 37

Dson
1

Thanh ghi (Register):
Thanh ghi được đặt trong PIC, nó có thể được ghi, đọc. Hãy tưởng tượng các thanh ghi
giống như các mẩu giấy mà chúng ta có thể đọc hay viết thông tin lên nó. Hình bên dưới
mô tả file thanh ghi (register file) được ánh xạ vào PIC16F84.
PIC được chia làm 2 phần, Bank0 và
Bank1.
Bank1 dùng để điều khiển các hoạt động
của PIC, ví dụ như nói cho nó biết những
bit nào trên PortA là đi vào (Input) và
những bit nào xuất ra (Output).
Bank0 dùng để thao tác trên dữ liệu, ví dụ
ta muốn làm cho bit nào đó trên PortA lên
mức cao, đầu tiên ta ta phải chuyển đến
Bank1 để set 1 bit của 1 chân cụ thể nào
đó trên PortA trở thành Output, sau đó ta
chuyển đến Bank0 và gởi mức 1 tới chân
đó.
Những thanh ghi thông thường nhất trên
Bank1 mà chúng ta sẽ sử dụng là các
thanh ghi STATUS, TRISA and TRISB.
Đầu tiên chúng ta hãy quay vào Bank1,
thanh ghi TRISA cho phép ta chọn chân
nào đó trên PortA làm ngõ Output hay
Input, thanh ghi TRISB cho phép ta chọn
chân nào đó trên PortB làm ngõ Output
hay Input, thanh ghi STATUS cho phép
chọn sử dụng Bank0 hay Bank1.


PORTA và PORTB:
Để làm cho 1 trong những chân Output lên mức cao ta gởi 1 đến bit tương ứng trên
thanh ghi PORTA hoặc PORTB, giống như cách làm trên thanh ghi TRISA và TRISB, có
thể kiểm tra lại trên từng chân của Port.

Thanh ghi W:
Thanh ghi W là là thanh ghi mụch đích chung mà có thể đặt lên nó bất kỳ giá trị nào ta
muốn, khi gán cho thanh ghi W một giá trị nào đó, ta có thể cộng nó với 1 giá trị khác
hoặc có thể copy nó (Mov). Nếu bạn gán 1 giá trị nào đó lên thanh ghi W thì nội dung
trước đó của nó sẽ bị ghi đè lên.
Xem ví dụ sử dụng PortA:
Đầu tiên chúng ta cần chọn Bank0 hoặc Bank1 bằng cách set trên thanh ghi STATUS,
địa chỉ của STATUS là 03H và hãy set bit5 của nó lên 1 theo cách sau:

BSF 03h,5

BSF có nghĩa là Bit Set F, từ F nghĩa là chúng ta sẽ sử dụng một vị trí nào đó trong
memory hoặc trong thanh ghi, 2 con số “03H” sau câu lệnh BSF nghĩa là địa chỉ của
thanh ghi STATUS, con số “5” tức là bit5 của nó, như vậy ý nghĩa của câu lệnh trên là
set bit5 của STATUS lên 1.
Bây giờ chúng ta thao tác trong Bank1.

MOVLW b'00110'

Ta đã đặt giá trị binary 00110 vào trong thanh ghi mụch đích chung W, chữ b có nghĩa
là binary, dĩ nhiên ta cũng có thể viết lại trong dạng số hex, nó như sau:

MOVLW 06h

MOVLW có nghĩa là là ‘Move Literal Value Into W’ tạm dịch là di chuyển giá trị của

BCF 03h,5 ; Quay trở về Bank 0

Hãy đọc kỹ đoạn code trên cho đến khi nào bạn hiểu nó đang làm cái gì.

Ghi lên Port:
Trong phần trên chúng ta đã nói đến làm thế nào để thiết lập các chân của Port trở
thành Input hay Output, trong phần này ta sẽ nói tiếp làm sao có thể gởi data tới Port và
trong phần kế tiếp chúng ta sẽ kết thúc với một đoạn code làm cho đèn Led chớp tắt với
cả sơ đồ mạch để có thể hiểu rõ con Pic làm việc chính xác đến mức độ nào, đừng có
thử compile và nạp đoạn code vào con Pic của bạn vì nó chỉ là ví dụ mà thôi.
Đầu tiên hãy setup bit2 của Port A thành Output.

Bsf 03h,5 ; Vào Bank 1
Movlw 00h ; Đặt giá trị 00000 vào trong W
Movwf 85h ; Copy 00000 vào trong TRISA, tất
; cả các chân bây giờ sẽ trở ;thànhOutput
bcf 03h,5 ; Quay trở về Bank0

Đoạn code trên là những gì đã nói trong phần trước, chỉ khác là bây giờ ta set tất cả các
chân của PortA trở thành Output bằng cách gởi giá trị 0 đến thanh ghi w (thanh ghi W là
loại thanh ghi có 3 trạng thái tri-state register).
Bây giờ những gì mà ta muốn con Pic phải làm là bật tất cả Led lên, để làm điều này ta
phải gởi mức 1 đến các chân Led, hãy xem làm như thế nào đây:

movlw 02h ; Ghi 02h vào thanh ghi W. nó là 00010 nếu
; viết theo dạng binary, như vậy nó đặt 0 vào
; bit 2 (chân 18) trong khi giữ các chân khác ở ;
;mức 0.
movwf 05h ;Bây giờ copy nội dung của W (02H) vào
;PortA (địa chỉ là 05H).

Bsf 03h,5
Movlw 00h
Movwf 85h
bcf 03h,5
Start movlw 02h
Movwf 05h
Movlw 00h
Movwf 05h
Goto Start

Chúng ta chỉ nhìn thấy toàn những con số, bạn muốn hiểu được nó thì phải nhớ hết tất
cả những địa chỉ của các thanh ghi, các Port …. Nhưng ngay cả khi bạn nhớ được tất
cả thì một đoạn code ngắn nhất như trên cũng có thể làm bạn bối rối, để giải quyết vấn
đề này hãy gán cho các con số địa chỉ bằng 1 cái tên bằng lệnh EQU.
EQU đơn giản là thay một cái gì đó bằng một cái gì đó !, nó không phải là câu lệnh của
con PIC mà nó là câu lệnh của assembler, với lệnh EQU bạn có thể gán bất kỳ địa chỉ
thanh ghi nào bằng 1 cái tên gợi nhớ hoặc gán một cái tên cho một hằng số trong đoạn
chương trình. Hãy thử gán vài hằng số bằng những cái tên bạn sẽ thấy nó dể đọc đến
như thế nào.

STATUS equ 03h ; this assigns the word STATUS to the value of 03h,
; which is the address of the STATUS register.
TRISA equ 85h ; This assigns the word TRISA to the value of 85h,
; which is the address of the Tri-State register for
; PortA
PORTA equ 05h ;This assigns the word PORTA to 05h which is the
; address of Port A.

Bây giờ hãy thiếp lập các giá trị hằng số và đặt chúng vào chương trình, các giá trị hằng
số phải được định nghĩa trước khi đặt vào chương trình và hãy nhớ phải luôn đặt chúng

trị zero báo cho biết dừng chương trình delay và sẽ tiếp tục thực thi lại nếu ta muốn.
Đầu tiên chúng ta phải định nghĩa một hằng số dùng trong bộ đếm, tạm thời chúng ta
gọi là hằng số COUNT, kế đến chúng ta phải xác định bộ đếm sẽ thực hiện đếm bao
nhiêu, số lớn nhất mà ta có thể dùng cho bộ đếm là 255 hoặc số hex là FFh.
Lệnh EQU gán 1 giá trị cho 1 thanh ghi, điều này có nghĩa là bất kỳ con số nào mà ta
gán cho COUNT thì COUNT sẽ có giá trị bằng với nội dung của địa chỉ đó. Nếu thử gán
giá trị FFh cho COUNT ta sẽ nhận được thông báo lỗi khi compile chương trình bởi vì
địa chỉ FFH đã được dùng cho mụch đích khác và chúng ta không thể truy cập tới nó,
như vậy chúng ta phải gán một con số như thế nào cho hợp lệ ?, bạn đừng lo lắng, sẽ
có cách giải quyết.
Nếu chúng ta gán COUNT cho 1 địa chỉ nào đó, ví dụ 08h, nó sẽ trỏ tới vị trí thanh ghi
mụch đích chung, nhưng mà giá trị mặc nhiên sau khi mở nguồn của những vị trí không
dùng đến là FFh vì vậy nếu COUNT trỏ tới 08h thì nó sẽ có giá trị FFh.
Bây giờ tôi lại đang nghe bạn “khóc” rằng làm sao mà gán COUNT bằng một số nào đó
có giá trị trùng với 1 trong các địa chỉ của các thanh ghi đã sử dụng?, không sao, nếu
vậy thì điều mà chúng ta phải làm là MOV giá trị của bạn tới vị trí này, giả sử nếu bạn
muốn COUNT có giá trị là 85h, chúng ta không thể làm:

COUNT EQU 85h

Bởi vì 85h là vị trí của thanh ghi xuất (out) 3 trạng thái (Tri-State register) của PORTA.
Cái mà chúng ta phải làm là:

Movlw 85h ; Đầu tiên đặt giá trị 85h vào thanh ghi W.
Movwf 08h ; Kế đến copy giá trị tới thanh ghi 08h.

Bây giờ, khi chúng ta nói:

COUNT equ 08h


lại điểm bắt đầu ( là LABEL), nếu COUNT = 0 thì nó sẽ cho chương trình bỏ qua lệnh kế
tiếp và nhảy đến lệnh thứ 2, trong ví dụ này chương trình sẽ nhảy đến nơi có chữ ‘Carry
on here’.
Như bạn đã thấy, chúng ta đã làm cho chương trình lưu lại một thời gian trước khi nó
tiếp tục làm việc gì đó tiếp theo, cái này gọi là vòng trễ (Delay loop), nếu chúng ta muốn
thời gian trễ lớn hơn chúng ta phải làm một vòng trễ kiểu khác, nhưng mà cũng dể dàng
để hiểu ra rằng có nhiều Loop hơn thì thời gian sẽ trễ lâu hơn, chúng ta cần ít nhất là 2
Loop như trên nếu muốn nhìn thấy đèn Led chớp.
Bây giờ hãy đặt chúng vào trong chương trình và kết thúc chương trình, nhớ thêm các
ghi chú.

;*****Set up the Constants****

STATUS equ 03h ;Address of the STATUS register
TRISA equ 85h ;Address of the tristate register for Port A
PORTA equ 05h ;Address of Port A
COUNT1 equ 08h ;First counter for our delay loops
COUNT2 equ 09h ;Second counter for our delay loops

;****Set up the Port****

bsf STATUS,5 ;Switch to Bank 1
movlw 00h ;Set the Port A pins
movwf TRISA ;to Output.
Dson
7
bcf STATUS,5 ;Switch back to Bank 0

;****Turn the LED on****


end ;Needed by some compilers,
;and also just in case we miss
;the goto instruction.

Bạn có thể cpmpile chương trình này và nạp nó vào con PIC, dĩ nhiên là bạn sẽ muốn
thử cho nó hoạt động, ở đây có sẵn sơ đồ mạch cho bạn.
Xin chúc mừng, bạn vừa mới viết xong 1 chương trình cho con PIC và đã làm cho nó
hoạt động theo mong đợi. Cho đến bây giờ bạn đã học được 7 trong số 35 lệnh của con
PIC rồi đấy, nhưng mà như vậy bạn vẫn chưa thể điều khiển được các Port I/O của nó.
Tại sao bạn không thử thay đổi Delay Loop cho nó nhanh hơn để biết giá trị Delay Loop
tối thiểu mà mắt người có thể nhìn thấy đèn Led chớp tắt và thay đổi tốc độ chớp tắt của
Led, ví dụ mỗi lần là 1 giây. Trong trường hợp này bạn cần phải thử thay đổi các giá trị
hằng số COUNT khác nhau của mỗi Delay Loop.
Trong phần tiếp theo chúng ta sẽ bàn đến cái gì gọi là thủ tục con (subroutine) để giúp
chúng ta tiếp tục viết các chương trình nhỏ và thông thường nhất.


Thủ tục con (subroutine):
Dson
8
Một thủ tục con là một phần của một đoạn code hay một phần của một chương trình mà
bạn có thể gọi nó thực thi bất kỳ lúc nào cần thiết. Một thủ tục con được sử dụng khi mà
bạn muốn thực thi một chức năng nào đó nhiều hơn 1 lần, tức là làm đi làm lại chức
năng đó, ví dụ như Delay Loop. Cái thuận tiện của một thủ tục con là bạn có thể thay đổi
giá trị bên trong nó sau mỗi lần thực thi, ví dụ bạn có thể thay đổi 10 lần gía trị của nó
nếu cần thiết, nhưng quan trọng nhất của một thủ tục con là bạn có thể tiết kiệm bộ nhớ
chương trình chiếm đóng trong con Pic. Hãy xem một subroutine sau:


;*****Set up the Constants****

STATUS equ 03h ;Address of the STATUS register
TRISA equ 85h ;Address of the tristate register for Port A
PORTA equ 05h ;Address of Port A
COUNT1 equ 08h ;First counter for our delay loops
COUNT2 equ 09h ;Second counter for our delay loops ;****Set up the Port****
Dson
9
bsf STATUS,5 ;Switch to Bank 1
movlw 00h ;Set the Port A pins
movwf TRISA ;to Output.
Bcf STATUS,5 ;Switch back to Bank 0

;****Turn the LED on****
Start movlw 02h ;Turn the LED on by first putting it
movwf PORTA ;into the w register and then on the Port

;****Add a delay
call Delay
;****Delay finished, now turn the LED off****

movlw 00h ;Turn the LED off by first putting it
movwf PORTA ;into the w register and then on the Port

;****Add another delay****


Đọc Port (Reading from the I/O Ports):
Cho đến bây giờ bạn đã có thể ghi lên Port để làm cho Led chớp tắt, còn tiếp theo
chúng ta sẽ tìm cách đọc lại nội dung trên chân I/O của Port. Trước tiên cần kết nối các
chân Port tới mạch bên ngoài và theo dõi hoạt động tại đây.
Dson
10
Nếu bạn còn nhớ những thứ đã nói đến trong các phần trước, để setup I/O Port chúng
ta phải chuyển từ Bank0 sang Bank1, hãy làm cái này trước:

STATUS equ 03h ;Address of the STATUS register
TRISA equ 85h ;Address of the tristate register for Port A
PORTA equ 05h ;Address of Port A
Bsf STATUS,5 ;Switch to Bank 1

Để gán cho Port trở thành Output, chúng gởi 0 vào thanh ghi TrisA và để nó trở thành
Input ta phải gởi 1 đến thanh ghi TrisA, quá đơn giản !.

Movlw 01h ;Set the Port A pins
Movwf TRISA ;to Input.
Bcf STATUS,5 ;Switch back to Bank 0

Bây giờ chúng ta đặt bit0 của PortA trở thành Input, cái mà ta phải làm bây giờ là kiểm
tra lại xem chân này đang ở mức cao hay thấp (mức1 hay mức 0), để làm được điều
này ta sử dụng lệnh BTFSC và lệnh BTFSS.
Lệnh BTFSC có nghĩa là làm động tác thử xem 1 bit được chỉ định trên thanh ghi có = 0
hay không, nếu là 0 thì bỏ qua lệnh kế tiếp.
Lệnh BTFSS thì ngược lại, nó có nghĩa là làm động tác thử xem 1 bit được chỉ định trên
thanh ghi có = 1 hay không, nếu là 1 thì bỏ qua lệnh kế tiếp.
Chúng ta sẽ sử dụng lệnh nào?, cái này còn tuỳ thuộc vào bạn mong đợi chương trình

Bcf STATUS,5 ;Switch back to Bank 0
;****Turn the LED on****

Start
movlw 02h ;Turn the LED on by first putting it
Movwf PORTA ;into the w register and then on the Port

;****Check if the switch is closed
BTFSC PORTA,0 ;Get the value from PORT A
;BIT 0. If it is a zero
call Delay ;a zero, carry on as normal.If is is a 1,
;then add an extra delay routine
;****Add a delay
call Delay
;****Delay finished, now turn the LED off****
movlw 00h ;Turn the LED off by first putting it
movwf PORTA ;into the w register and then on the Port
;****Check if the switch is still closed
BTFSC PORTA,0 ;Get the value from PORT ABIT 0. If it is a zero,
Call Delay ;carry on as normal.If is a 1, then add anextra delay
;routine
;****Add another delay****
call Delay
;****Now go back to the start of the program
goto Start ;go back to Start and turn LED on again
;****Here is our Subroutine Delay
Loop1
Decfsz COUNT1,1 ;This second loop keeps the LED
Goto Loop1 ;turned off long enough for us to
decfsz COUNT2,1 ;see it turned off

Đầu tiên ta nạp vào thanh ghiW giá trị 02h, sau đó copy nó sang thanh ghi PortA để bật
Led on. Để tắt nó, ta Nạp gía trị 00h vào thanh ghi W sau đó copy nó tới thanh ghi
PortA. Ở giữa chương trình ta phải gọi subroutine để cho đèn chớp tắt, chúng ta phải
viết 2 lệnh MOV cho Led Off và 2 lệnh MOV cho Led on, 2 lệnh MOV sẽ thực hiện lần
lượt ghi data vào thanh ghi W rồi chuyển vào PORTA. Sau đó ta gọi 2 lần Delay
subroutine, 1 lần Delay cho Led on và 1 lần cho Led Off.
Có cách nào khác đơn giản hơn không ?, có đấy, đó là sử dụng lệnh XORF.
Lệnh XORF thực hiện hàm XOR cho data chứa trong thanh ghi, chắc là không cần phải
giải thích hàm XOR cho bạn phải không ?.
Như vậy để bật Led On/Off chúng ta chỉ cần 2 dòng Lệnh.

MOVLW 02h
XORWF PORTA,1

Đầu tiên nạp vào W giá trị 02h sau đó thực hiện lệnh XORF cho data trên PortA với giá
trị 1, nếu hiện tại PortA có giá trị 1 thì nó sẽ thay đổi thành 0 còn nếu PortA đang là 0
sau khi lệnh XORF thực hiện nó sẽ trở thành 1.
Hãy xem mô tã lại những gì mà chúng ta đã nói:

PORTA
00010
xorwf 00000
xorwf 00010
xorwf 00000
xorwf 00010

Thật ra chúng ta không cần phải nạp mỗi lần cùng một giá trị vào trong thanh ghi W bởi
vì có thể làm điều này ngay lúc bắt đầu chương trình, chỉ cần quay trở về lệnh lật ngược
PortA lại mà thôi. Ngoài ra chúng ta cũng không cần phải gán một giá trị cho thanh ghi
PortA, tại sao vậy?, bởi vì khi mới cấp nguồn cho con Pic thì PortA mặc nhiên đã = 1 rồi

decfsz COUNT1,1 ;This second loop keeps the LED
Goto Loop1 ;turned off long enough for us to
decfsz COUNT2,1 ;see it turned off
goto Loop1 ;
return
;****End of the program****
end ;Needed by some compilers, and also
;just in case we miss the goto instruction.

;*******Flashing LED With Switch:
;*******Set up the Constants****
STATUS equ 03h ;Address of the STATUS register
TRISA equ 85h ;Address of the tristate register for Port A
PORTA equ 05h ;Address of Port A
COUNT1 equ 08h ;First counter for our delay loops
COUNT2 equ 09h ;Second counter for our delay loops
;****Set up the Port****
bsf STATUS,5 ;Switch to Bank 1
movlw 01h ;Set the Port A pins:
movwf TRISA ;bit 1to Output, bit 0 to Input.
Bcf STATUS,5 ;Switch back to Bank 0
movlw 02h ; Set up our w register with 02h
;****Turn the LED on and off****
Start
xorwf PORTA,1 ;Toggle the LED
;****Check if the switch is closed
BTFSC PORTA,0 ;Get the value from PORT A BIT 0.If it is a
;zero
call Delay ;carry on as normal. If is a 1, then add an
;extra delay routine

Program Change Size (Bytes)

Flashing LED Original 120
Flashing LED Subroutine Added 103
Flashing LED XOR Function Used 91
LED With Switch Original 132
LED With Switch XOR Function Used 124.

Chúng ta không chỉ học vài lệnh mới mà còn học cách làm sao giảm kích thước của
chương trình.

Toán hạng Logic và Số học:
Trong phần trên chúng ta được giới thiệu lệnh XORF và cách sử dụng nó, trong phần
này sẽ nói tiếp các toán hạng và lệnh Logic mà con Pic có hỗ trợ.
Bây giờ ta sẽ nói làm sao thao tác trên các bit riêng rẽ, thực hiện vài thuật toán thông
thường trên dữ liệu. Sẽ không có ví dụ nữa nhưng mà sẽ giải thích cặn kẽ làm thế nào
dùng các toán hạng trong các đoạn code nhỏ.

Lệnh ANDLW và ANDWF:
Con Pic cho ta 2 món được chế biến từ hàm AND, đó là lệnh ANDLW và ANDWF.
Lệnh ANDLW cho phép ta AND nội dung trong thanh ghi W với một con số xác định, cú
pháp là:
ANDLW <number>
<number> là cái mà ta sẽ AND với nội dung trong thanh ghi W, kết quả AND sẽ lưu
trong thanh ghi W.
Lệnh ANDWF cho phép ta AND thanh ghi W với một thanh ghi khác, ví dụ như với
PortA, cú pháp là:
ANDWF <register>,d



Nhờ tải bản gốc

Tài liệu, ebook tham khảo khác

Music ♫

Copyright: Tài liệu đại học © DMCA.com Protection Status