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ại | Bộ định thời | Đặc điểm |
|---|---|---|
| Cơ bản | TIM6, TIM7 | 16 bit, chỉ đếm tăng, không có chân GPIO ngoài |
| Đa năng | TIM2, TIM3, TIM4, TIM5 | 16 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ấp | TIM1, TIM8 | 16 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ĩa | Ghi chú cho TIM cơ bản |
|---|---|---|
TIM_Prescaler | Chia xung đầu vào, 0-65535 | Bắt buộc cấu hình |
TIM_CounterMode | Hướng đếm | Chỉ hỗ trợ đếm tăng, không cần khởi tạo |
TIM_Period | Giá trị ARR, 0-65535 | Bắt buộc cấu hình |
TIM_ClockDivision | Tỷ lệ lấy mẫu bộ lọc | Không có chức năng, bỏ qua |
TIM_RepetitionCounter | Số lần lặp trước khi ngắt | Chỉ 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 MHzTIM_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.