Nội Dung Bài Viết
Trong lập trình vi điều khiển STM32 thanh ghi, Cấu hình timer mode là một trong những chức năng quan trọng nhất, được sử dụng để tạo delay chính xác, đo thời gian, tạo ngắt định kỳ, PWM, encoder và nhiều ứng dụng thời gian thực khác.
Trong bài viết này, chúng ta sẽ lập trình STM32F103RCT6 ở mức thanh ghi (bare-metal) để cấu hình Timer mode STM32F103, cụ thể là TIM2 tạo ngắt mỗi 1ms.
Từ đó xây dựng biến millis tương tự Arduino và sử dụng nó để đếm thời gian chính xác theo giây, điều khiển LED nhấp nháy 1Hz.
👉 Bài viết tập trung vào:
- Hiểu bản chất Timer mode STM32F103
- Cách tính Prescaler (PSC) và Auto Reload Register (ARR)
- Cơ chế ngắt Timer (Timer Interrupt)
- Kiểm chứng độ chính xác thời gian trong thực tế
Tổng quan về Timer Mode trên STM32F103
STM32F103RCT6 sở hữu nhiều timer đa năng, trong đó TIM2 là timer 32-bit, hỗ trợ các chế độ:
- Đếm lên (up-counter)
- Đếm xuống (down-counter)
- Center-aligned mode
Timer mode STM32F103 thường được sử dụng để tạo sự kiện định kỳ, giúp vi điều khiển xử lý tác vụ theo thời gian mà không cần polling liên tục, từ đó tiết kiệm tài nguyên CPU.
Trong bài viết này, chúng ta tập trung vào chế độ cơ bản nhất: tạo ngắt định kỳ 1ms với tần số hệ thống 72MHz, rất phù hợp cho:
- Xây dựng hàm
millis - Delay chính xác
- Đồng bộ thời gian
- Scheduler đơn giản
Giới thiệu Timer 2 (TIM2)
Timer 2 (TIM2) là một timer 32-bit trên STM32F103RCT6, được sử dụng để tạo ngắt định kỳ.
Cấu hình cơ bản:
- Bật clock:
RCC->APB1ENR.TIM2EN = 1 - Prescaler:
PSC = 71→ 72MHz / 72 = 1MHz - Auto Reload:
ARR = 999→ 1kHz = 1ms - Kích hoạt ngắt khi đếm xong một chu kỳ
Mục tiêu cấu hình Timer Mode STM32F103
Cấu hình TIM2 với Timer mode STM32F103 với các yêu cầu:
- TIM2 tạo ngắt mỗi 1ms
- Sử dụng clock hệ thống 72MHz
- Tăng biến
millistrong hàm ngắt - Dùng
millisđể đếm 1 giây (1000ms) và toggle LED
Define struct các thanh ghi TIMx cho hướng dẫn lập trình STM32F103 thanh ghi
Dựa trên RM0008, Section 15.4 (trang 404-408):
Define struct TIMx Control Register 1

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // Thanh ghi Điều khiển 1 của TIM (TIM Control Register 1) typedef union { struct { __IOM uint32_t CEN : 1; // Bit 0: Counter enable __IOM uint32_t UDIS : 1; // Bit 1: Update disable __IOM uint32_t URS : 1; // Bit 2: Update request source __IOM uint32_t OPM : 1; // Bit 3: One-pulse mode __IOM uint32_t DIR : 1; // Bit 4: Counter direction __IOM uint32_t CMS : 2; // Bit 5-6: Center-aligned mode __IOM uint32_t ARPE : 1; // Bit 7: Auto-reload preload enable __IOM uint32_t CKD : 2; // Bit 8-9: Clock division uint32_t reserved : 22; // Bit 10-31: Reserved }; __IOM uint32_t reg; } TIM_CR1_Type; |
Define struct TIMx Slave Mode Control Register

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // Thanh ghi Điều khiển Chế độ Slave của TIM (TIM Slave Mode Control Register) typedef union { struct { __IOM uint32_t SMS : 3; // Bit 0-2: Slave mode selection uint32_t reserved0 : 1; // Bit 3: Reserved __IOM uint32_t TS : 3; // Bit 4-6: Trigger selection __IOM uint32_t MSM : 1; // Bit 7: Master/slave mode __IOM uint32_t ETF : 4; // Bit 8-11: External trigger filter __IOM uint32_t ETPS : 2; // Bit 12-13: External trigger prescaler __IOM uint32_t ECE : 1; // Bit 14: External clock enable __IOM uint32_t ETP : 1; // Bit 15: External trigger polarity uint32_t reserved1 : 16; // Bit 16-31: Reserved }; __IOM uint32_t reg; } TIM_SMCR_Type; |
Define struct TIMx Status Register

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | // Thanh ghi Trạng thái của TIM (TIM Status Register) typedef union { struct { __IOM uint32_t UIF : 1; // Bit 0: Update interrupt flag __IOM uint32_t CC1IF : 1; // Bit 1: Capture/compare 1 interrupt flag __IOM uint32_t CC2IF : 1; // Bit 2: Capture/compare 2 interrupt flag __IOM uint32_t CC3IF : 1; // Bit 3: Capture/compare 3 interrupt flag __IOM uint32_t CC4IF : 1; // Bit 4: Capture/compare 4 interrupt flag uint32_t reserved0 : 1; // Bit 5: Reserved __IOM uint32_t TIF : 1; // Bit 6: Trigger interrupt flag uint32_t reserved1 : 2; // Bit 7-8: Reserved __IOM uint32_t CC1OF : 1; // Bit 9: Capture/compare 1 overcapture flag __IOM uint32_t CC2OF : 1; // Bit 10: Capture/compare 2 overcapture flag __IOM uint32_t CC3OF : 1; // Bit 11: Capture/compare 3 overcapture flag __IOM uint32_t CC4OF : 1; // Bit 12: Capture/compare 4 overcapture flag uint32_t reserved2 : 19; // Bit 13-31: Reserved }; __IOM uint32_t reg; } TIM_SR_Type; |
Bản đồ thanh ghi TIMx (TIMx register map)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // Bản đồ thanh ghi TIM (15.4.19 TIMx register map – Trang 423) typedef struct { TIM_CR1_Type CR1; // 0x00: Control 1 __IO uint32_t CR2; // 0x04: Control 2 TIM_SMCR_Type SMCR; // 0x08: Slave mode control __IO uint32_t DIER; // 0x0C: DMA/interrupt enable TIM_SR_Type SR; // 0x10: Status __O uint32_t EGR; // 0x14: Event generation __IO uint32_t CCMR1; // 0x18: Capture/compare mode 1 __IO uint32_t CCMR2; // 0x1C: Capture/compare mode 2 __IO uint32_t CCER; // 0x20: Capture/compare enable __IO uint32_t CNT; // 0x24: Counter value __IO uint32_t PSC; // 0x28: Prescaler __IO uint32_t ARR; // 0x2C: Auto-reload __IO uint32_t RCR; // 0x30: Repetition counter __IO uint32_t CCR1; // 0x34: Capture/compare 1 __IO uint32_t CCR2; // 0x38: Capture/compare 2 __IO uint32_t CCR3; // 0x3C: Capture/compare 3 __IO uint32_t CCR4; // 0x40: Capture/compare 4 __IO uint32_t BDTR; // 0x44: Break and dead-time __IO uint32_t DCR; // 0x48: DMA control __IO uint32_t DMAR; // 0x4C: DMA address } TIM_TypeDef; |
#define TIM2 ((TIM_TypeDef *)0x40000000UL)
Giải thích:
- CR1: Điều khiển bộ đếm (CEN, DIR, ARPE; Section 15.4.1, trang 404).
- SMCR: Chọn chế độ slave và trigger (SMS, TS; Section 15.4.3, trang 407).
- SR: Cờ trạng thái (UIF, CCxIF; Section 15.4.5, trang 410).
Clock Timer và bus APB1
Timer mode STM32F103 hoạt động dựa trên clock từ bus APB1.
Với cấu hình:
- SYSCLK = 72MHz
- APB1 prescaler = 1
➡️ Clock cấp cho TIM2 là 72MHz
Lưu ý: Nếu APB1 prescaler ≠ 1, clock timer sẽ được nhân đôi theo quy tắc trong RM0008.
Bật clock cho TIM2
Thanh ghi RCC->APB1ENR điều khiển clock cho các ngoại vi trên bus APB1, trong đó TIM2 thuộc nhóm này.
Đặt bit TIM2EN = 1 để bật clock cho TIM2.
⚠️ Nếu không bật clock, timer sẽ không hoạt động, counter không tăng – đây là lỗi rất thường gặp khi lập trình STM32 thanh ghi.
Cấu hình Prescaler (PSC)

Vai trò Prescaler
Prescaler chia tần số clock đầu vào của timer để tạo tần số đếm thấp hơn.
Tính toán Prescaler
- Clock TIM2 = 72MHz
- Chọn
PSC = 71
Công thức:
➡️ Sau prescaler, timer đếm với chu kỳ 1µs (1MHz).
Lưu ý: Giá trị PSC chỉ được cập nhật khi có update event, vì vậy nên set PSC trước khi bật timer.
Cấu hình Auto Reload Register (ARR)

Vai trò ARR
ARR xác định giá trị tối đa mà timer đếm tới trước khi:
- Tràn
- Reload về 0
- Tạo update event (và ngắt nếu được bật)
Tính toán ARR
- Chu kỳ đếm = 1µs
- 1ms = 1000µs
Vì timer đếm từ 0 → ARR:
➡️ Timer đếm từ 0 đến 999 → đúng 1ms cho mỗi chu kỳ.
Kích hoạt ngắt Timer
Thanh ghi DIER (DMA/Interrupt Enable Register) điều khiển các nguồn ngắt của timer.
Bit 0:
UIE– Update Interrupt Enable
Update event xảy ra khi timer tràn từ ARR về 0, tức là mỗi 1ms trong cấu hình này.
Bật Timer
Thanh ghi CR1 điều khiển hoạt động của timer.
- Bit
CEN = 1→ bật bộ đếm
Sau khi bật:
- Timer bắt đầu đếm từ 0
- Mỗi 1µs tăng 1
- Khi đạt 999 → tràn → tạo ngắt
Cơ chế hoạt động của Timer Mode STM32F103
- TIM2 đếm từ 0 → 999
- Mỗi lần đếm = 1µs
- Sau 1000 lần (1ms):
- Cờ
UIFtrongTIM2->SRđược set - Nếu
UIE = 1→ CPU nhảy vàoTIM2_IRQHandler()
- Cờ
⚠️ Trong hàm ngắt bắt buộc phải xóa cờ UIF, nếu không ngắt sẽ lặp vô hạn.
Code cấu hình Timer 2 (1ms Interrupt)
1 2 3 4 5 6 7 8 9 10 | void TIM2_Timer_Config(void) { // Enable TIM2 clock (RM0008, Section 7.3.8, page 115) RCC->APB1ENR.TIM2EN = 1; // Configure TIM2 for 1ms interrupts TIM2->PSC = 71; // Prescaler: 72MHz / 72 = 1MHz TIM2->ARR = 999; // Auto-reload: 1MHz / 1000 = 1kHz TIM2->DIER |= (1 << 0); // Enable update interrupt TIM2->CR1.CEN = 1; // Enable counter } |
Hàm ngắt TIM2
1 2 3 4 5 6 7 8 | void TIM2_IRQHandler(void) { // Check UIF flag if (TIM2-> SR.UIF) { TIM2->SR.UIF = 0; // Remove flag millis++; } } |
Ứng dụng: Đếm thời gian 1 giây và nhấp nháy LED
Ý tưởng
- TIM2 tạo ngắt mỗi 1ms → tăng
millis - So sánh
millisvới mốc thời gian - Mỗi 1000ms → tăng biến đếm giây và toggle LED
Code main
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | uint32_t countevery1second = 0; int main(void) { SystemClock_Config(); // Initialize system clock GPIO_LED_Config(); GPIO_Button_Config(); SysTick_Config_1ms(); TIM2_Timer_Config(); NVIC_Interrupt_Enable(TIM2_IRQ); NVIC_Set_Interrupt_Priority(TIM2_IRQ, 5); uint32_t startTimer = millis; while (1) { if (millis - startTimer >= 1000) { startTimer = millis; countevery1second++; LED_Toggle(); } } } |
Mức ưu tiên 5 là mức trung bình, thấp hơn các ngắt thời gian quan trọng như SysTick (nếu sử dụng).
Link Github: Download chương trình cấu hình STM32F103 timer mode 1ms TIM2
Ý nghĩa chương trình
- Timer mode STM32F103 tạo tick 1ms chính xác
millislà bộ đếm thời gian toàn cụccountevery1second:- Đếm số giây đã trôi qua
- Dùng để kiểm chứng độ chính xác timer
- LED nhấp nháy 1Hz
NVIC_Interrupt_Enable(TIM2_IRQ): cho phép CPU nhận ngắt từ TIM2NVIC_Set_Interrupt_Priority(28, 5): Đặt mức ưu tiên 5 cho ngắt từ TIM2
Kiểm chứng thực tế (Real Test)

- Thời điểm bắt đầu: 12:03:00

- Thời điểm sau 2 phút: 12:05:00
- Giá trị
countevery1second = 120
➡️ Timer 2 hoạt động chính xác trong 120 giây, sai số gần như bằng 0.
Kết luận
Qua bài viết này, bạn đã nắm vững:
- Cách cấu hình Timer mode trong lập trình STM32F103 bằng thanh ghi
- Hiểu rõ PSC, ARR và cơ chế update interrupt
- Tự xây dựng hệ thống đo thời gian 1ms / 1s
- Kiểm chứng timer trong điều kiện thực tế
Đây là nền tảng quan trọng để phát triển các ứng dụng thời gian thực trên STM32 như scheduler, delay không blocking hoặc RTOS.
