一、什么是输入捕获
定时器的计数器CNT在不停地计数,当选定的输入引脚上出现了设定的 上升沿或下降沿时,把CNT的值记录到CCR中。
二、框图
三、流程图
四、程序分析
static void MX_TIM4_Init(void)
{
TIM_MasterConfigTypeDef sMasterConfig;
TIM_IC_InitTypeDef sConfigIC;
//-----------------------这一段初始化定时器---------------------------
htim4.Instance = TIM4;
htim4.Init.Prescaler = 71;
htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
htim4.Init.Period = 0xFFFF;
htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_IC_Init(&htim4) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
//--------------------这一段以后再解------------------------------------
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
//-------------------下面中的x为通道号----------------------------------------
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;//下降沿捕获,CCER-->CCxP位
sConfigIC.ICSelection = TIM_ICSELECTION_INDIRECTTI;//定义捕获通道IC3映射在输入通道TI4上
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;//分频为0
sConfigIC.ICFilter = 0;//滤波为0
if (HAL_TIM_IC_ConfigChannel(&htim4, &sConfigIC, TIM_CHANNEL_3) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;//上升沿
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;//定义IC4映射在TI4上
if (HAL_TIM_IC_ConfigChannel(&htim4, &sConfigIC, TIM_CHANNEL_4) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
初始化完以后,主函数要调用HAL_TIM_IC_Start_IT(&htim4,TIM_CHANNEL_3);来开启通道,置1 DDER–>CC3IE位。
那么定时器4将会发生三类中断,
1、CNT计数到FFFF时,溢出中断
2、上升沿捕获通道4中断
3、下降沿捕获通道3中断
在中断函数中,要处理这三类中断。
五、问题点
1、在中断中,清0 计数器CNT,重新计数,得到上升沿的时间,和下降沿时间,然后计算频率为72M/tmp1,占空比为tmp2/tmp1(假设时钟为72M)
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef * htim)
{
// static uint8_t TIM4CH34_CAPTURE_STA=0;//标记输入捕获状态
if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_4)//如果是TIM_IT_CC4中断,上升沿
{
__HAL_TIM_SET_COUNTER(htim,0);//清0计数器CNT,从0开始计数
tmp1=HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_4);
}
else if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_3)//如果是TIM_IT_CC3中断,下降沿
{
tmp2=HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_3);
}
}
这程序计算得不够准,当上升沿捕获中断的时候,进入中断,然后清0计数器,这之间已经跑了几个时钟了。所以tmp1和tmp2都会比实际小一点。还有进入定时器的频率72M/65535=1098 不能测试低于1098的频率,会溢出。
2、改成以下状态机,会更准确
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef * htim)
{
static uint8_t state=0;//标记输入捕获状态
static uint16_t CaptureValue1_CH4;
if(state==0)
{
if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_4)//如果是TIM_IT_CC4中断,上升沿
{
CaptureValue1_CH4 =HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_4);
state=1;
}
}
else if(state==1)
{
if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_3)//如果是TIM_IT_CC3中断,下降沿
{
tmp2=HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_3);
if(tmp2>CaptureValue1_CH4) tmp2=tmp2-CaptureValue1_CH4;
else tmp2= (0xFFFF-CaptureValue1_CH4)+tmp2;
state=2;
}
}
else if(state==2)
{
if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_4)//如果是TIM_IT_CC4中断,上升沿
tmp1=HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_4);
if(tmp1>CaptureValue1_CH4) tmp1=tmp1-CaptureValue1_CH4;
else tmp1= (0xFFFF-CaptureValue1_CH4)+tmp1;
state=0;
}
else state=0;
}
这个文章写得细https://blog.csdn.net/qq_38410730/article/details/80011330