Skip to content

Công nghệ 9 giây

“Website hướng dẫn, thử nghiệm và giải thích công nghệ theo cách dễ hiểu cho mọi người.”

Menu
  • Home
  • Công nghệ
  • STM32
  • ESP32
  • Altium Desinger
  • Kiến thức điện máy
Menu

BÀI 38 – TIMER INPUT/OUTPUT COMPARE TRÊN STM32F103

Posted on August 23, 2026August 23, 2026 by congnghe9s

BÀI 38 – TIMER INPUT/OUTPUT COMPARE TRÊN STM32F103

Hiểu sâu CNT, PSC, ARR, CCR và cách Timer tự tạo sự kiện

Ở Bài 36–37, chúng ta đã dùng TIM2 để tạo:

TIM2
  ↓
1 ms
  ↓
Interrupt
  ↓
millis++
  ↓
Software Timer
  ↓
Nhiều task

Bây giờ chúng ta đi sâu hơn vào bản chất thật sự của Timer STM32.

Bài này đặc biệt quan trọng vì từ đây bạn sẽ gặp những khái niệm:

CNT
PSC
ARR
CCR
Input Capture
Output Compare
PWM

Và chúng liên kết với nhau thành một hệ thống rất mạnh.


1. Timer STM32 thực sự làm gì?

Đừng nghĩ Timer chỉ là:

“Một cái đồng hồ để tạo delay.”

Timer của STM32 thực chất là một bộ đếm phần cứng có khả năng tự phát hiện và tạo sự kiện.

Có thể hình dung:

Clock
  ↓
Prescaler
  ↓
Counter CNT
  ↓
Compare
  ↓
Capture / Output / Interrupt

CPU không nhất thiết phải liên tục kiểm tra Timer.


2. Bốn thanh ghi quan trọng

Trong bài này, hãy đặc biệt nhớ:

PSC
CNT
ARR
CCR

PSC – Prescaler

TIM2->PSC

Dùng để chia clock trước khi đưa vào bộ đếm.


CNT – Counter

TIM2->CNT

Là giá trị hiện tại của bộ đếm.


ARR – Auto Reload Register

TIM2->ARR

Quy định giới hạn đếm.


CCR – Capture/Compare Register

Ví dụ:

TIM2->CCR1

Dùng cho:

  • Output Compare
  • Input Capture
  • PWM

3. Mối quan hệ giữa chúng

Sơ đồ:

             TIM2 CLOCK
                 │
                 ▼
              PSC
                 │
                 ▼
             CNT tăng
                 │
          ┌──────┴──────┐
          │             │
          ▼             ▼
         ARR           CCR1
          │             │
          │             │
          ▼             ▼
     Update Event    Compare Event

Đây chính là cấu trúc quan trọng của Timer.


4. CNT là gì?

Giả sử:

TIM2->CNT

đang tăng:

0
1
2
3
4
5
6
...

Nếu:

TIM2->ARR = 999;

thì Timer đếm:

0 → 999

sau đó tạo Update Event và quay lại:

0

5. PSC quyết định tốc độ CNT

Ví dụ Timer clock:

72 MHz

Nếu:

TIM2->PSC = 7199;

thì:

[
72MHz/(7199+1)=10kHz
]

Tức:

CNT tăng 10.000 lần/giây

Mỗi bước:

100 µs

6. ARR quyết định chu kỳ

Nếu:

TIM2->ARR = 99;

thì:

100 ticks

Mỗi tick:

100 µs

Do đó:

[
100 \times 100\mu s=10ms
]

Timer tạo Update Event mỗi:

10 ms

7. CCR lại khác

Giả sử:

TIM2->CCR1 = 30;

Timer có:

CNT = 0
1
2
...
30

Khi:

CNT == CCR1

Timer phát hiện:

Compare Match

Đây gọi là:

Output Compare


8. So sánh ARR và CCR

Thanh ghi Ý nghĩa
PSC Chia clock
CNT Giá trị đếm hiện tại
ARR Mốc kết thúc chu kỳ
CCR1 Mốc so sánh

Ví dụ:

PSC = 7199
ARR = 99
CCR1 = 30

Timer:

CNT
0
│
│
30 ← Compare Event
│
│
99 ← Update Event
│
└──→ 0

9. Output Compare là gì?

Hiểu đơn giản:

Timer tự theo dõi CNT và khi CNT đạt đến CCR, nó tạo ra một sự kiện.

CPU không cần:

if (TIM2->CNT == 30)

liên tục.

Phần cứng Timer tự làm.

Đây là điểm cực kỳ quan trọng.


10. Tại sao điều này tốt hơn polling?

Cách polling:

while (1)
{
    if (TIM2->CNT >= 30)
    {
        DoSomething();
    }
}

CPU phải liên tục kiểm tra.

Output Compare:

CNT
 ↓
CCR
 ↓
Compare Event
 ↓
Hardware

Timer tự phát hiện.

Nếu bật interrupt:

Compare Event
      ↓
CC1 Interrupt
      ↓
TIM2_IRQHandler()

11. Thanh ghi CCR1

Với Channel 1:

TIM2->CCR1

Channel 2:

TIM2->CCR2

Channel 3:

TIM2->CCR3

Channel 4:

TIM2->CCR4

STM32F103 Timer có thể có nhiều Compare/Capture Channel.


12. Timer có thể có nhiều mốc thời gian

Ví dụ:

ARR = 999

và:

CCR1 = 100
CCR2 = 300
CCR3 = 500
CCR4 = 800

Một chu kỳ Timer:

0
│
100 ← CC1
│
300 ← CC2
│
500 ← CC3
│
800 ← CC4
│
999 ← Update
│
0

Đây là một khả năng rất mạnh.


13. Output Compare có thể tạo interrupt

Ta cần bật:

TIM2->DIER |= TIM_DIER_CC1IE;

CC1IE:

Capture/Compare 1 Interrupt Enable

Sau đó NVIC:

NVIC_EnableIRQ(TIM2_IRQn);

14. ISR

Trong ISR:

void TIM2_IRQHandler(void)
{
    if (TIM2->SR & TIM_SR_CC1IF)
    {
        TIM2->SR &= ~TIM_SR_CC1IF;

        // Compare event
    }
}

CC1IF:

Capture/Compare 1 Interrupt Flag.


15. Ví dụ: tạo sự kiện mỗi 10 ms

Ta cấu hình:

TIM2 clock = 72 MHz
PSC = 7199

→

10 kHz

Chọn:

ARR = 99;

→ chu kỳ:

10 ms

Nếu:

CCR1 = 50;

thì Compare xảy ra tại:

50 × 100 µs
= 5 ms

Timeline:

0 ms
│
├──────── 5 ms
│           ↑
│          CCR1
│           │
│           └── Compare Interrupt
│
├────────────────── 10 ms
                    ↑
                   ARR
                    │
                    └── Update Event

16. Đây là điểm rất hay

Một Timer có thể đồng thời tạo:

5 ms  → Compare Event
10 ms → Update Event

mà không cần hai Timer.


17. Ví dụ thực hành: Toggle LED bằng Compare Interrupt

Ta muốn:

TIM2
 ↓
Compare
 ↓
LED Toggle

Cấu hình:

TIM2->PSC = 7199;
TIM2->ARR = 999;
TIM2->CCR1 = 500;

Khi:

CNT == 500

CC1 interrupt xảy ra.


18. Nhưng có một vấn đề

Nếu:

ARR = 999
CCR1 = 500

thì Compare chỉ xảy ra một lần mỗi chu kỳ Timer.

Nếu muốn tạo sự kiện đều đặn, chúng ta có thể cập nhật:

TIM2->CCR1 += ...

Đây là một kỹ thuật rất quan trọng.


19. Output Compare theo kiểu “lập lịch”

Ví dụ Timer tick:

100 µs

Ta muốn event mỗi:

5 ms

5 ms tương đương:

50 ticks

Sau mỗi Compare:

TIM2->CCR1 += 50;

Timeline:

CCR1 = 50
   ↓
Compare
   ↓
CCR1 = 100
   ↓
Compare
   ↓
CCR1 = 150
   ↓
Compare
   ↓
CCR1 = 200

Timer phần cứng đang trở thành một scheduler chính xác theo tick.


20. Đây khác millis() thế nào?

millis():

TIM2
 ↓
mỗi 1 ms
 ↓
millis++
 ↓
CPU kiểm tra

Output Compare:

TIM2
 ↓
CNT == CCR
 ↓
Hardware Compare
 ↓
Interrupt

Output Compare cho phép:

Phần cứng lập lịch một sự kiện tại một thời điểm cụ thể của Timer.


21. Input Capture là gì?

Bây giờ chúng ta chuyển sang phần còn lại của bài:

Input Capture

Ý tưởng ngược lại.

Output Compare:

Timer → so sánh với CCR

Input Capture:

GPIO event → chụp giá trị CNT vào CCR

22. Hình dung

Giả sử một tín hiệu ngoài đi vào:

PA0
 │
 ▼
TIM2_CH1

Tín hiệu:

HIGH ──────┐      ┌──────
           │      │
LOW        └──────┘
           ↑
        cạnh lên

Khi cạnh xảy ra:

GPIO edge
   ↓
Timer Capture
   ↓
CCR1 = CNT

Timer chụp lại thời điểm xảy ra cạnh.


23. Đây là ý tưởng cực kỳ quan trọng

Ví dụ:

CNT = 1000

tín hiệu cạnh lên xảy ra.

Hardware tự động:

CCR1 = 1000

Sau đó:

CNT = 1500

cạnh tiếp theo:

CCR1 = 1500

Khoảng thời gian:

1500 - 1000 = 500 ticks

Ta đo được độ rộng/thời gian tín hiệu.


24. Input Capture dùng để làm gì?

Rất nhiều thứ:

  • đo tần số;
  • đo chu kỳ;
  • đo độ rộng xung;
  • đo PWM từ thiết bị khác;
  • đo thời gian Echo của HC-SR04;
  • đọc encoder;
  • đo tốc độ động cơ;
  • đo tín hiệu cảm biến.

Đặc biệt:

HC-SR04 mà bạn từng làm với robot chính là một ứng dụng rất phù hợp để hiểu Input Capture.


25. Ví dụ HC-SR04

HC-SR04 tạo:

TRIG
 ↓
phát siêu âm

Sau đó chân:

ECHO

có một xung HIGH.

Ví dụ:

ECHO

LOW ─────┐
         │
         └──────────────┐
                        │
                        └──── LOW
         ↑              ↑
      Rising          Falling

Ta có thể dùng Timer Input Capture:

Rising edge
    ↓
CCR1 = thời điểm bắt đầu

Falling edge
    ↓
CCR1 = thời điểm kết thúc

Sau đó:

[
t = t_{falling}-t_{rising}
]

Từ thời gian Echo:

[
Distance \approx \frac{t \times 0.0343}{2}
]

với t tính bằng microsecond.


26. Bạn thấy sự liên kết chưa?

Bài 38 đang chuẩn bị trực tiếp cho:

Timer
 ↓
Input Capture
 ↓
HC-SR04

Và sau đó:

Timer
 ↓
PWM
 ↓
Servo

và:

Timer
 ↓
PWM
 ↓
Motor

27. Timer Channel

Một Timer có các channel:

TIM2_CH1
TIM2_CH2
TIM2_CH3
TIM2_CH4

Mỗi channel có:

Capture/Compare Register

Ví dụ:

CH1 → CCR1
CH2 → CCR2
CH3 → CCR3
CH4 → CCR4

28. CCR là thanh ghi rất đa năng

Đây là điều bạn cần nhớ:

CCR
│
├── Output Compare
│
├── Input Capture
│
└── PWM

Tùy chế độ Timer Channel.


29. Bây giờ hãy hiểu sâu hơn về PWM

PWM mà bạn sẽ học sau này cũng dựa trên:

CNT
ARR
CCR

Ví dụ:

ARR = 999
CCR1 = 250

Có thể tạo:

Duty ≈ 25%

Nếu:

CCR1 = 500

thì:

Duty ≈ 50%

Nếu:

CCR1 = 750

thì:

Duty ≈ 75%

30. Một hình ảnh tư duy cực kỳ quan trọng

Hãy tưởng tượng:

              ARR
               │
               ▼
0 ───────────────────────── 999
│
│─────── CCR1
│
└───────────────

ARR quyết định:

chu kỳ

CCR quyết định:

mốc so sánh / độ rộng xung tùy chế độ

Đây chính là nền tảng của PWM.


31. Tổng hợp Timer

Bạn có thể nhớ bằng bảng:

Thành phần Chức năng
PSC Chia clock
CNT Bộ đếm
ARR Chu kỳ
CCR Mốc Capture/Compare
Update CNT đạt ARR
Compare CNT đạt CCR
Capture GPIO event → lưu CNT
PWM Dùng CNT + CCR để tạo xung

32. Thí nghiệm Output Compare đơn giản

Bây giờ chúng ta tạo:

TIM2
 ↓
Compare CH1
 ↓
Interrupt
 ↓
Toggle PC13

Mục tiêu:

LED toggle mỗi 100 ms

33. Tính Timer

Giữ:

TIM2 = 72 MHz
PSC = 7199

Timer tick:

100 µs

Muốn:

100 ms

cần:

1000 ticks

Có thể:

ARR = 9999;

nhưng khi dùng Compare, ta có thể chọn mốc CCR.

Ví dụ:

CCR1 = 1000;

→ Compare tại:

100 ms

nếu CNT bắt đầu từ 0 và tick 100 µs.


34. Code minh họa Output Compare

#include "stm32f10x.h"

void GPIO_Init(void)
{
    RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;

    /* PC13 output */
    GPIOC->CRH &= ~(0xF << 20);
    GPIOC->CRH |=  (0x2 << 20);
}

void TIM2_OC_Init(void)
{
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;

    /*
        TIM2 = 72 MHz

        72 MHz / 7200
        = 10 kHz

        1 tick = 100 us
    */

    TIM2->PSC = 7199;

    /*
        Timer period = 1 second
        10000 ticks
    */

    TIM2->ARR = 9999;

    /* First compare after 100 ms */
    TIM2->CCR1 = 1000;

    /* Enable CC1 interrupt */
    TIM2->DIER |= TIM_DIER_CC1IE;

    NVIC_SetPriority(TIM2_IRQn, 2);
    NVIC_EnableIRQ(TIM2_IRQn);

    TIM2->CNT = 0;

    TIM2->CR1 |= TIM_CR1_CEN;
}

void TIM2_IRQHandler(void)
{
    if (TIM2->SR & TIM_SR_CC1IF)
    {
        TIM2->SR &= ~TIM_SR_CC1IF;

        GPIOC->ODR ^= (1 << 13);

        /*
           Schedule next compare
           100 ms later
        */

        TIM2->CCR1 += 1000;
    }
}

int main(void)
{
    GPIO_Init();

    TIM2_OC_Init();

    while (1)
    {
    }
}

35. Nhưng hãy chú ý một vấn đề

Ở đây:

TIM2->CCR1 += 1000;

sẽ tạo:

100 ms
200 ms
300 ms
400 ms
...

cho đến khi:

CNT

và:

CCR1

quay vòng theo Timer.

Với:

ARR = 9999

sau 1 giây:

CNT → 0

và CCR1 cũng cần được quản lý phù hợp.

Trong bài học đầu tiên, điều quan trọng nhất là hiểu cơ chế:

Compare Event xảy ra khi CNT đạt CCR.


36. Một cách đơn giản hơn để học

Chúng ta có thể đặt:

ARR = 999;
CCR1 = 500;

và quan sát:

CNT = 0
   ↓
CNT = 500
   ↓
CC1 interrupt
   ↓
CNT = 999
   ↓
Update
   ↓
CNT = 0

Đây là mô hình dễ hiểu nhất.


37. So sánh ba kỹ thuật

Polling

CPU → đọc CNT → đọc CNT → đọc CNT

Interrupt

Timer → Event → CPU ISR

Hardware Output

Timer → Event → GPIO hardware

Càng về sau:

CPU càng ít phải can thiệp.

Đây là xu hướng rất quan trọng trong thiết kế embedded.


38. Ví dụ cao hơn

Trong PWM:

CPU
 ↓
CCR = giá trị mới
 ↓
Timer tự tạo PWM
 ↓
GPIO

CPU không cần:

ON
delay
OFF
delay
ON
delay

Phần cứng Timer tự làm.

Đây là lý do PWM bằng Timer tốt hơn rất nhiều so với tự viết GPIO bằng software.


39. Từ đây bạn sẽ gặp CCER

Khi đi sâu vào Input Capture/Output Compare, bạn sẽ gặp:

TIM2->CCER

Capture/Compare Enable Register.

Nó quyết định channel:

  • enable/disable;
  • polarity;
  • input/output configuration.

Ví dụ khái niệm:

CC1E

cho phép Channel 1.

Và:

CC1P

liên quan đến polarity.

Chúng ta sẽ học kỹ ở bài chuyên sâu hơn, chưa cần học thuộc ngay hôm nay.


40. Tại sao bài 38 quan trọng?

Vì từ đây:

Timer

không còn chỉ là:

delay

mà trở thành:

Timer
 ├── Time base
 ├── Interrupt
 ├── Output Compare
 ├── Input Capture
 └── PWM

Một Timer phần cứng có thể làm được rất nhiều việc.


41. Sơ đồ tổng quát

Hãy ghi sơ đồ này:

                       TIMER
                         │
              ┌──────────┼──────────┐
              │          │          │
              ▼          ▼          ▼
             CNT        ARR        CCR
              │                     │
              │               ┌─────┴─────┐
              │               │           │
              ▼               ▼           ▼
           Update         Compare      Capture
              │               │           │
              ▼               ▼           ▼
          Interrupt        Output      Input Event
                              │
                              ▼
                             PWM

42. Bài tập 1

Hãy cấu hình:

TIM2 clock = 72 MHz
PSC = 7199

Tính:

Timer tick bao nhiêu microsecond?

Đáp án:

[
72MHz/7200=10kHz
]

nên:

1 tick = 100 µs

43. Bài tập 2

Nếu:

PSC = 7199;
ARR = 99;

thì Timer period bao nhiêu?

Có:

100 ticks

mỗi tick:

100 µs

nên:

10 ms

44. Bài tập 3

Nếu:

CCR1 = 25;

thì Compare xảy ra sau bao lâu?

Có:

25 ticks

mỗi:

100 µs

→ khoảng:

2.5 ms

45. Bài tập 4 – cực kỳ quan trọng

Cho:

TIM2CLK = 72 MHz
PSC = 7199
ARR = 999
CCR1 = 250

Hãy xác định:

1. Timer tick
2. Update period
3. Compare time

Đáp án:

Timer tick = 100 µs

Update:
1000 × 100 µs
= 100 ms

Compare:
250 × 100 µs
= 25 ms

46. Bài tập 5 – suy nghĩ

Nếu:

ARR = 999
CCR1 = 250

thì:

CNT = 249

có Compare chưa?

Chưa.

Khi:

CNT = 250

thì:

Compare Event

được tạo.

Đây chính là bản chất của Output Compare.


47. Điều bạn cần thuộc lòng sau Bài 38

PSC
 ↓
chia clock

CNT
 ↓
đang đếm

ARR
 ↓
giới hạn / chu kỳ

CCR
 ↓
mốc Capture / Compare

Và:

CNT == ARR
    ↓
Update Event

trong mô hình đếm lên thông thường.

Còn:

CNT == CCR
    ↓
Compare Event

48. Lộ trình tiếp theo

Chúng ta đã đi:

Bài 35
Debounce + EXTI + Timer
       ↓
Bài 36
Timer Interrupt + millis
       ↓
Bài 37
Software Timer + Scheduler
       ↓
Bài 38
CNT + PSC + ARR + CCR
       ↓

Bước tiếp theo rất hợp lý là:

BÀI 39 – INPUT CAPTURE TRÊN STM32F103: ĐO THỜI GIAN, ĐO TẦN SỐ VÀ ĐO XUNG BẰNG TIMER

Ở Bài 39 chúng ta sẽ thực sự cấu hình một chân Timer, đưa một tín hiệu vuông vào nó và để phần cứng tự chụp:

Cạnh lên
   ↓
CCR1 = CNT

Cạnh lên tiếp theo
   ↓
CCR1 = CNT

ΔCNT
   ↓
Thời gian
   ↓
Tần số

Sau đó có thể áp dụng trực tiếp vào HC-SR04 để đo Echo, rồi từ đó chuyển sang đo tốc độ động cơ/encoder.

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Recent Posts

  • Bạn có thể hướng dẫn tôi quy trình sửa chữa một mainboard laptop cũng như mainboard của máy tính để bàn không?
  • Có những mức nguồn DC nào trên một bo mạch mainboard laptop?Kỹ thuật đốt dòng để kiểm tra nguồn laptop được thực hiện như thế nào?
  • bài tiếp theo hợp lý là: BÀI 63 – SENSOR FUSION THỰC CHIẾN: ENCODER + IMU MPU6050 + EKF + ODOMETRY X,Y,θ TRÊN STM32F103
  • BÀI 62 – EKF (EXTENDED KALMAN FILTER) CHO ROBOT 2 BÁNH: FUSION ENCODER + IMU + ƯỚC LƯỢNG X, Y, θ, V, ω
  • BÀI 61 – KALMAN FILTER CHO ENCODER + IMU: ƯỚC LƯỢNG TỐC ĐỘ, GÓC θ VÀ SENSOR FUSION

Recent Comments

No comments to show.

Archives

  • September 2026
  • August 2026
  • July 2026
  • June 2026
  • May 2026
  • February 2026

Categories

  • Altium Desinger
  • Công nghệ
  • ESP32
  • Khác
  • Kiến thức điện máy
  • STM32
Live 3D Globes Visitor
©2026 Công nghệ 9 giây | Design: Newspaperly WordPress Theme