I. Giới thiệu
Chào các bạn!
Bộ định thời/bộ đếm (Timer/Counter) là một trong những tính năng ngoại vi phổ biến mà tất cả các dòng vi điều khiển đều có. Timer/Counter có thể được sử dụng trong nhiều ứng dụng như điều khiển LED, tạo xung PWM, đo tần số, và định thời.
Trước khi sử dụng Timer/Counter, chúng ta cần hiểu rõ và nắm bắt cách hoạt động của nó trên các dòng vi điều khiển cấp thấp như 8051. Việc này sẽ là bước tiếp theo để sử dụng Timer/Counter trên các dòng chip cao cấp trong tương lai.
1. Timer/Counter là gì và hoạt động như thế nào?
- Timer/Counter là một bộ đếm xung nhịp (xung clock) và bao gồm các thanh ghi chứa giá trị đếm và thanh ghi điều khiển hoạt động của bộ đếm này.
- Xung nhịp có hai loại: xung nhịp nội (nằm trong vi điều khiển) và xung nhịp bên ngoài (đưa vào từ một chân nào đó).
- Người dùng có thể lập trình cho Timer/Counter bắt đầu đếm từ một giá trị bằng cách ghi giá trị đó vào thanh ghi chứa giá trị đếm. Khi giá trị đếm vượt quá giá trị tối đa của thanh ghi chứa Timer/Counter, hiện tượng tràn (overflow) sẽ xảy ra.
2. Timer/Counter trên 8051
Trong vi điều khiển 8051, có hai bộ Timer/Counter:
- Timer/Counter 0
- Timer/Counter 1
Trong trường hợp của vi điều khiển 8052, còn có thêm một bộ Timer/Counter 2.
Trong bài viết này, tôi sẽ hướng dẫn bạn cách lập trình và điều khiển hai bộ Timer/Counter của 8051. Bạn có thể tự tìm hiểu về Timer/Counter 2 hoặc tôi sẽ viết về nó trong bài viết khác. Hãy cùng bắt đầu tìm hiểu về Timer/Counter trên 8051 nhé!
II. Các thanh ghi điều khiển Timer/Counter trong 8051.
2.1. Thanh ghi chứa giá trị đếm.
Mỗi bộ Timer/Counter trong 8051 có một thanh ghi 16 bit chứa giá trị đếm, có thể truy cập thông qua hai thanh ghi 8 bit độc lập gọi là byte thấp (TLx) và byte cao (THx).
-
Thanh ghi chứa giá trị đếm của Timer/Counter 0:

-
Thanh ghi chứa giá trị đếm của Timer/Counter 1:

2.2. Thanh ghi cài đặt chế độ hoạt động: TMOD.
Cả Timer/Counter 0 và Timer/Counter 1 sử dụng chung một thanh ghi TMOD để thiết lập các chế độ hoạt động. TMOD là một thanh ghi 8 bit. 4 bit thấp được sử dụng để thiết lập chế độ cho Timer/Counter 0, trong khi 4 bit cao được sử dụng để thiết lập chế độ hoạt động cho Timer 1.

Các bit M1 và M0 được sử dụng để thiết lập chế độ hoạt động cho các bộ Timer/Counter.
Các chế độ hoạt động của Timer/Counter được mô tả như sau:

-
Bit C/T được sử dụng để chọn xung clock.
-
Khi bit C/T = 0, bộ Timer/Counter hoạt động dựa vào xung clock nội (bên trong vi điều khiển). Tần số của xung clock này được tính bằng 1/12 của tần số thạch anh. Ví dụ: nếu sử dụng thạch anh 12MHz, tần số của Timer/Counter sẽ là (1/12)*12MHz = 1MHz.
-
Khi bit C/T = 1, bộ Timer/Counter hoạt động dựa vào xung clock từ bên ngoài (đưa vào trên một chân nào đó).
-
Bit GATE được sử dụng để xác định việc điều khiển khởi động/dừng hoạt động của bộ Timer.
-
Nếu GATE = 0, bộ Timer/Counter được khởi động bằng cách set bit TRx lên 1 (TR0 cho Timer/Counter 0, TR1 cho Timer/Counter 1). Bộ Timer/Counter dừng hoạt động nếu bit TRx được xóa về 0.
-
Nếu GATE = 1, bộ Timer/Counter được khởi động bằng cách set bit TRx lên 1 và chân INTx được set lên mức 1. Nếu TRx không được set lên 1 hoặc chân INTx không được set lên 1, bộ Timer/Counter sẽ dừng hoạt động.
Trong phạm vi bài học này, chúng ta sẽ viết các chương trình với bit GATE = 0, có nghĩa là không cần khởi động và dừng các bộ định thời bằng phần cứng từ bên ngoài.
2.3. Thanh ghi điều khiển và trạng thái: TCON.
Thanh ghi TCON đã được đề cập trong bài viết trước với các bit được sử dụng để thiết lập chế độ cho ngắt ngoài. Trong bài viết này, chúng ta sẽ tiếp tục tìm hiểu thanh ghi TCON với các bit sử dụng cho Timer/Counter.
- Có 4 bit trong thanh ghi TCON được sử dụng cho bộ Timer/Counter.
- Có 2 bit để điều khiển khởi động/dừng hoạt động của Timer/Counter:
- Bit TR0 dùng để khởi động/dừng Timer/Counter 0. TR0 = 1: khởi động, TR0 = 0: dừng.
- Bit TR1 dùng để khởi động/dừng Timer/Counter 1. TR1 = 1: khởi động, TR1 = 0: dừng.
- Có 2 bit cờ báo trạng thái tràn của bộ Timer/Counter:
- Bit TF0 báo tràn cho Timer/Counter 0. Khi giá trị trong thanh ghi chứa giá trị đếm TL0, TH0 bị tràn, bit TF0 sẽ được bật lên 1.
- Bit TF1 báo tràn cho Timer/Counter 1. Khi giá trị trong thanh ghi chứa giá trị đếm TL1, TH1 bị tràn, bit TF1 sẽ được bật lên 1.
- Cả hai bit TF0 và TF1 đều được bật bằng phần cứng và phải được xóa bằng phần mềm.
III. Các bước thiết lập cho Timer/Counter trong 8051.
Để sử dụng bộ Timer/Counter trong 8051, chúng ta cần thực hiện các bước sau:
-
Gán giá trị cho thanh ghi TMOD để thiết lập chế độ hoạt động cho bộ Timer/Counter. Ví dụ: nếu bạn muốn sử dụng Timer/Counter 0 ở chế độ 16 bit (M1 = 0, M0 = 1), sử dụng nguồn clock nội (C/T = 0), bạn sẽ gán giá trị 0x01 cho thanh ghi TMOD (TMOD = 0x01).
-
Khởi tạo giá trị cho thanh ghi chứa giá trị đếm TLx, THx.
- Mặc định, giá trị của hai thanh ghi TLx, THx sẽ là 0. Điều này có nghĩa là khi Timer/Counter hoạt động, bộ đếm sẽ đếm từ 0 đến 65535 (với chế độ 16 bit) trước khi xảy ra tràn. Tức là bộ đếm sẽ đếm được (65535 – 0 + 1 = 65536 lần) trước khi xảy ra tràn. Tuy nhiên, trong trường hợp bạn chỉ muốn bộ đếm đếm 100 lần trước khi tràn, bạn cần gán giá trị cho TLx, THx. Ví dụ: để bộ đếm đếm được 100 lần trước khi tràn (65536 – 100 = 65436), bạn cần gán giá trị TLx = 0x9C và THx = 0xFF.
-
Bật bit TRx để khởi động bộ Timer/Counter.
Như vậy, chúng ta đã tìm hiểu về Timer/Counter, các thanh ghi và cách thiết lập chúng. Tiếp theo, chúng ta sẽ tìm hiểu về hoạt động của Timer/Counter qua các ví dụ cụ thể để hiểu rõ hơn.
IV. Một số ví dụ
Giả sử bạn muốn tạo xung có tần số 2KHz trên chân P2.0, trong đó độ rộng mức 1 chiếm 70% và độ rộng mức 0 chiếm 30%. Biết rằng mạch sử dụng thạch anh có tần số 12MHz.
- Do mạch sử dụng thạch anh có tần số 12MHz, tần số xung nhịp cấp cho bộ Timer/Counter là (1/12)*12=1MHz (mỗi xung clock mất 1us).
- Yêu cầu xung có tần số f = 2KHz, tức là T = 1/f = 0.5ms = 500us. Để đạt được điều này, bộ Timer/Counter cần đếm 500 lần.
- Độ rộng mức 1 chiếm 70%, vì vậy ta sẽ set chân P2.0 lên 1 và cho đếm 350 lần.
- Độ rộng mức 0 chiếm 30%, sau đó ta sẽ clear chân P2.0 về 0 và cho đếm 150 lần.
Dưới đây là hình vẽ để bạn hình dung rõ hơn:

Ở đây, tôi sẽ chọn Timer/Counter 0 để thực hiện bài toán này. Vì giá trị gán cho thanh ghi đếm vượt quá 255, nên tôi sẽ sử dụng Timer/Counter 0 ở chế độ 16 bit (TMOD = 0x01).
Dưới đây là đoạn code thực hiện tạo xung:
#include <8051.h>
void main() {
TMOD = 0x01; // Chế độ 16 bit cho Timer/Counter 0
TL0 = 0xF0; // Gán giá trị cho thanh ghi TL0
TH0 = 0xD8; // Gán giá trị cho thanh ghi TH0
TR0 = 1; // Khởi động Timer/Counter 0
while (1) {
// Gắn chân P2.0 lên 1 và đếm 350 lần
P2_0 = 1;
for (int i = 0; i < 350; i++);
// Clear chân P2.0 về 0 và đếm 150 lần
P2_0 = 0;
for (int i = 0; i < 150; i++);
}
}
Trong đoạn code trên, tôi đã viết cụ thể ý nghĩa của từng lệnh, nên không cần giải thích thêm. Nếu bạn có bất kỳ điểm nào chưa rõ, xin vui lòng comment dưới bài viết.
Sau đây là kết quả mô phỏng:

Bộ định thời gian. (Tiếp tục…)
Để biết thêm thông tin về lập trình bộ định thời-bộ đếm với 8051, hãy truy cập website của HEFC.
Edited by HEFC
