STM32F103 捕获配置
目录
在《STM32F103 PWM
配置》我们介绍了PWM
配置,这一节将会介绍输入捕获配置。
一、输入捕获概述
1.1 通用定时器框图

在通用定时器框图中,主要涉及如下几个部分:
- 时钟源的选择(最上面部分);
- 时基单元(中间部分;);
- 输入捕获(左下部分);
PWM
输出(右下部分)。
其中时钟源的选择以及时基单元配置我们在《STM32F103
定时器配置》介绍过,而PWM
配置在《STM32F103 PWM
配置》中介绍过,本节主要介绍输入捕获。
1.2 输入捕获原理
输入捕获模式可以用来测量脉冲宽度或者测量频率。STM32
的定时器,除了TIM6
、TIM7
,其它的定时器都有输入捕获的功能。
下面以一个简单的脉冲输入为例,简单地讲述一下输入捕获用于测量脉冲宽度的工作原理:
先设置输入捕获为上升沿检测,记录发生上升沿时TIMx_CNT
的值。
然后配置捕获信号为下降沿捕获,当下降沿到来的时候发生捕获,并记录此时的TIMx_CNT
的值。
这样,前后两次TIMx_CNT
的值之差就是高电平的脉宽。
同时根据TIMx
的计数频率,我们就能知道高电平脉宽的准确时间。
1.3 输入捕获的通道概览
每一个捕获/比较通道都是围绕着着一个捕获/比较寄存器(TIMx_CCRx
、包含影子寄存器),包括捕获的输入部分(数字滤波、多路复用和预分频器),和输出部分(比较器和输出控制)。
捕获/比较模块由一个预装载寄存器和一个影子寄存器组成。读写过程仅操作预装载寄存器;
- 在捕获模式下,捕获发生在影子寄存器上,然后再复制到预装载寄存器中;
- 在比较模式下,预装载寄存器的内容被复制到影子寄存器中,然后影子寄存器的内容和计数器进行比较;

输入部分对相应的TIx
输入信号采样,并产生一个滤波后的信号TIxF
。
然后,一个带极性选择的边缘检测器产生一个信号(TIxFPx
),它可以作为从模式控制器的输入触发或者作为捕获控制。该信号通过预分频进入捕获寄存器(ICxPS
)。
一句话总结工作过程:通过检测TIMx_CHx
通道上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT
)存放到对应的捕获/比较寄存器(TIMx_CCRx
)里面,完成一次捕获。同时,还可以配置捕获时是否触发中断/DMA
等。
1.3.1 设置输入捕获滤波器
输入捕获滤波器ICxF[3:0]
,这个用于设置采样频率和数字滤波器长度。
其中:fCK_INT
是定时器的输入频率,fDTS
是根据TIMx_CR1
的CKD[1:0]
的设置来确定的。
这里滤波器的作用是什么意思呢?数字滤波器由一个事件计数器组成,它记录到N
个事件后会产生一个输出的跳变。
也就是说连续N
次采样,如果都是高电平,则说明这是一个有效的触发,就会进入输入捕捉中断(如果设置了的话)。这样就可以滤除那些高电平脉宽低于8
个采样周期的脉冲信号,从而达到滤波的作用。
1.3.2 设置输入捕获极性
捕获输出极性CCxP
,这个用于设置捕捉事件是发生在上升沿还是下降沿。
1.3.3 设置输入捕获映射关系
在TIMx_CH1
和TIMx_CH2
两条通道的情况下,我们可以看出除了TIMx_CH1
捕捉到的信号可以连接到IC1
,TIMx_CH2
捕捉到的信号可以连接到IC2
之外,TIMx_CH1
捕捉到的信号也可以连接到IC2
,TIMx_CH2
捕捉到的信号也可以连接到IC1
。
一般情况下,我们设置成TIMx_CH1
捕捉到的信号可以连接到IC1
,TIMx_CH2
捕捉到的信号可以连接到IC2
。
输入捕获选择(CCxS
)配置为:CC1
通道被配置为输入、IC1
映射在TI1
上(01
)。
1.3.4 设置输入捕获分频器
输入捕获预分频器ICxPSC
:设置的是每N
个事件触发一次捕捉。
也就是说,我们可以设置成每2次上升沿事件触发一次捕捉。
二、输入捕获源码
2.1 输入捕获初始化步骤
输入捕获配置流程如下:
(1) TIMx
时钟使能:通过配置RCC_APB1ENR/RCC_APB2ENR
寄存器使能TIMx
时钟;
(2)GPIO
口配置:以TIM2_CH1
(PA0
)为例;
- 配置
PA0
为下拉输入; GPIOA
时钟使能;
(3) 配置TIMx
时基单元;
- 配置
TIMx_ARR
寄存器自动重装载的值(0xFFFF
); - 配置
TIMx_PSC
寄存器预分频系数(71
);
(4) 配置输入捕获相关寄存器;
- 配置
TIMx_CCMRx
寄存器:- 输入捕获预滤波器(
ICxF
):配置采样频率和数字滤波器长度,用于消除输入信号的抖动; - 输入捕获/比较输出选择(
CCxS
):配置为01
,即CC1
通道被配置为输入、IC1
映射在TI1
上;用于实现输入信号捕获功能; - 输入捕获预分频器(
ICxPSC
):配置为无预分频器(00
);
- 输入捕获预滤波器(
- 配置
TIMx_CCER
寄存器:- 输入捕获/比较输出使能(
CCxE
):即开启输入捕获功能,这样捕获事件发生时,计数器的值会被保存到捕获寄存器(TIMx_CCRx
); - 捕获输出极性(
CCxP
):0
用于上升沿捕获,1
up没回下降沿捕获;
- 输入捕获/比较输出使能(
(5) 配置TIMx_DIER
寄存器:
- 更新中断(
UIE
)配置为允许(1b
); - 输入捕获/比较输出中断(
CCxE
)配置为允许(1b
);
(6) 设置NVIC
;
- 参考《
STM32F103
嵌套向量中断控制器》:设置中断优先级分组、设置响应优先级和抢断优先级、使能相应中断位;
(7) 中断处理函数;
- 设置中断服务函数(包括清除中断标志,清
SR
寄存器状态标志位(UIF=0
、CCxIF=0
))。
(8) 允许TIMx
工作:配置TIMx_CR1
位0
为1
。
2.2 源码实现
2.2.1 输入捕获初始化
输入捕获初始化函数TIM_CAP_Init
定义如下:
/******************************************************************************************************
*
* Description: 电平脉宽捕获
timn: 定时器 TIMER1~5 8 定时器8程序有问题 勿用
Channel: 输入通道 CAP_CH1~4
mode: 0:捕获低电平 1:捕获高电平
*
******************************************************************************************************/
void TIM_CAP_Init(TIMn timn,CAP_CHANNEL Channel,u8 mode)
{
u8 REMAP=0x00; //映射情况 0x00默认 0x01 0x02: 0x03 自己设置
// if(timn==0||timn==7) //定时器1或8
// {
// fclk = 72; //默认APB2 1倍频
// }
// else
// {
// fclk =72; //默认APB1 2倍频
// }
//******************************************************************************************
if(timn==0) //定时器1
{
RCC->APB2ENR |=1<<11; //高级定时器1时钟使能
if(REMAP==0x00)
{
if(Channel==CAP_CH1)
{
gpio_init(PA8,GPI_DOWN,HIGH); //输入下拉
PAout(8)=0;
TIM1->CCMR1 |=0x01; //CC1S=1 CC1配置为输入 IC1映射到TI1上
TIM1->CCMR1 |=0x03<<4; //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM1->CCMR1 |=0x00<<2; //IC1PS=0 不分频
}
else if(Channel==CAP_CH2)
{
gpio_init(PA9,GPI_DOWN,HIGH); //输入下拉
PAout(9)=0;
TIM1->CCMR1 |=0x01<<8; //01: CC2配置为输入 IC2映射到TI2上
TIM1->CCMR1 |=0x03<<12; //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM1->CCMR1 |=0x00<<10; //IC2PS=0 不分频
}
else if(Channel==CAP_CH3)
{
gpio_init(PA10,GPI_DOWN,HIGH); //输入下拉
PAout(10)=0;
TIM1->CCMR2 |=0x01; //01: CC3配置为输入 IC3映射到TI3上
TIM1->CCMR2 |=0x03<<4; //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM1->CCMR2 |=0x00<<2; //IC3PS=0 不分频
}
else if(Channel==CAP_CH4)
{
gpio_init(PA11,GPI_DOWN,HIGH); //输入下拉
PAout(11)=0;
TIM1->CCMR2 |=0x01<<8; //01:CC4通道被配置为输入,IC4映射在TI4上;
TIM1->CCMR2 |=0x03<<12; //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM1->CCMR2 |=0x00<<10; //IC4PS=0 不分频
}
else
{
ASSERT(0);
}
}
//*******************************
else if(REMAP==0x01)
{
RCC->APB2ENR |= 1<<0; //使能I/O复用时钟
AFIO->MAPR &=~(0x3<<6); //位7:6清零
AFIO->MAPR |= REMAP<<6; //TIM1部分映射
if(Channel==CAP_CH1)
{
gpio_init(PA8,GPI_DOWN,HIGH); //输入下拉
PAout(8)=0;
TIM1->CCMR1 |=0x01; //CC1S=1 CC1配置为输入 IC1映射到TI1上
TIM1->CCMR1 |=0x03<<4; //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM1->CCMR1 |=0x00<<2; //IC1PS=0 不分频
}
else if(Channel==CAP_CH2)
{
gpio_init(PA9,GPI_DOWN,HIGH); //输入下拉
PAout(9)=0;
TIM1->CCMR1 |=0x01<<8; //01: CC2配置为输入 IC2映射到TI2上
TIM1->CCMR1 |=0x03<<12; //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM1->CCMR1 |=0x00<<10; //IC2PS=0 不分频
}
else if(Channel==CAP_CH3)
{
gpio_init(PA10,GPI_DOWN,HIGH); //输入下拉
PAout(10)=0;
TIM1->CCMR2 |=0x01; //01: CC3配置为输入 IC3映射到TI3上
TIM1->CCMR2 |=0x03<<4; //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM1->CCMR2 |=0x00<<2; //IC3PS=0 不分频
}
else if(Channel==CAP_CH4)
{
gpio_init(PA11,GPI_DOWN,HIGH); //输入下拉
PAout(11)=0;
TIM1->CCMR2 |=0x01<<8; //01:CC4通道被配置为输入,IC4映射在TI4上;
TIM1->CCMR2 |=0x03<<12; //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM1->CCMR2 |=0x00<<10; //IC4PS=0 不分频
}
else
{
ASSERT(0);
}
}
//**********************************
else if(REMAP==0x03) //完全映射
{
RCC->APB2ENR |= 1<<0; //使能I/O复用时钟
AFIO->MAPR &=~(0x3<<6); //位7:6清零
AFIO->MAPR |= REMAP<<6; //TIM1完全映射
if(Channel==CAP_CH1)
{
gpio_init(PE9,GPI_DOWN,HIGH); //输入下拉
PEout(9)=0;
TIM1->CCMR1 |=0x01; //CC1S=1 CC1配置为输入 IC1映射到TI1上
TIM1->CCMR1 |=0x03<<4; //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM1->CCMR1 |=0x00<<2; //IC1PS=0 不分频
}
else if(Channel==CAP_CH2)
{
gpio_init(PE11,GPI_DOWN,HIGH); //输入下拉
PEout(11)=0;
TIM1->CCMR1 |=0x01<<8; //01: CC2配置为输入 IC2映射到TI2上
TIM1->CCMR1 |=0x03<<12; //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM1->CCMR1 |=0x00<<10; //IC2PS=0 不分频
}
else if(Channel==CAP_CH3)
{
gpio_init(PE13,GPI_DOWN,HIGH); //输入下拉
PEout(13)=0;
TIM1->CCMR2 |=0x01; //01: CC3配置为输入 IC3映射到TI3上
TIM1->CCMR2 |=0x03<<4; //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM1->CCMR2 |=0x00<<2; //IC3PS=0 不分频
}
else if(Channel==CAP_CH4)
{
gpio_init(PE14,GPI_DOWN,HIGH); //输入下拉
PEout(14)=0;
TIM1->CCMR2 |=0x01<<8; //01:CC4通道被配置为输入,IC4映射在TI4上;
TIM1->CCMR2 |=0x03<<12; //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM1->CCMR2 |=0x00<<10; //IC4PS=0 不分频
}
else
{
ASSERT(0);
}
}
//****************************************
else
{
ASSERT(0);
}
}
//**********************************************************************************************************
else if(timn==1) //定时器2
{
// REMAP=0x01;
RCC->APB1ENR |=1<<0; //定时器2时钟使能
if(REMAP==0x00)
{
if(Channel==CAP_CH1)
{
gpio_init(PA0,GPI_DOWN,HIGH); //输入下拉
PAout(0)=0;
TIM2->CCMR1 |=0x01; //CC1S=1 CC1配置为输入 IC1映射到TI1上
TIM2->CCMR1 |=0x03<<4; //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM2->CCMR1 |=0x00<<2; //IC1PS=0 不分频
}
else if(Channel==CAP_CH2)
{
gpio_init(PA1,GPI_DOWN,HIGH); //输入下拉
PAout(1)=0;
TIM2->CCMR1 |=0x01<<8; //01: CC2配置为输入 IC2映射到TI2上
TIM2->CCMR1 |=0x03<<12; //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM2->CCMR1 |=0x00<<10; //IC2PS=0 不分频
}
else if(Channel==CAP_CH3)
{
gpio_init(PA2,GPI_DOWN,HIGH); //输入下拉
PAout(2)=0;
TIM2->CCMR2 |=0x01; //01: CC3配置为输入 IC3映射到TI3上
TIM2->CCMR2 |=0x03<<4; //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM2->CCMR2 |=0x00<<2; //IC3PS=0 不分频
}
else if(Channel==CAP_CH4)
{
gpio_init(PA3,GPI_DOWN,HIGH); //输入下拉
PAout(3)=0;
TIM2->CCMR2 |=0x01<<8; //01:CC4通道被配置为输入,IC4映射在TI4上;
TIM2->CCMR2 |=0x03<<12; //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM2->CCMR2 |=0x00<<10; //IC4PS=0 不分频
}
else
{
ASSERT(0);
}
}
//*******************************
else if(REMAP==0x01) //部分映射
{
RCC->APB2ENR |= 1<<0; //使能I/O复用时钟
AFIO->MAPR &=~(0x3<<8); //位9:8清零
AFIO->MAPR |= REMAP<<8; //TIM2部分映射
if(Channel==CAP_CH1)
{
gpio_init(PA15,GPI_DOWN,HIGH); //输入下拉
PAout(15)=0;
TIM2->CCMR1 |=0x01; //CC1S=1 CC1配置为输入 IC1映射到TI1上
TIM2->CCMR1 |=0x03<<4; //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM2->CCMR1 |=0x00<<2; //IC1PS=0 不分频
}
else if(Channel==CAP_CH2)
{
gpio_init(PB3,GPI_DOWN,HIGH); //输入下拉
PBout(3)=0;
TIM2->CCMR1 |=0x01<<8; //01: CC2配置为输入 IC2映射到TI2上
TIM2->CCMR1 |=0x03<<12; //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM2->CCMR1 |=0x00<<10; //IC2PS=0 不分频
}
else if(Channel==CAP_CH3)
{
gpio_init(PA2,GPI_DOWN,HIGH); //输入下拉
PAout(2)=0;
TIM2->CCMR2 |=0x01; //01: CC3配置为输入 IC3映射到TI3上
TIM2->CCMR2 |=0x03<<4; //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM2->CCMR2 |=0x00<<2; //IC3PS=0 不分频
}
else if(Channel==CAP_CH4)
{
gpio_init(PA3,GPI_DOWN,HIGH); //输入下拉
PAout(3)=0;
TIM2->CCMR2 |=0x01<<8; //01:CC4通道被配置为输入,IC4映射在TI4上;
TIM2->CCMR2 |=0x03<<12; //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM2->CCMR2 |=0x00<<10; //IC4PS=0 不分频
}
else
{
ASSERT(0);
}
}
//*********************************
else if(REMAP==0x02) //部分映射
{
RCC->APB2ENR |= 1<<0; //使能I/O复用时钟
AFIO->MAPR &=~(0x3<<8); //位9:8清零
AFIO->MAPR |= REMAP<<8; //TIM2部分映射
if(Channel==CAP_CH1)
{
gpio_init(PA0,GPI_DOWN,HIGH); //输入下拉
PAout(0)=0;
TIM2->CCMR1 |=0x01; //CC1S=1 CC1配置为输入 IC1映射到TI1上
TIM2->CCMR1 |=0x03<<4; //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM2->CCMR1 |=0x00<<2; //IC1PS=0 不分频
}
else if(Channel==CAP_CH2)
{
gpio_init(PA1,GPI_DOWN,HIGH); //输入下拉
PAout(1)=0;
TIM2->CCMR1 |=0x01<<8; //01: CC2配置为输入 IC2映射到TI2上
TIM2->CCMR1 |=0x03<<12; //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM2->CCMR1 |=0x00<<10; //IC2PS=0 不分频
}
else if(Channel==CAP_CH3)
{
gpio_init(PB10,GPI_DOWN,HIGH); //输入下拉
PBout(10)=0;
TIM2->CCMR2 |=0x01; //01: CC3配置为输入 IC3映射到TI3上
TIM2->CCMR2 |=0x03<<4; //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM2->CCMR2 |=0x00<<2; //IC3PS=0 不分频
}
else if(Channel==CAP_CH4)
{
gpio_init(PB11,GPI_DOWN,HIGH); //输入下拉
PBout(11)=0;
TIM2->CCMR2 |=0x01<<8; //01:CC4通道被配置为输入,IC4映射在TI4上;
TIM2->CCMR2 |=0x03<<12; //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM2->CCMR2 |=0x00<<10; //IC4PS=0 不分频
}
else
{
ASSERT(0);
}
}
//**********************************
else if(REMAP==0x03) //完全映射
{
RCC->APB2ENR |= 1<<0; //使能I/O复用时钟
AFIO->MAPR &=~(0x3<<8); //位9:8清零
AFIO->MAPR |= REMAP<<8; //TIM2部分映射
if(Channel==CAP_CH1)
{
gpio_init(PA15,GPI_DOWN,HIGH); //输入下拉
PAout(15)=0;
TIM2->CCMR1 |=0x01; //CC1S=1 CC1配置为输入 IC1映射到TI1上
TIM2->CCMR1 |=0x03<<4; //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM2->CCMR1 |=0x00<<2; //IC1PS=0 不分频
}
else if(Channel==CAP_CH2)
{
gpio_init(PB3,GPI_DOWN,HIGH); //输入下拉
PBout(3)=0;
TIM2->CCMR1 |=0x01<<8; //01: CC2配置为输入 IC2映射到TI2上
TIM2->CCMR1 |=0x03<<12; //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM2->CCMR1 |=0x00<<10; //IC2PS=0 不分频
}
else if(Channel==CAP_CH3)
{
gpio_init(PB10,GPI_DOWN,HIGH); //输入下拉
PBout(10)=0;
TIM2->CCMR2 |=0x01; //01: CC3配置为输入 IC3映射到TI3上
TIM2->CCMR2 |=0x03<<4; //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM2->CCMR2 |=0x00<<2; //IC3PS=0 不分频
}
else if(Channel==CAP_CH4)
{
gpio_init(PB11,GPI_DOWN,HIGH); //输入下拉
PBout(11)=0;
TIM2->CCMR2 |=0x01<<8; //01:CC4通道被配置为输入,IC4映射在TI4上;
TIM2->CCMR2 |=0x03<<12; //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM2->CCMR2 |=0x00<<10; //IC4PS=0 不分频
}
else
{
ASSERT(0);
}
}
//****************************************
else
{
ASSERT(0);
}
}
//**************************************************************************************************************
else if(timn==2) //定时器3
{
RCC->APB1ENR |=1<<1; //定时器3时钟使能
if(REMAP==0x00)
{
if(Channel==CAP_CH1)
{
gpio_init(PA6,GPI_DOWN,HIGH); //输入下拉
PAout(6)=0;
TIM3->CCMR1 |=0x01; //CC1S=1 CC1配置为输入 IC1映射到TI1上
TIM3->CCMR1 |=0x03<<4; //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM3->CCMR1 |=0x00<<2; //IC1PS=0 不分频
}
else if(Channel==CAP_CH2)
{
gpio_init(PA7,GPI_DOWN,HIGH); //输入下拉
PAout(7)=0;
TIM3->CCMR1 |=0x01<<8; //01: CC2配置为输入 IC2映射到TI2上
TIM3->CCMR1 |=0x03<<12; //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM3->CCMR1 |=0x00<<10; //IC2PS=0 不分频
}
else if(Channel==CAP_CH3)
{
gpio_init(PB0,GPI_DOWN,HIGH); //输入下拉
PBout(0)=0;
TIM3->CCMR2 |=0x01; //01: CC3配置为输入 IC3映射到TI3上
TIM3->CCMR2 |=0x03<<4; //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM3->CCMR2 |=0x00<<2; //IC3PS=0 不分频
}
else if(Channel==CAP_CH4)
{
gpio_init(PB1,GPI_DOWN,HIGH); //输入下拉
PBout(1)=0;
TIM3->CCMR2 |=0x01<<8; //01:CC4通道被配置为输入,IC4映射在TI4上;
TIM3->CCMR2 |=0x03<<12; //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM3->CCMR2 |=0x00<<10; //IC4PS=0 不分频
}
else
{
ASSERT(0);
}
}
//*******************************
else if(REMAP==0x02)
{
RCC->APB2ENR |= 1<<0; //使能I/O复用时钟
AFIO->MAPR &=~(0x3<<10); //位7:6清零
AFIO->MAPR |= REMAP<<10; //TIM3部分映射
if(Channel==CAP_CH1)
{
gpio_init(PB4,GPI_DOWN,HIGH); //输入下拉
PBout(4)=0;
TIM3->CCMR1 |=0x01; //CC1S=1 CC1配置为输入 IC1映射到TI1上
TIM3->CCMR1 |=0x03<<4; //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM3->CCMR1 |=0x00<<2; //IC1PS=0 不分频
}
else if(Channel==CAP_CH2)
{
gpio_init(PB5,GPI_DOWN,HIGH); //输入下拉
PBout(5)=0;
TIM3->CCMR1 |=0x01<<8; //01: CC2配置为输入 IC2映射到TI2上
TIM3->CCMR1 |=0x03<<12; //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM3->CCMR1 |=0x00<<10; //IC2PS=0 不分频
}
else if(Channel==CAP_CH3)
{
gpio_init(PB0,GPI_DOWN,HIGH); //输入下拉
PBout(0)=0;
TIM3->CCMR2 |=0x01; //01: CC3配置为输入 IC3映射到TI3上
TIM3->CCMR2 |=0x03<<4; //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM3->CCMR2 |=0x00<<2; //IC3PS=0 不分频
}
else if(Channel==CAP_CH4)
{
gpio_init(PB1,GPI_DOWN,HIGH); //输入下拉
PBout(1)=0;
TIM3->CCMR2 |=0x01<<8; //01:CC4通道被配置为输入,IC4映射在TI4上;
TIM3->CCMR2 |=0x03<<12; //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM3->CCMR2 |=0x00<<10; //IC4PS=0 不分频
}
else
{
ASSERT(0);
}
}
//**********************************
else if(REMAP==0x03) //完全映射
{
RCC->APB2ENR |= 1<<0; //使能I/O复用时钟
AFIO->MAPR &=~(0x3<<10); //位7:6清零
AFIO->MAPR |= REMAP<<10; //TIM1完全映射
if(Channel==CAP_CH1)
{
gpio_init(PC6,GPI_DOWN,HIGH); //输入下拉
PCout(6)=0;
TIM3->CCMR1 |=0x01; //CC1S=1 CC1配置为输入 IC1映射到TI1上
TIM3->CCMR1 |=0x03<<4; //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM3->CCMR1 |=0x00<<2; //IC1PS=0 不分频
}
else if(Channel==CAP_CH2)
{
gpio_init(PC7,GPI_DOWN,HIGH); //输入下拉
PCout(7)=0;
TIM3->CCMR1 |=0x01<<8; //01: CC2配置为输入 IC2映射到TI2上
TIM3->CCMR1 |=0x03<<12; //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM3->CCMR1 |=0x00<<10; //IC2PS=0 不分频
}
else if(Channel==CAP_CH3)
{
gpio_init(PC8,GPI_DOWN,HIGH); //输入下拉
PCout(8)=0;
TIM3->CCMR2 |=0x01; //01: CC3配置为输入 IC3映射到TI3上
TIM3->CCMR2 |=0x03<<4; //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM3->CCMR2 |=0x00<<2; //IC3PS=0 不分频
}
else if(Channel==CAP_CH4)
{
gpio_init(PC9,GPI_DOWN,HIGH); //输入下拉
PCout(9)=0;
TIM3->CCMR2 |=0x01<<8; //01:CC4通道被配置为输入,IC4映射在TI4上;
TIM3->CCMR2 |=0x03<<12; //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM3->CCMR2 |=0x00<<10; //IC4PS=0 不分频
}
else
{
ASSERT(0);
}
}
//****************************************
else
{
ASSERT(0);
}
}
//********************************************************************************************************************
else if(timn==3) //定时器4
{
RCC->APB1ENR |=1<<2; //定时器4时钟使能
if(REMAP==0x00)
{
if(Channel==CAP_CH1)
{
gpio_init(PB6,GPI_DOWN,HIGH); //输入下拉
PBout(6)=0;
TIM4->CCMR1 |=0x01; //CC1S=1 CC1配置为输入 IC1映射到TI1上
TIM4->CCMR1 |=0x03<<4; //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM4->CCMR1 |=0x00<<2; //IC1PS=0 不分频
}
else if(Channel==CAP_CH2)
{
gpio_init(PB7,GPI_DOWN,HIGH); //输入下拉
PBout(7)=0;
TIM4->CCMR1 |=0x01<<8; //01: CC2配置为输入 IC2映射到TI2上
TIM4->CCMR1 |=0x03<<12; //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM4->CCMR1 |=0x00<<10; //IC2PS=0 不分频
}
else if(Channel==CAP_CH3)
{
gpio_init(PB8,GPI_DOWN,HIGH); //输入下拉
PBout(8)=0;
TIM4->CCMR2 |=0x01; //01: CC3配置为输入 IC3映射到TI3上
TIM4->CCMR2 |=0x03<<4; //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM4->CCMR2 |=0x00<<2; //IC3PS=0 不分频
}
else if(Channel==CAP_CH4)
{
gpio_init(PB9,GPI_DOWN,HIGH); //输入下拉
PBout(9)=0;
TIM4->CCMR2 |=0x01<<8; //01:CC4通道被配置为输入,IC4映射在TI4上;
TIM4->CCMR2 |=0x03<<12; //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM4->CCMR2 |=0x00<<10; //IC4PS=0 不分频
}
else
{
ASSERT(0);
}
}
//*******************************
else if(REMAP==0x01)
{
RCC->APB2ENR |= 1<<0; //使能I/O复用时钟
AFIO->MAPR &=~(0x1<<12); //位12清零
AFIO->MAPR |= REMAP<<12; //TIM4部分映射
if(Channel==CAP_CH1)
{
gpio_init(PD12,GPI_DOWN,HIGH); //输入下拉
PDout(12)=0;
TIM4->CCMR1 |=0x01; //CC1S=1 CC1配置为输入 IC1映射到TI1上
TIM4->CCMR1 |=0x03<<4; //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM4->CCMR1 |=0x00<<2; //IC1PS=0 不分频
}
else if(Channel==CAP_CH2)
{
gpio_init(PD13,GPI_DOWN,HIGH); //输入下拉
PDout(13)=0;
TIM4->CCMR1 |=0x01<<8; //01: CC2配置为输入 IC2映射到TI2上
TIM4->CCMR1 |=0x03<<12; //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM4->CCMR1 |=0x00<<10; //IC2PS=0 不分频
}
else if(Channel==CAP_CH3)
{
gpio_init(PD14,GPI_DOWN,HIGH); //输入下拉
PDout(14)=0;
TIM4->CCMR2 |=0x01; //01: CC3配置为输入 IC3映射到TI3上
TIM4->CCMR2 |=0x03<<4; //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM4->CCMR2 |=0x00<<2; //IC3PS=0 不分频
}
else if(Channel==CAP_CH4)
{
gpio_init(PD15,GPI_DOWN,HIGH); //输入下拉
PDout(15)=0;
TIM4->CCMR2 |=0x01<<8; //01:CC4通道被配置为输入,IC4映射在TI4上;
TIM4->CCMR2 |=0x03<<12; //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM4->CCMR2 |=0x00<<10; //IC4PS=0 不分频
}
else
{
ASSERT(0);
}
}
else
{
ASSERT(0);
}
}
//*********************************************************************************************************
else if(timn==4) //定时器5
{
RCC->APB1ENR |=1<<3; //定时器5时钟使能
if(Channel==CAP_CH1)
{
gpio_init(PA0,GPI_DOWN,HIGH); //输入下拉
PAout(0)=0;
TIM5->CCMR1 |=0x01; //CC1S=1 CC1配置为输入 IC1映射到TI1上
TIM5->CCMR1 |=0x03<<4; //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM5->CCMR1 |=0x00<<2; //IC1PS=0 不分频
}
else if(Channel==CAP_CH2)
{
gpio_init(PA1,GPI_DOWN,HIGH); //输入下拉
PAout(1)=0;
TIM5->CCMR1 |=0x01<<8; //01: CC2配置为输入 IC2映射到TI2上
TIM5->CCMR1 |=0x03<<12; //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM5->CCMR1 |=0x00<<10; //IC2PS=0 不分频
}
else if(Channel==CAP_CH3)
{
gpio_init(PA2,GPI_DOWN,HIGH); //输入下拉
PAout(2)=0;
TIM5->CCMR2 |=0x01; //01: CC3配置为输入 IC3映射到TI3上
TIM5->CCMR2 |=0x03<<4; //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM5->CCMR2 |=0x00<<2; //IC3PS=0 不分频
}
else if(Channel==CAP_CH4)
{
gpio_init(PA3,GPI_DOWN,HIGH); //输入下拉
PAout(3)=0;
TIM5->CCMR2 |=0x01<<8; //01:CC4通道被配置为输入,IC4映射在TI4上;
TIM5->CCMR2 |=0x03<<12; //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM5->CCMR2 |=0x00<<10; //IC4PS=0 不分频
}
else
{
ASSERT(0);
}
}
//******************************************************************************************************
else if(timn==7)
{
RCC->APB2ENR |=1<<13; //定时器8时钟使能
if(Channel==CAP_CH1)
{
gpio_init(PC6,GPI_DOWN,HIGH); //输入下拉
PCout(6)=0;
TIM8->CCMR1 |=0x01; //CC1S=1 CC1配置为输入 IC1映射到TI1上
TIM8->CCMR1 |=0x03<<4; //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM8->CCMR1 |=0x00<<2; //IC1PS=0 不分频
}
else if(Channel==CAP_CH2)
{
gpio_init(PC7,GPI_DOWN,HIGH); //输入下拉
PCout(7)=0;
TIM8->CCMR1 |=0x01<<8; //01: CC2配置为输入 IC2映射到TI2上
TIM8->CCMR1 |=0x03<<12; //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM8->CCMR1 |=0x00<<10; //IC2PS=0 不分频
}
else if(Channel==CAP_CH3)
{
gpio_init(PC8,GPI_DOWN,HIGH); //输入下拉
PCout(8)=0;
TIM8->CCMR2 |=0x01; //01: CC3配置为输入 IC3映射到TI3上
TIM8->CCMR2 |=0x03<<4; //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM8->CCMR2 |=0x00<<2; //IC3PS=0 不分频
}
else if(Channel==CAP_CH4)
{
gpio_init(PC9,GPI_DOWN,HIGH); //输入下拉
PCout(9)=0;
TIM8->CCMR2 |=0x01<<8; //01:CC4通道被配置为输入,IC4映射在TI4上;
TIM8->CCMR2 |=0x03<<12; //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
TIM8->CCMR2 |=0x00<<10; //IC4PS=0 不分频
}
else
{
ASSERT(0);
}
}
//********************************************************************************************************
else
{
ASSERT(0);
}
TIMx[timn]->PSC = 71; //预分频值 Fclk=fclk/(71+1) 1MHZ
TIMx[timn]->ARR = 0xFFFF; //重新装载的值
if(mode==0x00) //捕获低电平
{
TIMx[timn]->CCER |= 0x3<<(4*Channel); //下降沿捕获 捕获低电平 捕获使能
}
else //捕获高电平
{
TIMx[timn]->CCER |= 0x01<<(4*Channel); //上升沿捕获 捕获高电平 捕获使能
}
TIMx[timn]->DIER |= 1<<(Channel+1); //开启捕获比较中断
TIMx[timn]->DIER |= 1<<0; //允许更新中断 UIE=1;
TIMx[timn]->CR1 |= 0<<4; //DIR=0; 向上计数
TIMx[timn]->CR1 |= 1<<0; //使能计数器 开始计数
//中断优先级设置
}
TIM_CAP_Init
函数同时实现了高电平和低电平脉冲宽度的捕获。
2.2.2 TIM1/8
溢出/捕获/比较中断
定时器1
和定时器8
都是高级定时器,拥有独立的溢出(更新)中断、以及捕获/比较中断事件。
接下来我们将会以高级定时器TIM1
为例介绍这个脉冲宽度捕获是如何实现的,并且我们以捕获高电平为例进行讲解。
在中断处理函数中,先判断是否捕获成功,如果捕获成功了,说明是在脉冲低电平的阶段,什么都不需要做。
如果捕获没有成功,说明是在脉冲高电平的阶段,就需要执行不同的处理逻辑;
- 在更新(溢出)中断中,表示此时高电平脉冲长度过长,
TIM1CH1_CAP_STA
加1
; - 在捕获/比较中断中;
- 判断是否是第一次捕获到(捕捉到的是上升沿),如果是,计数器当前值(
TIM1_CNT
)清零,TIM1CH1_CAP_VAL
清零,同时标记第一次捕获到高电平,设置极性下降沿捕捉; - 判断是否是第二次捕获到(捕获到的是下降沿),如果是标记捕获完成,保存当前计数器(
TIM1_CNT
)的值到TIM1CH1_CAP_VAL
,设置极性上升沿捕获。
- 判断是否是第一次捕获到(捕捉到的是上升沿),如果是,计数器当前值(
2.2.2.1 TIM1_UP_IRQHandler
定时器1
更新(溢出)中断TIM1_UP_IRQHandler
实现;
/*******************************************************************************
* Function Name : TIM1_UP_IRQHandler
* Description : This function handles TIM1 overflow and update interrupt
* request.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void TIM1_UP_IRQHandler(void) //定时器1溢出中断
{
u16 timsr; //存放定时器标志位
timsr = TIM1->SR;
if((TIM1CH1_CAP_STA&0x80)==0) //还未成功捕获
{
/****************************************/
if(timsr&0x01) //发生更新(溢出)中断
{
if(TIM1CH1_CAP_STA&0x40) //已经捕获到高/低电平
{
if((TIM1CH1_CAP_STA&0x3F)==0X3F) //高/低电平太长了 强制捕获完成
{
TIM1CH1_CAP_STA |=0x80; //标记成功捕获一次
TIM1CH1_CAP_VAL =0xFFFF;
}
else
{
TIM1CH1_CAP_STA++; //自增1
}
}
}
}
//***********************************************
if((TIM1CH2_CAP_STA&0x80)==0) //还未成功捕获
{
/****************************************/
if(timsr&0x01) //发生更新(溢出)中断
{
if(TIM1CH2_CAP_STA&0x40) //已经捕获到高/低电平
{
if((TIM1CH2_CAP_STA&0x3F)==0X3F) //高/低电平太长了 强制捕获完成
{
TIM1CH2_CAP_STA |=0x80; //标记成功捕获一次
TIM1CH2_CAP_VAL =0xFFFF;
}
else
{
TIM1CH2_CAP_STA++; //自增1
}
}
}
}
//********************************************
if((TIM1CH3_CAP_STA&0x80)==0) //还未成功捕获
{
/****************************************/
if(timsr&0x01) //发生更新(溢出)中断
{
if(TIM1CH3_CAP_STA&0x40) //已经捕获到高/低电平
{
if((TIM1CH3_CAP_STA&0x3F)==0X3F) //高/低电平太长了 强制捕获完成
{
TIM1CH3_CAP_STA |=0x80; //标记成功捕获一次
TIM1CH3_CAP_VAL =0xFFFF;
}
else
{
TIM1CH3_CAP_STA++; //自增1
}
}
}
}
//*********************************************
if((TIM1CH4_CAP_STA&0x80)==0) //还未成功捕获
{
/****************************************/
if(timsr&0x01) //发生更新(溢出)中断
{
if(TIM1CH4_CAP_STA&0x40) //已经捕获到高/低电平
{
if((TIM1CH4_CAP_STA&0x3F)==0X3F) //高/低电平太长了 强制捕获完成
{
TIM1CH4_CAP_STA |=0x80; //标记成功捕获一次
TIM1CH4_CAP_VAL =0xFFFF;
}
else
{
TIM1CH4_CAP_STA++; //自增1
}
}
}
}
//**********************自定义用户任务****************************//
//*****************************************************************//
TIM1->SR &=~(1<<0); //清中断标志 必须 (置0清 非写1)
}
在更新(溢出)中断处理函数中,先判断是否捕获成功,如果捕获成功了,什么都不需要做。如果捕获没有成功,就需要进行逻辑处理。
由于我们进行输入捕获,一旦捕捉到了上升沿,就设置计数器当前值为0
,让它从0
开始重新计数。
但是如果高脉冲的长度过于宽了,也就是说,从0
开始计数到自动重加载值一个循环结束了,脉冲还是没有结束。这个情况下,显而易见不能只记录一下最后的计数器当前值。
亲爱的读者和支持者们,自动博客加入了打赏功能,陆陆续续收到了各位老铁的打赏。在此,我想由衷地感谢每一位对我们博客的支持和打赏。你们的慷慨与支持,是我们前行的动力与源泉。
日期 | 姓名 | 金额 |
---|---|---|
2023-09-06 | *源 | 19 |
2023-09-11 | *朝科 | 88 |
2023-09-21 | *号 | 5 |
2023-09-16 | *真 | 60 |
2023-10-26 | *通 | 9.9 |
2023-11-04 | *慎 | 0.66 |
2023-11-24 | *恩 | 0.01 |
2023-12-30 | I*B | 1 |
2024-01-28 | *兴 | 20 |
2024-02-01 | QYing | 20 |
2024-02-11 | *督 | 6 |
2024-02-18 | 一*x | 1 |
2024-02-20 | c*l | 18.88 |
2024-01-01 | *I | 5 |
2024-04-08 | *程 | 150 |
2024-04-18 | *超 | 20 |
2024-04-26 | .*V | 30 |
2024-05-08 | D*W | 5 |
2024-05-29 | *辉 | 20 |
2024-05-30 | *雄 | 10 |
2024-06-08 | *: | 10 |
2024-06-23 | 小狮子 | 666 |
2024-06-28 | *s | 6.66 |
2024-06-29 | *炼 | 1 |
2024-06-30 | *! | 1 |
2024-07-08 | *方 | 20 |
2024-07-18 | A*1 | 6.66 |
2024-07-31 | *北 | 12 |
2024-08-13 | *基 | 1 |
2024-08-23 | n*s | 2 |
2024-09-02 | *源 | 50 |
2024-09-04 | *J | 2 |
2024-09-06 | *强 | 8.8 |
2024-09-09 | *波 | 1 |
2024-09-10 | *口 | 1 |
2024-09-10 | *波 | 1 |
2024-09-12 | *波 | 10 |
2024-09-18 | *明 | 1.68 |
2024-09-26 | B*h | 10 |
2024-09-30 | 岁 | 10 |
2024-10-02 | M*i | 1 |
2024-10-14 | *朋 | 10 |
2024-10-22 | *海 | 10 |
2024-10-23 | *南 | 10 |
2024-10-26 | *节 | 6.66 |
2024-10-27 | *o | 5 |
2024-10-28 | W*F | 6.66 |
2024-10-29 | R*n | 6.66 |
2024-11-02 | *球 | 6 |
2024-11-021 | *鑫 | 6.66 |
2024-11-25 | *沙 | 5 |
2024-11-29 | C*n | 2.88 |

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了