
时钟配置(72MHz 系统时钟)、TIM2 PWM 输出(PA0,10Hz)保持不变;
TIM3 引脚仍为 PA6(CH1),但功能从「输入捕获」改为「外部时钟源输入」。
- TIM3 外部时钟源配置
打开 CubeMX → 进入 TIM3 的「Configuration」界面;
第一步:配置从模式(Slave Mode)
点击「Slave Mode Configuration」标签;
Trigger Selection(触发源):选择 TI1FP1(TIM3_CH1 引脚的滤波后信号,即 PWM 输入);
Slave Mode(从模式):选择 External Clock Mode 2(外部时钟模式 2,由触发源驱动计数器);
Trigger Polarity(触发极性):选择 Rising(上升沿触发计数,对应 PWM 的上升沿);
Filter(滤波):设为 0(无滤波,若 PWM 有噪声可设 1~15);
Prescaler(分频):设为 0(不分频,每个上升沿都计数);
第二步:计数器基础配置
Counter Settings:
Counter Mode:Up(向上计数);
Prescaler (PSC):0(外部时钟源模式下,内部 PSC 失效,仅外部分频生效);
Counter Period (ARR):65535(16 位最大值,避免快速溢出);
Auto-reload preload:Enabled;
第三步:启用 TIM3 更新中断(用于检测溢出 / 计数完成)
进入「NVIC Settings」→ 勾选 TIM3 global interrupt,优先级默认即可;
点击「OK」保存配置,重新生成代码。
#include "tim.h"
#include "stdio.h"
// TIM3 外部时钟源相关变量
uint32_t tim3_counter = 0; // TIM3计数器值
uint32_t pwm_period_ticks = 0; // PWM周期对应的计数值
float pwm_frequency_ext = 0.0f; // 外部时钟模式下的PWM频率
uint8_t tim3_overflow_flag = 0; // TIM3溢出标志
uint32_t overflow_count_ext = 0; // 溢出次数
// TIM3全局中断处理函数
void TIM3_IRQHandler(void)
{
// 处理HAL库默认中断
HAL_TIM_IRQHandler(&htim3);
// 检测更新中断(溢出/计数器归零)
if (__HAL_TIM_GET_FLAG(&htim3, TIM_FLAG_UPDATE) != RESET)
{
__HAL_TIM_CLEAR_FLAG(&htim3, TIM_FLAG_UPDATE);
overflow_count_ext++; // 溢出次数+1
// 计算PWM周期(外部时钟源下,1个tick=1个PWM上升沿)
// 若ARR=65535,溢出一次表示计数了65536个PWM周期
pwm_period_ticks = 65536 * overflow_count_ext;
// 10Hz PWM的理论计数值:1秒内计数10次 → 频率=计数次数/时间
pwm_frequency_ext = (float)pwm_period_ticks / (overflow_count_ext * (65536.0f / 10.0f));
// 重置标志(按需)
tim3_overflow_flag = 1;
overflow_count_ext = 0;
}
}
int main(void)
{
// 1. 基础初始化
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM2_Init();
MX_TIM3_Init();
// 2. 启动TIM2 PWM输出(10Hz,PA0)
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, 499); // 50%占空比
// 3. 启动TIM3计数器(外部时钟源模式)
HAL_TIM_Base_Start_IT(&htim3); // 启动TIM3基础定时器+中断
// 4. 主循环
while (1)
{
// 读取TIM3当前计数值(即已捕获的PWM上升沿次数)
tim3_counter = __HAL_TIM_GET_COUNTER(&htim3);
// 溢出后打印结果
if (tim3_overflow_flag)
{
printf("TIM3计数值:%lu,PWM频率:%.2f Hz\r\n", tim3_counter, pwm_frequency_ext);
tim3_overflow_flag = 0;
}
// 实时打印计数值(每500ms)
HAL_Delay(500);
printf("当前计数值:%lu(溢出次数:%lu)\r\n", tim3_counter, overflow_count_ext);
}
}
四、简化版:直接通过计数值计算频率
若只需测量 10Hz PWM(周期 100ms),可不用等溢出,直接在主循环计算:
c
运行
while (1)
{
// 记录初始计数值和时间
uint32_t start_cnt = __HAL_TIM_GET_COUNTER(&htim3);
uint32_t start_tick = HAL_GetTick();
// 延时1秒(10Hz PWM应计数10次)
HAL_Delay(1000);
// 记录结束计数值和时间
uint32_t end_cnt = __HAL_TIM_GET_COUNTER(&htim3);
uint32_t end_tick = HAL_GetTick();
// 计算实际计数次数(考虑溢出)
uint32_t cnt_diff = end_cnt - start_cnt + (overflow_count_ext * 65536);
// 计算频率 = 计数次数 / 实际时间(秒)
pwm_frequency_ext = (float)cnt_diff / ((end_tick - start_tick) / 1000.0f);
printf("1秒内计数:%lu次,PWM频率:%.2f Hz\r\n", cnt_diff, pwm_frequency_ext);
// 重置溢出计数
overflow_count_ext = 0;
}
硬件接线:必须将 TIM2_CH1(PA0)与 TIM3_CH1(PA6)短接,PWM 信号才能输入到 TIM3 作为外部时钟;
触发极性选择:若选Rising则按上升沿计数,选Falling则按下降沿计数,需与 PWM 的有效边沿匹配;
外部时钟模式区别:
外部时钟模式 1:由 TRGI 触发计数器启动 / 停止;
外部时钟模式 2:由 TRGI 直接驱动计数器计数(推荐用于 PWM 时钟源);
计数精度:外部时钟模式下,TIM3 的计数精度完全由 PWM 信号的边沿决定,无内部时钟分频误差。
总结
CubeMX 核心配置:TIM3 选择「External Clock Mode 2」,触发源设为 TI1FP1(TIM3_CH1),触发极性为上升沿,启用更新中断;
代码逻辑:启动 TIM3 基础定时器 + 中断,通过计数器值 / 溢出次数计算 PWM 频率(10Hz PWM 每秒应计数 10 次);
优势:相比输入捕获,外部时钟源模式无需逐边沿捕获,直接通过计数次数反映 PWM 频率,更简洁且抗干扰性更强。