Nguyên lý đo và lựa chọn phương pháp
Hai phương pháp đo cơ bản
| Phương pháp | Ưu điểm | Nhược điểm | Dải tần phù hợp |
|---|---|---|---|
| Đo chu kỳ | Độ chính xác cao ở tần số thấp | Sai số lớn ở tần số cao | 1Hz - 100KHz |
| Đo tần số | Độ chính xác cao ở tần số cao | Cần cổng thời gian định trước | 100KHz - 10MHz |
Giải pháp đề xuất: Tự động chuyển đổi giữa đo chu kỳ và đo tần số
Kết nối phần cứng
| Tín hiệu | Chân STM32 | Lưu ý |
|---|---|---|
| Tín hiệu đo | PA0 (TIM2_CH1) | Chấp nhận đầu vào 3.3V |
| Điện trở phân áp | 1kΩ + 9kΩ | Bảo vệ đầu vào |
| Mạch định dạng | Bộ kích Schmitt | Tùy chọn |
Bảo vệ đầu vào: Bắt buộc thêm điện trở 1kΩ nối tiếp + diode kẹp 3.3V
Cấu hình bộ định thời STM32
1. TIM2 (Phương pháp đo chu kỳ - Chế độ Capture)
- Kênh: CH1
- Chế độ: Input Capture
- Kích cạnh: Cạnh lên
- Bộ chia: 72-1 → Tần số đếm 1MHz
- Ngắt: Ngắt capture + ngắt tràn
2. TIM3 (Phương pháp đo tần số - Chế độ đếm ngoài)
- Kênh: ETR
- Chế độ: External Clock Mode 1
- Kích cạnh: Cạnh lên
- Bộ chia: 1-1
- Ngắt: Ngắt cập nhật
Cấu trúc dữ liệu chính
typedef struct {
uint32_t freq_value; // Tần số cuối cùng
uint8_t method_type; // 0=đo chu kỳ 1=đo tần số
float duty_ratio; // Hệ số nhiệm vụ
} FrequencyData_t;
FrequencyData_t freq_data = {0};
Triển khai phương pháp đo chu kỳ (TIM2 Capture)
1. Mã khởi tạo
#include "stm32f1xx_hal.h"
TIM_HandleTypeDef timer2;
volatile uint32_t cap_value1 = 0, cap_value2 = 0;
volatile uint8_t capture_status = 0;
volatile uint16_t overflow_counter = 0;
void TIM2_Configuration(void)
{
TIM_ClockConfigTypeDef clock_config = {0};
TIM_MasterConfigTypeDef master_config = {0};
TIM_IC_InitTypeDef ic_config = {0};
timer2.Instance = TIM2;
timer2.Init.Prescaler = 72-1; // 72MHz/72 = 1MHz
timer2.Init.CounterMode = TIM_COUNTERMODE_UP;
timer2.Init.Period = 0xFFFFFFFF;
timer2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_IC_Init(&timer2);
clock_config.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
HAL_TIM_ConfigClockSource(&timer2, &clock_config);
ic_config.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
ic_config.ICSelection = TIM_ICSELECTION_DIRECTTI;
ic_config.ICPrescaler = TIM_ICPSC_DIV1;
ic_config.ICFilter = 0;
HAL_TIM_IC_ConfigChannel(&timer2, &ic_config, TIM_CHANNEL_1);
master_config.MasterOutputTrigger = TIM_TRGO_RESET;
master_config.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&timer2, &master_config);
HAL_TIM_IC_Start_IT(&timer2, TIM_CHANNEL_1);
HAL_TIM_Base_Start_IT(&timer2);
}
2. Xử lý ngắt (Phần quan trọng)
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) {
if (capture_status == 0) {
cap_value1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
capture_status = 1;
} else {
cap_value2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
// Tính chu kỳ (xét trường hợp tràn)
uint32_t period_count = 0;
if (cap_value2 >= cap_value1) {
period_count = cap_value2 - cap_value1;
} else {
period_count = 0xFFFFFFFF - cap_value1 + cap_value2;
}
// Tính tần số
freq_data.freq_value = 1000000 / period_count; // Đồng hồ 1MHz
capture_status = 0;
overflow_counter = 0;
}
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM2) {
overflow_counter++;
}
}
Triển khai phương pháp đo tần số (TIM3 đếm ngoài)
1. Mã khởi tạo
TIM_HandleTypeDef timer3;
volatile uint32_t count_result = 0;
void TIM3_Configuration(void)
{
TIM_SlaveConfigTypeDef slave_config = {0};
TIM_MasterConfigTypeDef master_config = {0};
timer3.Instance = TIM3;
timer3.Init.Prescaler = 0;
timer3.Init.CounterMode = TIM_COUNTERMODE_UP;
timer3.Init.Period = 0xFFFF;
timer3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&timer3);
slave_config.SlaveMode = TIM_SLAVEMODE_EXTERNAL1;
slave_config.InputTrigger = TIM_TS_ETRF;
slave_config.TriggerPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
slave_config.TriggerFilter = 0;
HAL_TIM_SlaveConfigSynchro(&timer3, &slave_config);
master_config.MasterOutputTrigger = TIM_TRGO_RESET;
master_config.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&timer3, &master_config);
}
2. Đo định kỳ (Cổng 1 giây)
void Frequency_Measurement(void)
{
static uint32_t previous_count = 0;
uint32_t current_count = __HAL_TIM_GET_COUNTER(&timer3);
// Ngắt định thời 1 giây kích hoạt
freq_data.freq_value = current_count - previous_count;
previous_count = current_count;
}
Logic tự động chuyển dải
void Auto_Range_Selection(void)
{
static uint32_t previous_frequency = 0;
static uint8_t stability_counter = 0;
if (freq_data.freq_value > 100000) { // >100KHz
freq_data.method_type = 1; // Phương pháp đo tần số
} else {
freq_data.method_type = 0; // Phương pháp đo chu kỳ
}
// Chống nhiễu
if (abs(freq_data.freq_value - previous_frequency) < 10) {
stability_counter++;
if (stability_counter > 5) {
stability_counter = 0;
previous_frequency = freq_data.freq_value;
}
} else {
stability_counter = 0;
}
}
Đo hệ số nhiệm vụ (Capture hai cạnh)
float Duty_Cycle_Measurement(void)
{
uint32_t high_duration, low_duration, total_period;
// Cấu hình capture cạnh lên và cạnh xuống
// ... mã khởi tạo
// Tính hệ số nhiệm vụ
total_period = high_duration + low_duration;
if (total_period > 0) {
freq_data.duty_ratio = (float)high_duration / total_period * 100.0f;
}
return freq_data.duty_ratio;
}
Ví dụ hàm chính
int main(void)
{
HAL_Init();
SystemClock_Config();
GPIO_Initialize();
TIM2_Configuration();
TIM3_Configuration();
HAL_TIM_IC_Start_IT(&timer2, TIM_CHANNEL_1);
HAL_TIM_Base_Start_IT(&timer2);
HAL_TIM_Base_Start_IT(&timer3);
while (1) {
Auto_Range_Selection();
printf("Tần số: %lu Hz, Phương pháp: %s, Hệ số nhiệm vụ: %.1f%%\r\n",
freq_data.freq_value,
freq_data.method_type ? "Đo tần số" : "Đo chu kỳ",
freq_data.duty_ratio);
HAL_Delay(500);
}
}
Tối ưu hóa hiệu suất
1. Trung bình đồng bộ nhiều chu kỳ
#define SAMPLE_COUNT 10
uint32_t frequency_samples[SAMPLE_COUNT];
2. Điều chỉnh tín hiệu đầu vào
- Bộ kích Schmitt
- Điều khiển khuếch đại tự động
- Bộ lọc thông dải
3. Tự động hiệu chỉnh điểm 0
void Auto_Zero_Adjustment(void)
{
uint32_t average = 0;
for (int i=0; i<100; i++) {
average += ADC_ReadValue();
}
zero_calibration = average / 100;
}
Dải đo và độ chính xác
| Dải tần | Phương pháp | Độ phân giải |
|---|---|---|
| 1Hz - 100Hz | Đo chu kỳ | 0.1Hz |
| 100Hz - 10KHz | Đo chu kỳ | 1Hz |
| 10KHz - 100KHz | Đo chu kỳ | 10Hz |
| 100KHz - 1MHz | Đo tần số | 100Hz |
| 1MHz - 10MHz | Đo tần số | 1KHz |
Độ chính xác cao nhất: 0.1Hz @ 1Hz
Sai số lớn nhất: < 0.1%