Timer trong STM32: Prescaler, Auto Reload Value chi tiết

Timer trong STM32 là ngoại vi cực kỳ quan trọng, cho phép đếm thời gian chính xác, tạo ngắt theo chu kỳ, phát xung PWM hay đo tín hiệu đầu vào. Bài viết này tập trung vào cơ chế time base của Timer: ba khái niệm cốt lõi Timer Clock, Prescaler và Auto Reload Value, công thức tính thời gian và ví dụ cấu hình TIM4. Nếu bạn muốn tìm hiểu sâu về cơ chế ngắt (EXTI, NVIC, độ ưu tiên), hãy xem bài Ngắt trong STM32 (EXTI, Timer, UART Interrupt).

Timer trong STM32 là gì?

Hiểu một cách đơn giản, Timer là một mạch digital logic có vai trò đếm mỗi chu kỳ clock (đếm lên hoặc đếm xuống). Timer còn có thể hoạt động ở chế độ Counter – nhận xung clock từ tín hiệu bên ngoài (ví dụ một nút nhấn), bộ đếm tăng sau mỗi lần bấm (sườn lên hoặc sườn xuống tùy cấu hình).

Khi giá trị trong thanh ghi đếm của Timer tràn (đạt tới giá trị nạp sẵn), Timer sẽ sinh ra một sự kiện Update – thường được dùng để tạo ngắt Timer theo chu kỳ. Vì đây là ngắt nội trong MCU nên thanh ghi đếm sẽ tự nạp lại (auto reload) để tạo chu kỳ tiếp theo.

Ngoài chế độ time base, Timer còn nhiều chế độ hoạt động khác (sẽ có bài viết riêng cho từng chế độ):

  • PWM Mode / Advanced PWM Mode
  • Output Compare Mode
  • One-Pulse Mode
  • Input Capture Mode
  • Encoder Mode
  • Timer Gate Mode
  • Timer DMA Burst Mode
  • IRTIM Infrared Mode

Các Timer trên STM32F103C8

STM32F103C8 có tất cả 7 timer, trong đó đã bao gồm 1 SysTick timer và 2 Watchdog timer. Như vậy chỉ còn lại 4 timer dùng cho các chức năng như ngắt, time base, PWM, Encoder, Input Capture… Trong đó:

  • TIM1 là Timer đặc biệt, chuyên dụng cho việc xuất xung với đầy đủ các mode xuất xung và mode bảo vệ. TIM1 thuộc khối clock APB2.
  • TIM2, TIM3, TIM4 thuộc nhóm clock APB1.

Ba khái niệm cốt lõi: Timer Clock, Prescaler, Auto Reload

Timer Clock

Khi không cấu hình gì liên quan đến clock và đã gắn đúng thạch anh ngoài trên chân PD0(5) và PD1(6), clock tương ứng của TIM1, TIM2, TIM3, TIM4 đã là 72 MHz. Cần ghi nhớ: sử dụng timer nào thì phải cấp clock cho timer đó theo đúng nhánh clock (APB1 hoặc APB2).

Prescaler (bộ chia tần số)

Prescaler là bộ chia tần số của timer, có giá trị tối đa 16 bit (tương ứng 65535) và có thể thay đổi bằng lập trình. Tần số sau bộ chia được tính:

fCK_CNT = fCK_PSC / (PSC + 1)

  • fCK_CNT: tần số sau bộ chia.
  • fCK_PSC: tần số clock đầu vào cấp cho timer.
  • PSC: giá trị nạp vào bộ chia, được lập trình bằng phần mềm.

Auto Reload Value (ARR)

Auto Reload Value là giá trị bộ đếm tối đa nạp vào cho timer, cũng có độ rộng tối đa 16 bit (65535). Khi bộ đếm đếm tới giá trị này thì tràn và sinh ra ngắt Update. Từ các thông số trên, ta có công thức tính tần số/thời gian ngắt tràn cuối cùng:

FTIMER = fSYSTEM / [ (PSC + 1) × (Period + 1) ]

  • FTIMER: tần số ngắt tràn của timer, đơn vị Hz.
  • fSYSTEM: tần số clock hệ thống cấp cho timer, đơn vị Hz.
  • PSC: giá trị nạp vào bộ chia tần số (tối đa 65535).
  • Period: giá trị bộ đếm nạp vào timer (tối đa 65535).

Cấu hình Timer trong STM32

Tương tự các ngoại vi khác, ta cần xác định clock cấp cho timer, khai báo tham số trong struct TIM_TimeBaseInitTypeDef, cuối cùng gọi TIM_TimeBaseInit() để khởi tạo. Ví dụ cấu hình TIM4 tạo ngắt tràn mỗi 1 giây:

/* Cấp clock cho TIM4 (nhánh APB1) */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);

/* TIM4 Configuration */
TIM_TimeBaseInitStructure.TIM_Prescaler   = 7199;
TIM_TimeBaseInitStructure.TIM_Period      = 9999;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseInitStructure);

TIM_ClearFlag(TIM4, TIM_FLAG_Update);          /* Xóa cờ update */
TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);     /* Cho phép ngắt Update */
TIM_Cmd(TIM4, ENABLE);                          /* Bật TIM4 */

Trong ví dụ trên, 7199 là giá trị PSC (Prescaler) và 9999 là Period (Auto Reload Value). Clock cấp cho TIM4 là 72 MHz. Thay vào công thức:

FTIMER = 72.000.000 / [ (7199 + 1) × (9999 + 1) ] = 72.000.000 / (7200 × 10000) = 1 Hz

Nghĩa là thời gian ngắt tràn đúng bằng 1 giây. Sau khi bật ngắt Update, bạn xử lý sự kiện trong hàm phục vụ ngắt TIM4_IRQHandler() (chi tiết cách viết ISR và cấu hình NVIC được trình bày trong bài Ngắt trong STM32).

Bảng ví dụ chọn PSC và Period

Với clock 72 MHz, một mẹo phổ biến là đặt PSC = 7199 để bộ đếm chạy ở 10 kHz (mỗi tick = 0,1 ms), sau đó chỉ cần đổi Period để có chu kỳ mong muốn:

Mục tiêuPSCPeriodKết quả
Ngắt mỗi 1 ms7199910 kHz → 10 tick = 1 ms
Ngắt mỗi 10 ms71999910 kHz → 100 tick = 10 ms
Ngắt mỗi 100 ms719999910 kHz → 1000 tick = 100 ms
Ngắt mỗi 1 s7199999910 kHz → 10000 tick = 1 s

Ứng dụng của Timer

Nắm vững time base là bước đệm để triển khai nhiều ứng dụng thực tế:

  • Tạo delay non-blocking: đếm mili-giây bằng ngắt Timer thay cho delay() chặn CPU.
  • Lập lịch tác vụ (scheduler): chạy các hàm định kỳ theo tick hệ thống.
  • PWM: điều khiển độ sáng LED, tốc độ động cơ, servo.
  • Input Capture: đo tần số/độ rộng xung tín hiệu đầu vào.
  • Encoder: đọc vị trí và chiều quay của encoder.

Kết luận

Qua bài viết, bạn đã nắm được ba khái niệm cốt lõi của Timer trong STM32Timer Clock (72 MHz), Prescaler (bộ chia tần số) và Auto Reload Value (giá trị đếm tối đa). Công thức FTIMER = fSYSTEM / [(PSC+1)(Period+1)] là chìa khóa để tính chính xác thời gian ngắt tràn – như ví dụ TIM4 với PSC = 7199 và Period = 9999 cho ngắt đúng 1 giây.

Đây là nền tảng để tiến tới các ứng dụng nâng cao như PWM điều khiển động cơ, Input Capture đo tần số hay Encoder đọc vị trí – những chức năng thường gặp trong automotive embedded. Các chế độ này sẽ được trình bày chi tiết ở những bài viết tiếp theo.

Leave a Reply