使用stm32的TIM4的通道1与通道2来主要实现捕获功能,低频是捕获值依旧准确。
环境使用的stm32f103vet6
一、贴出初始化部分的代码
void TIM4_Mode_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//PB6 ch1 A,PB7 ch2
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //使能TIM4时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能GPIOA时钟
GPIO_StructInit(&GPIO_InitStructure); //将GPIO_InitStruct中的参数按缺省值输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //PA6 PA7浮空输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
TIM_DeInit(TIM4);
TIM_TimeBaseStructure.TIM_Period = TIM4_TIM_Period;//55999;根据个人需求进行配置
TIM_TimeBaseStructure.TIM_Prescaler = 0; //预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //输入时钟不分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
TIM_TimeBaseInit(TIM4,&TIM_TimeBaseStructure);
//输入捕捉方式
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //捕捉上升沿
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //捕捉中断
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //捕捉不分频
TIM_ICInitStructure.TIM_ICFilter = 0x3; //捕捉输入滤波
TIM_ICInit(TIM4, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2 ;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //捕捉上升沿
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //捕捉中断
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //捕捉不分频
TIM_ICInitStructure.TIM_ICFilter = 0x3; //捕捉输入滤波 0x0-0xF
TIM_ICInit(TIM4, &TIM_ICInitStructure);
TIM_ClearFlag(TIM4, TIM_IT_CC1 | TIM_IT_CC2| TIM_IT_Update);
/* Enable the TIM4Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_ClearFlag(TIM4,TIM_FLAG_Update);
TIM_ARRPreloadConfig(TIM4,DISABLE);
/* Enable the CC2 Interrupt Request */
TIM_ITConfig(TIM4, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_Update , ENABLE);
/* TIM enable counter */
TIM_Cmd(TIM4, ENABLE);
}
二、贴出中断处理函数,对于低频捕获必须要配置更新中断(TIM_IT_Update),当发生溢出中断时计数一次,最终算得的捕获时间需要加上(溢出次数*装载值),这样获得的低频捕获的值才是正确的。
void TIM4_IRQHandler(void) //定时器中断
{
//频率缓冲区计数
static u32 this_time_CH1 = 0;
static u32 last_time_CH1 = 0;
static u8 capture_number_CH1 = 0;
vu32 tmp16_CH1;
static u16 this_time_CH2 = 0;
static u16 last_time_CH2 = 0;
static u8 capture_number_CH2 = 0;
vu32 tmp16_CH2;
if (TIM_GetITStatus(TIM4,TIM_IT_Update) != RESET) //计数器更新中断
{
TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
//溢出次数通道1、2分开统计
CH1_Cycles_Count++;
CH2_Cycles_Count++;
}
if(TIM_GetITStatus(TIM4, TIM_IT_CC1) != RESET) //通道1脉冲检测中断
{
TIM_ClearITPendingBit(TIM4, TIM_IT_CC1);
if(capture_number_CH1 == 0) //收到第一个上升沿
{
capture_number_CH1 = 1;
last_time_CH1 = TIM_GetCapture1(TIM4);
}
else if(capture_number_CH1 == 1) //收到第二个上升沿
{
//capture_number_CH1 = 0;
this_time_CH1 = TIM_GetCapture1(TIM4);
if(this_time_CH1 > last_time_CH1)
{
tmp16_CH1 = this_time_CH1 - last_time_CH1 + TIM4_TIM_Period * CH1_Cycles_Count;
}
else
{
tmp16_CH1 = TIM4_TIM_Period * CH1_Cycles_Count - last_time_CH1 + this_time_CH1;
}
CH1_Cycles_Count = 0;
last_time_CH1 = this_time_CH1;
}
}
if(TIM_GetITStatus(TIM4, TIM_IT_CC2) != RESET) //通道2脉冲检测中断
{
TIM_ClearITPendingBit(TIM4, TIM_IT_CC2);
pulse_count++;
if(capture_number_CH2 == 0)
{
capture_number_CH2 = 1;
last_time_CH2 = TIM_GetCapture2(TIM4);
}
else if(capture_number_CH2 == 1)
{
//capture_number_CH2 = 0;
this_time_CH2 = TIM_GetCapture2(TIM4);
if(this_time_CH2 > last_time_CH2)
{
tmp16_CH2 = this_time_CH2 - last_time_CH2 + TIM4_TIM_Period * CH2_Cycles_Count;
}
else
{
tmp16_CH2 = TIM4_TIM_Period * CH2_Cycles_Count - last_time_CH2 + this_time_CH2;
}
CH2_Cycles_Count = 0;
last_time_CH2 = this_time_CH2;
}
}
}
三、注意事项
初始化部分就不说了,看到很多网友在捕获过程中存在问题。基本上大部分网友都是下图中“圈1”中没有屏蔽,“圈2”内容没有。这样的配置会造成丢失百分之五十的脉冲没有统计。大家自己体会一下下面的操作 。