ST给的TIM例子都是实现一个固定频率的当时输出,如果想在每次定时中断后改变定时器值,那么需要动态的修改定时器周期配置。
实测中发现一有坑,给大家共享。
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
- {
- /* USER CODE BEGIN Callback 0 */
- /* USER CODE END Callback 0 */
- if (htim->Instance == TIM22) {
- HAL_IncTick();
- }
- /* USER CODE BEGIN Callback 1 */
- if (htim->Instance == TIM2) {
- IrdaTransfer(pDataNEC);
- }
- /* USER CODE END Callback 1 */
- }
复制代码 首先在HAL_TIM_PeriodElapsedCallback中添加TIM的Update事件中断回调函数,自己写IrdaTransfer(pDataNEC)实现NEC编码的红外遥控。
- uint16_t IrdaTransfer(uint8_t* pDataNEC)
- {
- PulseVal=TimeSerial(pDataNEC,PulseSteps);
- PulseSteps++;
- if(PulseVal>0)
- {
- htim2.Init.Period = PulseVal&0x7fff;
- HAL_TIM_Base_Init(&htim2);
- __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);
- HAL_TIM_Base_Start_IT(&htim2);
- }
- else
- {
- __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);
- HAL_TIM_Base_Stop_IT(&htim2);
- }
- if(PulseVal&0x8000)
- HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_SET);
- else
- HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_RESET);
- return PulseVal;
- }
复制代码 注意这里的坑是:
htim2.Init.Period = PulseVal&0x7fff;
HAL_TIM_Base_Init(&htim2);
__HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);//这是坑,必须在此处加。
HAL_TIM_Base_Start_IT(&htim2);
在初始化定时时长后,必须先清除中断标志,再启动定时器中断,否则会直接进中断而没有在定时结束时进,这个坑调了我一天,不明白为啥初始化定时器就会触发一次UPDATE中断。
以上代码即可实现每次定时后立即更新定时值,实现任意的序列控制。具体的NEC红外序列实现功能我就不放了,留点自己动脑子的地方,填的坑与大家共享。
|
HAL_TIM_Base_Start_IT(&htim2);
在初始化定时时长后,必须先清除中断标志,再启动定时器中断,否则会直接进中断而没有在定时结束时进,这个坑调了我一天,不明白为啥初始化定时器就会触发一次UPDATE中断。
==>不能算是个坑,应该是手册没看清楚。
因为有些寄存器比方PSC/RCR寄存器必须通过更新事件才能更新,我们初始化时只能操作预转载寄存器,所以让我们用户数据生效,就手动产生个更新事件,让预装载寄存器的数据拷贝到影子寄存器【实际寄存器】发挥作用。但这个操作会置位更新中断标志,所以我们在使能更新中断前有必要清除下该标志UIF,否则可能一使能更新中断就跳进更新中断服务程序。