HAL STM32 基于定时器外部时钟源测量频率
📙STM32 基于定时器外部时钟源测量频率原理
将被测信号作为定时器的计数时钟源,而将一个已知的、稳定的高频信号(通常来自系统时钟)作为定时器的计数周期基准。通过在一个固定的基准时间内统计被测信号的脉冲个数,即可计算出频率。
📑STM32 外设资源分配
- Timer 2 (作为计数器):工作于 外部时钟源模式。
- 时钟源:来自外部的被测频率信号 Fx。
- 角色:纯粹地对 Fx 的上升沿或下降沿进行计数。
- 角色:产生一个固定、精确的时间窗口 T_measure(例如 1秒、100毫秒)。这个时间窗口用来统计 Timer 2 的计数个数所用的时间。

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


代码实现
/* 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 */

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

-
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

- 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
飞书交流群
QQ群名片

|