1. Trang chủ
  2. » Kỹ Thuật - Công Nghệ

Tổng quan về vi điều khiển PIC.PDF

37 2,1K 22
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Tổng Quan Về Vi Điều Khiển PIC
Thể loại tài liệu
Định dạng
Số trang 37
Dung lượng 514,76 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

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

Trang 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

STATUS:

Để thay đổi từ Bank0 sang Bank1 ta sử

dụng thanh ghi trạng thái STATUS, set bit5

của thanh ghi trạng thái lên1 để chọn

Bank1 hoặc xoá bit5 về 0 để chọn Bank0,

thanh ghi STATUS có địa chỉ 03H

TRISA và TRISB:

2 thanh ghi TRISA and TRISB đặt tại địa

chỉ 85H và 86H, để lập trình cho các chân

trên 2 thanh ghi này thông thường người ta

gởi mức 0 hay 1 đến các bit tương ứng

trên thanh ghi, có thể làm điều này trong cả

2 dạng hoặc là bằng số binary (bin) hay

hex Dùng kiểu binary thì rõ ràng hơn là

kiểu hex nhưng mà trông lượm thượm hơn !

Trên PortA ta có 5 chân tương ứng 5 bit, nếu muốn đặt 1 trong 5 chân này thành Output

ta phải gởi 1 đến bit tương ứng với nó, những bít này có tên bit đúng chính xác với tên của nó, nói cách khác bit0 là RA0, bit1 là RA1, bit2 là RA2… Hãy xem ví dụ:

Nếu ta muốn set RA0, RA3 và RA4 thành Output và RA1, RA2 thành Inputs, ta phải gởi 00110 (=06h), nên nhớ bit thấp nằm bên phải, xem hình:

Port A Pin RA4 RA3 RA2 RA1 RA0

Bit Number 4 3 2 1 0

Binary 0 0 1 1 0

Trang 2

Tương tự chúng ta cũng làm như vậy cho TRISB

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

Literal vào thanh ghi W, để rõ ràng hơn ta có thể nói là “ đặt giá trị trực tiếp sau đây (06H) vào trong thanh ghi W “

Bây giờ ta tiếp tục đặt giá trị đó vào trong thanh ghi TRISA để thiết lập trạng thái cho Port:

MOVWF 85h Lệnh này có nghĩa là “MOV nội dung của W vào (thanh ghi có) địa chỉ 85h”, trong trường hợp này con trỏ địa chỉ sẽ trỏ tới TRISA, thanh ghi TRISA bây giờ chứa giá trị

00110, xem lại mô tả các câu lệnh bằng hình sau:

Port A Pin RA4 RA3 RA2 RA1 RA0

Trang 3

Lệnh BCF thì đối nghịch với BSF, nó có nghĩa là “ Bit Clear F” tạm dịch là xoá bit nào

đó trong vùng memory hay trong thanh ghi nào đó, trong trường hợp này là thanh ghi STATUS (vì địa chỉ của nó là 03H) và lệnh này xoá bit5 của STATUS

Bên dưới là đoạn code:

BSF 03h,5 ; vào Bank 1 MOVLW 06h ; Đặt giá trị 00110 vào W MOVWF 85h ; Move 00110 vào trong TRISA 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)

Con Led bây giờ đã bật on, chúng ta thử tắt nó xem:

movlw 00h ; Ghi 00h vào thanh ghi W nó là 00000 nếu

; viết theo dạng binary, như vậy nó đặt 0 vào

; tất cả các chân

movwf 05h ; Bây giờ copy nội dung của W ( 02H) vào

; PortA Bây giờ Led đã bị tắt

Để làm cho led sáng, tắt liên tục chúng ta phải làm cho chương trình quay trở lại điểm bắt đầu bằng cách đặt nhãn cho chương trình và nói cho nó biết đó là điểm bắt đầu mà

nó phải quay lại thực hiện lần nữa Rất đơn giản, hãy đặt 1 cái nhãn có tên là START ngay tại điểm bắt đầu của đoạn code

Trang 4

Start

movlw 02h ; Write 02h to the W register In binary

; this is 00010, which puts a ‘1’ on pin2

; while keeping the other pins to ‘0’

movwf 05h ; Now move the contents of W (02h)

; onto the PortA, whose address is 05h movlw 00h ; Write 00h to the W register This puts a

; 0’ on all pins

movwf 05h ; Now move the contents of W (0h) onto

; the Port A, whose address is 05h goto Start ; Goto where we say Start

Bây giờ hãy xem lại đoạn code:

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 vào vị trí bắt đầu của chương trình

Bây giờ hãy xoá hết các ghi chú sau các câu lệnh, bạn thử nhìn xem có dể dàng hiểu được đoạn code trên khi không có các dòng ghi chú:

STATUS equ 03h

TRISA equ 85h

PORTA equ 05h

Trang 5

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

Thì COUNT sẽ tương đương với giá trị 85h Thật là quỷ quyệt, có phải không ?!

Trang 6

Tiếp tục, đầu tiên ta định nghĩa cho một hằng số

COUNT equ 08h

kế đến giảm COUNT xuống 1 cho đến khi nó = 0, chỉ cần 1 lệnh đơn để làm việc này với

sự hỗ trợ của lệnh GOTO và một cái nhãn, lệnh đơn được dùng là:

DECFSZ COUNT,1

Lệnh DECFSZ sẽ giảm thanh ghi ( trong trường hợp này là COUNT) xuống một đơn vị

được điền sau dấu phẩy (,), trong ví dụ này đơn vị là 1 Nếu nó giảm tới zero chương trình sẽ bỏ qua lệnh kế tiếp để nhảy đến thực thi lệnh thứ 2

Mất nhiều lời để giải thích cho 1 lệnh đơn có phải không?, hãy xem cái gì xảy ra khi ta đặt nó vào chương trình

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

Trang 7

bcf STATUS,5 ;Switch back to Bank 0

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

Start movlw 02h ;Turn the LED on by first putting

movwf PORTA ;it into the w register and then

;on the Port

;****Start of the delay loop 1****

Loop1 decfsz COUNT1,1 ;Subtract 1 from 255

Goto Loop1 ;If COUNT is zero, carry on

Decfsz COUNT2,1 ;Subtract 1 from 255 Goto Loop1 ;Go back to the start of our loop

;This delay counts down from

;255 to zero, 255 times

;****Delay finished, now turn the LED off****

movlw 00h ;Turn the LED off by first putting

movwf PORTA ; it into the w register and then onthe Port

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

Loop2 decfsz COUNT1,1 ;This second loop keeps the

Goto Loop2 ;LED turned off long enough for decfsz COUNT2,1 ;us to see it turned off

goto Loop2 ;

;****Now go back to the start of the program

goto Start ;go back to Start and turn LED

;on again

;****End of the program****

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):

Trang 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:

ROUTINE

COUNT equ 255 LABEL decfsz COUNT,1

Goto LABEL RETURN

Đầu tiên chúng ta phải đặt cho subroutine một cái tên, tôi chọn tên ROUTINE, sau đó viết đoạn chương trình mà tôi muốn nó thực hiện, tôi viết lại chương trình Led chớp tắt như phần trên, cuối cùng tôi kết thúc subroutine bằng lệnh RETURN

Bạn có thể đặt subroutine này bất cứ nơi nào trong chương trình chính (MAIN) và khi muốn nó thực thi bạn chỉ cần gọi nó bằng lệnh CALL theo sau là tên của subroutine Subroutine sẽ thực thi đoạn code bên trong nó cho đến khi nó gặp lệnh RETURN thì dừng lại, chương trình sẽ tự động quay về chương trình chính đúng tại nơi mà nó gọi subroutine và thực thi lệnh kế tiếp sau lệnh CALL

Bạn có thể CALL nhiều lần để thực thi cùng một subroutine nếu bạn muốn, đó là lý do tại sao người ta sử dụng subroutine để giảm độ dài của chương trình

Tuy nhiên có hai thứ mà bạn phải nghĩ đến, thứ nhất là bất kỳ hằng số nào cũng phải được khai báo trước khi bạn sử dụng nó nhưng mà trong trường hợp subroutine bạn có thể khai báo ngay trong bản thân nó hoặc ngay tại đầu chương trình chính như thông thường, tuy nhiên tôi lại khuyên bạn nên khai báo mọi thứ tại đầu chương trình chính vì như bạn đã biết, để mọi thứ ở cùng một nơi thì dể tìm kiến hơn, có phải không? Vấn đề thứ hai rất quan trọng là bạn phải bảo đảm đặt subroutine sau lệnh RETURN của chương trình chính trừ phi trong chương trình chính bạn dùng lệnh GOTO để nhảy qua subroutine, nếu không nó sẽ thực thi bất kỳ lệnh nào mà nó bắt gặp bất kể bạn có muốn hay không bởi vì con Pic không phân biệt được đâu là chương trình chính đâu là subroutine

Hãy xem lại đoạn chương trình chớp Led nhưng mà lần này ta sử dụng subroutine cho Delay Loop bạn sẽ thấy chương trình đơn giản đến mức nào và xem subroutine làm việc ra sao

;*****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****

Trang 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****

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

Goto Loop1 ;

Return

;****End of the program****

end ;Needed by some compilers, and

;also

;just in case we miss the goto instruction

Rõ ràng kích thước chương trình đã giảm đi nhiều khi sử dụng subroutine cho Delay Loop, mỗi lần ta muốn thực hiện Delay để làm cho Led ON hoặc cho Led Off, ta chỉ cần gọi subroutine Delay Tại điểm kết thúc subroutine chương trình sẽ quay trở về ngay sau dòng lệnh CALL

Nếu không sử dụng subroutine chương trình chớp Led trên có thể cần đến 120byte bộ nhớ chương trình, nhưng khi sử dụng subroutine nó chỉ còn cần 103byte, thật ra số byte chênh lệch như vậy cũng không phải là vấn đề quan trọng lắm, nhưng mà bạn chỉ có 1024byte để chứa chương trình trong con Pic thì việc tiết kiệm được số byte như vậy quả là không uổng công nặn óc để làm subroutine, có phải không

Trong phần kế tiếp chúng ta sẽ tìm hiểu làm sao mà đọc được Port

Đọ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

Trang 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 đọc được cái gì trên Port

Ví dụ: Nếu bạn đang mong đợi ngõ Input là 1 thì hãy dùng lệnh BTFSS, hãy xem cái này:

Chương trình sẽ chỉ nhảy đến dòng “Carry on here” nếu bit0 của PortA = 1

Bây giờ bạn hãy viết lại chương trình đèn Led chớp ở 1 tốc độ cố định, nhưng mà nếu đóng 1 cái Switch nào đó thì đèn Led sẽ chớp chậm hơn ½ Bạn hoàn toàn có thể tự làm được mà, đừng có nhìn vào đoạn Code bên dưới xem sao

Chúng ta sử dụng cùng một mạch giống như phần trên nhưng mà thêm một cái Switch

có một đầu nối vào chân RA0 của con Pic còn đầu kia mắc lên nguồn

;*****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

Trang 11

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

goto Loop1 ;

return

;****End of the program****

end ;Needed by some compilers, and also

;just in case we miss the goto instruction

Đầu tiên chương trình bật Led on, kế đến kiểm tra xem cái Switch có đóng không, nếu

nó đóng chương trình sẽ gọi Delay subroutine, thời gian Delay giống y như trước nhưng

mà gọi subroutine thực thi 2 lần, nó sẽ làm tương tự như vậy cho trường hợp Led Off Bây giờ bạn hãy compile chương trình và cho con Pic chạy thử, nhưng mà tôi có một lời cảnh cáo bạn rằng, toàn bộ những thứ mà bạn làm sẽ không gây ấn tượng cho bất kỳ ai không thích thú với lập trình cho vi xử lý, vì vậy cũng đừng có thất vọng nếu mà bạn đem khoe với những người thân trong gia đình rồi chỉ cho họ làm sao cho con Led chớp châm đi ….họ sẽ chỉ giả vờ ngạc nhiên thích thú mà thôi !, đó là những kinh nghiệm xương máu của tôi !

Nếu bạn theo sát từ đầu đến giờ thì bạn đã biết tổng cộng 10 trong số 35 lệnh của con Pic 16F84 rồi đấy và tất cả những thứ mà bạn biết chỉ đơn giản là làm cho con Led chớp tắt !, thật phí phạm thời gian có phải không ?, còn tôi thì nghĩ thật là phí phạm bộ nhớ của con Pic nếu phải viết chương trình dài như vậy chỉ để chớp tắt, nhan chậm đèn Led !, phải có cách gì đó làm cho hay hơn

Trang 12

Hãy xem ví dụ bên dưới, nó mới thật sự là một chương trình làm đèn Led chớp tắt, nhanh chậm

movlw 02h

movwf PORTA

movlw 00h

movlw PORTA

Đầ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 chúng ta chỉ cần lật qua lật lại cho PortA =0 rồi =1 mà thôi, ngay cả khi ban đầu PortA =

0 thì chúng ta cũng sẽ vẫn làm như vậy

Hãy xem 2 đoạn code mới, đoạn code thứ nhất viết theo kiểu như ban đầu, đoạn code thứ hai là viết lại nhưng dùng lệnh XORF

;*****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

Trang 13

movlw 00h ;Set the Port A pins

movwf TRISA ;to Output

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

;****Add a 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

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

;****Add a delay

call Delay

;****Check if the switch is still 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

Trang 14

;extra 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

goto Loop1 ;

return

;****End of the program****

end ;Needed by some compilers, and also

;just in case we miss the goto instruction

Chỉ cần dùng các lệnh đơn giản chúng ta có thể giảm kích thước của chương trình Thực sự ta đã giảm được bao nhiêu byte khi viết lại các chương trình bằng các lệnh đơn giản, hãy xem thống kê:

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

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à:

Trang 15

<register> là thanh ghi mà ta chỉ định, ví dụ PortA, d nói cho Pic biết nơi lưu kết quả Nếu d=0 thì kết quả lưu vào thanh ghi W và d=1 thì kết quả lưu vào thanh ghi đứng trước d

Hai đoạn code bên dưới sẽ mô tã 1 ví dụ cho mỗi hàm AND Đầu tiên kiểm tra trạng thái PortA là nơi mà ta cần biết ngõ vào có = 1100 hay không và đặt kết quả vào trong thanh ghi W

Lệnh IOR đơn giản như là một hàm OR, khi một trong hai bit =1 hoặc cả hai đều = 1 mà

OR với nhau sẽ cho kết quả = 1, ngược lại sẽ =0

Lệnh SUBLW and SUBWF:

Hàm SUB, tôi dám đánh cược bạn không thể đoán được hàm này làm cái gì ?!, thôi được rồi, xem như bạn đã đoán ra, hàm SUB này trừ 1bit với 1bit khác

Một lần nữa con Pic lại cho ta 2 món được chế biến từ hàm SUB, đó là SUBLW and SUBWF, cú pháp thì giống y như là những món của hàm ADD nhưng mà thay vì cộng thì nó trừ

Lệnh INCF và INCFSZ:

Nếu chúng ta muốn cộng 1 với một số trong Pic, đơn giản ta sử dụng hàm ADD và số 1, cái bất tiện là đầu tiên ta phải bỏ con số 1 vào trong thanh ghi W, sau đó dùng lệnh ADDLW 1 để tăng nó lên 1 Nếu ta chỉ muốn cộng số 1 vào một thanh ghi bất kỳ thì còn tồi tệ hơn, đầu tiên phải đặt số 1 vào thanh ghi W, sau đó dùng lệnh ADDWF <register>,1

Ví dụ ta muốn cộng số 1 với nội dung của địa chỉ 0Ch, ta phải viết đoạn code sau:

Movlw 01

addwf 0c,1

Có một cách tốt hơn cách này đó là dùng lệnh INCF trong con Pic, cú pháp là:

INCF <register>,d

Trang 16

Với <register> là thanh ghi, hoặc địa chỉ mà ta chỉ định, còn d thì nói cho con Pic biết nơi đặt kết quả Nếu d=0 thì kết quả lưu trong thanh ghi W, nếu d=1 kết quả sẽ được lưu trong thanh ghi chỉ định nằm trước nó (tức là <register>)

Bằng cách này ta có thể tiết kiệm ½ bộ nhớ của Pic Nếu ta muốn kết quả lưu trong W thì sử dụng ví dụ trên sau đó thêm một lệnh khác để MOV nội dung trong địa chỉ 0Ch trở vào trong thanh ghi W sau đó đặt vào thanh ghi 0Ch bất cứ cái gì

Có một lệnh increment khác, đó là INCFSZ, lệnh này sẽ tăng thanh ghi mà ta chỉ định lên 1, nhưng nếu thanh ghi này =0 sau khi thực thi lệnh ( xảy ra khi cộng 1 vào FFh) thì con Pic sẽ bỏ qua lệnh kế tiếp, đoạn code bên dưới sẽ mô tả lệnh này:

=127 (FFh) Lần này khi tăng lên 1, nội dung của 0Ch sẽ =0

Lệnh INCFSZ sẽ nói cho con Pic bíêt hãy bỏ qua lệnh kế tiếp, trong trường hợp ví dụ trên nó bỏ qua lệnh GOTO Loop để thực thi tiếp đoạn code còn lại

Toán hạng trên Bit:

Các toán hạng dùng cho Bit cho phép chúng ta thao tác trên các bit đơn lẽ trong byte,

nó cho phép MOV, SET và CLEAR bit trong thanh ghi hoặc những địa chỉ được chỉ định, phần cuối của tutorial này ta sẽ trình bày một chương trình làm cho con Led sáng chạy theo nhiều cách khác nhau

Lệnh BCF:

Trong các phần trước chúng ta đã xem một số lệnh thực thi trên bit, trong phần này ta

sẽ xem một số lệnh còn lại tác động lên bit như thế nào

BCF là lệnh xoá 1 bit được chỉ định trong thanh ghi, cú pháp là:

Trang 17

BCF <register>,<bit>

Chúng ta đã sử dụng lệnh này trong phần trước để thay đổi từ Bank1 sang Bank0 bằng cách xoá bit trong thanh ghi STATUS, chúng ta cũng có thể Clear 1 bit về 0 tại bất kỳ bit nào trong bất kỳ thanh ghi nào, ví dụ, nếu bạn muốn Clear bit thứ 3 trong thanh ghi 0Ch

có nội dung = 11001101, bạn có thể làm như sau:

BCF 0C,03

Lệnh BSF:

Lệnh BSF ngược lại, nó có thể Set 1 bit lên 1 tại bất kỳ bit nào trong bất kỳ thanh ghi nào, ta đã dùng cái này trong phần trước để nhảy từ Bank0 sang Bank1, cú pháp là: BSF <register>,<bit>

Cách dùng BSF giống y như cách dùng BCF

Lệnh BTFSC:

Chúng ta đã có thể Set bit và Clear bit trong thanh ghi, nhưng mà nếu bạn chỉ muốn thử xem bit nào đó trong thanh ghi là = 1 hay = 0 thì sao, rất đơn giản, hảy dùng lệnh BTFSC, nó được gọi là “Bit Test Register F and Skip If It Is Clear”, tạm dịch là “lệnh thử kiểm tra bit trong thanh ghi và bỏ qua lệnh kế nếu bit = 0”, quá rõ ràng rồi, không cần phải giải thích gì thêm nữa phải không ?!, ta sẽ dùng lệnh này để kiểm tra một cái cờ (flag) nào đó ví dụ như cờ Carry, nó tránh cho ta khỏi phải đọc thanh ghi STATUS để tìm xem trạng thái của từng bit như thế nào Ví dụ, nếu bạn muốn thử bit cờ Carry =1 chưa sau khi bạn cộng 2 byte với nhau, bạn hãy thử làm cái này:

BTFSC 03h,0 Nếu cờ Carry=1 thì chương trình thực thi tiếp lệnh đứng kế tiếp, nếu Carry=0 nó sẽ bỏ qua lệnh kế tiếp, xem đoạn code sau:

Trong đoạn code trên, con Pic sẽ đi ra khỏi Loop nếu bit0 trong thanh ghi STATUS ( hay

cờ Carry) bị xoá về 0, nói cách khác nếu cờ Carry=0 lệnh GOTO sẽ được thực hiện

Trang 18

TIME EQU 9FH ; Variable for the delay loop

PORTB EQU 06H ; Port B address

TRISB EQU 86H ; Port B Tristate address

PORTA EQU 05H ; Port A address

TRISA EQU 85H ; Port A Tristate address

STATUS EQU 03H ; Page select register

COUNT1 EQU 0CH ; Loop register

COUNT2 EQU 0DH ; Loop register

BSF STATUS,5 ; Go to page 1

MOVLW 00H ; and set up

MOVWF TRISB ; both Ports A and B

MOVLW 00H ; to Output,

MOVWF TRISA ; then return to

Ngày đăng: 20/08/2012, 09:41

HÌNH ẢNH LIÊN QUAN

Bảng dữ liệu ( Data Table): - Tổng quan về vi điều khiển PIC.PDF
Bảng d ữ liệu ( Data Table): (Trang 21)
Sơ đồ mạch: - Tổng quan về vi điều khiển PIC.PDF
Sơ đồ m ạch: (Trang 29)

TỪ KHÓA LIÊN QUAN

w