HAL STM32 基于定时器外部时钟源测量频率
📙 STM32 基于定时器外部时钟源测量频率原理
将被测信号作为定时器的计数时钟源,而将一个已知的、稳定的高频信号(通常来自系统时钟)作为定时器的计数周期基准。通过在一个固定的基准时间内统计被测信号的脉冲个数,即可计算出频率。
📑 STM32 外设资源分配

🛠 定时器配置
- 使用定时器2,时钟源配置为外部时钟源,时钟源输入引脚 PA0。
- 最大计数范围:
4294967295(0xffffffff)。


代码实现
🌿 tim.c
/* USER CODE BEGIN 0 */
// 频率测量相关变量
static volatile uint32_t last_counter_value = 0;
static volatile uint32_t current_counter_value = 0;
static volatile uint32_t measurement_start_tick = 0;
static volatile uint32_t measurement_period_ms = 1000; // 默认测量周期1秒
static volatile uint8_t measurement_ready = 0;
/* USER CODE END 0 */
/* USER CODE BEGIN 1 */
/**
* @brief 启动频率测量
* @retval None
*/
void TIM2_Start_Frequency_Measurement(void)
{
// 启动定时器计数
HAL_TIM_Base_Start(&htim2);
// 清空计数器
__HAL_TIM_SET_COUNTER(&htim2, 0);
// 记录开始时间和当前计数器值
measurement_start_tick = HAL_GetTick();
last_counter_value = 0; // 从0开始计数
measurement_ready = 0;
}
/* USER CODE BEGIN 1 */
/**
* @brief 测量频率
* @retval 频率测量结果结构体
*/
TIM2_Frequency_Result_t TIM2_Measure_Frequency(void)
{
TIM2_Frequency_Result_t result = {0};
if (measurement_ready)
{
uint32_t elapsed_time_ms = HAL_GetTick() - measurement_start_tick;
if (elapsed_time_ms >= measurement_period_ms)
{
current_counter_value = __HAL_TIM_GET_COUNTER(&htim2);
// 计算计数器增量(处理计数器溢出)
uint32_t counter_delta;
if (current_counter_value >= last_counter_value)
{
counter_delta = current_counter_value - last_counter_value;
}
else
{
// 处理计数器溢出情况
counter_delta = (0xFFFFFFFF - last_counter_value) + current_counter_value + 1;
}
// 计算频率:脉冲数 / 时间(秒)
float frequency = (float)counter_delta / ((float)elapsed_time_ms / 1000.0f);
// 填充结果结构体
result.frequency = frequency;
result.pulse_count = current_counter_value;
result.delta_count = counter_delta;
result.elapsed_ms = elapsed_time_ms;
// 清空计数器并重新开始测量
__HAL_TIM_SET_COUNTER(&htim2, 0);
last_counter_value = 0;
measurement_start_tick = HAL_GetTick();
}
}
return result;
}
/* USER CODE END 1 */
/**
* @brief 清空定时器计数器
* @retval None
*/
void TIM2_Clear_Counter(void)
{
// 停止定时器(可选,根据需求决定)
// HAL_TIM_Base_Stop(&htim2);
// 清空计数器
__HAL_TIM_SET_COUNTER(&htim2, 0);
// 重置测量变量
last_counter_value = 0;
current_counter_value = 0;
measurement_start_tick = HAL_GetTick();
// 如果需要重新启动定时器
// HAL_TIM_Base_Start(&htim2);
}
/**
* @brief 获取脉冲计数
* @retval 当前脉冲计数值
*/
uint32_t TIM2_Get_Pulse_Count(void)
{
return __HAL_TIM_GET_COUNTER(&htim2);
}
/**
* @brief 设置测量周期
* @param period_ms: 测量周期(毫秒)
* @retval None
*/
void TIM2_Set_Measurement_Period(uint32_t period_ms)
{
measurement_period_ms = period_ms;
}
/**
* @brief 检查测量是否就绪
* @retval 测量就绪状态(1=就绪,0=未就绪)
*/
uint8_t TIM2_Is_Measurement_Ready(void)
{
uint32_t elapsed_time_ms = HAL_GetTick() - measurement_start_tick;
measurement_ready = (elapsed_time_ms >= measurement_period_ms) ? 1 : 0;
return measurement_ready;
}
/* USER CODE END 1 */
🌿 tim.h
/* USER CODE BEGIN Private defines */
// 频率测量结果结构体
typedef struct {
float frequency; // 频率值(Hz)
uint32_t pulse_count; // 脉冲计数值
uint32_t delta_count; // 增量计数值
uint32_t elapsed_ms; // 测量时间(毫秒)
} TIM2_Frequency_Result_t;
/* USER CODE END Private defines */
/* USER CODE BEGIN Prototypes */
void TIM2_Start_Frequency_Measurement(void);
TIM2_Frequency_Result_t TIM2_Measure_Frequency(void); // 修改返回类型
uint32_t TIM2_Get_Pulse_Count(void);
void TIM2_Clear_Counter(void); // 添加计数器清零函数
/* USER CODE END Prototypes */
📝 main.c 中调用内容:
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
/* USER CODE BEGIN 2 */
uint32_t tick = HAL_GetTick();
// 初始化频率测量
TIM2_Start_Frequency_Measurement();
frequency_measurement_started = 1;
frequency_measurement_tick = HAL_GetTick();
manual_clear_tick = HAL_GetTick();
printf("Frequency Measurement Started\r\n");
printf("Timer2 configured as external clock counter (PA0 pin)\r\n");
printf("Measurement period: 1 second\r\n");
printf("Max frequency: ~84 MHz (system clock)\r\n");
printf("Counter will be cleared after each measurement\r\n");
printf("Detailed count information will be displayed\r\n");
printf("Press any key to manually clear counter\r\n");
printf("----------------------------------------\r\n");
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
// 频率测量和显示(每1秒)
if (frequency_measurement_started &&
(HAL_GetTick() - frequency_measurement_tick >= 1000)) {
frequency_measurement_tick = HAL_GetTick();
// 检查测量是否就绪
if (TIM2_Is_Measurement_Ready()) {
TIM2_Frequency_Result_t result = TIM2_Measure_Frequency();
if (result.frequency > 0) {
// 显示详细的频率和计数信息
printf("=== Frequency Measurement Result ===\r\n");
// 智能频率显示:1KHz以上只显示整数
if (result.frequency >= 1000.0f) {
// 1KHz以上:显示整数部分
printf("Frequency: %.0f Hz\r\n", result.frequency);
} else if (result.frequency >= 100.0f) {
// 100Hz-999Hz:显示1位小数
printf("Frequency: %.1f Hz\r\n", result.frequency);
} else if (result.frequency >= 10.0f) {
// 10Hz-99Hz:显示1位小数
printf("Frequency: %.1f Hz\r\n", result.frequency);
} else if (result.frequency >= 1.0f) {
// 1Hz-9Hz:显示2位小数
printf("Frequency: %.2f Hz\r\n", result.frequency);
} else {
// 1Hz以下:显示3位小数
printf("Frequency: %.3f Hz\r\n", result.frequency);
}
printf("Pulse Count: %lu pulses\r\n", result.pulse_count);
printf("Delta Count: %lu pulses (in %lu ms)\r\n", result.delta_count, result.elapsed_ms);
printf("Measurement Time: %lu ms\r\n", result.elapsed_ms);
// 根据频率范围显示不同信息
if (result.frequency < 1.0f) {
printf("Range: Very low frequency (<1 Hz)\r\n");
} else if (result.frequency < 1000.0f) {
printf("Range: Low frequency (1 Hz - 1 kHz)\r\n");
} else if (result.frequency < 1000000.0f) {
printf("Range: Medium frequency (1 kHz - 1 MHz)\r\n");
} else {
printf("Range: High frequency (>1 MHz)\r\n");
}
// 显示计数速率信息(1KHz以上只显示整数)
float count_rate = (float)result.delta_count / (float)result.elapsed_ms;
if (count_rate >= 1.0f) {
printf("Count Rate: %.0f pulses/ms (%.0f pulses/s)\r\n",
count_rate, count_rate * 1000.0f);
} else {
printf("Count Rate: %.2f pulses/ms (%.0f pulses/s)\r\n",
count_rate, count_rate * 1000.0f);
}
printf("Counter cleared for next measurement\r\n");
printf("========================================\r\n");
} else {
uint32_t current_count = TIM2_Get_Pulse_Count();
printf("=== No Signal Detection ===\r\n");
printf("No signal detected on PA0 pin\r\n");
printf("Current Pulse Count: %lu\r\n", current_count);
printf("========================================\r\n");
}
}
}
/* USER CODE END 3 */
// 检查串口输入,手动清空计数器
uint8_t rx_data;
if (HAL_UART_Receive(&huart1, &rx_data, 1, 10) == HAL_OK) {
// 收到任意字符,手动清空计数器
TIM2_Clear_Counter();
printf("Manual counter clear triggered!\r\n");
printf("Counter reset to 0, starting new measurement...\r\n");
frequency_measurement_tick = HAL_GetTick();
}
HAL_Delay(10); // 添加小延迟避免过度占用CPU
}
}
|