STM32HAL定时器同时使用两路输入捕获(含对中断函数内容详解)
先把结果放一下,想知其所以然的继续看
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim == &htim2)/* 判断是否为定时器TIM2 */
{
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
//通道1中断处理程序
}
else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{
//通道2中断处理程序
}
}
}
因为一个定时器四个通道共用一个中断函数
所以问题的核心就是解决在中断中判断是哪个通道触发的
首先从寄存器角度看
可以通过查看TIMx_SR->CCxIF是否为1来判断触发通道
所以是不是可以在中断回调函数中
通过 __HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC2) 获取标志位
程序处理完成后 __HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_CC2) 清除标志位呢
并不是
因为在hal库中,对中断的调用进行了封装
首先在stm32f1xx_it.c中找到void TIM2_IRQHandler(void)函数定义(以TIM2为例)d
可以看到在里面调用了中断处理函数HAL_TIM_IRQHandler(&htim2);
接下来对处理函数中的内容进行一下分析
@endverbatim
* @{
*/
/**
* @brief This function handles TIM interrupts requests.
* @param htim TIM handle
* @retval None
*/
void HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim)
{
uint32_t itsource = htim->Instance->DIER;
uint32_t itflag = htim->Instance->SR;
/* Capture compare 1 event */
if ((itflag & (TIM_FLAG_CC1)) == (TIM_FLAG_CC1))
{
if ((itsource & (TIM_IT_CC1)) == (TIM_IT_CC1))
{
{
__HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_CC1);
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_1;
/* Input capture event */
if ((htim->Instance->CCMR1 & TIM_CCMR1_CC1S) != 0x00U)
{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->IC_CaptureCallback(htim);
#else
HAL_TIM_IC_CaptureCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
/* Output compare event */
else
{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->OC_DelayElapsedCallback(htim);
htim->PWM_PulseFinishedCallback(htim);
#else
HAL_TIM_OC_DelayElapsedCallback(htim);
HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
}
}
}
/* Capture compare 2 event */
if ((itflag & (TIM_FLAG_CC2)) == (TIM_FLAG_CC2))
{
if ((itsource & (TIM_IT_CC2)) == (TIM_IT_CC2))
{
__HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_CC2);
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_2;
/* Input capture event */
if ((htim->Instance->CCMR1 & TIM_CCMR1_CC2S) != 0x00U)
{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->IC_CaptureCallback(htim);
#else
HAL_TIM_IC_CaptureCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
/* Output compare event */
else
{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->OC_DelayElapsedCallback(htim);
htim->PWM_PulseFinishedCallback(htim);
#else
HAL_TIM_OC_DelayElapsedCallback(htim);
HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
}
}
/* Capture compare 3 event */
if ((itflag & (TIM_FLAG_CC3)) == (TIM_FLAG_CC3))
{
if ((itsource & (TIM_IT_CC3)) == (TIM_IT_CC3))
{
__HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_CC3);
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_3;
/* Input capture event */
if ((htim->Instance->CCMR2 & TIM_CCMR2_CC3S) != 0x00U)
{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->IC_CaptureCallback(htim);
#else
HAL_TIM_IC_CaptureCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
/* Output compare event */
else
{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->OC_DelayElapsedCallback(htim);
htim->PWM_PulseFinishedCallback(htim);
#else
HAL_TIM_OC_DelayElapsedCallback(htim);
HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
}
}
/* Capture compare 4 event */
if ((itflag & (TIM_FLAG_CC4)) == (TIM_FLAG_CC4))
{
if ((itsource & (TIM_IT_CC4)) == (TIM_IT_CC4))
{
__HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_CC4);
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_4;
/* Input capture event */
if ((htim->Instance->CCMR2 & TIM_CCMR2_CC4S) != 0x00U)
{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->IC_CaptureCallback(htim);
#else
HAL_TIM_IC_CaptureCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
/* Output compare event */
else
{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->OC_DelayElapsedCallback(htim);
htim->PWM_PulseFinishedCallback(htim);
#else
HAL_TIM_OC_DelayElapsedCallback(htim);
HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
}
}
/* TIM Update event */
if ((itflag & (TIM_FLAG_UPDATE)) == (TIM_FLAG_UPDATE))
{
if ((itsource & (TIM_IT_UPDATE)) == (TIM_IT_UPDATE))
{
__HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_UPDATE);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->PeriodElapsedCallback(htim);
#else
HAL_TIM_PeriodElapsedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
}
/* TIM Break input event */
if ((itflag & (TIM_FLAG_BREAK)) == (TIM_FLAG_BREAK))
{
if ((itsource & (TIM_IT_BREAK)) == (TIM_IT_BREAK))
{
__HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_BREAK);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->BreakCallback(htim);
#else
HAL_TIMEx_BreakCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
}
/* TIM Trigger detection event */
if ((itflag & (TIM_FLAG_TRIGGER)) == (TIM_FLAG_TRIGGER))
{
if ((itsource & (TIM_IT_TRIGGER)) == (TIM_IT_TRIGGER))
{
__HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_TRIGGER);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->TriggerCallback(htim);
#else
HAL_TIM_TriggerCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
}
/* TIM commutation event */
if ((itflag & (TIM_FLAG_COM)) == (TIM_FLAG_COM))
{
if ((itsource & (TIM_IT_COM)) == (TIM_IT_COM))
{
__HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_COM);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->CommutationCallback(htim);
#else
HAL_TIMEx_CommutCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
}
}
首先,获取通道使能状态
uint32_t itsource = htim->Instance->DIER;
来看寄存器表
可以看到CC1IE是中断的使能位,所以这里是在获取定时器通道的使能状态
这个位是软件置位的,也就是在初始化的时候就置位了,可以在中断初始化中找到
HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1); /* 以中断方式开启TIM2的输入捕获模式 */然后,获取中断请求标志位
uint32_t itflag = htim->Instance->SR;
就是上面提到的在TIMx_SR中的各个通道标志位,这里不多说了然后是并列的四个通道的判断,以第一个为例,看注释
/* Capture compare 1 event */
if ((itflag & (TIM_FLAG_CC1)) == (TIM_FLAG_CC1))//判断通道一是否申请中断
{
if ((itsource & (TIM_IT_CC1)) == (TIM_IT_CC1))//判断通道一是否使能中断
{
{
__HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_CC1);//清除中断标志位(上图有讲,需软件清零)
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_1;//改变htim结构体中Channel为对应通道
/* Input capture event */
if ((htim->Instance->CCMR1 & TIM_CCMR1_CC1S) != 0x00U)//判断是输入还是输出只,要不是00即为输入
{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)//动态回调函数,也是就可以在程序运行中加入或取消回调函数
htim->IC_CaptureCallback(htim);
#else//如果没有设置动态回调的宏(默认不设置),就会进入回调函数。
HAL_TIM_IC_CaptureCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
/* Output compare event */
else//如果是输出,则运行以下内容
{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->OC_DelayElapsedCallback(htim);
htim->PWM_PulseFinishedCallback(htim);
#else
HAL_TIM_OC_DelayElapsedCallback(htim);
HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;//完成后把结构体内的Channel变量清除
}
}
}
判断输入输出的寄存器内容
在中断函数中,已经将寄存器的标志位清零了,并且把htim中的Channel设置为了对应通道,所以回调函数中判断Channel的值即可。
中断函数后面还有对四种事件的处理,简单一说吧
/* TIM Update event */
更新事件,也就是计时溢出后触发事件,调用对应回调函数HAL_TIM_PeriodElapsedCallback(htim);
/* TIM Break input event */
对Break信号的处理,刹车功能,定时器会停止计数,并执行一些保护措施,例如复位所有输出比较通道(OCx),清除所有捕获/比较寄存器(CCR),以及复位更新事件标志
/* TIM Trigger detection event */
外部触发信号触发事件,触发信号可以来自另一个定时器的更新事件、捕获/比较事件或其他信号源。
/* TIM commutation event */
换相事件,主要用在三相电机控制中
作者:溯游_