找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1243

积分

0

好友

159

主题
发表于 2025-12-24 05:14:49 | 查看: 64| 回复: 0

HAL STM32 基于定时器外部时钟源测量频率

  • 本例程基于 STM32F401RC 单片机

📙 STM32 基于定时器外部时钟源测量频率原理

将被测信号作为定时器的计数时钟源,而将一个已知的、稳定的高频信号(通常来自系统时钟)作为定时器的计数周期基准。通过在一个固定的基准时间内统计被测信号的脉冲个数,即可计算出频率。

📑 STM32 外设资源分配

  • Timer 2 (作为计数器):工作于 外部时钟源模式

    • 时钟源:来自外部的被测频率信号 Fx。
    • 角色:纯粹地对 Fx 的上升沿或下降沿进行计数。
  • Systick (作为基准时基)

    • 角色:产生一个固定、精确的时间窗口 T_measure(例如 1秒、100毫秒)。这个时间窗口用来统计 Timer 2 的计数个数所用的时间。
  • 单片机时钟树配置参数

在这里插入图片描述

🛠 定时器配置

  • 使用定时器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
  }
}




上一篇:Vue前端调用Python接口实战:从Neo4j图数据库查询递归数据
下一篇:金融级VPC流量管控安全架构:租户间安全访问最佳实践
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-2-8 04:57 , Processed in 0.298599 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表