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

Tài liệu ASM - PIC (P2) potx

17 203 0
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

Định dạng
Số trang 17
Dung lượng 216,26 KB

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

Nội dung

Chúng ta có thể gán cho thanh ghi W bất kỳ giá trị nào nhưng phải chắc chắn rằng con số này sau khi cộng với PC trong subroutine bảng tra dữ liệu sẽ tìm ra được một lệnh RETLW, trong ví

Trang 1

Bảng dữ liệu ( Data Table):

Có một điểm rất đặc biệt trong tập lệnh mà nó cho phép bạn truy xuất dữ liệu theo kiểu tra bảng (data table) Một bảng dữ liệu thông thường là một danh sách liệt kê các giá trị của dữ liệu, mỗi giá trị được đọc phụ thuộc vào việc phải thoả mãn vài tiêu thức nào đó

Ví dụ, bạn có một con Pic và bạn muốn đếm số lần ngõ vào Input được nâng lên mức cao trong thời gian 1giây là bao nhiêu sau đó hiễn thị lên Led 7 đoạn Mỗi lần thời gian bắt đầu tính, con Pic sẽ đếm số lần ngõ Input vào được nâng lên mức cao trong thời gian 1 giây, sau 1 giây nó hiễn thị con số nó đếm được tương ứng với số lần ngõ vào Input được nâng lên mức cao Cái này rất tiện dụng bởi vì chúng ta không biết được hiện tại con số đếm đã là bao nhiêu cho đến khi con Pic dừng lại, bằng cách sử dụng bảng tra dữ liệu chúng ta có thể cho phép con Pic quýêt định con số nào nó cần hiễn thị Bây giờ trước khi giải thích bảng tra dữ liệu làm việc ra sao ta sẽ bàn xem con Pic bám theo chổ nào trong chương trình trong lúc chương trình đang chạy Nếu bạn đã từng lập trình trong BASIC thì đở mệt nhọc hơn, còn nếu không bạn cũng đừng lo lắng, bạn sẽ vẫn tìm thấy các khái niệm ở đây

Hãy tưỡng tượng chúng ta có một chương trình BASIC như chương trình bên dưới:

10 LET K=0

11 K=K+1

12 IF K>10 THEN GOTO 20 ELSE GOTO 11

21 END

Chương trình bắt đầu tại dòng số 10, mỗi lần K =0 nó tiến tới dòng 11, sau khi cộng thêm 1 cho K nó di chuyển đến dòng 12 Ở đây chúng ta hỏi K có lớn hơn 10 không ?, nếu đúng nó tiếp tục đi tới dòng 20, nếu sai nó quay trở lại dòng 11, dòng 20 sẽ xuất giá trị của K và dòng 21 sẽ kết thúc chương trình

BASIC sử dụng con số thứ tự dòng để giúp cho lập trình viên bám theo chương trình một khi những cái nhãn nhận dạng không cho phép sử dụng trong BASIC

Con Pic có sử dụng những cái nhãn để nhảy qua lại các vị trí hay không?, chúng ta dùng những cái nhãn nhận dạng vì vậy chúng ta biết những thứ gì, ở đâu và nói cho con Pic biết con đường nó phải đi Cái mà thực sự con Pic đã dùng đó là bộ đếm dòng lệnh bên trong còn gọi là bộ đếm chương trình Program Counter Program Counter viết

Trang 2

tắt là PC dò tìm các vị trí trong bộ nhớ để tìm kiếm vị trí hiện tại của câu lệnh mà chương trình đang thực thi Khi chúng ta nói cho con Pic bíêt phải đi đến cái nhãn nào

đó, nó bíêt vị trí của cái nhãn này trong bộ nhớ và nó gia tăng PC lên cho tới khi nó đọc được vị trí đó Điều này giống y như cái cách mà chúng ta đọc chương trình trong BASIC

Bên dưới là đoạn code và các vị trí bộ nhớ hay nói cách khác chính là nội dung trong

PC, kế bên là các dòng lệnh

04 end

Trong ví dụ trên, ta set PC tới 0000 tại vị trí này ta có lệnh movlw 03 Khi con Pic thực thi lệnh này nó tăng PC lên và vì vậy nó đọc tiếp lệnh kế, ở đây con Pic lại thấy lệnh movwf 0C, nó lại tăng PC lên một lần nữa, lần này nó thấy lệnh decfsc 03, nếu nội dung trong địa chỉ 0C không = 0 con Pic sẽ tăng PC lên 1 và đọc lệnh kế tiếp, lệnh Goto loop nói con Pic hãy quay lại vị trí 0002 Nếu nội dung trong 0C là 0 thì con Pic nói PC phải tăng lên 2 hay nói cách khác là bỏ qua lệnh kế tiếp nó, như vậy nó sẽ đến vị trí 0004, tại đây là điểm kết thúc của chương trình Các vị trí được thiết lập bởi assembler, và chúng

ta không cần lo lắng con Pic đang làm cái gì cho tới khi chúng ta cần kiểm soát nó như trong trường hợp của bảng tra dữ liệu Cách tốt nhất để giải thích bảng dữ liệu làm việc

ra sao là hãy chấm dứt ngay cái ví dụ này và xem cái bên dưới đây !

:

table addwf PC

retlw 01

retlw 02

retlw 03

retlw 04

retlw 05

retlw 06

retlw 07

return

Lệnh đầu tiên gán cái nhãn PC có địa chỉ của Program Counter (02h), sau đó chúng ta đặt giá trị của thanh ghi 03h vào trong thanh ghi W Bây giờ ta làm một lệnh gọi bảng tra

dữ liệu Dòng đầu tiên trong subroutine bảng dữ liệu sẽ công nội dung của thanh ghi W (03h) với PC, điều này làm cho PC tăng lên 3, tương đương với việc PC sẽ đi xuống 3 dòng Khi PC xuống dòng thứ 3 con Pic trông thấy lệnh reltw, lệnh này chuyển giá trị đứng sau nó vào thanh ghi W rồi quay trở về lại subroutine Lệnh RETLW có nghĩa là quay về và trả giá trị phía sau nó về thanh ghi W Lưu ý là có 2 động tác được thực hiện trong lệnh RETLW

Khi ta đang đứng trong một subroutine ta cần có một lệnh quay về để thoát ra khỏi subroutine đó là lệnh RET

Trang 3

Phía sau lệnh RETLW là một con số, con số này là thứ mà ta sẽ đặt vào trong thanh ghi

W, trong trường hợp này nó là số 03

Chúng ta có thể gán cho thanh ghi W bất kỳ giá trị nào nhưng phải chắc chắn rằng con

số này sau khi cộng với PC trong subroutine bảng tra dữ liệu sẽ tìm ra được một lệnh RETLW, trong ví dụ trên, điều này có nghĩa là ta có thể có bất kỳ con số nào từ 1 đến 7, nếu ta đi lọt ra ngoài subroutine thì có thể sẽ làm cho con Pic không thể thực hiện bất kỳ phần nào của chương trình nữa Chính vì điều này mà người ta hay đặt bảng tra dữ liệu

ở cuối của chương trình, như vậy nếu bị lọt ra khỏi subroutine thì sẽ đến điểm kết thúc chương trình (End)

Ngắt (Interrupt):

Chủ đề nói về các Ngắt (Interrupts) hầu như là dài nhất và khó hiểu nhất, không phải dể

để giải thích về ngắt cho người nào đó hiểu, nhưng mà hy vọng sau khi kết thúc phần này chúng ta có thể áp dụng ngắt vào trong chương trình của chúng ta Chúng ta sẽ chia phần này thành 2 phần nhỏ, mụch đích là để cho bạn nghỉ giải lao !

Đầu tiên, Ngắt (interrupt) là cái gì vậy ?, nó thật sự có ý nghĩa giống như tên gọi của nó vậy, một Interrupt là một tác vụ xử lý hay là một tín hiệu xử lý mà nó có thể bắt con Pic dừng lại những gì đang làm để làm một công việc khác Một ví dụ dể hiểu, hãy lấy sinh hoạt hàng ngày của bạn, giả sử bạn đang ngồi ở nhà, rồi bạn đang tán gẫu với ai đó, thình lình chuông điện thoại reo, bạn ngưng cuộc nói chuyện lại, nhặt điện thoại lên và nói chuyện với người gọi đến Khi bạn kết thúc cuộc nói chuyện bằng điện thoại bạn lại quay trở về và tiếp tục tán gẩu với người đã nói chuyện với bạn trước khi điện thoại reo Bây giờ bạn hãy tưởng tượng, chương trình chính là quá trình tán gẫu của bạn với người bạn ngồi ở nhà, điện thoại reo tạo ra một Interrupt và thủ tục (routine) Interrups là cuộc nói chuyện với người ở đầu dây bên kia, khi kết thúc cuộc nói chuyện bằng điện thoại bạn quay về “chương trình chính” để tiếp tục tán gẫu, Ví dụ này giải thích chính xác một Interrups tạo ra một tiến trình xử lý như thế nào Một chương trình chính đang chạy, thực hiện một vài chức năng nào đó trên mạch điện, nhưng khi Interrupt xảy ra chương trình chính sẽ tạm ngưng và ngay lúc đó một thủ tục khác được thực hiện, khi thủ tục này kết thúc con Pic sẽ lại quay về chương trình chính

Con Pic có 4 Interrupt, nó có thể được chia thành 2 nhóm, 2 Interrupts phục vụ cho các thiết bị kết nối ngoại vi và 2 Interrupts cho bên trong nó Trước tiên ta hãy nói về 2 Interrupts bên ngoài, 2 Interrups bên trong Pic sẽ nói đến trong phần Timers và lưu trữ Data

Nếu bạn quan sát trên sơ đồ chân của Pic bạn sẽ thấy chân số 6 có ghi là RB0/INT, RB0 là bit0 của PortB, ký hiệu INT là ký hiệu chức năng Interrupt ngoài Ngoài ra các chân từ 10 đến 13 ( bit 4 tới 7 của PortB) cũng có thể sử dụng cho Interrupt Trước khi

sử dụng Interrupt hay dùng nó như là Port in out thông thường chúng ta cần phải làm 2 việc Đầu tiên ta cần nói cho con Pic biết rằng ta sẽ sử dụng Interrupt, kế đến ta cần xác định chân nào của PortB sẽ dùng như Interrupt

Trong con Pic có 1 thanh ghi gọi là INTCON, địa chỉ là 0Bh, trong thanh ghi này có 8bit

có thể thiết lập chế độ cho phép hay không cho phép Bit7 của INTCON được gọi là GIE

có nghĩa là Global Interrngupt Enable tạm dịch là chân cho phép sử dụng toàn bộ Interrup Nếu set bit này lên 1 con Pic sẽ cho phép sử dụng Interrupt Bit4 của INTCON gọi là INTE có nghĩa là INTerrupt Enable tạm dịch là cho phép Interrupt, set bit này lên

1 sẽ cho phép chân RB0 trở thành chân Interrupt Bit3 còn gọi là bit RBIE nếu được set=1 sẽ báo cho con Pic biết ta sẽ sử dụng từ bit4 cho đến bit7 của PortB Bây giờ thì con Pic đã biết và theo dõi khi nào chân này lên cao hay xuống thấp, nó biết cần phải dừng chương trình chính lại khi nào để quay ra phục vụ thủ tục của Interrupt

Bây giờ chúng ta cần nói cho con Pic biết sẽ khởi động Interrupt bằng cạnh lên (từ 0V lên 5V) hay cạnh xuống ( từ 5V xuống 0V) của tín hiệu vào chân Interrupt Nói cách

Trang 4

khác, ta muốn con Pic phục vụ Interrupt khi tín hiệu vào thay đổi từ thấp lên cao hay từ cao xuống thấp Mặc nhiên sau khi bật nguồn con Pic sẽ thiết lập chế độ Interrupt cạnh lên, có nghĩa là interrup xảy ra khi tín hiệu vào thay đổi từ thấp lên cao (cạnh lên)

Thanh ghi OPTION ở địa chỉ 81h chính là thanh ghi thiết lập chế độ cho Interrupt tích cực ở cạnh lên hay cạnh xuống của tín hiệu vào, bit6 của thanh ghi OPTION được gọi là INTEDG, nếu setbit6=1 sẽ thiết lập interrupt tích cực ở cạnh lên của tín hiệu vào (trạng thái default) , nếu Clear bit6=0 sẽ thiết lập interrupt tích cực ở cạnh xuống của tín hiệu vào

Nếu bạn muốn con Pic thiết lập interrupt xảy ra ở cạnh lên của tín hiệu thì bạn không cần phải làm gì trên bit6 của thanh ghi OPTION

Thật không may mắn, thanh ghi OPTION lại nằm trên Bank1, vì vậy bạn phải làm động tác di chuyển từ Bank0 sang Bank1 sau đó Set bit6 trên thanh ghi OPTION rồi lại quay trở về Bank0 Có một mánh lới để làm tất cả chuyện này trên Bank1 như là thiết lập các chân Port, quay trở vào Bank0 ! Được rồi, cho đến giờ chúng ta đã biết chân nào của con PIC sẽ trở thành Interrupt và tích cực cạnh nào của tín hiệu, cái gì sẽ xảy ra trong chương trình và Interrupt xảy ra khi nào

Có 2 thứ xảy ra, thứ nhất là có 1 cờ ‘flag’ được set để nói cho con Pic biết rằng có 1 Interrupt đã xảy ra, thứ hai bộ đếm chương trình (program counter) trỏ đến một địa chỉ đặc biệt trong con Pic, hãy xem từng vấn đề như thế nào

Cờ Ngắt (Interrupt Flag):

Trong thanh ghi INTCON bit1 chính là cờ báo Interrupt gọi là INTF, khi có Interrupt xảy

ra, cờ này sẽ được set lên 1, trước khi có Interrupt xảy ra nó =0 Trong khi cờ Interrupt được set lên 1 thì con Pic sẽ không thể và không bao giờ đáp ứng bất kỳ một Interrupt nào nữa Cái cờ được set lên 1 và con Pic sẽ thực thi chương trình (routine) của Interrupt, nếu cái cờ vì lý do gì đó không thể set lên 1 và con Pic đang thực thi chương trình Interrupt thì tín hiệu đổ vào liên tục tại chân Interrupt sẽ liên tục gây ra Interrupt trên con Pic làm cho nó phải liên tục quay trở về điểm bắt đầu của chương trình (routine) Interrupt và sẽ không bao giờ nó có thể kết thúc được chương trình Interrupt này

Bây giờ quay lại ví dụ về chuyện tán gẫu và cuộc nói chuyện điện thoại của bạn, nó giống như là bạn vừa nhặt điện thoại lên định nói chuyện thì chuông lại reo lần nữa vì có

ai đó cũng đang muốn nói chuyện với bạn! Tại sao không phải là sau khi kết thúc cuộc chuyện trò với người thứ nhất bạn lại nhặt điện thoại lên một lần nữa để nói chuyện với ngưòi thứ hai, có phải tốt hơn không!, tôi đoán đó là lý do tại sao mà điện thoại không thể reo trong khi bạn đã nhấc ống nghe

Có một trở ngại nhỏ trên cái cờ này, mặc dù con Pic tự động set cờ này lên 1 nhưng nó lại từ chối trách nhiệm Clear cái cờ này về 0 ! vì vậy mà trách nhiệm cao cả này được trao cho người lập trình viên !, nếu không thì sẽ không bao giờ có interrupt xảy ra nữa Cái này thì dể dàng thôi và tôi chắn chắn rằng bạn sẽ làm được

Địa chỉ bộ nhớ:

Memory Location

Lần đầu tiên mở nguồn hoặc khi reset con Pic, Bộ đếm chương trình (Program Counter) trỏ đến địa chỉ 000h, đó chính là điểm bắt đầu của bộ nhớ chương trình Tuy nhiên hki

có Interrupt xảy ra thì PC sẽ trỏ đến địa chỉ 0004h, vì vậy khi viết chương trình mà có s73 dụng Interrupt thì đầu tiên chúng ta phải nói cho con Pic nhảy (jump) đến địa chỉ 0004h và tách riêng chương trình Interrupt ( bắt đầu tại 0004h) với các chương trình khác, điều này thì rất dễ làm có phải không ?

(dầu tiên chúng ta khởi động chương trình bằng lệnh ORG, lệnh này nghĩa là Origin, or start tạm dịch là điểm khởi đầu hay điểm khởi động, theo sau ORG là một địa chỉ xác định Bởi vì con Pic khởi động tại 0000h nên chúng ta viết:

Trang 5

ORG 000h

Kế đến chúng ta cần nhảy qua khỏi địa chỉ 0004h, bạn hãy dùng lệnh GOTO để làm điều này và theo sau GOTO là 1 cái nhãn mà nó sẽ trỏ tới điểm bắt đầu của đoạn code của chương trình chính Sau đó ta đặt tiếp một ORG khác, vì ta đang nói đến Interrupt nên bạn phải đặt ORG 0004h

Theo sau lệnh ORG 0004h chúng ta sẽ viết chương trình Interrupt hoặc có thể đặt 1 lệnh GOTO để nhảy đến chương trình Interrupt đặt ở đâu đó

Viết chương trình Interrupt theo sau ORG 0004h Hay dùng lệnh GOTO để nhảy đến 1 chương trình Interrupt đặt ở đâu đó thật sự là vấn đề để chọn lựa

Để chấm dứt 1 chương trình Interrupt ta cần đặt lệnh RTFIE tại cuối chương trình Interrupt đó, RTFIE có nghĩa là return from the interrupt routine tạm dịch quay trở về từ chương trình Interrupt, khi con Pic nhìn thấy lệnh RTFIE nó báo cho Program Counter biết để dời tới vị trí lần cuối cùng nó đứng trong chương trình chính trước khi Interrupt xảy ra, hãy xem một đoạn code ngắn bên dưới đây:

ORG 0000h ;PIC starts here on power up and reset

GOTO start ;Goto our main program

ORG 0004h ;The PIC will come here on an interrupt

: ;This is our interrupt routine that we

: ;want the PIC to do when it receives

: ;an interrupt

RETFIE ;End of the interrupt routine

start ;This is the start of our main program

Có 2 điều quan trọng mà bạn cần chú ý khi sử dụng Interrupt:

Thứ nhất, nếu bạn sử dụng cùng một thanh ghi cho chương trình chính và cho Interrupt thì rất có thể nội dung của thanh ghi này bị thay đổi khi Interrupt xảy ra, ví dụ: bạn sử dụng thanh ghi W để gởi Data tới PortA trong chương trình chính và cũng dùng thanh ghi W trong Interrupt để di chuyển nội dung từ nơi này đến nơi khác, nếu bạn không cẩn thận thì thanh ghi W sẽ chứa giá trị cuối cùng trong chương trình Interrupt (khi interrupt xảy ra), và rồi, khi bạn quay về chương trình chính bạn lại gởi nội dung này vào PortA thay vì một nội dung khác trước khi Interrupt xảy ra Cách đơn giản để tránh thảm hoạ này là bạn hãy lưu thanh ghi W vào vị trí tạm nào đấy và dùng nó lại sau khi chương trình Interrupt kết thúc

Thứ hai, đó là thời gian nghỉ bắt buộc giữa 2 lần interrupt xảy ra liên tiếp, như bạn biết, con Pic có một bộ dao động bên trong hoạt động bằng cách mắc với bên ngoài hoặc dùng thạch anh hoặc dùng mạch RC, tần số dao động này được chia 4 bên trong để tạo

ra xung Clock làm nhịp cho 1 chu kỳ lệnh, Ví dụ: nếu thạch anh là 4MHz kết nối với con Pic thì 1 chu kỳ lệnh là: 4MHz/4 = 1MHz

Bây giờ hãy xem hướng dẫn sử dụng cho con Pic của nhà sản xuất, phải có ít nhất là 3 đến 4 chu kỳ lệnh giữa 2 interrupt, tôi chọn và khuyên bạn cũng nên chọn 4 chu kỳ lệnh giữa 2 interrupt cho chắc ăn !

Lý do mà con Pic cần thời gian nghĩ giữa 2 lần Interrupt là nó phải làm đủ thứ chuyện như là nhảy đến địa chỉ Interrupt, set cờ interrupt, thoát ra khỏi chương trình interrupt Như vậy, dựa trên những gì đã bàn trong phần trên, bạn phải lưu ý khi sử dụng mạch kết nối với các thiết bị ngoại vi kích hoạt interrupt của con Pic

Bây giờ lại có một thứ cần phải nhớ, đó là khi bạn sử dụng từ bit4 đến bit7 của PortB như Interrupt thì bạn không thể chọn riêng từng chân trên PortB để nó làm việc như Interrupt, nếu bạn cho phép (enable) những chân này thì bạn đã cho phép tất cả

Trong phần tiếp theo chúng ta sẽ viết chương trình cho Interrupt

Trang 6

Interrupts – Chương trình Interrupt:

Chương trình mà ta sẽ viết là đếm số lần 1 cái Switch bật on rồi hiễn thị con số đó CHương trình sẽ đếm từ 0 đến 9, hiễn thị lên 4 Led dưới dạng Binary, ngõ vào interrupt

là RB0 Đầu tiên ta cần phải báo cho con Pic nhảy đến địa chỉ mà bộ đếm chương trình

sẽ trỏ đến khi Interrupt xảy ra, hãy lưu ý chúng ta sẽ sử dụng 1 cách khác để biểu diễn

số Hex Trước đây chúng ta hay viết F9h với h có nghĩa là hexadecimal, bây giờ chúng

ta viết lại là 0xF9, và cái này chính là dạng mà chúng ta sẽ viết từ giờ trở đi

Org 0x00 ;This is where the PC points to on power up and reset

Goto main ;Goto our main program

Org 0x04 ;This is where our interrupt routine will start

Retfie ;This tells the PIC that the interrupt routine has

;finished and the PC will point back to the main program main ;This is the start of our main program

Bây giờ chúng ta cần nói cho con Pic biết rằng chúng ta sẽ sử dụng Interrupt và sử dụng RB0 (chân 6) như là chân Interrupt

bsf INTCON,7 ;GIE – Global interrupt enable (1=enable)

bsf INTCON,4 ;INTE - RB0 interrupt enable (1=enable)

Kế đến chúng ta xoá cờ Interrupt, mặc dù chúng ta đã nói khi mở nguồn lần đầu tiên thì

cờ Interrupt mặc nhiên bị xoá về 0, nhưng mà tôi chưa bao giờ tin vào bất kỳ điều gì ! bcf INTCON,1 ;INTF - Clear flag bit just in case

Và bây giờ setup 2 Port, nhớ rằng khi chúng ta sử dụng RB0 như một Interrupt thì ta phải setup nó như một ngõ vào Input

Bsf STATUS,5 ;Switch to Bank 1

Movwf TRISB ;Set RB0 as Input

Movwf TRISA ;Set the first 4 pins on PortA as Output

Bcf STATUS,5 ;Come back to Bank 0

Chúng ta sẽ sử dụng biến COUNT để lưu số lần Switch On, bạn có thể hỏi tại sao chúng ta không làm đơn giản là tăng giá trị của PortA rồi đọc lại giá trị này, nhưng bạn

sẽ biết lý do tại sao mà tôi sử dụng biến COUNT khi viết chương trình Interrupt

loop

movf COUNT,0 ;Move the contents of COUNT into W

movwf PORTA ;Now move it to Port A

goto loop ;Keep on doing this

Chương trình chính đã có, bây giờ ta nói cho con Pic biết cái gì sẽ làm khi Interrutp xảy

ra, trong trường hơp này Interrupt của chúng ta sẽ là cái Switch

Chúng ta muốn con Pic cộng thêm 1 vào biến COUNT mỗi lần cái Switch đóng lại Nhưng mà PortA có 5 bit, nếu chúng ta chỉ đơn giản tăng Port lên 1 thì chúng ta sẽ có

số đếm tối đa là 31

Trang 7

Có 2 lý do mà tôi chọn không tăng lên đến 31 Thứ nhất chúng ta dùng Led 7 đoạn, mà thông thường nó chỉ biểu diễn được từ 0 đến 15 ( từ 0 đến Fh) Thứ hai, tôi cũng muốn biểu diễn vài thuật toán thông thường để bạn hiểu những thứ sẽ trình bày trong phần cuối của cuốn sách này

Cái đầu tiên chúng ta cần làm là lưu nội dung của thanh ghi W vào chỗ tạm thời vì chúng ta sẽ dùng W để tải nội dung của COUNT vào PortA, nếu không làm vậy có thể ta

sẽ tải nội dung khác lên PortA chứ không phải COUNT

Movwf TEMP ;Store w register in a temporary location

Kế tiếp ta muốn công 1 vào biến COUNT:

Incf COUNT,1 ;Increment COUNT by 1, and put the result back into

;COUNT

Kế đến chúng ta muốn kiểm tra xem COUNT đã lớn hơn 9 chưa bằng cách là lấy COUNT trừ cho 10

Movlw 0x0A ;Move the value 10 into w

Subwf COUNT,0 ;Subtract w from COUNT, and put the result in w

Trong các phần trước bạn đã biết, nếu ta lấy một số nhỏ trừ cho số lớn hơn thì cờ Carry

sẽ set lên 1, ngoài ra cờ Carry cũng sẽ được set lên 1 khi chúng ta trừ 2 số bằng nhau Btfss STATUS,0 ;Check the Carry flag It will be set if

;COUNT is equal to, or is greater than w,

;and will be set as a result of the subwf instruction Chúng ta muốn, nếu COUNT lớn hơn 9 thì đặt lại giá trị 0 cho nó, ngược lại sẽ quay về chương trình chính để xuất giá trị COUNT ra PortA

Lệnh BTFSS như bạn biết là nó sẽ bỏ qua lệnh kế nếu cờ Carry =1

Trong truờng hợp này nếu COUNT=10:

goto carry_on ;If COUNT is <10, then we can carry on

goto clear ;If COUNT is >9, then we need to clear it

carry_on

bcf INTCON,0x01 ;We need to clear this flag to enable

;more interrupts movfw TEMP ;Restore w to the value before the interrupt

retfie ;Come out of the interrupt routine

clear

clrf COUNT ;Set COUNT back to 0

bcf INTCON,1 ;We need to clear this flag to enable

;more interrupts retfie ;Come out of the interrupt routine

Bây giờ hãy ráp lại tất cả các đoạn code lại với nhau

Bên dưới là 1 chương trình hoàn chỉnh, mạch điện trình bày sau chương trình này, mỗi lần bạn cho Switch On đèn Led sẽ đếm theo số Binary từ 0000 đến 1010 rồi quay trở

về 0000

Trang 8

org 0x00 ;This is where we come on power up and reset

;*******************SETUP CONSTANTS*******************

INTCON EQU 0x0B ;Interrupt Control Register

PORTB EQU 0x06 ;Port B register address

PORTA EQU 0x05 ;Port A register address

TRISA EQU 0x85 ;TrisA register address

TRISB EQU 0x86 ;TrisB register address

STATUS EQU 0X03 ;Status register address

COUNT EQU 0x0c ;This will be our counting variable

TEMP EQU 0x0d ;Temporary store for w register

Goto main ;Jump over the interrupt address

;***************INTERRUPT ROUTINE***************

org 0x04 ;This is where PC points on an interrupt

movwf TEMP ;Store the value of w temporarily

incf COUNT,1 ;Increment COUNT by 1, and put the result

;back into COUNT movlw 0x0A ;Move the value 10 into w

subwf COUNT,0 ;Subtract w from COUNT, and put the result in w

btfss STATUS,0 ;Check the Carry flag It will be set if

;COUNT is equal to, or is greater than w, and will be set

;as a result of the subwf instruction goto carry_on ;If COUNT is <10, then we can carry on

goto clear ;If COUNT is >9, then we need to clear it

carry_on

bcf INTCON,0x01 ;We need to clear this flag to enable more interrupts

movfw TEMP ;Restore w to the value before the interrupt

retfie ;Come out of the interrupt routine

clear

clrf COUNT ;Set COUNT back to 0

bcf INTCON,1 ;We need to clear this flag to enable more interrupts

retfie ;Come out of the interrupt routine

;*******************Main Program*********************

main

;*******************Set Up The Interrupt Registers****

bsf INTCON,7 ;GIE – Global interrupt enable (1=enable)

bsf INTCON,4 ;INTE - RB0 Interrupt Enable (1=enable)

bcf INTCON,1 ;INTF - Clear FLag Bit Just In Case

;*******************Set Up The Ports******************

bsf STATUS,5 ;Switch to Bank 1

movlw 0x01

movwf TRISB ;Set RB0 as Input

movlw 0x10

movwf TRISA ;Set R 0 to RA3 on PortA as Output

bcf STATUS,5 ;Come back to Bank 0

;*******************Now Send The Value Of COUNT To Port A

loop

movf COUNT,0 ;Move the contents of Count into W

movwf PORTA ;Now move it to Port A

goto loop ;Keep on doing this

Trang 9

Sơ đồ mạch:

Bên dưới là sơ đồ mạch mà nó sẽ làm việc với đoạn code bên trên, có 2 thứ mà sơ đồ mạch đã “ném” ra cho bạn, thứ nhất là mạch này không có tụ điện trong mạch dao động, cái này là một chút mẹo vặt, bởi vì chúng ta sử dụng các điện dung tản mạn giữa chân dao động của con Pic và mass trên mạch điện để thay thế các tụ điện mắc trong mạch dao động, như vậy điện trở và điện dung tản mạn trên mạch tạo thành khung dao động RC, nó có thể sẽ bị thay đổi tuỳ theo cấu hình của mạch điện

Thứ hai có một mạch chống rung cho các cái Switch, cái này thật sự cần thiết, vì khi bạn

ấn Switch nó sẽ bị rung, lúc đóng lúc hở và con Pic có thể hiểu nhầm rằng bạn đã ấn Switch rất nhiều lần Với mạch chống rung này, khi bạn ấn Switch tụ điện sẽ nạp khi bạn nhả Switch ra tụ điện sẽ xả từ từ, thời gian xả của tụ điện sẽ bỏ qua các lần rung của Switch

Watchdog Timer:

Bây giờ chúng ta bàn về một bộ định thời bên trong Pic gọi là Watchdog Timer, vậy Watchdog Timer là cái gì?

Giả sử bạn viết một chương trình, bạn mong đợi chương trình này sẽ chạy nếu không

có gì trục trặc xảy ra thì nó sẽ không bao giờ dừng lại, như vậy bạn phải làm một vòng lặp để khi chương trình chạy đến điểm cuối thì nó lại quay trở về điểm bắt đầu Nhưng

mà hãy xem một trường hợp:

Giả sử chương trình kiểm tra một chân input, nếu nó lên mức cao thì con Pic sẽ tiếp tục kiểm tra một chân input thứ hai có lên mức cao hay không, nếu chân input thứ hai không lên mức cao, con Pic sẽ ngồi đó chờ và nó sẽ chỉ thoát ra khỏi chỗ ngồi của nó nếu chân input thứ hai lên mức cao

Bây giờ hãy xem một trường hợp khác, giả sử như bạn viết một chương trình, bạn compiled nó thành công, và ngay cả bạn đã cho chạy mô phỏng từng bước, từng bước một trên máy tính, bằng MPLAB chẳng hạn, có vẽ như mọi chuyện đều tốt, bạn đem nạp vào con Pic Sau một thời gian chạy thử, con Pic thình lình bị kẹt vào nơi nào đó trong chương trình mà không thể thoát ra được trạng thái hiện tại

Điều gì là cần thiết để giải quyết hai trường hợp trên, reset lại hay vẫn để cho nó bị kẹt không thoát ra được ?, đó là mụch đích của mạch watchdog

Mạch watchdog thì không phải là mới mẽ gì, có rất nhiều microprocessors và microcontrollers đã có mạch watchdog, nhưng mà nó làm việc ra sao?

Trang 10

Bên trong con Pic có một mạch RC, mạch này cung cấp 1 xung Clock độc lập với bất kỳ xung Clock nào cung cấp cho Pic Khi Watchdog Timer (viết tắt là WDT) được cho phép (enabled), nó sẽ đếm bắt đầu từ 00 và tăng lên 1 cho đến FFh, khi nó tăng từ FFh đến

00 ( FFh+1) thì con Pic sẽ bị Reset bất kể đang làm gì, chỉ có 1 cách là ngăn không cho WDT đếm tới 00

Khi con Pic bị kẹt không thể thoát ra khỏi tình trạng hiện tại thì WDT vẫn tiếp tục đếm

mà không bị bất kỳ điều gì ngăn cấm nó đếm tới FF và đến FF+1, vì vậy nó sẽ reset con Pic làm cho chương trình phải khởi động lại từ đầu

Để sử dụng WDT chúng ta cần làm 3 việc

Thứ nhất, cần thời gian bao lâu để reset WDT?

Thứ hai, làm sao xoá WDT?

Cuối cùng, chúng ta phải nói cho con Pic biết chương trình cho phép WDT hoạt động Bây giờ bạn hãy xem từng cái một:

Trong Datasheet của con Pic có nói rằng, WDT có thời gian từ lúc Start cho đến khi kết thúc là 18ms, tuy nhiên nó cũng phụ thuộc vào vài yếu tố, nguồn cung cấp, nhiệt độ của con Pic bởi vì mạch dao động của WDT là RC Tuy nhiên chúng ta cũng có thể làm cho thời gian dài hơn Bên trong con Pic có một cái gọi là Prescaler tạm dịch là đặt tỷ lệ, chúng ta có thể lập trình để chia xung Clock của mạch RC, chúng ta chia RC Clock càng nhiều thì thời gian WDT reset càng dài

Prescaler nằm trên thanh ghi OPTION có địa chỉ 81h từ bit0 đến bit2, bên dưới là bảng chia tỷ lệ thời gian WDT

Hãy nhớ rằng các khoảng thời gian này không phụ thuộc vào tần số xung Clock bên ngoài, nó xác định bằng thời gian thực chứ không phải đếm chu kỳ xung clock

Hãy xem ví dụ WDT sẽ reset con Pic trong khoảng ½ giây khi con Pic bị kẹt

Giá trị gần nhất mà ta có theo bảng trên là 576mS hoặc 0.576 seconds

Đầu tiên chúng ta gởi giá trị b’101’ tới thanh ghi OPTION, như sau:

movlw b’101’ ;This is 0x05 in Hex

movwf 81h ;This is the Option Register

Quá đơn giản !, bây giờ, có một mẹo nhỏ

Mặc nhiên prescaler được gán cho một bộ định thời khác, vì vậy ta phải thay đổi toàn bộ WDT Trước tiên phải reset một bộ đếm khác tới giá trị 0, sau đó chuyển sang Bank1 để gán prescaler cho WDT và thiết lập thời gian rồi sau đó lại quay về Bank0, đoạn code bên dưới với xx là giá trị ta sẽ chọn cho prescaler

Bcf STATUS,0 ;make sure we are in Bank 0

Clrf 01h ;address of the other timer – TMR0

Ngày đăng: 02/07/2014, 00:20

HÌNH ẢNH LIÊN QUAN

Bảng dữ liệu ( Data Table): - Tài liệu ASM - PIC (P2) potx
Bảng d ữ liệu ( Data Table): (Trang 1)
Sơ đồ mạch: - Tài liệu ASM - PIC (P2) potx
Sơ đồ m ạch: (Trang 9)

TỪ KHÓA LIÊN QUAN

w