在《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
)配置为CC1
通道被配置为输入、IC1
映射在TI1
上(01
); - 输入捕获预分频器(
ICxPSC
)配置为无预分频器(00
);
- 输入捕获预滤波器(
- 配置
TIMx_CCER
寄存器:- 捕获输出使能(
CCxE
)配置为使能(1
); - 捕获输出极性(
CCxP
)配置(0
:上升沿捕获,1
:下降沿捕获);
- 捕获输出使能(
(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~2
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; //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; //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; //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; //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; //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; //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; //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; //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; //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; //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; //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; //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; //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; //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
开始计数到自动重加载值一个循环结束了,脉冲还是没有结束。这个情况下,显而易见不能只记录一下最后的计数器当前值。
解决的方法即使引入TIM1CH1_CAP_STA
,TIM1CH1_CAP_STA
是我们自己定义的全局变量,即自定义捕获状态寄存器;
/*********************************************************************************************************
*
* Description: 自定义捕获状态寄存器
bit7 bit6 bit5~0
捕获完成标志 第一次捕获到高电平标志 捕获高电平后定时器溢出次数
*
********************************************************************************************************/
u8 TIM1CH1_CAP_STA=0; //定时器1通道1捕获状态
u16 TIM1CH1_CAP_VAL=0; //输入捕获值
u8 TIM1CH2_CAP_STA=0; //定时器1通道2捕获状态
u16 TIM1CH2_CAP_VAL=0; //输入捕获值
u8 TIM1CH3_CAP_STA=0; //定时器1通道3捕获状态
u16 TIM1CH3_CAP_VAL=0; //输入捕获值
u8 TIM1CH4_CAP_STA=0; //定时器1通道4捕获状态
u16 TIM1CH4_CAP_VAL=0; //输入捕获值
.......
位[5-0
]为捕捉高电平后定时器溢出的次数,位6
为捕捉到高电平标志,位7
为捕获完标志。
这里定时器1
向上计数为例,TIM1_CNT
计数到自动加载值(TIMx_ARR
),将会触发计数器溢出中断,
在溢出中断处理函数TIM1_UP_IRQHandler
的任务就是统计高电平持续周期触发了多少次溢出中断。
2.2.2.2 TIM1_CC_IRQHandler
定时器1
捕获/比较中断TIM1_CC_IRQHandler
实现;
/*******************************************************************************
* Function Name : TIM1_CC_IRQHandler
* Description : This function handles TIM1 capture compare interrupt request.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void TIM1_CC_IRQHandler(void) //定时器1捕获比较中断
{
u16 timsr; //存放定时器标志位
timsr = TIM1->SR;
if((TIM1CH1_CAP_STA&0x80)==0) //还未成功捕获
{
if(timsr&0x02) //捕获1发生捕获事件
{
if(TIM1CH1_CAP_STA&0X40) //第二次捕获到
{
TIM1CH1_CAP_STA |=0X80; //高/低电平捕获成功
TIM1CH1_CAP_VAL =TIM1->CCR1; //获取当前的捕获值
}
else //第一次捕获到
{
TIM1CH1_CAP_VAL=0;
TIM1CH1_CAP_STA =0X40; //标记捕获到
TIM1->CNT =0; //计数器清空
}
if( TIM1->CCER&(1<<1)) //上次设置为下降沿
{
TIM1->CCER &=~(1<<1); //清零
TIM1->CCER |=0<<1; //CC1P设置为上升沿
}
else //上次设置为上升沿
{
TIM1->CCER &=~(1<<1); //清零
TIM1->CCER |=1<<1; //CC1P设置为下降沿
}
TIM1->SR &=~(1<<1); //清中断标志 必须 (置0清 非写1)
}
}
//*******************************************************
if((TIM1CH2_CAP_STA&0x80)==0) //还未成功捕获
{
if(timsr&0x04) //捕获1发生捕获事件
{
if(TIM1CH2_CAP_STA&0X40)
{
TIM1CH2_CAP_STA |=0X80; //高/低电平捕获成功
TIM1CH2_CAP_VAL =TIM1->CCR2; //获取当前的捕获值
}
else
{
TIM1CH2_CAP_VAL=0;
TIM1CH2_CAP_STA =0X40; //标记捕获到
TIM1->CNT =0; //计数器清空
}
if( TIM1->CCER&(1<<5)) //上次设置为下降沿
{
TIM1->CCER &=~(1<<5); //清零
TIM1->CCER |=0<<5; //CC2P设置为上升沿
}
else //上次设置为上升沿
{
TIM1->CCER &=~(1<<5); //清零
TIM1->CCER |=1<<5; //CC2P设置为下降沿
}
TIM1->SR &=~(1<<2); //清中断标志 必须 (置0清 非写1)
}
}
//***********************************************************
if((TIM1CH3_CAP_STA&0x80)==0) //还未成功捕获
{
if(timsr&0x08) //捕获1发生捕获事件
{
if(TIM1CH3_CAP_STA&0X40)
{
TIM1CH3_CAP_STA |=0X80; //高/低电平捕获成功
TIM1CH3_CAP_VAL =TIM1->CCR3; //获取当前的捕获值
}
else
{
TIM1CH3_CAP_VAL=0;
TIM1CH3_CAP_STA =0X40; //标记捕获到
TIM1->CNT =0; //计数器清空
}
if( TIM1->CCER&(1<<9)) //上次设置为下降沿
{
TIM1->CCER &=~(1<<9); //清零
TIM1->CCER |=0<<9; //CC3P设置为上升沿
}
else //上次设置为上升沿
{
TIM1->CCER &=~(1<<9); //清零
TIM1->CCER |=1<<9; //CC3P设置为下降沿
}
TIM1->SR &=~(1<<3); //清中断标志 必须 (置0清 非写1)
}
}
//*******************************************8
if((TIM1CH4_CAP_STA&0x80)==0) //还未成功捕获
{
if(timsr&0x10) //捕获1发生捕获事件
{
if(TIM1CH4_CAP_STA&0X40)
{
TIM1CH4_CAP_STA |=0X80; //高/低电平捕获成功
TIM1CH4_CAP_VAL =TIM1->CCR4; //获取当前的捕获值
}
else
{
TIM1CH4_CAP_VAL=0;
TIM1CH4_CAP_STA =0X40;
TIM1->CNT =0; //计数器清空
}
if( TIM1->CCER&(1<<13)) //上次设置为下降沿
{
TIM1->CCER &=~(1<<13); //清零
TIM1->CCER |=0<<13; //CC4P设置为上升沿
}
else //上次设置为上升沿
{
TIM1->CCER &=~(1<<13); //清零
TIM1->CCER |=1<<13; //CC4P设置为下降沿
}
TIM1->SR &=~(1<<4); //清中断标志 必须 (置0清 非写1)
}
}
//**********************自定义用户任务****************************//
//*****************************************************************//
}
在捕获/比较中断中;
- 判断是否是第一次捕获到(捕捉到的是上升沿),如果是,计数器当前值(
TIM1_CNT
)清零,TIM1CH1_CAP_VAL
清零,同时标记第一次捕获到高电平,设置极性下降沿捕捉; - 判断是否是第二次捕获到(捕获到的是下降沿),如果是标记捕获完成,保存当前计数器(
TIM1_CNT
)的值到TIM1CH1_CAP_VAL
,设置极性上升沿捕获。
2.2.2.3 脉宽计算
接下来我们介绍一下高电平脉宽如何计算,以TIM1
通道1为例:
其中:\(F_{clk} = 72MHz\)。
2.2.3 TIM2~5
更新中断
定时器TIM2~5
更新中断处理函数基本是一样的,这里以TIM2_IRQHandler
为例。
由于定时器TIM2~5
均是通用定时器,其不像高级定时器那样有单独的溢出中断、捕获/比较中断事件,其只有中断事件,对应的中断处理函数为TIMx_IRQHandler
;
/*******************************************************************************
* Function Name : TIM2_IRQHandler
* Description : This function handles TIM2 global interrupt request.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void TIM2_IRQHandler(void)
{
u16 timsr; //存放定时器标志位
timsr = TIM2->SR;
//****************************************** 通道1 ****************************************************************
if((TIM2CH1_CAP_STA&0x80)==0) //还未成功捕获
{
/****************************************/
if(timsr&0x01) //发生更新(溢出)中断
{
if(TIM2CH1_CAP_STA&0x40) //已经捕获到高/低电平
{
if((TIM2CH1_CAP_STA&0x3F)==0X3F) //高/低电平太长了 强制捕获完成
{
TIM2CH1_CAP_STA |=0x80; //标记成功捕获一次
TIM2CH1_CAP_VAL =0xFFFF;
}
else
{
TIM2CH1_CAP_STA++; //自增1
}
}
}
/***********************************************/
if(timsr&0x02) //捕获1发生捕获事件
{
if(TIM2CH1_CAP_STA&0X40) //第二次发生捕获
{
TIM2CH1_CAP_STA |=0X80; //高电平/低电平捕获成功
TIM2CH1_CAP_VAL =TIM2->CCR1; //获取当前的捕获值
}
else //第一次发生捕获
{
TIM2CH1_CAP_VAL=0;
TIM2CH1_CAP_STA =0X40; //标记捕获到上升沿/下降沿
TIM2->CNT =0; //计数器清空
}
if( TIM2->CCER&(1<<1)) //上次设置为下降沿
{
TIM2->CCER &=~(1<<1); //清零
TIM2->CCER |=0<<1; //CC1P设置为上升沿
}
else //上次设置为上升沿
{
TIM2->CCER &=~(1<<1); //清零
TIM2->CCER |=1<<1; //CC1P设置为下降沿
}
}
}
//*************************************** 通道2 **************************************************************
if((TIM2CH2_CAP_STA&0x80)==0) //还未成功捕获
{
/****************************************/
if(timsr&0x01) //发生更新(溢出)中断
{
if(TIM2CH2_CAP_STA&0x40) //已经捕获到高/低电平
{
if((TIM2CH2_CAP_STA&0x3F)==0X3F) //高、低电平太长了 强制捕获完成
{
TIM2CH2_CAP_STA |=0x80; //标记成功捕获一次
TIM2CH2_CAP_VAL =0xFFFF;
}
else
{
TIM2CH2_CAP_STA++; //自增1
}
}
}
/***********************************************/
if(timsr&0x04) //捕获2发生捕获事件
{
if(TIM2CH2_CAP_STA&0X40) //标记第二次捕捉
{
TIM2CH2_CAP_STA |=0X80; //高/低电平捕获成功
TIM2CH2_CAP_VAL =TIM2->CCR2; //获取当前的捕获值
}
else //标记第一次捕捉
{
TIM2CH2_CAP_VAL=0;
TIM2CH2_CAP_STA =0X40; //标记第一次捕捉到
TIM2->CNT =0; //计数器清空
}
if( TIM2->CCER&(1<<5)) //上次设置为下降沿
{
TIM2->CCER &=~(1<<5); //清零
TIM2->CCER |=0<<5; //CC2P设置为上升沿
}
else //上次设置为上升沿
{
TIM2->CCER &=~(1<<5); //清零
TIM2->CCER |=1<<5; //CC2P设置为下降沿
}
}
}
//*************************************** 通道3 **************************************************************
if((TIM2CH3_CAP_STA&0x80)==0) //还未成功捕获
{
/****************************************/
if(timsr&0x01) //发生更新(溢出)中断
{
if(TIM2CH3_CAP_STA&0x40) //已经捕获到高/低电平
{
if((TIM2CH3_CAP_STA&0x3F)==0X3F) //高/低电平太长了 强制捕获完成
{
TIM2CH3_CAP_STA |=0x80; //标记成功捕获一次
TIM2CH3_CAP_VAL =0xFFFF;
}
else
{
TIM2CH3_CAP_STA++; //自增1
}
}
}
/***********************************************/
if(timsr&0x08) //捕获3发生捕获事件
{
if(TIM2CH3_CAP_STA&0X40)
{
TIM2CH3_CAP_STA |=0X80; //高/低电平捕获成功
TIM2CH3_CAP_VAL =TIM2->CCR3; //获取当前的捕获值
}
else
{
TIM2CH3_CAP_VAL=0;
TIM2CH3_CAP_STA =0X40; //标记捕获到
TIM2->CNT =0; //计数器清空
}
if( TIM2->CCER&(1<<9)) //上次设置为下降沿
{
TIM2->CCER &=~(1<<9); //清零
TIM2->CCER |=0<<9; //CC3P设置为上升沿
}
else //上次设置为上升沿
{
TIM2->CCER &=~(1<<9); //清零
TIM2->CCER |=1<<9; //CC3P设置为下降沿
}
}
}
//*************************************** 通道4 **************************************************************
if((TIM2CH4_CAP_STA&0x80)==0) //还未成功捕获
{
/****************************************/
if(timsr&0x01) //发生更新(溢出)中断
{
if(TIM2CH4_CAP_STA&0x40) //已经捕获到高/低电平
{
if((TIM2CH4_CAP_STA&0x3F)==0X3F) //高、低电平太长了 强制捕获完成
{
TIM2CH4_CAP_STA |=0x80; //标记成功捕获一次
TIM2CH4_CAP_VAL =0xFFFF;
}
else
{
TIM2CH4_CAP_STA++; //自增1
}
}
}
/***********************************************/
if(timsr&0x10) //捕获4发生捕获事件
{
if(TIM2CH4_CAP_STA&0X40)
{
TIM2CH4_CAP_STA |=0X80; //高/低电平捕获成功
TIM2CH4_CAP_VAL =TIM2->CCR4; //获取当前的捕获值
}
else
{
TIM2CH4_CAP_VAL=0;
TIM2CH4_CAP_STA =0X40; //标记第一次捕获到
TIM2->CNT =0; //计数器清空
}
if( TIM2->CCER&(1<<13)) //上次设置为下降沿
{
TIM2->CCER &=~(1<<13); //清零
TIM2->CCER |=0<<13; //CC4P设置为上升沿
}
else //上次设置为上升沿
{
TIM2->CCER &=~(1<<13); //清零
TIM2->CCER |=1<<13; //CC4P设置为下降沿
}
}
}
//**********************自定义用户任务****************************//
//*****************************************************************//
TIM2->SR =0; //清中断标志 更新中断和比较捕获中断
}
2.3 功能实现
接下来我们以TIM3
通道1
(PA6
引脚)为例进行输入捕获测试,我们将PC7
模拟成PWM
输出,高电平持续大约时间为258us
,低电平持续时间为500us
。
2.3.1 main
函数实现
int main()
{
u32 temp = 0;
STM32_Clock_Init(9); //系统时钟初始化
gpio_init(PC7,GPO_SpeedMax_50,HIGH);
STM32_NVIC_Init(2,USART1_IRQn,0,1); //串口中断优先级初始化,其中包括中断使能
usart_init(USART_1,115200); //串口1初始化,波特率115200 映射到PA9 PA10
STM32_NVIC_Init(2,TIM3_IRQn,0,1); //定时器3中断使能
TIM_CAP_Init(TIMER3,CAP_CH1,1); //定时器3通道1输入捕获 PA6
while(1)
{
//把PC7和PA6相连,测量PA6高电平脉宽
PCout(7)=1;
delay_us(258);
PCout(7)=0;
delay_ms(500);
while(TIM3CH1_CAP_STA&0X80)
{
temp = TIM3CH1_CAP_STA&0X3F;
temp *=65536;
temp +=TIM3CH1_CAP_VAL;
printf("PA6 high level time: %d us\n",temp);
TIM3CH1_CAP_STA=0;
}
}
}
2.3.2 测试
编译程序并下载,我们需要将PC7
引脚连接到PA6
引脚;

可以看到高电平时间大概为262us
,比延时时间258us
略长一些,这是因为我们程序执行也会消耗一定时间,可以看到这个测量结果还是比较准的。
三、源码下载
源码下载路径:stm32f103
。
参考文章