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

322

积分

0

好友

40

主题
发表于 12 小时前 | 查看: 2| 回复: 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 */

![](https://static1.yunpan.plus/attachment/453e934155ad.png)
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 32

  • 33

  • 34

  • 35

  • 36

  • 37

  • 38

  • 39

  • 40

  • 41

  • 42

  • 43

  • 44

  • 45

  • 46

  • 47

  • 48

  • 49

  • 50

  • 51

  • 52

  • 53

  • 54

  • 55

  • 56

  • 57

  • 58

  • 59

  • 60

  • 61

  • 62

  • 63

  • 64

  • 65

  • 66

  • 67

  • 68

  • 69

  • 70

  • 71

  • 72

  • 73

  • 74

  • 75

  • 76

  • 77

  • 78

  • 79

  • 80

  • 81

  • 82

  • 83

  • 84

  • 85

  • 86

  • 87

  • 88

  • 89

  • 90

  • 91

  • 92

  • 93

  • 94

  • 95

  • 96

  • 97

  • 98

  • 99

  • 100

  • 101

  • 102

  • 103

  • 104

  • 105

  • 106

  • 107

  • 108

  • 109

  • 110

  • 111

  • 112

  • 113

  • 114

  • 115

  • 116

  • 117

  • 118

  • 119

  • 120

  • 121

  • 122

  • 123

  • 124

  • 125

  • 126

  • 127

  • 128

  • 129

  • 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 */

![](https://static1.yunpan.plus/attachment/453e934155ad.png)
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 📝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

![](https://static1.yunpan.plus/attachment/453e934155ad.png)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128

HAL STM32 基于定时器外部时钟源测量频率 - 图片 - 1 飞书交流群
HAL STM32 基于定时器外部时钟源测量频率 - 图片 - 2QQ群名片
HAL STM32 基于定时器外部时钟源测量频率 - 图片 - 3




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

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

GMT+8, 2025-12-24 17:18 , Processed in 0.242638 second(s), 35 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

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