CHƯƠNG TRÌNH DELAY

Một phần của tài liệu tổng quan về vi điều khiển (Trang 84 - 89)

CHƯƠN G4 MỘT SỐ ỨNG DỤNG CỤ THỂ CỦA PIC16F877A

4.1.1 CHƯƠNG TRÌNH DELAY

Chương trình trên giúp ta đưa giá trị ra các PORT của vi điều khiển và các LED sẽ sáng hay tắt tùy theo mức logic đưa ra các PORT. Bây giờ ta lại muốn các LED sẽ chớp tắt sau một khoảng thời gian định trước. Muốn vậy ta dùng thêm một đoạn chương trình DELAY. Thực chất của chương trình DELAY là cho vi điều khiển làm một công việc vô nghĩa nào đó trong một khoảng thời gian định trước. Khoảng thời gian này được tính toán dựa trên quá trình thực thi lệnh, hay cụ thể hơn là dựa vào thời gian của một chu kì lệnh. Có thể viết chương trình DELAY dựa trên đoạn chương trình sau:

MOVLW MOVWL loop DECFSZ

GOTO ………

Nếu dùng đoạn chương trình này thì thời gian delay được tính gần đúng như sau: td = 3(1+tv)ti

Trong đó td là thời gian delay, tv là giá trị đưa vào thanh ghi delay-reg và ti là thời gian của một chu kì lệnh và được tính theo công thức:

ti = 4/f0

Với f0 là tần số của oscillator. Sở dĩ có công thức này là vì một chu kì lệnh bao gồm 4 xung clock. Công thức này chỉ gần đúng vì ta đã bỏ qua thời gian thực thi các lệnh trước label “loop” và một chu kì lệnh phát sinh khi thanh ghi delay-reg mang giá trị 0 (trường hợp này cần hai chu kì lệnh để thực thi lệnh DECFSZ).

Do thanh ghi delay-reg chỉ mang giá trị lớn nhất là FFh nên thời gian delay chỉ giới hạn ở một khoảng thời gian nhất định tùy thuộc vào xung clock sử dụng để cấp cho vi điều khiển. Muốn tăng thời gian delay ta có thể gọi chương trình delay nhiều lần hoặc tăng số lượng vòng lặp của chương trình delay như sau:

MOVLW 0Xff

MOVWF delay-reg1

Exit

Với đoạn chương trình trên thời gian delay chỉ kết thúc khi cả hai thanh ghi delay-reg1 và delay-reg2 đều mang giá trị 0.

Sau đây là một ví dụ cụ thể. Yêu cầu đặt ra là cho các LED trong chương trình 4.1 chớp tắt sau mỗi 100 miligiây. Giả sử ta đâang sử dụng oscillator 4MHz. Khi đó thời gian của một chu kì lệnh là:

ti = 4/4 MHz = 1 uS.

Với thời gian cần delay là td bằng 1s thì giá trị cần đưa vào thanh ghi delay-reg là: tv = (td/3ti) – 1 = 33332.

Như vậy ta đưa vào thanh ghi delay-reg2 giá trị 255 (FFh) và thanh ghi delay-reg1 giá trị 33332/255 = 131 (83h).

Chương trình được viết như sau: ;chương trình 4.1.2 ;PORTBTESTANDDELAY.ASM ;Version 1.1 processor include

CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _XT_OSC & _WRT_OFF & _LVP_OFF & _CPD_OFF

delay_reg1 delay_reg2

loop

loop1 loop2

exit1

loop3 DECFSZ delay_reg1

GOTO loop4

GOTO exit2

loop4 DECFSZ delay_reg2

GOTO loop4

GOTO loop3 ; delay 100 ms

exit2

GOTO loop ; vòng lặp vô hạn

END ; kết thúc chương trình

Với chương trình này các pin của PORTB sẽ thay đổi trạng thái sau mỗi khoảng thời gian delay là 100 ms. Điều này cho phép ta nhận thấy bằng mắt thường vì trong một giây các pin của PORTB sẽ thay đổi trạng thái 10 lần.

Tuy nhiên ta dễ dàng nhận thấy một nhược điểm của chương trình trên là cần tới hai đoạn chương trình delay với cấu trúc chương trình, thuật toán và chức năng hoàn toàn giống nhau. Điều này làm cho chương trình trở nên phức tạp và tốn nhiều dung lượng bộ nhớ của vi điều khiển. Điều này cần được chú trọng vì dung lượng bộ nhớ chương trình của một vi điều khiển thường nhỏ (đối với PIC16F877A dung lượng bộ nhớ chương trình là 8K word với một word là 14 bit). Một phương pháp để khắc phục nhược điểm này là sử dụng chương trình con và dùng lệnh “CALL” để gọi chương trình con đó. Chương trình con có thể đựơc đặt tại bất cứ vị trí nào trong chương trình chính. Chương trình 4.2 khi đó được viết lại như sau:

;chương trình 4.1.3 ;PORTBTESTANDDELAY.ASM ;Version 1.2 processor include

CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _XT_OSC & _WRT_OFF & _LVP_OFF & _CPD_OFF

; khai báo các “Configuration bits” delay_reg1

delay_reg2

start

CLRF CALL GOTO Delay100ms MOVLW 0x83 MOVWF delay_reg1 MOVLW 0xFF MOVWF delay_reg2

loop1 DECFSZ delay_reg1

GOTO loop2

GOTO exit

loop2 DECFSZ delay_reg2

GOTO loop2

GOTO loop1 ; delay 100 ms

Exit

RETURN ; trở về chương trình chính

END ; kết thúc chương trình

Với cách viết chương trình sử dụng chương trình con, cấu trúc chương trình sẽ trở nên gọn gàng dễ hiểu hơn, linh hoạt hơn và tiết kiệm được nhiều dung lượng bộ nhớ chương trình.

Bây giờ ta sẽ bàn đến một thuật toán khác để viết chương trình delay. Về nguyên tắc thì thuật toán mới này không có nhiều khác biệt so với thuật toán cũ, tuy nhiên lệnh sử dụng trong chương trình và cách tính toán thời gian delay thì khác nhau. Chương trình con delay100ms với oscillator 4 MHz có thể được viết lại như sau:

delay100ms

d1

delay_0

DECFSZ counta,1

END DECFSZ countb,1 GOTO delay_0 DECFSZ count1,1 GOTO d1 RETLW 0x00

Trước tiên ta xét đoạn chương trình kể từ label “delay_0”. Lệnh DECFSZ mất một chu kì lệnh (trừ trường hợp thanh ghi counta mang giá trị 0 thì cần 2 chu kì lệnh), lệnh GOTO $+2 mất hai chu kì lệnh. Lệnh này có tác dụng cộng vào bộ đếm chương trình giá trị 2, khi đó chương trình sẽ nhảy tới lệnh có địa chỉ (PC+2), tức là lệnh GOTO delay_0, lệnh này cũng tốn hai chu kì lệnh. Như vậy ta cần tổng cộng 5 chu kì lệnh để giảm giá trị trong thanh ghi counta 1 đơn vị. Thanh ghi counta mang giá trị 199 (C7h), do đó đoạn chương trình này sẽ tạo ra một khoảng thời gian delay:

td = 5(counta+1)*ti = 5(199+1)*1 uS = 1 mS

Muốn tạo ra thời gian delay 100 mS, ta chỉ việc đưa giá trị 100 vào thanh ghi count1. Với giải thuật này thời gian delay tạo ra sẽ dài hơn so với giải thuật mà ta sử dụng ở chương trình 4.2. Bên cạnh đó ta có thể viết một chương trình con có tác dụng delay một khoảng thời gian bất kì là bội số của 1 mS một cách dễ dàng.

Trong chương trình trên ta còn sử dụng thêm một lệnh khá lạ là lệnh RETLW. Lệnh này có tác dụng trở về vị trí mà chương trình con được gọi và thanh ghi W khi đó mang giá trị là tham số của lệnh RETLW (00h). Trong trường hợp này thanh ghi W không cần mang một giá trị cụ thể khi quay trở về chương trình chính nên lệnh RETLW chỉ có tác dụng như lệnh RETURN.

Một phần của tài liệu tổng quan về vi điều khiển (Trang 84 - 89)

Tải bản đầy đủ (DOCX)

(189 trang)
w