最近两个月一直很头秃,网上很多人吐槽HAL库,但是我一直没有舍弃,一直在努力的适应。问题如下:
电路板单板调试CAN发送数据,程序总是卡死在if ( ( Timeout == 0 ) || ( ( HAL_GetTick() - tickstart ) > Timeout ) ),有人说,有病,为何不用回环模式。当然可以!不过在设备正常运行的时候,如果有设备离线,总线上只剩下一个CAN节点的时候与现在恰好相同。
刚开始我也忽略这个问题,但设备联调中,一旦有某些设备故障,CAN上只剩下一个节点,程序卡死的问题不容虎视,我决定不在逃避,尝试解决这个问题。
网上大侠告诉我应该是发送和接收同时发生,导致邮箱不够用,OK,我都用子优先级相同的中断来操作,依旧不行;有大侠说是因为systick没有使能,我debug查看systick正常计数;有大侠说是CAN的自动离线管理出了问题,开启离线恢复就可以解决,我尝试,如果CAN总线其他节点没有恢复,程序仍然卡死。最终我检查程序发现systick的中断不能进入,导致uwTick++不能执行。查看HAL库的systick中断优先级配置,发现是最低的,然并卵,卡死的位置并不在中断内。
我浅尝辄止(主要是hal底层不懂),没有继续研究为何systick中断不进入,而且打算半路截胡,想看看如果投机取巧的解决这个问题。有人说,利用OS系统中的其他计数器替代可以解决,然而我并没有是用OS。有人说你可以把中断优先级设高一些,我认为这并不是一个好方案,1ms的中断对程序的影响还是存在的,而且我程序中本身就有10ms的定时器中断。于是,我决定用系统计数器更换uwTick的判断条件。方法如下
uint32_t ticks;
uint32_t told, tnow, tcnt = 0;
uint32_t reload = SysTick->LOAD;
ticks=Timeout*1000*fac_us; //需要的节拍数
told=SysTick->VAL; //刚进入时的计数器值
if ( tcnt<=ticks )
{
if(tnow<told)tcnt+=told-tnow; //这里注意一下SYSTICK是一个递减的计数器就可以了.
else tcnt+=reload-tnow+told;
told=tnow;
}
else
{
hcan->State = HAL_CAN_STATE_TIMEOUT;
/* Process unlocked */
__HAL_UNLOCK ( hcan );
return HAL_TIMEOUT;
}
虽然不是一个好方法,但是确实解决了问题。