Đo tần số chính xác trên STM32 bằng chế độ bắt tín hiệu đầu vào

Chế độ bắt tín hiệu đầu vào (Input Capture) của các bộ định thời (timer) trên vi điều khiển STM32 cho phép đo chính xác tần số, chu kỳ và độ rộng xung của tín hiệu ngoài — đặc biệt hiệu quả với tín hiệu xung vuông, cảm biến quang học hoặc mã hóa vị trí. Bài viết này trình bày phương pháp triển khai toàn bộ quy trình đo tần số dựa trên phần cứng timer, bao gồm cấu hình thời cơ bản, lựa chọn kênh đầu vào, thiết lập bộ lọc chống nhiễu, xử lý sự kiện cạnh, quản lý ngắt và tính toán tần số theo nguyên tắc đồng hồ đếm thời gian thực.

Cấu hình bộ định thời cơ bản

Để đo tần số, timer cần được thiết lập ở chế độ đếm lên với tần số mẫu ổn định. Giá trị prescaler và period xác định độ phân giải thời gian tối thiểu — ví dụ: với hệ thống clock 72 MHz và prescaler = 71, timer sẽ đếm với tần số 1 MHz (chu kỳ 1 µs). Việc chọn giá trị period đủ lớn (ví dụ 0xFFFF) giúp tránh tràn khi đo tín hiệu có chu kỳ dài.

// Khởi tạo cơ sở thời gian cho TIM3 (dùng làm ví dụ thay vì TIM2)
void Timer3_Base_Init(void) {
    RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;  // Kích hoạt clock cho TIM3
    TIM3->PSC = 71;                        // Prescaler = 72MHz / (71+1) = 1MHz
    TIM3->ARR = 0xFFFF;                    // Giới hạn đếm: 65535 → chu kỳ max ~65.5ms
    TIM3->CR1 = TIM_CR1_CEN | TIM_CR1_URS; // Bật đếm, chỉ cập nhật từ tràn
}

Lựa chọn và cấu hình kênh bắt tín hiệu

Mỗi timer hỗ trợ nhiều kênh đầu vào (CH1–CH4), mỗi kênh có thể được nối tới chân GPIO tương ứng qua chức năng alternate function. Ví dụ: TIM3_CH1 thường ánh xạ tới chân PA6 hoặc PB4 tùy dòng chip. Cần cấu hình chân GPIO ở chế độ AF_PP (alternate function push-pull) và bật clock cho port tương ứng.

// Cấu hình chân PA6 làm đầu vào bắt tín hiệu cho TIM3_CH1
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
GPIOA->CRL &= ~(0xF << 24);           // Xóa cấu hình cho pin 6
GPIOA->CRL |=  (0x2 << 24);           // AF_PP, tốc độ 50MHz
GPIOA->AFR[0] &= ~(0xF << 24);        // Xóa AFIO cho pin 6
GPIOA->AFR[0] |=  (0x2 << 24);        // Chọn AF2 cho TIM3_CH1

Thiết lập bộ lọc và phát hiện cạnh

Bộ lọc kỹ thuật số tích hợp trong timer giúp loại bỏ nhiễu ngắn hạn bằng cách yêu cầu tín hiệu giữ mức ổn định trong một số chu kỳ clock nhất định trước khi công nhận sự kiện cạnh. Tham số ICFilter (0–15) xác định độ rộng cửa sổ kiểm tra — giá trị cao hơn tăng khả năng chống rung nhưng giảm độ nhạy với tín hiệu có sườn dốc chậm.

// Cấu hình kênh 1 để bắt cạnh lên, dùng bộ lọc 4 chu kỳ clock
TIM3->CCMR1 &= ~TIM_CCMR1_CC1S;         // Xóa chế độ chọn kênh
TIM3->CCMR1 |= TIM_CCMR1_CC1S_0;       // Chọn TI1 (PA6)
TIM3->CCER |= TIM_CCER_CC1E;           // Bật kênh bắt CH1
TIM3->CCER |= TIM_CCER_CC1P;           // Cạnh lên (không set CC1NP)
TIM3->CCMR1 &= ~TIM_CCMR1_IC1F;         // Xóa trường lọc
TIM3->CCMR1 |= (0x4 << TIM_CCMR1_IC1F_Pos); // Bộ lọc 4 chu kỳ

Xử lý ngắt và tính toán tần số

Khi xảy ra sự kiện bắt tín hiệu, timer tự động lưu giá trị đếm hiện tại vào thanh ghi CCR1 và có thể phát sinh ngắt nếu được kích hoạt. Trong hàm xử lý ngắt, cần đọc giá trị CCR1, tính chênh lệch giữa hai lần bắt liên tiếp, sau đó suy ra tần số:

volatile uint32_t last_capture = 0;
volatile uint32_t current_capture = 0;
volatile uint8_t capture_ready = 0;

void TIM3_IRQHandler(void) {
    if ((TIM3->SR & TIM_SR_CC1IF) != RESET) {
        TIM3->SR &= ~TIM_SR_CC1IF;          // Xóa cờ ngắt
        current_capture = TIM3->CCR1;
        if (last_capture != 0) {
            uint32_t delta = (current_capture >= last_capture) 
                            ? (current_capture - last_capture) 
                            : (0x10000 + current_capture - last_capture);
            // Delta đơn vị: µs (vì timer chạy 1MHz)
            if (delta > 0) {
                uint32_t freq_hz = 1000000UL / delta;  // f = 1/T (T tính bằng µs)
                // Lưu kết quả hoặc gửi đi xử lý tiếp
                capture_ready = 1;
            }
        }
        last_capture = current_capture;
    }
}

Tối ưu độ chính xác đo

Để giảm sai số hệ thống, nên áp dụng các biện pháp sau:

  • Dùng nguồn xung clock ngoài (HSE) thay vì RC nội bộ để đảm bảo độ ổn định tần số.
  • Đo nhiều chu kỳ liên tiếp rồi chia trung bình — ví dụ: bắt 10 cạnh lên liên tiếp, tính tổng thời gian rồi chia 9 để có chu kỳ trung bình.
  • Loại bỏ các giá trị ngoại lệ bằng thuật toán median filter trước khi tính tần số.
  • Giảm độ trễ xử lý ngắt bằng cách giữ ISR ngắn gọn, chuyển xử lý phức tạp sang vòng lặp chính hoặc task RTOS.

Thẻ: STM32 input-capture frequency-measurement timer embedded-c

Đăng vào ngày 2 tháng 7 lúc 10:42