一、输入捕获
1.简介
-
IC(Input Capture)输入捕获输入
-
捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数
-
每个高级定时器和通用定时器都拥有4个输入捕获通道
-
可配置为PWMI模式,同时测量频率和占空比
-
可配合主从触发模式,实现硬件全自动测量
2.频率测量
- 测频法适合测量高频信号,测周法适合测量低频信号。测频法要求信号频率要稍微高一些。那对于测周法就要求信号频率低一些了,低频信号周期比较长,计次就会比较多,有助于减小误差。
- 对应图上,当待测信号频率小于中介频率时,测周法误差更小,选用测周法更合适。当待测信号频率大于中间频率时,测频法误差更小,选用测频法更合适。
3.输入捕获通道
4.主从触发模式
- 主从触发模式就是主模式、从模式和触发源选择这三个功能的简称。
- 其中主模式可以将定时器内部的信号映射到TRGO引脚。用于触发别的外设。所以这部分叫做主模式。
- 从模式,就是接收其他外设或者自身外设的一些信号,用于控制自身定时器的运行,也就是被别的信号控制,所以这部分叫从模式。
- 触发源选择就是选择从模式的触发信号源的,你可以认为它是从模式的一部分。触发源选择指定的一个信号,得到TRGI,TRGI去触发从模式,从模式可以在这个列表里选择一项操作来自动执行。
5.输入捕获基本结构
6.PWMI基本结构
- 配置为PWMI模式,同时测量频率和占空比。这个PWM模式就是PWM的输入模式,是专门为测量PWM频率和占空比设计的。
- PWM模式和主从触发模式设计的非常巧妙,把这两个功能结合起来测量频率占空比,就是硬件全自动执行。软件不需要进行任何干预,也不需要进行中断,需要测量的时候直接读取CCR计算器,极大的减轻了软件的压力。
二、输入捕获模式测频率
1.接线图
2.代码
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"int main(void)
{/*模块初始化*/OLED_Init(); //OLED初始化PWM_Init(); //PWM初始化IC_Init(); //输入捕获初始化/*显示静态字符串*/OLED_ShowString(1, 1, "Freq:00000Hz"); //1行1列显示字符串Freq:00000Hz/*使用PWM模块提供输入捕获的测试信号*/PWM_SetPrescaler(720 - 1); //PWM频率Freq = 72M / (PSC + 1) / 100PWM_SetCompare1(50); //PWM占空比Duty = CCR / 100while (1){OLED_ShowNum(1, 6, IC_GetFreq(), 5); //不断刷新显示输入捕获测得的频率}
}
IC.c
#include "stm32f10x.h" // Device header/*** 函 数:输入捕获初始化* 参 数:无* 返 回 值:无*/
void IC_Init(void)
{/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //开启TIM3的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA6引脚初始化为上拉输入/*配置时钟源*/TIM_InternalClockConfig(TIM3); //选择TIM3为内部时钟,若不调用此函数,TIM默认也为内部时钟/*时基单元初始化*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定义结构体变量TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1; //计数周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //预分频器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器,高级定时器才会用到TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit,配置TIM3的时基单元/*输入捕获初始化*/TIM_ICInitTypeDef TIM_ICInitStructure; //定义结构体变量TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //选择配置定时器通道1TIM_ICInitStructure.TIM_ICFilter = 0xF; //输入滤波器参数,可以过滤信号抖动TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //极性,选择为上升沿触发捕获TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //捕获预分频,选择不分频,每次信号都触发捕获TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //输入信号交叉,选择直通,不交叉TIM_ICInit(TIM3, &TIM_ICInitStructure); //将结构体变量交给TIM_ICInit,配置TIM3的输入捕获通道/*选择触发源及从模式*/TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1); //触发源选择TI1FP1TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset); //从模式选择复位//即TI1产生上升沿时,会触发CNT归零/*TIM使能*/TIM_Cmd(TIM3, ENABLE); //使能TIM3,定时器开始运行
}/*** 函 数:获取输入捕获的频率* 参 数:无* 返 回 值:捕获得到的频率*/
uint32_t IC_GetFreq(void)
{return 1000000 / (TIM_GetCapture1(TIM3) + 1); //测周法得到频率fx = fc / N,这里不执行+1的操作也可
}
IC.c
#ifndef __IC_H
#define __IC_Hvoid IC_Init(void);
uint32_t IC_GetFreq(void);#endif
3.相关API
1. void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
功能:使能或禁用 APB1 总线上的外设时钟
参数:
-
RCC_APB1Periph
:选择 APB1 外设(x 为外设枚举值)
- 可选值(部分):
RCC_APB1Periph_TIM2
:TIM2 定时器RCC_APB1Periph_TIM3
:TIM3 定时器(输入捕获用)RCC_APB1Periph_I2C1
:I2C1 接口
- 可选值(部分):
-
NewState
:时钟使能状态
- 可选值:
ENABLE
:使能时钟DISABLE
:禁用时钟
返回值:无
- 可选值:
2. void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
功能:初始化 GPIO 引脚的模式、速度等参数
参数:
-
GPIOx
:选择 GPIO 端口(x 为端口字母)
- 可选值:
GPIOA
、GPIOB
、GPIOC
等(如 PA6 对应GPIOA
)
- 可选值:
-
GPIO_InitStruct
:指向 GPIO 配置结构体的指针
-
结构体成员(部分):
-
GPIO_Mode
:引脚模式
- 可选值:
GPIO_Mode_IPU
:上拉输入(输入捕获用)GPIO_Mode_AF_PP
:复用推挽输出
- 可选值:
-
GPIO_Pin
:引脚号
- 可选值:
GPIO_Pin_0
~GPIO_Pin_15
(如 PA6 对应GPIO_Pin_6
)
- 可选值:
-
GPIO_Speed
:输出速度(输入模式无效)
- 可选值:
GPIO_Speed_10MHz
、GPIO_Speed_50MHz
返回值:无
- 可选值:
-
-
3. void TIM_InternalClockConfig(TIM_TypeDef* TIMx);
功能:选择定时器的时钟源为内部时钟(默认配置)
参数:
-
TIMx
:选择定时器(x 为定时器编号)
- 可选值:
TIM2
、TIM3
(输入捕获用)、TIM4
等
返回值:无
- 可选值:
4. void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
功能:配置定时器的时基参数(计数周期、分频等)
参数:
-
TIMx
:选择定时器
- 可选值:
TIM3
(输入捕获用)、TIM2
、TIM4
等
- 可选值:
-
TIM_TimeBaseInitStruct
:指向时基配置结构体的指针
-
结构体成员(部分):
-
TIM_Period
:自动重装值(ARR)
- 可选值:
- 0~65535(16 位计数器,如
65535
对应最大周期)
- 0~65535(16 位计数器,如
- 可选值:
-
TIM_Prescaler
:预分频值(PSC)
- 可选值:
- 0~65535(如
71
对应 72 分频,计数器时钟 1MHz)
- 0~65535(如
- 可选值:
-
TIM_CounterMode
:计数模式
- 可选值:
TIM_CounterMode_Up
:向上计数(输入捕获用)TIM_CounterMode_Down
:向下计数
返回值:无
- 可选值:
-
-
5. void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
功能:初始化定时器的输入捕获通道参数
参数:
-
TIMx
:选择定时器
- 可选值:
TIM3
(输入捕获用)、TIM2
、TIM4
等
- 可选值:
-
TIM_ICInitStruct
:指向输入捕获配置结构体的指针
-
结构体成员(部分):
-
TIM_Channel
:捕获通道
- 可选值:
TIM_Channel_1
:通道 1(输入捕获用)TIM_Channel_2
~TIM_Channel_4
- 可选值:
-
TIM_ICPolarity
:捕获极性
- 可选值:
TIM_ICPolarity_Rising
:上升沿捕获(输入捕获用)TIM_ICPolarity_Falling
:下降沿捕获
- 可选值:
-
TIM_ICFilter
:输入滤波器参数
- 可选值:
- 0x0~0xF(如
0xF
表示最强滤波,抗干扰)
返回值:无
- 0x0~0xF(如
- 可选值:
-
-
6. void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TS);
功能:选择定时器从模式的触发源
参数:
-
TIMx
:选择定时器
- 可选值:
TIM3
(输入捕获用)、TIM2
、TIM4
等
- 可选值:
-
TIM_TS
:触发源选择
- 可选值(输入捕获相关):
TIM_TS_TI1FP1
:使用通道 1 的滤波后信号(输入捕获用)TIM_TS_TI2FP2
:使用通道 2 的滤波后信号
返回值:无
- 可选值(输入捕获相关):
7. void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode);
功能:配置定时器的从模式行为(如复位、门控)
参数:
-
TIMx
:选择定时器
- 可选值:
TIM3
(输入捕获用)、TIM2
、TIM4
等
- 可选值:
-
TIM_SlaveMode
:从模式类型
- 可选值:
TIM_SlaveMode_Reset
:复位模式(输入捕获用,触发时计数器归零)TIM_SlaveMode_Gated
:门控模式(触发有效时计数器运行)
返回值:无
- 可选值:
8. void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);
功能:启动或停止定时器计数
参数:
-
TIMx
:选择定时器
- 可选值:
TIM3
(输入捕获用)、TIM2
、TIM4
等
- 可选值:
-
NewState
:定时器使能状态
- 可选值:
ENABLE
:启动定时器(输入捕获用)DISABLE
:停止定时器
返回值:无
- 可选值:
9. uint16_t TIM_GetCapture1(TIM_TypeDef* TIMx);
功能:获取定时器通道 1 的捕获值(CCR1)
参数:
-
TIMx
:选择定时器
- 可选值:
TIM3
(输入捕获用)、TIM2
、TIM4
等
返回值:
- 可选值:
-
通道 1 的捕获寄存器值(0~65535,对应两次上升沿间的计数值)
现象:测量波形的输入口是PA6,用一根线把PA0和PA6连在一起,这样就能测量自己PWM模块产生波形的频率。
三、PWMI模式测频率占空比
1.接线图
2.代码
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"int main(void)
{/*模块初始化*/OLED_Init(); //OLED初始化PWM_Init(); //PWM初始化IC_Init(); //输入捕获初始化/*显示静态字符串*/OLED_ShowString(1, 1, "Freq:00000Hz"); //1行1列显示字符串Freq:00000HzOLED_ShowString(2, 1, "Duty:00%"); //2行1列显示字符串Duty:00%/*使用PWM模块提供输入捕获的测试信号*/PWM_SetPrescaler(720 - 1); //PWM频率Freq = 72M / (PSC + 1) / 100PWM_SetCompare1(50); //PWM占空比Duty = CCR / 100while (1){OLED_ShowNum(1, 6, IC_GetFreq(), 5); //不断刷新显示输入捕获测得的频率OLED_ShowNum(2, 6, IC_GetDuty(), 2); //不断刷新显示输入捕获测得的占空比}
}
IC.c
#include "stm32f10x.h" // Device header/*** 函 数:输入捕获初始化* 参 数:无* 返 回 值:无*/
void IC_Init(void)
{/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //开启TIM3的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA6引脚初始化为上拉输入/*配置时钟源*/TIM_InternalClockConfig(TIM3); //选择TIM3为内部时钟,若不调用此函数,TIM默认也为内部时钟/*时基单元初始化*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定义结构体变量TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1; //计数周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //预分频器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器,高级定时器才会用到TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit,配置TIM3的时基单元/*PWMI模式初始化*/TIM_ICInitTypeDef TIM_ICInitStructure; //定义结构体变量TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //选择配置定时器通道1TIM_ICInitStructure.TIM_ICFilter = 0xF; //输入滤波器参数,可以过滤信号抖动TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //极性,选择为上升沿触发捕获TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //捕获预分频,选择不分频,每次信号都触发捕获TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //输入信号交叉,选择直通,不交叉TIM_PWMIConfig(TIM3, &TIM_ICInitStructure); //将结构体变量交给TIM_PWMIConfig,配置TIM3的输入捕获通道//此函数同时会把另一个通道配置为相反的配置,实现PWMI模式/*选择触发源及从模式*/TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1); //触发源选择TI1FP1TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset); //从模式选择复位//即TI1产生上升沿时,会触发CNT归零/*TIM使能*/TIM_Cmd(TIM3, ENABLE); //使能TIM3,定时器开始运行
}/*** 函 数:获取输入捕获的频率* 参 数:无* 返 回 值:捕获得到的频率*/
uint32_t IC_GetFreq(void)
{return 1000000 / (TIM_GetCapture1(TIM3) + 1); //测周法得到频率fx = fc / N,这里不执行+1的操作也可
}/*** 函 数:获取输入捕获的占空比* 参 数:无* 返 回 值:捕获得到的占空比*/
uint32_t IC_GetDuty(void)
{return (TIM_GetCapture2(TIM3) + 1) * 100 / (TIM_GetCapture1(TIM3) + 1); //占空比Duty = CCR2 / CCR1 * 100,这里不执行+1的操作也可
}
IC.h
#ifndef __IC_H
#define __IC_Hvoid IC_Init(void);
uint32_t IC_GetFreq(void);
uint32_t IC_GetDuty(void);#endif
现象:
- 硬件连接:
PWM 输出(PA8) → 输入捕获引脚(PA6)
OLED 显示屏通过 I2C 接口连接(通常为 PB6/PB7)
- 参数配置:
PWM 频率:72MHz / (720) / 100 = 1kHz
PWM 占空比:50 / 100 = 50%
- 输入捕获配置:
TIM3 通道 1(PA6)配置为上升沿捕获,用于测量频率和占空比
从模式设为复位模式,确保每次上升沿触发计数器归零
2. 实时显示效果
OLED 显示内容:
Freq:00000Hz
Duty:00%