Bài 6: STM32 Timer Input Capture và Output Compare

STM32 Timer

STM32 Timer có nhiều chế độ, trong đó Input Capture (IC) và Output Compare (OC) là 2 chế độ được sử dụng rất nhiều trong lập trình nhúng. Trong bài này chúng ta sẽ tìm hiểu IC và OC là gì, cách cấu hình trên CubeMX và lập trình trên Keil C.

Bài 6 trong Serie Học lập trình STM32 từ A tới Z

STM32 Timer chế độ Input Capture

Input Capture là chế độ bắt sườn tín hiệu đầu vào, thường ứng dụng để đo tần số hoặc độ rộng xung. Các bạn cứ hình dung giống trọng tài cầm đồng hồ bấm giờ: mỗi khi vận động viên chạy qua vạch, trọng tài ghi lại con số đang hiện trên đồng hồ.

Input Capture có 2 chế độ là bắt sườn lên (Rising) hoặc sườn xuống (Falling).

Nguyên lý hoạt động như sau:

+ Sau khi khởi động Timer, mỗi khi có sườn lên (hoặc xuống) tại đầu vào Channel x của Timer, thanh ghi TIMx_CCRy (x là số Timer, y là số kênh) sẽ được nạp giá trị của thanh ghi đếm TIMx_CNT.

+ Bit CC1IF (cờ ngắt) được đặt lên 1. Bit CC1OF sẽ được đặt lên 1 nếu cờ CC1IF được đặt 2 lần liên tiếp mà không được xóa. Nghĩa là mỗi khi có sườn lên sẽ có ngắt xảy ra, lập trình viên phải đọc giá trị lưu trong CCR1 rồi xóa cờ CC1IF. Nếu không, cờ CC1OF sẽ bật lên báo tràn (overcapture), giá trị cũ bị ghi đè mà chưa kịp đọc.

+ Một ngắt được sinh ra nếu bit CC1IE được đặt lên 1

+ Một yêu cầu DMA được sinh ra nếu bit CC1DE được đặt lên 1

h1 1

Các bước khởi tạo IC như sau:

B1: Chọn nguồn xung đếm (internal, external, timer)

B2: Ghi dữ liệu vào thanh ghi ARR và thanh ghi PSC

B3: Chọn kênh đầu vào và sườn cần bắt bằng các bit CCxS (thanh ghi CCMRx), CCxP (thanh ghi CCER), sau đó bật kênh bằng bit CCxE

B4: Chọn bật ngắt hoặc DMA bằng bit CCxIE hoặc CCxDE trong thanh ghi DIER

B5: Khởi chạy bộ đếm bằng bit CEN của thanh ghi CR1

B6: Trong hàm ngắt đọc dữ liệu từ thanh ghi CCRx và xóa thanh ghi CNT về 0. Khi có ngắt thứ 2 sinh ra, giá trị của thanh ghi CCRx chính là khoảng thời gian giữa 2 lần ngắt.

Chi tiết các bạn tham khảo mục 15.3.4 trong Reference Manual.

STM32 Timer chế độ output compare

Output Compare là chế độ tác động lên chân ra khi giá trị bộ đếm bằng với giá trị đã cài đặt. Nó giống như chiếc đồng hồ báo thức: đặt sẵn 6h, khi kim chạy đến đúng 6h thì chuông reo.

Nguyên lý hoạt động: khi bộ đếm đếm đến giá trị được cài đặt trong thanh ghi CCR, Timer sẽ:

+ Tạo ra một tác động lên chân ra tùy vào chế độ được chọn của bộ OC

+ Set cờ ngắt CCxIF lên 1

+ Tạo ra một ngắt hoặc yêu cầu DMA nếu bit CCxIE hoặc CCxDE được bật

Các chế độ làm việc của OC:

H2 4

Các bước khởi tạo OC như sau:

B1: Chọn xung Clock cho Timer

B2: Ghi dữ liệu vào thanh ghi ARR và thanh ghi CCR

B3: Set bit CCxIE hoặc CCxDE nếu bật ngắt hoặc DMA

B4: Chọn chế độ OC bằng 3 bit OCxM trong thanh ghi CCMRx

B5: Chạy bộ đếm bằng bit CEN của thanh ghi CR1

Chi tiết các bạn tham khảo mục 15.3.8 trong Reference Manual.

Cấu hình STM32 Timer trong CubeMX

Trong bài này, chúng ta sẽ cấu hình Channel 1 của Timer 2 là Input Capture,

Channel 1 của Timer 3 là Output Compare.

Mở phần mềm lên, chọn khởi tạo trên MCU STM32F103C8, nhấn Start Project.

Trong SYS Debug chọn Serial Wire. Nếu các bạn chưa biết các bước cơ bản này thì đọc lại Bài 3 nhé.

Trong phần Timers chọn TIM2:

Clock Source – Internal Clock

Channel 1: Input Capture direct mode

Trong Parameter Settings chọn Prescaler là 8000 => mỗi lần đếm là 1ms (chi tiết trong bài 5)

Counter Period: 999, chu kì tràn là 1000ms. Vì mình sẽ đọc các xung có tần số lớn hơn 1Hz

Auto-reload preload: Enable

Polarity Selection: Rising (chọn bắt sườn lên)

H3 3

Timer 3 các bạn cấu hình như sau:

Internal Clock

Channel 1: Output Compare CH1

Prescaler 8000 => mỗi lần đếm là 1ms

Counter Period: 49, chu kì tràn là 50ms

Auto-reload preload: Enable

Mode: Toggle on Match, Pulse: 24 (đảo trạng thái CH1 khi Counter đếm lên 24 => 25ms)

H4 2

Trong NVIC Settings tick vào bật ngắt cho Timer 2.

H5 3

Đặt tên, chọn Toolchain và Gen code.

H6 3

Lập trình STM32 Timer chế độ IC và OC

Mở Project, nhấn F7 để build code. Trong stm32f1xx_it.c các bạn tìm đến hàm HAL_TIM_IRQHandler(&htim2); và Go To Definition nó.

H7 4

Trong định nghĩa của hàm đó các bạn sẽ tìm thấy hàm Callback cho ngắt Input Capture. Go To Definition hàm Callback đó, copy và paste vào phía trên hàm main() (nhớ bỏ từ khóa __weak).

H8 3

Trong main.c chúng ta tạo một biến chứa giá trị đọc được từ Counter. Trong hàm xử lý ngắt ta sẽ kiểm tra ngắt đến từ Timer nào, đọc giá trị Capture, sau đó xóa giá trị Counter về 0.

H9 3

Trước while(1), chúng ta viết các hàm khởi chạy IC và OC.

H10 3

Lưu ý: Input Capture phải khởi chạy bằng HAL_TIM_IC_Start_IT() thì mới có ngắt gọi về Callback. Output Compare chỉ cần HAL_TIM_OC_Start() vì phần cứng tự đảo chân ra, không cần ngắt.

Build và nạp chương trình vào KIT.

Nối chân PA0 với chân PA6 bằng 1 sợi dây như sơ đồ dưới (Timer 2 sẽ đọc xung do Timer 3 phát ra).

Sơ đồ nối dây STM32 Timer Input Capture: nối chân PA6 (TIM3_CH1 Output Compare) với PA0 (TIM2_CH1 Input Capture) trên Blue Pill

Bật Debug, click vào tên biến u16_CaptureVal chọn Add to Watch 1.

H11 3

Nhấn Run (F5) sẽ thấy u16_CaptureVal có giá trị là 100.

H12 2

Để giải thích vì sao có giá trị đó, các bạn dùng bộ Logic Analyzer cắm vào CH1 của Timer 3 để đọc xung của nó.

Nếu chưa biết sử dụng, bạn đọc bài viết: Hướng dẫn sử dụng Logic Analyzer.

H13 1

Khi bắt đầu chạy Timer, kênh CH1 sẽ đảo trạng thái ở mốc 25ms đầu tiên. Sau đó Timer 3 đếm đến 50ms rồi quay về 0, đến mốc 25ms của chu kì tiếp theo lại đảo trạng thái.

Như vậy 2 sườn lên liên tiếp sẽ cách nhau 2 lần đảo trạng thái, nghĩa là 100ms.

H14 1

Vì vậy giá trị Capture đọc được là 100 (đơn vị 1ms), đúng không nào.

Kết

Vậy là chúng ta đã học được cách sử dụng STM32 Timer chế độ Input Capture và Output Compare.

Đừng quên chia sẻ nếu thấy bài viết này có ích nhé!

5/5 - (5 bình chọn)

11 những suy nghĩ trên “Bài 6: STM32 Timer Input Capture và Output Compare”

  1. Nguyễn Hoàng Danh nói:

    /* Channel 1, Configuration in OC mode */
    TIM_OCStructInit(&TIM5_OCInitStructure);
    TIM5_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
    TIM5_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
    TIM5_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
    TIM_OC1Init(TIM5, &TIM5_OCInitStructure);
    TIM_OC1PreloadConfig(TIM5, TIM_OCPreload_Disable);
    Em đang gặp dính TIM5 xài m mode timing anh có thế giải thích cho em cái state với nstate k anh

  2. Foli nói:

    Anh nên chú thích các thanh nữa nhe.. em đọc vô chả hình dung được hết ^^!.
    ——————-
    – Counter Register (TIMx_CNT): Khi hoạt động, thanh ghi này tăng hoặc giảm giá trị theo mỗi xung clock đầu vào. Tùy vào bộ timer mà counter này có thể là 16bit hoặc 32bit.
    – Prescaler Register (TIMx_PSC): Giá trị của thanh ghi bộ chia tần (16bit) cho phép người dùng cấu hình chia tần số đầu vào (CK_PSC) cho bất kì giá trị nào từ [1- 65536]. Sử dụng kết hợp bộ chia tần của timer và của RCC giúp chúng ta có thể thay đổi được thời gian của mỗi lần CNT thực hiện đếm, giúp tạo ra được những khoảng thời gian, điều chế được độ rộng xung phù hợp với nhu cầu.
    – Auto-Reload Register (TIMx_ARR): Giá trị của ARR được người dùng xác định sẵn khi cài đặt bộ timer, làm cơ sở cho CNT thực hiện nạp lại giá trị đếm mỗi khi tràn (overflow khi đếm lên – CNT vượt giá trị ARR, underflow khi đếm xuống – CNT bé hơn 0).Tùy vào bộ timer mà counter này có thể là 16bit hoặc 32bit.

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *