输入捕获实验
这个实验的效果是:按住按钮,然后放开,串口会打印按住的时间.
捕获原理如图。计数器有捕获功能。没有捕获的时候,定时器也可以在工作。设置为上升沿捕获,有上升沿的时候,会触发中断进入中断函数。
先把定时器清零。然后在捕获期间,定时器会溢出,要计算溢出的次数。同时在中断函数中,已经修改为下降沿捕获了。
在下降沿捕获的时候,读取当时的计数器的值。这样再加上溢出的次数,就能算出总时间了。
中断函数的流程图如下:
函数代码如下:
#include "stm32f4xx.h"
#include "gpio_config.h"
#include "delay.h"
#include "usart.h"
// GPIO基本配置
// GPIO的AF映射
// 中断配置
// 计时器的基本配置
// 计时器的捕获配置
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM5_ICInitStructure;
u8 TIM5CH1_CAPTURE_STA=0;
u32 TIM5CH1_CAPTURE_VAL;
int main(void)
{
long long temp=0;
/* Clock Enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); // enable TIM5 clock
/* UART1 and delay init */
delay_init();
uart_init(115200);
/* GPIO init */
GPIO_Init(GPIOA,GpioPortAMode);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource0,GPIO_AF_TIM5); //PA0 AF to TIM5
/*nvic init */
NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//
NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;//
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //
NVIC_Init(&NVIC_InitStructure); //
TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新和捕获中断
/* TIM5 init */
// 定时器的时钟源有4个,最常用的就是内部时钟源CK_INT。经过选择器以后的时钟,叫做CK_PSC.
//如果选择了CK_INT做时钟源,CK_INT=CK_PSC
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; //即fDTS,是CK_INT与数字滤波器之间的分频比,和计数器的计数频率没关系
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数
TIM_TimeBaseStructure.TIM_Period=0XFFFFFFFF; //就是计数溢出值,也是自动重载值
TIM_TimeBaseStructure.TIM_Prescaler=83; //计数器的预分频,具体的频率为CK_PSC/(TIM_Perscaler+1)
TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure);
/* catch init */
TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //CCER寄存器,是通道选择,TIM5有4个通道
TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //见通用定时器框图,是TI1/2和IC1/2时间的映射关系
TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //类似捕获滤波,如高电平捕获,可以设置抓到1个高电平就捕获,还是连续8个高电平才捕获
TIM5_ICInitStructure.TIM_ICFilter = 0x00;//滤波器采样频率
TIM_ICInit(TIM5, &TIM5_ICInitStructure); //
TIM_Cmd(TIM5,ENABLE ); //使能定时器5
while(1)
{
delay_nms(300);
if(TIM5CH1_CAPTURE_STA&0x80)
{
temp=TIM5CH1_CAPTURE_STA&0X3F;
temp=temp*0xFFFFFFFF;
temp+=TIM5CH1_CAPTURE_VAL;
printf("HIGH:%lld us\r\n",temp);
TIM5CH1_CAPTURE_STA=0;
}
}
}
//捕获状态 TIM5CH1_CAPTURE_STA的定义
//[7]:0,没有成功的捕获;1,成功捕获到一次.
//[6]:0,还没捕获到低电平;1,已经捕获到低电平了.
//[5:0]:捕获低电平后溢出的次数(对于32位定时器来说,1us计数器加1,溢出时间:4294秒)
void TIM5_IRQHandler(void)
{
if((TIM5CH1_CAPTURE_STA&0X80)==0)
{
if(TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET) //判断是溢出中断
{
if(TIM5CH1_CAPTURE_STA==0x40) //是否已经捕获
{if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F) //是否溢出太多
{
TIM5CH1_CAPTURE_STA=0x80; //溢出次数太多,捕获时间太长,算一次成功捕获。
TIM5CH1_CAPTURE_VAL=0xFFFFFFFF;
}
else TIM5CH1_CAPTURE_STA++; //溢出次数没有太多,溢出次数加1
}
}
if(TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET) //捕获中断
{
if(TIM5CH1_CAPTURE_STA==0x40) //是否已经捕获到高电平
{
TIM5CH1_CAPTURE_STA|=0x80; //刚才已经捕获到高电平,这次又捕获,说明捕获到低电平了,就是一次成功的捕获了
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //为下一次捕获做准备
TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5); //读取当前计数器的值
}
else //第一次捕获,说明是高电平捕获
{TIM5CH1_CAPTURE_STA=0x0;
TIM5CH1_CAPTURE_VAL=0x0; //计数器清零
TIM5CH1_CAPTURE_STA|=0x40;
TIM_Cmd(TIM5,ENABLE );
TIM_SetCounter(TIM5,0);
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); // 配置为低电平捕获
TIM_Cmd(TIM5,ENABLE );
}
}
}
TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update);
}