Chào các bạn trong bài sẽ hướng dẫn về timer của PIC16F877A. Các bạn chú ý đây là 1 trong các module của PIC16F877A và nó cũng rất quan trọng và được sử dụng rất nhiều nên các bạn phải chú ý để nắm rõ về nó.
Các bạn xem clip bên dưới xem cách tính thời gian để khởi tạo timer.
1. Lý thuyết
Bộ timer0/counter0 có những đặc điểm sau: Là timer/counter 8 bit.
- Có thể đọc và ghi giá trị đếm của timer/counter.
- Có bộ chia trước 8 bit cho phép lập trình lựa chọn hệ số chia bằng phần mềm.
- Cho phép lựa chọn nguồn xung clock bên trong hoặc bên ngoài.
- Phát sinh ngắt khi bị tràn từ FFH về 00H.
- Cho phép lựa chọn tác động xung CK cạnh lên hoặc cạnh xuống.
Sơ đồ khối của timer0 và bộ chia trước với WDT như hình 6-1:
Để sử dụng timer0 thì phải khảo sát chức năng của thanh ghi điều khiển timer là OPTION_REG.
Cấu hình thanh ghi và chức năng các bit như sau:
Bit 7 RBPU : bit điều khiển điện trở treo của portb.
Bit 6 INTEDG
Bit 5 T0CS: bit lựa chọn nguồn xung cho TMR0 - TMR0 Clock Source Select bit.
1= sẽ đếm xung ngoại đưa đến chân T0CKI.
0= sẽ đếm xung clock nội bên trong.
1= sẽ đếm xung ngoại đưa đến chân T0CKI.
0= sẽ đếm xung clock nội bên trong.
Bit 4 T0SE: bit lựa chọn cạnh tích cực T0SE - TMR0 Source Edge Select bit.
0= tích cực cạnh lên ở chân T0CKI.
1= tích cực cạnh xuống ở chân T0CKI.
0= tích cực cạnh lên ở chân T0CKI.
1= tích cực cạnh xuống ở chân T0CKI.
Bit 3 PSA: bit gán bộ chia trước - prescaler assigment.
1= gán bộ chia cho WDT.
0= gán bộ chia Timer0.
1= gán bộ chia cho WDT.
0= gán bộ chia Timer0.
Bit 2-0 PS2:PS0: các bit lựa chọn tỉ lệ bộ chia trước - prescaler rate select bits:
PS2 | PS1 | PS0 | TMR0 | WDT |
---|---|---|---|---|
0 | 0 | 0 | 1:2 | 1:1 |
0 | 0 | 1 | 1:4 | 1:2 |
0 | 1 | 0 | 1:8 | 1:4 |
0 | 1 | 1 | 1:16 | 1:8 |
1 | 0 | 0 | 1:32 | 1:16 |
1 | 0 | 1 | 1:64 | 1:32 |
1 | 1 | 0 | 1:128 | 1:64 |
1 | 1 | 1 | 1:256 |
1:128
|
Nếu bit T0CS bằng 1 thì chọn chế độ đếm xung ngoài Counter. Trong chế độ đếm xung ngoài thì xung đếm đưa đến chân RA4/T0CKI. Bit T0SE = 0 thì chọn cạnh lên, ngược lại thì chọn cạnh xuống.
Bộ chia trước không thể đọc/ghi có mối quan hệ với Timer0 và Watchdog Timer.
a. Ngắt của Timer0
Khi giá trị đếm trong thanh ghi TMR0 tràn từ FFh về 00h thì phát sinh ngắt, cờ báo ngắt
TMR0IF lên 1. Ngắt có thể ngăn bằng bit cho phép ngắt TMR0IE.
Trong chương trình con phục vụ ngắt Timer0 phải xóa cờ báo ngắt TMR0IF. Ngắt của TMR0
không thể kích CPU thoát khỏi chế độ ngủ vì bộ định thời sẽ ngừng khi CPU ở chế độ ngủ.
b. Timer0 đếm xung ngoại
Muốn đếm xung ngoại thì xung được đưa đến ngõ vào T0CKI, việc đồng bộ tín hiệu xung ngõ vào T0CKI với xung clock bên trong được thực hiện bằng cách lấy mẫu ngõ ra bộ chia ở những chu kì Q2 và Q4 của xung clock bên trong. Điều này rất cần thiết cho T0CKI ở trạng thái mức cao ít nhất 2 TOSC và ở trạng thái mức thấp ít nhất 2 TOSC
c. Bộ chia trước
Bộ chia trước có thể gán cho Timer0 hoặc gán cho Watchdog Timer. Các bit PSA và PS2:PS0 chọn đối tượng gán và tỉ lệ chia.
Khi được gán cho Timer0 thì tất cả các lệnh ghi cho thanh ghi TMR0 (ví dụ CLRF 1, MOVWF 1, BSF 1, …) sẽ xoá bộ chia trước.
Khi được gán cho WDT thì lệnh CLRWDT sẽ xoá bộ chia trước cùng với Watchdog Timer.
Fig. 4-3 The function of the PSA bit 0
2. Timer0
Chúng ta sẽ có công thức tính thời gian để cài đặt cho Timer 0 như sau:
(8bit) 256 = giá trị nạp + (giá trị mong muốn/(tỉ lệ * chu kì lệnh))
Chu kì lệnh
= 4 * chu kì máy
Chu kì máy
= 1/ tần số của vdk
VD: Thạch anh 8MHz ~ F=8MHz
B1.
F = 8MHz =
8*10^6 Hz suy ra T = 1/F = 1/8*10^-6 (s)=1/8us
Suy ra: chu
kì lệnh = 4*1/OSC = 4*1/8 = 0.5 us
B2. áp dụng công thức trên
256 = giá trị nạp + (giá trị mong muốn/(tỉ lệ chia*chu kì lệnh)) (us)
với:
- tỉ lệ
chia: 8
- chu kì lệnh: 0.5 us
từ công thức suy ra
(256 - giá trị nạp) * 8*0.5 = giá trị mong muốn (us)
Chọn giá trị nạp sao cho giá trị mong muốn lớn nhất và là số
chia hết cho 1.000.000 us (~1s)
giá trị nạp
|
giá trị mong muốn
|
số lần tràn để được 1 giây
|
Chọn 6
|
1.000 us
|
1.000.000/1000=1000 lần
|
Chọn 56
|
800
us
|
1000000/800=1250 lần
|
2. Timer1
Chúng ta sẽ tính toán các thông số để cài đặt cho Timer 1 theo công thức sau : Ví dụ muốn định thời 50ms = 50000us sử dụng prescaler 1:8, Fosc = 4 Mhz thì ta có công thức tính như sau :
GT = 65536 - Tdelay.Fosc/(4.Kprescaler)
Từ công thức trên thay số vào ta được như sau :
GT = 65536 - 50.10^-3.4.10^6.(4/8) = 59286
3. Counter
Hướng dẫn về Counter của Timer 0 của Vi Điều Khiển PIC16F877A dử dụng trình biên dịch PIC C Compiler để viết và biện dịch code.
A. CÁC LỆNH CỦA TIMER – COUNTER TRONG CCS
Các lệnh của ngôn ngữ lập trình C liên quan đến timer/counter bao gồm
SETUP_TIMER_X()SET_TIMER_X()SETUP_COUNTERS()SETUP_WDT()RESTART_WDT() GET_TIMER_X()
B. LỆNH SETUP_TIMER_0(MODE)
Cú pháp:
setup_timer_0(mode)
Thông số: mode có thể là 1 hoặc 2 hằng số định nghĩa trong file device.h. Các thông số gồm :
RTCC_INTERNAL, RTCC_EXT_H_TO_LRTCC_EXT_L_TO_H
RTCC_DIV_2,
RTCC_DIV_4,
RTCC_DIV_8,
RTCC_DIV_16,
RTCC_DIV_32,
RTCC_DIV_64,
RTCC_DIV_128,
RTCC_DIV_256.
Các hằng số từ nhiều nhóm khác nhau thì có thể or với nhau.
Chức năng: Định cấu hình cho TIMER0.
Có hiệu lực: cho tất cả các vi điều khiển PIC.
C. LỆNH SET_TIMERx(value)
Cú pháp:
set_timerX(value) ; x là 0, 1, 2
Thông số: value là hằng số nguyên 8 hoặc 16 bit dùng để thiết lập giá trị mới cho timer.
Chức năng: thiết lập giá trị bắt đầu cho TIMER.
Có hiệu lực: cho tất cả các vi điều khiển PIC có timer.
4. LỆNH GET_TIMERx()
Cú pháp:
value = get_timerX() ; x là 0, 1, 2
Thông số: không có.
Chức năng: đọc giá trị của TIMER/COUNTER.
Có hiệu lực: cho tất cả các vi điều khiển PIC có timer.
- Đây là code chương trình.
int dem=0;
void main()
{
setup_timer_0(RTCC_EXT_L_TO_H|RTCC_DIV_1|RTCC_8_bit);
set_tris_b(0x00);
set_timer0(0);
lcd_init();
while(TRUE)
{
//TODO: User Code
dem = get_timer0();
lcd_gotoxy(1,1);
lcd_putc(dem/100 + 48);
lcd_putc((dem%100)/10 + 48);
lcd_putc((dem%100)%10 + 48);
}
{
//TODO: User Code
dem = get_timer0();
lcd_gotoxy(1,1);
lcd_putc(dem/100 + 48);
lcd_putc((dem%100)/10 + 48);
lcd_putc((dem%100)%10 + 48);
}
}
Link download project bên dưới phần mô tả video