You are on page 1of 9

Chương 4: BỘ ĐỊNH THỜI VÀ BỘ ĐẾM (20 tiết)

4.1. Khái niệm về bộ định thời


Bộ định thời tạo ra thời gian trì hoãn từ lúc có tín hiệu đầu vào cho đến khi có tín hiệu ra,
thời gian từ lúc có tín hiệu vào đến lúc có tín hiệu ra gọi là thời gian định thời. Bộ định thời
hoạt động độc lập với CPU
Trong vi điều khiển cũng như các hệ thống số, bộ định thời được tạo ra dựa trên bộ đếm
cạnh lên và khoảng thời gian giữa 2 lần đếm liên tiếp đã biết trước nên thời gian định thời
chính là tích của 2 thông số trên
Đối với PIC16F887, chu kỳ xung nhịp là Tosc, chu kỳ lệnh cơ bản Tck = 4Tosc. Nếu chạy
với tần số thạch anh 20MHz thì Tck là 200ns. Tck này được đưa vào bộ đếm, muốn tạo ra thời
gian trể 20000ns thì bộ đếm cần đếm 20000ns / 200ns = 100 lần đếm. Như vậy 200ns ở đây là
khoảng cách giữa 2 lân đếm (2 lần có xung cạnh lên) đã biết trước, khi sử dụng bộ định thời
chỉ cần tìm số lần đếm từ thời gian cần định thời
4.2. Bộ định thời, bộ đếm TIMER0
4.2.1. Cấu trúc và hoạt động của TIMER0
Timer0 là bộ định thời/bộ đếm 8 bit, cho phép lựa chọn nguồn xung nhịp từ bên ngoài (chân
T0CKI) hay từ dao động cơ bản của vi điều khiển với bộ chia trước (prescale) 8 bit, cho phép
ngắt tràn

Xung nhịp được đưa vào bộ đếm TMR0 thông qua các công tắc chọn lựa chuyển mạch số
T0CS_bit, PSA_bit, PS<2:0>, T0SE. Tùy theo yêu cầu định thời và độ chính xác định thời mà
có các lập trìn phù hợp
4.2.2. Các bit và thanh ghi liên quan đến TIMER0
Các bit chuyển mạch sử dụng trong Timer0 gồm:
- T0SE_bit (Timer0 Select Edge): bit chọn cạnh tác động lên khi bằng 0 và tác động cạnh
xuống khi bằng 1, bit này chỉ có tác dụng khi chọn nguồn xung nhịp bên ngoài
- T0CS_bit (Timer0 Clock Source): bit chọn nguồn xung nhịp từ dao dộng cơ bản Fosc/4
nếu bằng 0 hay xung nhịp bên ngoài nếu bằng 1
- PSA_bit (Prescaler Assignment): bit cho phép truy cập bộ chia trước nếu bằng 0 và ngược
lại
- PS<2:0> (Prescaler Rate Select): 3 bit này để chọn lựa bộ chia trước theo bảng.
4.2.3. Hoạt động định thời và bộ chia trước
Trường hợp chọn bộ chia trước khi thời gian định thời có số lần đếm vượt quá 255. Nếu
chọn bộ chia trước, khoảng cách giữa 2 lần đếm của Timer sẽ tăng lên tỉ lệ với bộ chia nên độ
chính xác định thời trên 1 lần đếm sẽ giảm tương ứng.
Như đã nêu ở phần định nghĩa, hoạt động định thời thực chất là hoạt động đếm số xung nhịp
nhận được dùng bộ đếm (counter) kết hợp khoảng thời gian giữa 2 lần đếm liên tiếp đã biết
trước
Do là hoạt động định thời nên chỉ cần chọn xung nhịp bên trong là đủ
Gọi thời gian giữa 2 lần đếm liên tiếp (chu kỳ đếm) là Tc, số lần đếm của Timer là N thì
thời gian trì hoãn do Timer tạo ra là T = NxTc
Ví dụ 1: Muốn tạo thời gian trì hoãn 22000ns thì tính như sau:
Tc = 1/(Fosc/4) = 200ns với thạch anh 20MHz
N = T/Tc = 22000/200 = 110 lần đếm

Ví dụ 2: Muốn tạo thời gian trì hoãn 220000ns thì tính như sau:
Tc = 1/(Fosc/4) = 200ns với thạch anh 20MHz
N = T/Tc = 220000/200 = 1100 lần đếm
Số lần đếm tính được vượt quá 255 nên 1100 không thể chứa được trong thanh ghi 8 bit. Để
định thời được phải sử dụng bộ chia trước (prescale)
Gọi tỉ lệ chia trước là p. Chọn p sao cho p là nhỏ nhất (theo bảng và thỏa TMR0 <=255
p = N/256 = 1100/256 = 4.3
Chọn p = 8, lúc này chu kỳ đếm Tc = p x Tc = 8 x 200ns = 1600ns
Tính lại N = T/Tc = 220000/1600 = 137.5 làm tròn xuống 137
Tại sao không chọn p = 4 gần với giá trị trong bảng hơn? Thử tính lại N với p = 4
Tc = p x Tc = 800ns
N = T/Tc = 220000/800 = 275 > 255
Kết quả N vẫn không thể chứa trong TMR0. Do đó chọn giá trị gần nhất lớn hơn
Còn N = 137.5 làm tròn xuống còn 137. Trong hệ thống số ngoài thời gian định thời còn có
thời gian để thực thi các lệnh, thời gian nảy từ chương trình chính sang chương trình ngắt. Nếu
làm tròn 138 cộng với thời gian thực thi lệnh
Tổng thời gian trì hoãn sẽ là: 138xTc + T(lệnh) = 220800 + T(lệnh)
Sai số sẽ là: [220800 + T(lệnh)] – 220000 = 800ns + T(lệnh) > 800ns
Còn nếu lấy 137 cộng với thời gian thực thi lệnh, tổng thời gian trì hoãn sẽ là 137xTc +
T(lệnh) = 219200 + T(lệnh)
Sai số sẽ là: 220000 - [219200 + T(lệnh)] = 800ns - T(lệnh) < 800ns
4.2.4. Hoạt động đếm của TIMER0
Ngoài chức năng định thời, Timer0 còn được thiết kế để tạo bộ đếm xung từ bên ngoài. Nếu
xung từ bên ngoài có chu kỳ không đổi thì cũng có thể lập trình được chức năng định thời. Tuy
nhiên thông thường xung từ bên ngoài dùng để đếm số lần có tác động cạnh lên hoặc xuống
(tùy theo T0SE_bit)
Chức năng đếm lập trình sẽ đơn giản hơn định thời. Lập trình đưa trực tiếp xung bên ngoài
vào TMR0 mà không qua bộ chia trước. Đọc giá trị TMR0 sẽ biết được có bao nhiêu cạnh từ
bên ngoài đưa vào
4.2.5. Ngắt TIMER0
Do bộ đinh thời hoạt động độc lập với CPU nên cần 1 báo hiệu để phát hiện bộ định thời đã
đủ thời gian định thời. Báo hiệu đó là ngắt
Ngắt Timer0 chỉ xảy ra khi TMR0 bằng 255 và trở về 0 hay còn gọi là ngắt tràn Timer0.
Khi ngắt cờ ngắt T0IF_bit tự động được set, nếu có cho phép ngắt tương ứng CPU sẽ trỏ đến
địa chỉ chương trình ngắt và thực hiện chương trình ngắt (xem lại phần ngắt và ngắt ngoài)
Quay lại ví dụ 1 ở trên, làm sao để biết được bộ định thời đã đếm được 110 lần đếm nếu
dùng hỏi vòng là không thể chính xác do chương trình hỏi vòng còn thực hiện các nhiệm vụ
khác nữa. Do đó ngắt là cách để nhận biết bộ định thời đã hoạt động xong
Ngắt Timer0 chỉ khi TMR0 từ 255 về 0 nên cần phải nạp giá trị ban đầu cho TMR0 sao cho
sau số lần đếm 110 lần thì xảy ra ngắt, TMR0 được nạp là TMR0 = 256 – số lần đếm = 256 -
110
Cấu hình ngắt định thời Timer0:
- Cho phép ngắt toàn cục
- Cài đặt các bit chuyển mạch T0CS_bit, PSA_bit, PS<2:0>, T0SE
- Nạp giá trị TMR0 ban đầu
- Xóa cờ ngắt T0IF_bit và cho phép ngắt Timer0 bằng cách set T0IE_bit
Chương trình ngắt:
- Kiểm tra cờ ngắt để xác định loại ngắt
- Xóa cờ ngắt
- Nạp lại giá trị TMR0 ban đầu nếu tiếp tục thực hiện định thời mới. Nếu không tiếp tục
định thời, ta có thể vô hiệu hóa cho phép ngắt Timer0
- Thực hiện nội dung ngắt
Ví dụ 3: Cấu hình ngắt và chương trình ngắt Timer0
void interrupt() iv 0x04 {
if ((T0IF_bit==1)&&( T0IE_bit==1)){
T0IF_bit=0; // Xóa cờ ngắt
TMR0=155; // nạp lại TMR0
RE0_bit=!RE0_bit;// thực hiện nội dung ngắt
}
}
void main() {
GIE_bit=1;
T0CS_bit=0
PSA_bit=1
PS2_bit=0;PS1_bit=0;PS0_bit=0;
TMR0=155;
T0IF_bit=0;T0IE_bit=1;
while(1){}
}
4.3. Bộ định thời, bộ đếm TIMER1
4.3.1. Cấu trúc và hoạt động của TIMER1
Timer 1 là bộ định thời/bộ đếm 16 bit, kết quả của bộ đếm 16 bit được lưu trong 2 thanh ghi
8 bit là TMR1H và TMR1L

Vì TMR1L và TMR1H là thanh ghi 8 bit nên khi TMR1L đếm đến 255 nếu có thêm 1 xung
nhịp thì sẽ về 0, đồng thời TMR1H sẽ tăng thêm 1 đơn vị. Tương tự khi TMR1H đếm đến 255
mà có thêm một lần TMR1L từ 255 về 0 thì TMR1H sẽ về 0

Khi cả 2 thanh ghi TMR1L và TMR1H từ 255 về 0 thì sẽ xảy ra ngắt tràn Timer1

Tóm lại: xem 2 thanh ghi TMR1H và TMR1L ghép lại như một thanh ghi 16 bit và được
đếm đến 255 * 256 + 255 = 65535 và trở về 0 thì sẽ xảy ra ngắt tràn Timer1

4.3.2. Các bit và thanh ghi liên quan đến TIMER1


Các bit chuyển mạch sử dụng trong Timer1 gồm:
- TMR1CS_bit (Timer1 Clock Source): bit chọn nguồn xung nhịp, bằng 0 nếu chọn dao
động nội, bằng 1 nếu chọn dao động từ bên ngoài thông qua chân T1CKI hoặc T1OSI và
T1OSO
- T1OSCEN_bit (Timer1 Oscillator Enable): bit cho phép mạch tạo dao động kết hợp thạch
anh bên ngoài hoặc lấy xung nhịp từ bên ngoài
- T1CKPS<1:0> (Timer1 Input Clock Prescale Select): 2 bit chọn bộ chia trước
11 : Tỉ lệ 1:8
10 : Tỉ lệ 1:4
01 : Tỉ lệ 1:2
00 : Tỉ lệ 1:1
- TMR1GE_bit (Timer1 Gate Enable): bit cho phép cổng Timer1
- TMR1ON_bit (Timer1 On): bit bật cho phép Timer1 chạy
4.3.3. Hoạt động định thời và bộ chia trước
Tương tự Timer0, trường hợp chọn bộ chia trước khi thời gian định thời có số lần đếm vượt
quá 65535. Nếu chọn bộ chia trước, khoảng cách giữa 2 lần đếm của Timer sẽ tăng lên tỉ lệ với
bộ chia nên độ chính xác định thời trên 1 lần đếm sẽ giảm tương ứng.
Gọi thời gian giữa 2 lần đếm liên tiếp (chu kỳ đếm) là Tc, số lần đếm của Timer là N thì
thời gian trì hoãn do Timer tạo ra là T = NxTc
Ví dụ 4: Muốn tạo thời gian trì hoãn 46000us dùng timer1 thì tính như sau:
Tc = 1/(Fosc/4) = 200ns với thạch anh 20MHz
N = T/Tc = 46000000/200 = 230000 lần đếm
Số lần đếm tính được vượt quá 65535 nên 230000 không thể chứa được trong 2 thanh ghi 8
bit. Để định thời được phải sử dụng bộ chia trước (prescale)
Gọi tỉ lệ chia trước là p. Chọn p sao cho p là nhỏ nhất
(theo bảng tỉ lệ T1CKPS<1:0> và thỏa TMRL + 256 * TMR1H <= 65535)
p = N/65536 = 230000/65536 = 3.5
Chọn p = 4, lúc này chu kỳ đếm Tc = p x Tc = 4 x 200ns = 800ns
Tính lại N = T/Tc = 46000000/800 = 57500 lần đếm <= 65535
4.3.4. Hoạt động đếm của TIMER1
Ngoài chức năng định thời, Timer1 cũng còn được thiết kế để tạo bộ đếm xung hoặc định
thời từ xung nhịp bên ngoài.
Nếu xung từ bên ngoài có chu kỳ không đổi thì cũng có thể lập trình được chức năng định
thời. Timer1 có tích hợp thêm mạch dao động kết hợp cổng not qua 2 chân T1OSI và T1OSO.
Người dùng có thể mắc thêm dao động thạch anh bên ngoài tần số thấp 32.768kHz, mục đích
của việc này là để định thời khoảng thời gian lớn hơn nếu dùng dao động nội và bộ chia trước
không giải quyết được
Xung nhịp đưa vào chân T1CKI hoặc T1OSI để đếm như chức năng bộ đếm bình thường
4.3.5. Ngắt TIMER1
Ngắt Timer1 chỉ xảy ra khi TMR1L + TMR1H*256 bằng 65535 và trở về 0 hay còn gọi là
ngắt tràn Timer1. Khi ngắt cờ ngắt TMR1IF_bit tự động được set, nếu có cho phép ngắt tương
ứng CPU sẽ trỏ đến địa chỉ chương trình ngắt và thực hiện chương trình ngắt (xem lại phần
ngắt và ngắt ngoài)
Cấu hình ngắt định thời Timer1:
- Cho phép ngắt toàn cục và ngắt ngoại vi
- Cài đặt các bit chuyển mạch: TMR1CS_bit, T1OSCEN_bit, T1CKPS<1:0>,
TMR1GE_bit=0
- Nạp giá trị TMR1L và TMR1H ban đầu
- Xóa cờ ngắt TMR1IF_bit và cho phép ngắt Timer1 bằng cách set TMR1IE_bit
- Bật TMR1ON_bit cho phép Timer1 chạy
Chương trình ngắt:
- Kiểm tra cờ ngắt để xác định loại ngắt
- Xóa cờ ngắt
- Nạp lại giá trị TMR1L và TMR1H ban đầu nếu tiếp tục thực hiện định thời mới. Nếu
không tiếp tục định thời, ta có thể vô hiệu hóa cho phép ngắt Timer1
- Thực hiện nội dung ngắt
Ví dụ 5: Cấu hình ngắt và chương trình ngắt Timer1
void interrupt(){
if ((TMR1IF_bit==1)&& (TMR1IE_bit==1)){
TMR1IF_bit=0;
TMR1H=4;TMR1L=89;
RE1_bit=!RE1_bit
}
}
void main(){
PEIE_bit=1;GIE_bit=1;
T1OSCEN_bit=0;
TMR1CS_bit=0;
T1CKPS1_bit=1;T1CKPS0_bit=1;
TMR1H=4;TMR1L=89;
TMR1IF_bit=0; TMR1IE_bit=1;
TMR1ON_bit=1;
while(1){}
}
4.4. Bộ định thời, bộ đếm TIMER2
4.4.1. Cấu trúc và hoạt động của TIMER2
Timer2 là bộ định thời 8 bit, nguồn bên trong từ dao động cơ bản của vi điều khiển với bộ
chia trước (prescaler) và bộ chia sau (postscaler)
TMR2ON

Xung nhịp được đưa trực tiếp vào bộ chia trước, sau đó vào TMR2. Giá trị TMR2 được so
sánh với PR2 (đã đặt trước), nếu TMR2 đếm đến bằng PR2 thì sẽ tự động xóa TMR2 và xuất
ngõ ra TMR2 (dùng cho chức năng PWM). Bộ chia sau postscaler sẽ quyết định số lần TMR2
bị xóa để xảy ngắt (Timer2 ngắt là ngắt so sánh chứ không phải là ngắt tràn như Timer0 và
Timer1)
Timer1 ngoài chức năng định thời còn hổ trợ chức năng PWM, CCP, Capture trên 2 chân
CCP1 và CCP2. Timer2 sẽ được quay lại phân tích kỹ hơn ở phần PWM.
4.4.2. Các bit và thanh ghi liên quan đến TIMER2
- T2CKPS<1:0> (Timer2 Clock Prescale Select): bit tạo bộ chia trước

- TOUTPS<3:0> (Timer2 Output Postscaler Select): bit tạo bộ chia sau

- TMR2ON_bit (Timer2 On): bật cho phép Timer2 chạy


4.4.3. Ngắt TIMER2
Ngắt Timer2 xảy ra khi xảy ra có sự so sánh bằng giữa TMR2 và PR2 lần thứ n tương ứng
với n là bộ chia sau (1: n). Khi ngắt cờ ngắt TMR2IF_bit tự động được set, nếu có cho phép
ngắt tương ứng CPU sẽ trỏ đến địa chỉ chương trình ngắt và thực hiện chương trình ngắt (xem
lại phần ngắt và ngắt ngoài)
4.5. Bài tập ứng dụng
4.5.1. Bài tập 1
Thực hiện việc sáng tắt 1 led nối với chân RD2 (led sáng 100us, tắt 100us sau đó lặp lại liên
tục) dùng Timer0
4.5.2. Bài tập 2
Thực hiện việc sáng tắt 1 led nối với chân RD2 (led sáng 1000us, tắt 1000us sau đó lặp lại
liên tục) dùng Timer1
4.5.3. Bài tập 3
Thực hiện việc sáng tắt 1 led nối với chân RD1 (led sáng 100us, tắt 100us sau đó lặp lại liên
tục) dùng Timer0 đồng thời thực hiện việc sáng tắt 1 led khác nối với chân RD2 (led sáng
5000us, tắt 5000us sau đó lặp lại liên tục) dùng Timer1
4.5.4. Bài tập 4
Tạo xung vuông 1kHz trên chân RA1 dùng Timer0
4.5.5. Bài tập 5
Tạo xung vuông 1kHz trên chân RA1 và xung vuông 2kHz trên chân RA1 dùng Timer0
4.5.6. Bài tập 6
Tạo xung có Ton = 40us và Toff = 20us trên chân RB3 dùng Timer0
4.5.7. Bài tập 7
Tạo xung có Ton = 24ms và Toff = 5ms trên chân RB3 dùng Timer1
4.5.9. Bài tập 9
Thực hiện sáng dịch 1led (như hình), mỗi lần dịch cách nhau 100ms dùng Timer1

4.5.10. Bài tập 10


- Kết nối cảm biến với chân T0CKI, cảm biến phát hiện có vật sẽ lên mức 1
- Lập trình đếm số vật mỗi khi vật đi qua, hiển thị số vật đếm được trên LCD 16x2
4.5.11. Bài tập 11
- Kết nối cảm biến với chân T1CKI, cảm biến phát hiện có vật sẽ lên mức 1
- Lập trình đếm số vật mỗi khi vật đi qua, hiển thị số vật đếm được trên LCD 16x2
4.5.12. Bài tập 12
- Kết nối thạch anh 32768Hz trên 2 chân T1OSO và T1OSI
- Lập trình tạo xung vuông 0.5Hz trên chân RC1
4.5.13. Bài tập 13
Nguồn xung vuông được đưa vào chân RB0 như hình dưới
Ứng dụng ngắt ngoài và Timer 0 hoặc Timer 1 để đo chu kỳ của xung vuông trên. Hiển thị
chu kỳ xung trên LCD 16x2
4.5.14. Bài tập 14
Nguồn xung vuông được đưa vào chân RB0 như hình bài tập 13
Ứng dụng ngắt thay đổi RB và Timer 0 hoặc Timer 1 để đo chu kỳ của xung vuông trên.
Hiển thị chu kỳ xung trên LCD 16x2

You might also like