Timer là một ngoại vi quan trọng của vi điều khiển. Timer về bản chất là một bộ đếm (counter) mà khi đạt đến một giá trị được cài đặt trước thì có thể tạo ra các sự kiện, biến cố nhất định – ví dụ như tạo Ngắt, đo thời gian, đo độ rộng của xung tín hiệu, đếm xung tín hiệu, tạo tín hiệu điều khiển PWM, khởi động các Timer cũng như các ngoại vi khác, phóng tên lửa, phóng tàu du hành vào vũ trụ và rất rất nhiều ứng dụng khác. Điều thú vị ở chỗ là tất các đều xảy ra ở cấp độ phần cứng, nghĩa là không có sự can thiệp của CPU.
Đối với vi điều khiển dòng STM32F103x được trang bị 4 timer 16 bit bao gồm:
- 3 Timer – TIM2, TIM3, TIM4 general – purpose (Trang 159 Reference manual)
- TIM1 là timer có nhiều chức năng đặc biệt hơn các Timer còn lại (advanced – control timers Trang 292 Reference manual)
Ngoài ra còn có 2 WatchDog Timer và 1 SysTick Timer mà chúng ta sẽ tìm hiểu sau.
Timer 16 bit là bộ đếm có thể đếm từ 0 đến 65535 (2^16 – 1), khi đạt tới giá trị 65535 thì bộ đếm sẽ tạo ra một tín hiệu ngắt hay sự kiện gì đó đồng thời quay trở về giá trị 0 và bắt đầu đếm lại từ đầu.
Tất cả các Timer hoạt động độc lập và không phụ thuộc vào nhau. Timer đếm tick từ tần số xung nhịp của hệ thống cho nên không tiêu tốn tài nguyên. Nếu như vi điều khiển STM32F103C8T6 của chúng ta làm việc với xung nhịp là 72MHz (nghĩa là 72 000 000 xung trong 1s) thì Timer 16 bit sẽ đạt tới giá trị 65535 trong vòng (1/72000000) * 65536 = 0,9 ms.
Trong bài viết ngày hôm nay chúng ta sẽ sử dụng ngắt để minh họa một trong số những ứng dụng của Timer.
Bài toán đặt ra: sử dụng ngắt Timer để nháy 2 đèn Led với chu kỳ một Led 500ms và Led còn lại 1s. Chúng ta sẽ sử dụng Timer1 cho ứng dụng.
Các bạn mở STM32CubeMX, thiết lập Clock Configuration như các bài trước, chọn xung nhịp cho vi điều khiển là 72MHz. Tiếp theo trong mục Timer các bạn chọn Timer1, sau đó việc đầu tiên cần làm là chọn nguồn xung nhịp cho Timer. Clock Source -> Internal Clock, nghĩa là chúng ta chọn nguồn xung nhịp cho Timer chính là xung nhịp của vi điều khiển với tần số 72MHz.

Internal Clock là nguồn xung nhịp bên trong và tần số lấy từ Bus APB, mỗi Timer sẽ có nguồn xung nhịp lấy từ APB1 hoặc APB2, để biết Timer nào được cung cấp từ APB nào chúng ta dựa vào datasheet của vi điều khiển. Đối với STM32F103C8T6 tại trang 146 và 148 đã mô tả chi tiết những Timer nào lấy xung nhịp từ Bus APB2 và APB1, Timer1 tương ứng là APB2. Như trong Clock Configuration cấu hình xung nhịp cho Timer1 có tần số là 72Mhz.

Tiếp theo chúng ta đi đến cài đặt các giá trị cần thiết cho Timer1 như sau:

Prescaler – là một counter, có nhiệm vụ đếm đến giá trị được cài đặt thì quay về 0 và tiếp tục lặp lại chu kỳ trước. Mỗi lần counter này đạt đến giá trị cài đặt thì Timer của chúng ta sẽ đếm thêm 1 đơn vị. Giá trị cài đặt luôn là N-1, tại vì counter sẽ đếm từ 0, như hình trên giá trị Prescaler là giá trị nguyên 16 bit được cài đặt trị số: 720-1, có nghĩa là cứ 720 tick thì Timer sẽ đếm thêm 1 đơn vị, nghĩa là tần số của Timer sẽ là 72 000 000 / 720 = 100 000 Hz.
Counter Mode: Up – counter sẽ đếm từ 0 cho đến giá trị cài đặt
Down – counter sẽ đếm từ cao (từ giá trị cài đặt) xuống đến 0
Chế độ Center Aligned chúng ta sẽ tìm hiểu sau.
Counter Period: đây là giá trị cài đặt cho Counter hay còn gọi là giá trị tràn của Counter. Như trong ví dụ, Counter Timer sẽ đếm đến giá trị 50000 sau đó sẽ quay về 0 và lặp lại chu kỳ đếm. Với tần số là 100 000 Hz thì Timer sẽ đếm 50000 trong vòng 50000 * 1/100 000 = 500ms
Các chức năng khác các bạn không thay đổi, để nguyên các giá trị mặc định nhé.
Tiếp theo cho phép Ngắt Timer hoạt động

Cấu hình chân của vi điều khiển với 2 Led như sau

Chọn chân PA8, PA9 là 2 chân output tương ứng với Led1 và Led2. Cách kết nối Led tới chân vi điều khiển như các bài viết trước.
Sau khi generate code, đầu tiên chúng ta cần phải cho phép Timer chạy ở chế độ Ngắt, trước vòng lặp while các bạn gọi hàm sau:

Tiếp theo là hàm gọi callback khi có Ngắt xảy ra

Trong hàm callback này, chúng ta sẽ nháy 2 đèn led với chu kỳ khác nhau là 500ms và 1s.
Như tính toán ở trên, hiện tại Timer1 đang tràn với chu kỳ là 500ms, cứ 500ms hàm callback sẽ được kích hoạt, và mỗi khi hàm này được gọi chúng ta sẽ thay đổi trạng thái của Led1. Để thay đổi trạng thái của Led2 với chu kỳ 1ms, các bạn cần thay đổi trạng thái Led khi mà hàm callback được gọi 2 lần của chu kỳ 500ms. Chúng ta bổ sung một biến đếm vào hàm callback như đoạn code trên.
Kết quả sau khi nạp code vào vi điều khiển, hai đèn Led thay đổi trạng thái với chu kỳ như dự tính.https://youtube.com/shorts/R44fiD2Z5hg?feature=share
Như vậy trong bài viết ngày hôm nay, chúng ta đã sử dụng Ngắt của Timer để minh họa một ví dụ thay đổi trạng thái của 2 Led với chu kỳ khác nhau. Trong bài viết tiếp theo chúng ta sẽ cùng nhau tìm hiểu tiếp về các chức năng khác của Timer để giải quyết bài toán.


Bình luận về bài viết này