STM32 实现输入捕获 库函数版
输入捕获学好了 才能学好电容触摸
相关介绍
输入捕获简介
在定时器中断实验章节中我们介绍了通用定时器具有多种功能,输入
捕获就是其中一种。STM32F1除了基本定时器TIM6和TIM7,其他定时器都
具有输入捕获功能。输入捕获可以对输入的信号的上升沿,下降沿或者
双边沿进行捕获,通常用于测量输入信号的脉宽、测量 PWM 输入信号的
频率及占空比。
在输入捕获模式下,当相应的 ICx
信号检测到跳变沿后,将使用捕获/比较寄存器(TIMx_CCRx)来锁存计数
器的值。简单的说就是通过检测TIMx_CHx上的边沿信号,在边沿信号发
生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)
存放到对应的通道的捕获/比较寄存(TIMx_CCRx)里面,完成一次捕获
。同时还可以配置捕获时是否触发中断/DMA 等。
工作原理图
实现步骤:
1.使能定时器及端口时钟(在APB1)
2.初始化定时器参数,包含自动重装值,分频系数,计数方式等
3.设置通用定时器的输入捕获参数,开启输入捕获功能
如果我们需要配置TIM5的通道1为输入捕获功能,并且为上升沿捕获、
不分频、直接映射到TI,可以如下配置:
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel=TIM_Channel_1; //通道1
TIM_ICInitStructure.TIM_ICFilter=0x00; //滤波
TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//捕获极性
TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1; //分频系数
TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//直接映射到TI1
TIM_ICInit(TIM5,&TIM_ICInitStructure);
实现代码如下:
#include "Cap.h"
u8 Cap_Sta; //捕获状态
u16 Cap_Val; //捕获值
void Cap_Init(u16 pre, u16 psc)
{
TIM_TimeBaseInitTypeDef timT;
TIM_ICInitTypeDef timI;
NVIC_InitTypeDef nvicN;
GPIO_InitTypeDef gpioP;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);
//A0 KEY_UP键
gpioP.GPIO_Mode = GPIO_Mode_IPD;
gpioP.GPIO_Speed = GPIO_Speed_50MHz;
gpioP.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOA,&gpioP);
//设置定时器5
timT.TIM_Period = pre; //自动重装载
timT.TIM_Prescaler = psc; //分频系数
timT.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
timT.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM5,&timT);
timI.TIM_Channel = TIM_Channel_1; //通道1
timI.TIM_ICFilter = 0x00; //滤波
timI.TIM_ICPolarity = TIM_ICPolarity_Rising; //捕获极性 上升沿
timI.TIM_ICPrescaler = TIM_ICPSC_DIV1; //分频系数
timI.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI
TIM_ICInit(TIM5,&timI);
TIM_ITConfig(TIM5,TIM_IT_Update | TIM_IT_CC1, ENABLE);
TIM_Cmd(TIM5,ENABLE); //使能
nvicN.NVIC_IRQChannel = TIM5_IRQn;
nvicN.NVIC_IRQChannelCmd = ENABLE;
nvicN.NVIC_IRQChannelPreemptionPriority = 2;
nvicN.NVIC_IRQChannelSubPriority = 2;
NVIC_Init(&nvicN);
}
void TIM5_IRQHandler(void)
{
if((Cap_Sta & 0x80) == 0) //未捕获
{
if(TIM_GetITStatus(TIM5,TIM_IT_Update)) //发生更新中断
{
if(Cap_Sta & 0x40) //捕获到高电平
{
if((Cap_Sta & 0x3F) == 0x3F) //捕获时间长
{
Cap_Sta |= 0x80; //标志一次捕获成功
Cap_Val = 0xFFFF;
}
else
{
Cap_Sta++;
}
}
}
if(TIM_GetITStatus(TIM5,TIM_IT_CC1)) //发送捕获中断
{
if(Cap_Sta&0X40)//捕获到了低电平
{
Cap_Sta|=0x80; //成功捕获一次高电平
Cap_Val=TIM_GetCapture1(TIM5);
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //设置上升沿捕获
}
else
{
Cap_Sta=0;
Cap_Val=0;
Cap_Sta|=0x40; //捕获到高电平 标志
TIM_Cmd(TIM5,DISABLE);
TIM_SetCounter(TIM5,0); //定时器初值为0
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); //设置下降沿捕获
TIM_Cmd(TIM5,ENABLE);
}
}
}
TIM_ClearITPendingBit(TIM5,TIM_IT_CC1 | TIM_IT_Update);
}
主函数实现:
#include "stm32f10x.h"
#include "Uart.h"
#include "Cap.h"
int main()
{
u32 indata = 0;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
UART1_Init(9600);
printf ("捕获开始\r\n");
Cap_Init(0xFFFF,71); //1M频率计数
while(1)
{
if(Cap_Sta & 0x80) //捕获到
{
indata = Cap_Sta & 0x3F;
indata *= 0xFFFF;
indata += Cap_Val;
printf("高电平持续时间:%d us \r\n",indata);
Cap_Sta = 0;
}
}
}