title: TIM输入捕获 tags: [STM32, TIM, 输入捕获, 频率测量]
输入捕获(Input Capture)的工作流程:
外部信号 → GPIO(TIx) → 滤波器 → 边沿检测 → 捕获CNT → 存入CCR
↑ ↑ ↑
ICx配置 ICFilter ICPolarity
三种捕获模式:
直接模式: TI1 → IC1 (捕获通道1)
间接模式: TI1 → IC2 (交换捕获通道)
PWMI模式: TI1 → IC1 + TI2 → IC2 (同时捕获频率和占空比)
上升沿 上升沿 上升沿
↓ ↓ ↓
|----T----|----T----|
捕获1 捕获2
频率 = TIM_CLK / (PSC + 1) / (Capture2 - Capture1)
______ ______
| | | |
_________| |____________| |
↑ 捕获CH1 ↑ 捕获CH2 ↑ 捕获CH1
(上升沿) (下降沿) (下次上升沿)
频率 = 1 / (CCR1_2 - CCR1_1)
占空比 = (CCR2 - CCR1) / (CCR1_2 - CCR1_1)
16位计数器(ARR=65535)在1MHz时钟下约65ms溢出一次:
CNT: ───0────65535────0────65535────
↑溢出中断
记录溢出次数 overflow_cnt,则:
总时间 = overflow_cnt × 65536 + CCR
typedef struct {
uint16_t TIM_Channel; // TIM_Channel_1/2/3/4
uint16_t TIM_ICPolarity; // TIM_ICPolarity_Rising / Falling / Both
uint16_t TIM_ICSelection; // TIM_ICSelection_DirectTI / IndirectTI / TRC
uint16_t TIM_ICPrescaler; // 0/1/2/4/8 分频 (ICxPSC)
uint16_t TIM_ICFilter; // 0x00~0x0F 数字滤波
} TIM_ICInitTypeDef;
| 函数 | 描述 |
|---|---|
TIM_ICInit(TIMx, &TIM_ICInitStructure) |
初始化输入捕获通道 |
TIM_PWMIConfig(TIMx, &TIM_ICInitStructure) |
配置 PWMI 模式(同时配 CH1+CH2) |
TIM_GetCapture1(TIMx) |
读取 CCR1 |
TIM_GetCapture2(TIMx) |
读取 CCR2 |
TIM_GetCapture3(TIMx) |
读取 CCR3 |
TIM_GetCapture4(TIMx) |
读取 CCR4 |
TIM_ITConfig(TIMx, TIM_IT_Update/CC1/CC2, ENABLE) |
使能中断 |
TIM_GetITStatus(TIMx, TIM_IT_Update) |
获取中断状态 |
TIM_ClearITPendingBit(TIMx, TIM_IT_Update) |
清除中断标志 |
TIM_SelectInputTrigger(TIMx, TIM_TS_TI1FP1) |
选择触发输入(从模式) |
TIM_SelectSlaveMode(TIMx, TIM_SlaveMode_Reset) |
选择从模式(复位模式自动清零CNT) |
| 宏 | 说明 |
|---|---|
TIM_ICPolarity_Rising |
上升沿捕获 |
TIM_ICPolarity_Falling |
下降沿捕获 |
TIM_ICPolarity_Both |
双边沿捕获(需 TIM5 或高级定时器) |
| 宏 | 说明 |
|---|---|
TIM_ICSelection_DirectTI |
直接模式,TIx → ICx |
TIM_ICSelection_IndirectTI |
间接模式,TIx → ICy |
TIM_ICSelection_TRC |
内部触发输入 |
TIM_ICFilter)| 值 | 采样频率 | 采样次数 | 说明 |
|---|---|---|---|
| 0x00 | — | — | 无滤波 |
| 0x01–0x0F | fDTS/N | 递增 | N 次一致才输出有效电平 |
#include "stm32f10x.h"
volatile uint16_t overflows = 0;
void Delay_ms(uint32_t ms)
{
SysTick->LOAD = 72000 - 1;
SysTick->VAL = 0;
SysTick->CTRL = 0x05;
for (uint32_t i = 0; i < ms; i++) {
while (!(SysTick->CTRL & (1 << 16)));
}
SysTick->CTRL = 0;
}
void TIM3_InputCapture_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Prescaler = 71; // 1MHz
TIM_TimeBaseStructure.TIM_Period = 65535; // 最大周期
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x0F; // 最大滤波
TIM_ICInit(TIM3, &TIM_ICInitStructure);
// 使能更新中断(用于溢出处理)
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM3, ENABLE);
}
uint32_t IC_GetFreq(void)
{
// 等待两个上升沿
TIM_SetCounter(TIM3, 0);
overflows = 0;
while (TIM_GetFlagStatus(TIM3, TIM_FLAG_CC1) == RESET); // 等待第一次捕获
TIM_ClearFlag(TIM3, TIM_FLAG_CC1);
while (TIM_GetFlagStatus(TIM3, TIM_FLAG_CC1) == RESET); // 等待第二次捕获
TIM_ClearFlag(TIM3, TIM_FLAG_CC1);
uint32_t capture = TIM_GetCapture1(TIM3);
uint32_t total = overflows * 65536UL + capture;
// 频率 = 1MHz / total(单位Hz)
return 1000000UL / total;
}
void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) {
overflows++;
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
}
int main(void)
{
TIM3_InputCapture_Init();
while (1) {
uint32_t freq = IC_GetFreq();
Delay_ms(500);
// 此处可用串口打印 freq
}
}
#include "stm32f10x.h"
volatile uint16_t overflows = 0;
void TIM3_PWMI_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Prescaler = 71;
TIM_TimeBaseStructure.TIM_Period = 65535;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
// PWMI 模式:CH1 上升沿测频率,CH2 下降沿测占空比
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x0F;
TIM_PWMIConfig(TIM3, &TIM_ICInitStructure); // 自动配置 CH1+CH2
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM3, ENABLE);
}
// 返回频率(Hz)和占空比(0.01%)
void IC_GetFreqAndDuty(uint32_t *freq, uint16_t *duty)
{
TIM_SetCounter(TIM3, 0);
overflows = 0;
while (TIM_GetFlagStatus(TIM3, TIM_FLAG_CC1) == RESET);
TIM_ClearFlag(TIM3, TIM_FLAG_CC1);
while (TIM_GetFlagStatus(TIM3, TIM_FLAG_CC1) == RESET);
TIM_ClearFlag(TIM3, TIM_FLAG_CC1);
uint16_t ccr1_2 = TIM_GetCapture1(TIM3); // 第二次上升沿
uint16_t ccr2 = TIM_GetCapture2(TIM3); // 下降沿
uint32_t period = overflows * 65536UL + ccr1_2;
if (period == 0) {
*freq = 0;
*duty = 0;
return;
}
*freq = 1000000UL / period;
*duty = (uint16_t)((uint32_t)ccr2 * 10000 / period);
}
void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) {
overflows++;
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
}
溢出处理:16位计数器在1MHz下每65.5ms溢出一次。测低频时必须用更新中断记录溢出次数,否则结果完全错误
滤波影响高频:TIM_ICFilter 过大会滤掉窄脉冲。测高频(>100kHz)时设 TIM_ICFilter = 0 或小值
从模式复位:使用 TIM_SlaveMode_Reset 可让捕获到边沿时自动清零 CNT,无需手动 TIM_SetCounter(0),但初始化较复杂
PSC 影响分辨率:PSC 越小分辨率越高,但计数器溢出更快。测低频需要大 PSC + 大 ARR,测高频需要小 PSC + 小 ARR
PWMI 模式注意:TIM_PWMIConfig() 会同时配置 CH1 和 CH2,不要再去手动调用 TIM_ICInit() 配置 CH2,否则覆盖
输入引脚:确保 GPIO 模式正确(浮空或上拉输入),不要误用为输出模式
捕获中断 vs 更新中断:需要分别使能,不要混淆 TIM_IT_CC1 和 TIM_IT_Update