脉冲计数实现

将定时器 2 通道 2 输入的低电平脉冲作为定时器 2 的时钟,并通过串口打印脉冲数 PSC=0,ARR=65535 外部时钟模式1、触发选择、上升沿触发、不分频、不滤波。

"外部时钟模式 1(ECM1)用 TIM2_CH2 计脉冲

main.c:

cpp 复制代码
#include "sys.h"        // 项目通用头(通常会包含芯片HAL头文件及时钟配置)
#include "delay.h"      // 延时相关
#include "led.h"        // LED 驱动(用于简单指示)
#include "uart1.h"      // 串口1 打印
#include "counter.h"    // 本实验的计数器对外接口(见下方)

int main(void)
{
    HAL_Init();                         /* 初始化HAL库:复位外设、初始化Flash接口、Systick等 */
    stm32_clock_init(RCC_PLL_MUL9);     /* 配置系统时钟到72MHz(HSE*9),为后续外设/内核提供时钟 */
    led_init();                         /* LED初始化(可选,用于指示运行状态) */
    uart1_init(115200);                 /* 串口1初始化为115200-8-N-1,用于打印结果 */
    printf("hello world!\r\n");

    /* 
     * 计数器初始化:
     *  - arr = 65536 - 1 => 自动重装载寄存器ARR=0xFFFF(16位满量程)
     *  - psc = 0         => 预分频=0(即不分频,计数器每来一个外部脉冲就+1)
     *
     * 说明:TIM2本身是32位定时器,但你把ARR设成了16位最大值,这样更直观地做"0~65535"循环计数。
     * 如果你要更大计数范围,可把ARR设更大(比如0xFFFFFFFF,需要按32位读改)。
     */
    counter_init(65536 - 1, 0);

    while(1)
    {
        /* 方式1:读取当前CNT并在变化时打印(示例与原逻辑一致) */
        count_get();

        /* 方式2(推荐做实时计数):得到"自上次调用以来的增量脉冲数",更高效,避免频繁printf阻塞
           uint32_t incr = count_get_delta();
           if (incr) { printf("inc: %lu\r\n", incr); }
        */

        // 适当小延时,避免打印过快造成串口阻塞(根据实际脉冲频率调整)
        delay_ms(1);
    }
}

counter.h**:**

cpp 复制代码
#ifndef __COUNTER_H__
#define __COUNTER_H__

#include "stm32f1xx_hal.h"  // 确保包含到F1的HAL头;若你的sys.h已包含,可按需修改

#ifdef __cplusplus
extern "C" {
#endif

/* 对外接口函数声明 */

/**
 * @brief 外部时钟模式1:用 TIM2_CH2 计数外部脉冲
 * @param arr 自动重装载值(周期 - 1),例如 65536 - 1 表示16位满量程
 * @param psc 预分频(0 表示不分频)
 */
void     counter_init(uint32_t arr, uint16_t psc);

/**
 * @brief 读取当前CNT值,若变化则通过printf打印(和你的原函数一致)
 */
void     count_get(void);

/**
 * @brief 返回"自上次调用以来的增量脉冲数",自动处理ARR回卷(推荐统计增量用)
 * @return 增量(0 表示无新增脉冲)
 */
uint32_t count_get_delta(void);

#ifdef __cplusplus
}
#endif

#endif /* __COUNTER_H__ */

counter.c:

cpp 复制代码
#include "counter.h"
#include "stdio.h"

/* 全局句柄:TIM2 用于计外部脉冲 */
TIM_HandleTypeDef counter_handle = {0};

/* 保存上/下两次读取的计数值,用于变化打印与增量计算 */
static volatile uint32_t g_old_cnt = 0;      // 上一次读取的CNT
static volatile uint32_t g_arr     = 0xFFFF; // 记录配置的ARR,便于做回卷运算

/**
 * @brief  初始化 TIM2 为"外部时钟模式1",在 CH2(PA1) 上计数外部脉冲
 * @param  arr  自动重装载值(周期-1),例:65536-1
 * @param  psc  预分频系数(0=不分频)
 */
void counter_init(uint32_t arr, uint16_t psc)
{
    /* ------------ 1. 基本定时器参数配置(只负责计数器本体) ------------ */
    counter_handle.Instance = TIM2;                     // 选择 TIM2
    counter_handle.Init.Prescaler = psc;                // 计数器预分频:0=不分频
    counter_handle.Init.Period = arr;                   // 自动重装载值 ARR,计数达到ARR后回到0
    counter_handle.Init.CounterMode = TIM_COUNTERMODE_UP;         // 向上计数
    counter_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;   // 内部分频不再分(DIV1)
    HAL_TIM_Base_Init(&counter_handle);                 // 初始化基本定时器(装载上述配置)

    g_arr = arr;                                        // 保存ARR,供回卷计算

    /* ------------ 2. 配置输入捕获通道(把CH2当作触发源TI2FP2) ------------ */
    TIM_IC_InitTypeDef ic_cfg = {0};
    ic_cfg.ICPolarity  = TIM_INPUTCHANNELPOLARITY_RISING;  // 触发沿:上升沿(与你的"上升沿触发"一致)
    // 若要"低电平脉冲起始"为有效,可改成 FALLING(下降沿):
    // ic_cfg.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;

    ic_cfg.ICSelection = TIM_ICSELECTION_DIRECTTI;     // 选择直连TI(CH2直接接到IC)
    ic_cfg.ICPrescaler = TIM_ICPSC_DIV1;               // 输入捕获不分频(不跳边)
    ic_cfg.ICFilter    = 0;                            // 不滤波(0~15 可选,>0 可做数字滤波,抗抖/毛刺)
    HAL_TIM_IC_ConfigChannel(&counter_handle, &ic_cfg, TIM_CHANNEL_2);

    /* ------------ 3. 配置从模式为"外部时钟模式1"(ECM1) ------------ */
    TIM_SlaveConfigTypeDef slave_cfg = {0};
    slave_cfg.SlaveMode        = TIM_SLAVEMODE_EXTERNAL1; // 外部时钟模式1:由触发输入驱动计数器时钟
    slave_cfg.InputTrigger     = TIM_TS_TI2FP2;           // 触发选择:TI2 的滤波后信号(来自CH2)
    slave_cfg.TriggerPolarity  = TIM_TRIGGERPOLARITY_RISING; // 触发极性:上升沿
    // 若改下降沿,对应改为 TIM_TRIGGERPOLARITY_FALLING
    slave_cfg.TriggerPrescaler = TIM_TRIGGERPRESCALER_DIV1;  // 触发预分频(对触发边沿再做1/2/4/8分频)
    slave_cfg.TriggerFilter    = 0;                          // 触发滤波(通常对ETR有效;TIx滤波主看ICFilter)
    HAL_TIM_SlaveConfigSynchro(&counter_handle, &slave_cfg);

    /* ------------ 4. 使能通道与启动计数 ------------ */
    HAL_TIM_IC_Start(&counter_handle, TIM_CHANNEL_2);  // 使能CH2输入捕获(允许触发链路工作)
    HAL_TIM_Base_Start(&counter_handle);               // 打开计数器(CEN=1)。此后,每个外部有效边沿 => CNT+1
}

/**
 * @brief  由HAL库自动回调:定时器输入捕获 MSP(底层)初始化
 * @note   在这里打开GPIO/TIM时钟,并把PA1配置成输入
 */
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM2)
    {
        GPIO_InitTypeDef gpio = {0};

        __HAL_RCC_GPIOA_CLK_ENABLE();  // 使能 GPIOA 时钟(PA1 在 A 口)
        __HAL_RCC_TIM2_CLK_ENABLE();   // 使能 TIM2 时钟

        /* TIM2_CH2 => PA1,配置为"输入"
         * F1系列定时器通道的复用是固定映射,无需设置AF功能号。
         * 建议上拉(PULLUP),让空闲时为高电平,这样外部"低脉冲"更清晰地产生一个"下降+上升"的边沿对。
         */
        gpio.Pin   = GPIO_PIN_1;               // PA1
        gpio.Mode  = GPIO_MODE_INPUT;          // 输入模式(F1用这个即可;若是F4/07等系列可用GPIO_MODE_AF_PP/OD并上拉)
        gpio.Pull  = GPIO_PULLUP;              // 上拉:空闲=高,抗干扰
        gpio.Speed = GPIO_SPEED_FREQ_HIGH;     // 对输入影响不大,可保持高速
        HAL_GPIO_Init(GPIOA, &gpio);
    }
}

/**
 * @brief  读取当前CNT,若变化则打印(与你原始逻辑保持一致)
 * @note   printf 可能阻塞,脉冲频率高时建议换成 count_get_delta() 方案做累计
 */
void count_get(void)
{
    uint32_t new_cnt = __HAL_TIM_GET_COUNTER(&counter_handle);  // 读取TIM2->CNT(0..ARR循环)

    if (new_cnt != g_old_cnt)                                   // 仅在变化时打印,减少串口负担
    {
        g_old_cnt = new_cnt;                                    // 更新历史值
        printf("CNT: %lu\r\n", (unsigned long)new_cnt);         // 打印当前计数
    }
}

/**
 * @brief  返回"自上次调用以来"的增量脉冲数,自动处理ARR回卷
 * @return 增量(0 表示期间无新脉冲)
 */
uint32_t count_get_delta(void)
{
    uint32_t cur = __HAL_TIM_GET_COUNTER(&counter_handle);  // 当前CNT
    uint32_t inc;

    if (cur >= g_old_cnt) {
        inc = cur - g_old_cnt;                               // 常规情况:直接相减
    } else {
        inc = (g_arr + 1u - g_old_cnt) + cur;                // 回卷情况:先从old到ARR,再从0到cur
    }

    g_old_cnt = cur;                                         // 更新历史值
    return inc;
}

二、参数/函数逐点解释

1) ARR = 65536 - 1 为什么常这么写?

  • 计数范围是 0 ... ARR,所以把 ARR=65536-1 等价于 0...65535(16位满量程)。

  • 你当然可以改成别的数(比如 9999),那就是 0...9999 后回卷。

  • 若想极大范围 ,TIM2 是 32 位定时器,可以把 ARR 设得更大(如 0xFFFFFFFF),但相应地:

    • CNTuint32_t 读取与存储;

    • 增量/回卷逻辑也按 32 位来处理。

2) PSC = 0

  • 预分频器对"计数时钟"再做一次分频,PSC=0 表示不分频。

  • 在外部时钟模式 1 下,"有效触发边沿"就是计数器时钟源;通常我们希望每个脉冲计一次 ,所以 PSC=0

3) TIM_SLAVEMODE_EXTERNAL1 + TIM_TS_TI2FP2

  • 外部时钟模式1(ECM1):把"触发输入(TRGI)"当作计数器时钟。

  • TIM_TS_TI2FP2:把 CH2 的滤波后输入(TI2FP2)选作"触发输入"。

  • 效果:PA1 上每来一次选定极性的有效边沿 => CNT + 1

4) 极性与滤波

  • ICPolarity=RISING / TriggerPolarity=RISING:上升沿触发(你现在的需求)。

  • 若你的外部脉冲是"低电平脉冲 "(空闲高,短时拉低),一般脉冲开始 是一个下降沿脉冲结束 是一个上升沿

    • 你希望"每个低脉冲只记一次",通常选其中一个边沿(比如上升沿或下降沿),二选一即可

    • 想在"低脉冲开始就计数",把极性改成 FALLING

  • 滤波:

    • ICFilter(0~15)对 TIx 输入做数字滤波(多个采样一致才认为有效),可抑制毛刺/抖动。

    • 频率高且信号干净时设 0;有噪声/机械抖动时适当增大(但会降低最高可计频率)。

5) HAL_TIM_IC_StartHAL_TIM_Base_Start

  • HAL_TIM_IC_Start:打开通道的输入捕获功能(允许 TI2FP2 形成触发)。

  • HAL_TIM_Base_Start:真正使能计数器(CEN=1)。两者都要开。

三、脉冲计数原理(外部时钟模式1)

可以用一个简化方框图理解:

cpp 复制代码
外部信号(到PA1=TIM2_CH2)
       │
       ▼
   输入滤波(ICFilter) ──> 形成 TI2FP2(带滤波的CH2信号)
       │
       ▼
   触发选择(TS=TI2FP2) ──> 触发极性(上升/下降沿) ──> "触发事件"
       │
       └─────────────> 设从模式为 External1:把"触发事件"当作计数器时钟
                                 │
                                 ▼
                            计数器 CK_CNT
                                 │
                                 ▼
                              CNT = CNT + 1  (每个有效边沿+1)
  • 核心思想 :不是用内部APB时钟去"滴答",而是把外部边沿当作"时钟脉冲"。

  • 因此 CNT 的步进频率 = 外部有效边沿频率(再考虑触发/IC分频)

  • 你要的是"低电平脉冲的次数",那就选定某个边沿 (比如脉冲结束 的上升沿),每次出现就 CNT+1

1. TIM_HandleTypeDef.Init 的参数

这是定时器的基本配置部分。

cpp 复制代码
counter_handle.Init.Prescaler = psc;
counter_handle.Init.Period = arr;
counter_handle.Init.CounterMode = TIM_COUNTERMODE_UP;
counter_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  • Prescaler:预分频器 (PSC)

    • 0 ~ 0xFFFF

    • 实际计数频率 = 计数时钟 / (PSC+1)

  • Period:自动重装载寄存器 (ARR)

    • 定时器计数的上限,CNT 计到 ARR 后溢出回 0。
  • CounterMode:计数模式

    • TIM_COUNTERMODE_UP(向上计数)

    • TIM_COUNTERMODE_DOWN(向下计数)

    • TIM_COUNTERMODE_CENTERALIGNED1/2/3(中心对齐模式,常用于PWM)

  • ClockDivision:时钟分频(对内部时钟的进一步分频)

    • TIM_CLOCKDIVISION_DIV1

    • TIM_CLOCKDIVISION_DIV2

    • TIM_CLOCKDIVISION_DIV4

    • 通常用于滤波/死区计数。

2. TIM_IC_InitTypeDef 的参数

输入捕获通道配置。

cpp 复制代码
ic_cfg.ICPolarity  = TIM_INPUTCHANNELPOLARITY_RISING;
ic_cfg.ICSelection = TIM_ICSELECTION_DIRECTTI;
ic_cfg.ICPrescaler = TIM_ICPSC_DIV1;
ic_cfg.ICFilter    = 0;
  • ICPolarity(极性)

    • TIM_INPUTCHANNELPOLARITY_RISING(上升沿)

    • TIM_INPUTCHANNELPOLARITY_FALLING(下降沿)

    • TIM_INPUTCHANNELPOLARITY_BOTHEDGE(双边沿)

  • ICSelection(选择)

    • TIM_ICSELECTION_DIRECTTI(直连输入 TIx → 通道)

    • TIM_ICSELECTION_INDIRECTTI(间接输入,另一通道)

    • TIM_ICSELECTION_TRC(触发控制器输入)

  • ICPrescaler(输入分频)

    • TIM_ICPSC_DIV1(每个有效边沿都计)

    • TIM_ICPSC_DIV2(每 2 个有效边沿计 1)

    • TIM_ICPSC_DIV4(每 4 个)

    • TIM_ICPSC_DIV8(每 8 个)

  • ICFilter(滤波)

    • 0 ~ 15,越大抗干扰能力越强,但能识别的最高频率下降。

    • 常用于抖动/毛刺信号。

3. TIM_SlaveConfigTypeDef 的参数

从模式配置,用于外部时钟/触发同步。

cpp 复制代码
slave_cfg.SlaveMode        = TIM_SLAVEMODE_EXTERNAL1;
slave_cfg.InputTrigger     = TIM_TS_TI2FP2;
slave_cfg.TriggerPolarity  = TIM_TRIGGERPOLARITY_RISING;
slave_cfg.TriggerPrescaler = TIM_TRIGGERPRESCALER_DIV1;
slave_cfg.TriggerFilter    = 0;
  • SlaveMode(从模式)

    • TIM_SLAVEMODE_DISABLE(关闭从模式)

    • TIM_SLAVEMODE_RESET(触发信号使 CNT 复位)

    • TIM_SLAVEMODE_GATED(触发信号作为门控)

    • TIM_SLAVEMODE_TRIGGER(触发信号启动定时器)

    • TIM_SLAVEMODE_EXTERNAL1(外部时钟模式1,脉冲作为时钟源)← 你用的

  • InputTrigger(触发输入源)

    • TIM_TS_TI1FP1(通道1的滤波输入)

    • TIM_TS_TI2FP2(通道2的滤波输入)← 你用的

    • TIM_TS_ETRF(外部触发输入 ETR)

    • TIM_TS_ITR0~3(内部触发,用于定时器之间联动)

  • TriggerPolarity(触发极性)

    • TIM_TRIGGERPOLARITY_RISING

    • TIM_TRIGGERPOLARITY_FALLING

    • TIM_TRIGGERPOLARITY_BOTHEDGE

  • TriggerPrescaler(触发预分频)

    • TIM_TRIGGERPRESCALER_DIV1

    • TIM_TRIGGERPRESCALER_DIV2

    • TIM_TRIGGERPRESCALER_DIV4

    • TIM_TRIGGERPRESCALER_DIV8

  • TriggerFilter(触发滤波)

    • 0 ~ 15,抗干扰。

4. GPIO_InitTypeDef 的参数

IO 口配置(初始化 PA1)。

cpp 复制代码
gpio.Pin   = GPIO_PIN_1;
gpio.Mode  = GPIO_MODE_INPUT;
gpio.Pull  = GPIO_PULLUP;
gpio.Speed = GPIO_SPEED_FREQ_HIGH;
  • Pin :选择引脚,如 GPIO_PIN_0 | GPIO_PIN_1

  • Mode:模式

    • GPIO_MODE_INPUT(输入)

    • GPIO_MODE_OUTPUT_PP(推挽输出)

    • GPIO_MODE_OUTPUT_OD(开漏输出)

    • GPIO_MODE_AF_PP(复用推挽)

    • GPIO_MODE_AF_OD(复用开漏)

    • GPIO_MODE_ANALOG(模拟输入)

  • Pull:上下拉

    • GPIO_NOPULL

    • GPIO_PULLUP

    • GPIO_PULLDOWN

  • Speed:输出速度(对输入无关)

    • GPIO_SPEED_FREQ_LOW

    • GPIO_SPEED_FREQ_MEDIUM

    • GPIO_SPEED_FREQ_HIGH

不同结构体对应不同的参数选择:

  • 计数器基本配置PrescalerPeriodCounterModeClockDivision

  • 输入捕获配置ICPolarityICSelectionICPrescalerICFilter

  • 从模式配置SlaveModeInputTriggerTriggerPolarityTriggerPrescalerTriggerFilter

  • GPIO 配置PinModePullSpeed

STM32 HAL 定时器常见配置参数速查表:每张表都包含:字段、可选宏/取值、含义/作用、常用场景示例(含你本l例"外部时钟模式1计数"的推荐值)。

TIM_Base 初始化(TIM_HandleTypeDef.Init

字段 可选值/范围 作用 常用场景示例
Prescaler 0 ~ 0xFFFF(F1) 计数器预分频:计数时钟 = 输入时钟 / (PSC+1) 外部时钟计数0(每个外部边沿+1);定时中断:按期望溢出频率计算
Period 0 ~ 0xFFFF(F1,16位TIM);0~0xFFFFFFFF(32位TIM,如 TIM2/5) 自动重装载(ARR),CNT 到 ARR 后回卷 计数器满量程65535(写 65536-1);定时中断:按周期计算
CounterMode TIM_COUNTERMODE_UP / DOWN / CENTERALIGNED1/2/3 计数模式 计数/定时UPPWM中心对齐CENTERALIGNEDx
ClockDivision TIM_CLOCKDIVISION_DIV1/2/4 内部分频,影响数字滤波/死区采样 一般 DIV1
RepetitionCounter* 仅高级定时器(TIM1/TIM8) N 次更新后再触发一次更新事件 高级PWM特殊应用

* F1 的 HAL 里 RepetitionCounter 通过 TIMx->RCR 访问,不总在 Init 中暴露。


输入捕获配置(TIM_IC_InitTypeDef

字段 可选值/范围 作用 外部脉冲计数(ECM1)推荐 频率/周期测量常用
ICPolarity TIM_INPUTCHANNELPOLARITY_RISING / FALLING / BOTHEDGE 识别哪种边沿为有效 视脉冲定义:每个脉冲只记一次 → 选 RISINGFALLING 之一 测周期多用 RISING
ICSelection TIM_ICSELECTION_DIRECTTI / INDIRECTTI / TRC 通道输入选择 DIRECTTI(TIx直连) DIRECTTI(两通道互联时另一路可用 INDIRECTTI
ICPrescaler TIM_ICPSC_DIV1/2/4/8 边沿抽取分频 DIV1(每个边沿都记) 噪声多时可降采样
ICFilter 0 ~ 15 数字滤波(越大越抗抖,但最高可测频率下降) 0 或小值;有毛刺时增大 依输入噪声设定

从模式/触发配置(TIM_SlaveConfigTypeDef

字段 可选值/范围 作用 外部脉冲计数(ECM1)推荐 其他常见用途
SlaveMode DISABLE / RESET / GATED / TRIGGER / EXTERNAL1 从模式选择 TIM_SLAVEMODE_EXTERNAL1(外部时钟模式1) 主从同步TRIGGER/RESET门控GATED
InputTrigger TIM_TS_TI1FP1 / TI2FP2 / ETRF / ITR0~3 触发源选择(TRGI) TIM_TS_TI2FP2(CH2 触发) 定时器联动ITR0~3外部脚ETRF
TriggerPolarity RISING / FALLING / BOTHEDGE 触发极性 ICPolarity 对应选一个边沿即可 同步/门控时按边沿需求
TriggerPrescaler DIV1/2/4/8 触发预分频 DIV1 降低触发频率
TriggerFilter 0 ~ 15 触发滤波 0 或小值 抗干扰

备注:ECM1 实际计数由 TRGI 驱动,TRGI 又来自 InputTrigger 选定的源(如 TI2FP2),因此 IC 配置 + 从模式配置 两部分要匹配。


主模式(触发输出)配置(TIM_MasterConfigTypeDef

字段 可选值/范围 作用 常用场景
MasterOutputTrigger TIM_TRGO_RESET / ENABLE / UPDATE / OC1 / OC1REF / OC2REF / OC3REF / OC4REF 决定 TRGO 输出的事件 多定时器同步:用 UPDATE 让别的TIM以此为触发
MasterSlaveMode TIM_MASTERSLAVEMODE_ENABLE/DISABLE 使能主从模式(便于同步) 级联/同步启动等

通道级(输出比较/PWM)配置(TIM_OC_InitTypeDef)---(若你做PWM会用到)

字段 可选值/范围 作用 常用场景
OCMode TIM_OCMODE_TIMING / ACTIVE / INACTIVE / TOGGLE / PWM1 / PWM2 / FORCED_ACTIVE / FORCED_INACTIVE 通道输出模式 PWM1/PWM2 生成PWM
Pulse 0 ~ ARR CCRx,占空比 占空比 = CCR / (ARR+1)
OCPolarity TIM_OCPOLARITY_HIGH/LOW 有效电平极性 反相输出时选 LOW
OCFastMode ENABLE/DISABLE 快速比较 特殊应用

外部触发输入(ETR)/ 外部时钟模式2(了解即可)

可选值/范围 说明
外部时钟模式2 HAL_TIM_ConfigClockSource(..., TIM_CLOCKSOURCE_ETRMODE2) 通过 ETR 脚作为时钟源(与 ECM1 不同路径)
ETR 极性/滤波/预分频 TIM_ETRPOLARITY_NONINVERTED/INVERTEDTIM_ETR_PRESCALER_DIV1/2/4/8TIM_ETR_FILTER 0~15 当使用 ETR 时可单独配置

GPIO 初始化(GPIO_InitTypeDef,与定时器通道配合)

字段 可选值/范围 作用 外部脉冲计数建议
Pin GPIO_PIN_x 选择引脚 例:GPIO_PIN_1(TIM2_CH2=PA1)
Mode INPUT / AF_PP / AF_OD / OUTPUT_PP / OUTPUT_OD / ANALOG 引脚模式 F1 用输入模式GPIO_MODE_INPUT)接外部信号
Pull PULLUP / PULLDOWN / NOPULL 上下拉 建议 PULLUP,空闲为高,低脉冲清晰
Speed LOW/MEDIUM/HIGH 输出速率 对输入影响不大,可 HIGH

常见"目标任务"推荐配置(速查)

目标 关键配置 备注
外部脉冲计数(ECM1) IC: Polarity=RISING(或FALLING), Selection=DIRECTTI, Prescaler=DIV1, Filter=0~NSlave: Mode=EXTERNAL1, Trigger=TIxFPx(与你用的通道对应), TriggerPolarity=同上, TriggerPrescaler=DIV1, TriggerFilter=0~NPSC=0, ARR=期望满量程 你这题:TIM2_CH2→TI2FP2,上升沿记一次脉冲
定时中断(TimeBase) SlaveMode=DISABLE;根据目标周期设置 PSC/ARRHAL_TIM_Base_Start_IT 常用来做固定周期任务
PWM 输出 OC: Mode=PWM1/2, Pulse=CCR, Polarity=HIGHPSC/ARR 设置PWM频率;HAL_TIM_PWM_Start 频率 = TimerClk / (PSC+1) / (ARR+1);占空比 = CCR/(ARR+1)
频率/占空比测量(PWM输入模式) HAL_TIM_PWM_ConfigChannel / HAL_TIM_IC_ConfigChannel(成对配置) + HAL_TIM_...PWM 输入模式(或两通道互联) 用一通道测周期,另一通道测高电平宽度

计算方法:

  • 内部时钟定时模式

    • 计数频率 f_cnt = f_tim / (PSC+1)

    • 溢出频率 f_ov = f_cnt / (ARR+1)周期 T = (PSC+1)*(ARR+1)/f_tim

  • 外部时钟模式1(ECM1)

    • 计数步进由触发有效边沿 决定:f_cnt ≈ f_edge / (ICPrescaler * TriggerPrescaler)(忽略滤波饱和)
  • PWM

    • PWM 频率 f_pwm = f_tim / (PSC+1) / (ARR+1)

    • 占空比 D = CCR / (ARR+1)