Đồng hồ định thời cơ bản TIM trên STM32F1

Phân loại đồng h định thời

Dòng STM32F1 tích hợp tổng cộng 8 bộ định thời, được phân thành ba nhóm chính:

LoạiBộ định thờiĐặc điểm
Cơ bảnTIM6, TIM716 bit, chỉ đếm tăng, không có chân GPIO ngoài
Đa năngTIM2, TIM3, TIM4, TIM516 bit, đếm tăng/giảm, có 4 chân GPIO, hỗ trợ đầu ra so sánh và đầu vào bắt
Cao cấpTIM1, TIM816 bit, đếm tăng/giảm, 8 chân GPIO, hỗ trợ điều khiển động cơ 3 pha

Cấu trúc bộ định thời cơ bản

Bộ định thời cơ bản gồm các thành phần cốt lõi tạo nên thời gian cơ sở (time base), là nền tảng cho cả bộ định thời đa năng và cao cấp.

Nguồn xung nhịp

Xung TIMxCLK lấy từ CK_INT sau khi qua bộ chia tần APB1. Quy tắc:

  • Nếu hệ số chia APB1 = 1: tần số giữ nguyên
  • Nếu hệ số chia APB1 > 1: tần số nhân đôi

Với cấu hình mặc định của thư viện chuẩn, APB1 = 36 MHz, do đó TIMxCLK = 36 × 2 = 72 MHz.

Bộ chia tần trước (PSC)

Đây là bộ chia 16 bit, cho phép chia xung TIMxCLK với tỷ lệ từ 1 đến 65536:

CK_CNT = TIMxCLK / (PSC + 1)

Bộ đếm (CNT)

Bộ đếm 16 bit chỉ đếm tăng, giá trị tối đa là 65535. Khi đạt giá trị trong thanh ghi nạp lại tự động, sự kiện cập nhật phát sinh và bộ đếm quay về 0.

Thanh ghi nạp lại tự động (ARR)

Thanh ghi 16 bit chứa giới hạn đếm. Khi CNT == ARR, cờ tràn được bật và nếu cho phép ngắt, sẽ phát sinh yêu cầu ngắt.

Công thức tính thời gian định thời

Tần số xung đếm:

fCNT = fTIMxCLK / (PSC + 1)

Thời gian mỗi lần đếm:

Tđếm = (PSC + 1) / fTIMxCLK

Chu kỳ ngắt tràn (một lần):

Tngắt = (ARR + 1) × (PSC + 1) / fTIMxCLK

Tổng thời gian sau n lần ngắt:

Ttổng = (ARR + 1) × (PSC + 1) × n / fTIMxCLK

Cấu trúc khởi tạo TIM_TimeBaseInitTypeDef

Định nghĩa trong stm32f10x_tim.h:

typedef struct {
    uint16_t TIM_Prescaler;        // Hệ số chia tần
    uint16_t TIM_CounterMode;      // Chế độ đếm
    uint32_t TIM_Period;           // Chu kỳ (giá trị ARR)
    uint16_t TIM_ClockDivision;    // Chia tần bổ sung
    uint8_t  TIM_RepetitionCounter;// Bộ đếm lặp lại
} TIM_TimeBaseInitTypeDef;
TrườngÝ nghĩaGhi chú cho TIM cơ bản
TIM_PrescalerChia xung đầu vào, 0-65535Bắt buộc cấu hình
TIM_CounterModeHướng đếmChỉ hỗ trợ đếm tăng, không cần khởi tạo
TIM_PeriodGiá trị ARR, 0-65535Bắt buộc cấu hình
TIM_ClockDivisionTỷ lệ lấy mẫu bộ lọcKhông có chức năng, bỏ qua
TIM_RepetitionCounterSố lần lặp trước khi ngắtChỉ dành cho TIM cao cấp, bỏ qua

Ví dụ thực hành

Ví dụ 1: Tạo ngắt mỗi giây

Yêu cầu: Ngắt 1 giây/lần với xung hệ thống 72 MHz.

Tham số:

  • TIM_Prescaler = 71 → chia xuống 1 MHz
  • TIM_Period = 999999 → đếm 1 triệu xung = 1 giây
TIM_TimeBaseInitTypeDef cau_hinh_tim;

cau_hinh_tim.TIM_Prescaler = 71;
cau_hinh_tim.TIM_CounterMode = TIM_COUNTERMODE_UP;
cau_hinh_tim.TIM_Period = 999999;
cau_hinh_tim.TIM_ClockDivision = TIM_CLOCKDIVISION_DIV1;
cau_hinh_tim.TIM_RepetitionCounter = 0;

TIM_TimeBaseInit(TIM1, &cau_hinh_tim);

Ví dụ 2: Điều khiển LED nhấp nháy qua TIM2

Phần cứng: LED gắn PA5

Khởi tạo GPIO:

#include "stm32f4xx.h"

void cau_hinh_gpio(void) {
    GPIO_InitTypeDef cau_hinh_gpio;
    
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    
    cau_hinh_gpio.GPIO_Pin = GPIO_Pin_5;
    cau_hinh_gpio.GPIO_Mode = GPIO_Mode_OUT;
    cau_hinh_gpio.GPIO_Speed = GPIO_Speed_50MHz;
    cau_hinh_gpio.GPIO_OType = GPIO_OType_PP;
    cau_hinh_gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
    
    GPIO_Init(GPIOA, &cau_hinh_gpio);
}

Khởi tạo TIM2 (ngắt 100ms):

void cau_hinh_tim2(void) {
    TIM_TimeBaseInitTypeDef cau_hinh_tim;
    NVIC_InitTypeDef cau_hinh_nvic;
    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    
    // 72MHz / (7199+1) = 10kHz -> T = 0.1ms
    // Đếm 1000 lần = 100ms
    cau_hinh_tim.TIM_Period = 999;
    cau_hinh_tim.TIM_Prescaler = 7199;
    cau_hinh_tim.TIM_ClockDivision = TIM_CKD_DIV1;
    cau_hinh_tim.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2, &cau_hinh_tim);
    
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
    TIM_Cmd(TIM2, ENABLE);
    
    cau_hinh_nvic.NVIC_IRQChannel = TIM2_IRQn;
    cau_hinh_nvic.NVIC_IRQChannelPreemptionPriority = 0;
    cau_hinh_nvic.NVIC_IRQChannelSubPriority = 1;
    cau_hinh_nvic.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&cau_hinh_nvic);
}

Xử lý ngắt:

void TIM2_IRQHandler(void) {
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
        GPIO_ToggleBits(GPIOA, GPIO_Pin_5);
    }
}

Chương trình chính:

int main(void) {
    SystemInit();
    cau_hinh_gpio();
    cau_hinh_tim2();
    
    while (1) {
        // Nhiệm vụ khác có thể đặt tại đây
        // LED tự động nhấp nháy nhờ ngắt
    }
}

Lưu ý khi tính toán tham số

Với xung 72 MHz, công thức chung để đạt chu kỳ T (giây):

(PSC + 1) × (ARR + 1) = T × 72 × 10⁶

Thông thường chọn PSC để xung đếm thuận tiện (ví dụ: 1 kHz, 10 kHz, 1 MHz), sau đó tính ARR tương ứng.

Thẻ: STM32 TIM NVIC GPIO Embedded C

Đăng vào ngày 29 tháng 9 lúc 06:02