STM32 中的CAN总线模块是具有故障监测功能的
就是CANx_SCE_IRQHandler
这个用的很少,它叫CAN总线状态改变中断
通过打开这个中断,配合代码可以精确的监测CAN总线的故障情况
就是监测对应CAN的ESR寄存器
可以使用轮询或者中断的方式
中断的方式,以CAN1为例
调用HAL_NVIC_EnableIRQ(CAN1_SCE_IRQn),调好优先级,在CAN1_SCE_IRQHandler里面编好功能就可以
只要CAN总线发送状态改变,就会触发中断
可以非常灵敏的检测CAN总线断线,短路等等故障
查询比较好些,这样不会频繁进中断
简单设计了一个故障监测计数的功能,1ms刷新一次CAN_Error_Process函数,计数超了就置位标志,可以提供到应用层作为收发函数的调用判断前提,并且把收发FIFO的故障检测一并做了进来,方便监测。
//CAN总线故障
#define CAN_FUNC_ERR 0x55
//CAN总线正常
#define CAN_FUNC_OK 0xaa
#define CANx_ERRx_MAX_TIME 1500//所有CAN的错误超过500ms就要告警了
//CPU中对CAN总线故障的细分
typedef enum {
CANx_ERR_NONE,//无故障
CANx_ERR_FILLIN,//填充错误
CANx_ERR_FORMAT,//格式错误
CANx_ERR_ACK,//应答错误
CANx_ERR_BIT_0,//位隐性错误
CANx_ERR_BIT_1,//位显性错误
CANx_ERR_CRC,//CRC错误
CANx_ERR_DEFAULT//软件默认错误
} EM_CANx_ERR_CODE;
typedef struct {
uint16_t Its_LEC[7]; // CAN各种错误状态次数:位填充,格式,确认,隐性,显性,CRC
uint16_t Its_BOF; // CAN离线错误次数
uint16_t Its_EPV;// CAN错误被动次数
uint16_t Its_EWG;// CAN错误警告标志次数
uint16_t Its_TX_MAILBOX_TX_ERR[3];//3个发送邮箱发送错误计数
uint16_t Its_TX_MAILBOX_ARB_ERR[3];//3个发送邮箱仲裁计数
uint16_t Its_RX_FIFOx_OVR[2];//2个接收FIFO上溢出
uint16_t Its_RX_FIFOx_FULL[2];//2个接收FIFO满
uint8_t Its_RX_ERR_FLAG;//CAN接收标志位
uint8_t Its_TX_ERR_FLAG;//CAN发送标志位
} ST_CAN_ERROR;
// 3个CAN故障检测变量定义
ST_CAN_ERROR g_Canx_Error_System[3];
//初始化任意一个CAN总线的故障监测功能
static void CAN_Error_System_Init(uint8_t CANx,CAN_HandleTypeDef* hcan)
{
memset(&g_Canx_Error_System[CANx], 0, sizeof(ST_CAN_ERROR));
g_Canx_Error_System[CANx].Its_RX_ERR_FLAG = CAN_FUNC_OK;
g_Canx_Error_System[CANx].Its_TX_ERR_FLAG = CAN_FUNC_OK;
hcan->Instance->ESR |= CAN_ESR_LEC; //将上次错误号设置为用户状态(程序不会设置该状态)以区分新的状态
}
//查询指定CAN总线的故障状态并记录
static void CAN_Error_Process(uint8_t CANx,CAN_HandleTypeDef* hcan)
{
// uint16_t TEC_VAL = ((hcan->Instance->ESR&CAN_ESR_TEC)>>CAN_ESR_TEC_Pos);
// uint16_t REC_VAL = ((hcan->Instance->ESR&CAN_ESR_REC)>>CAN_ESR_REC_Pos);
g_Canx_Error_System[CANx].Its_RX_ERR_FLAG = CAN_FUNC_OK;
g_Canx_Error_System[CANx].Its_TX_ERR_FLAG = CAN_FUNC_OK;
if (hcan->Instance->ESR) //有故障
{
//上一次错误处理
if ((hcan->Instance->ESR & CAN_ESR_LEC_Msk) != CAN_ESR_LEC) //故障不等于上一次默认故障
{
switch (((hcan->Instance->ESR & CAN_ESR_LEC_Msk) >> CAN_ESR_LEC_Pos))
{
case CANx_ERR_NONE:
{
// 没有故障的时候,清0所有计数器
g_Canx_Error_System[CANx].Its_LEC[CANx_ERR_FILLIN] = 0;
g_Canx_Error_System[CANx].Its_LEC[CANx_ERR_FORMAT] = 0;
g_Canx_Error_System[CANx].Its_LEC[CANx_ERR_ACK] = 0;
g_Canx_Error_System[CANx].Its_LEC[CANx_ERR_BIT_0] = 0;
g_Canx_Error_System[CANx].Its_LEC[CANx_ERR_BIT_1] = 0;
g_Canx_Error_System[CANx].Its_LEC[CANx_ERR_CRC] = 0;
break;
}
case CANx_ERR_DEFAULT:
{
break;
}
case CANx_ERR_FILLIN:
case CANx_ERR_FORMAT:
case CANx_ERR_ACK:
case CANx_ERR_BIT_0:
case CANx_ERR_BIT_1:
case CANx_ERR_CRC:
{
if (g_Canx_Error_System[CANx].Its_LEC[((hcan->Instance->ESR & CAN_ESR_LEC_Msk) >> CAN_ESR_LEC_Pos)] < CANx_ERRx_MAX_TIME)
{
// 对应故障计数++
g_Canx_Error_System[CANx].Its_LEC[((hcan->Instance->ESR & CAN_ESR_LEC_Msk) >> CAN_ESR_LEC_Pos)]++;
}
else
{
//拒绝发送&接收
g_Canx_Error_System[CANx].Its_TX_ERR_FLAG = CAN_FUNC_ERR;
g_Canx_Error_System[CANx].Its_RX_ERR_FLAG = CAN_FUNC_ERR;
}
break;
}
default:
{
break;
}
}
hcan->Instance->ESR |= CAN_ESR_LEC; //将上次错误号设置为用户状态(程序不会设置该状态)以区分新的状态
}
}
//存在离线错误
if (hcan->Instance->ESR & CAN_ESR_BOFF)
{
if (g_Canx_Error_System[CANx].Its_BOF < CANx_ERRx_MAX_TIME)
{
g_Canx_Error_System[CANx].Its_BOF++;
}
else
{
//告警
//拒绝发送&接收
g_Canx_Error_System[CANx].Its_TX_ERR_FLAG = CAN_FUNC_ERR;
g_Canx_Error_System[CANx].Its_RX_ERR_FLAG = CAN_FUNC_ERR;
}
}
else
{
g_Canx_Error_System[CANx].Its_BOF = 0;
}
//存在被动错误
if (hcan->Instance->ESR & CAN_ESR_EPVF)
{
if (g_Canx_Error_System[CANx].Its_EPV < CANx_ERRx_MAX_TIME)
{
g_Canx_Error_System[CANx].Its_EPV++;
}
else
{
//告警
//拒绝发送&接收
g_Canx_Error_System[CANx].Its_TX_ERR_FLAG = CAN_FUNC_ERR;
g_Canx_Error_System[CANx].Its_RX_ERR_FLAG = CAN_FUNC_ERR;
}
}
else
{
g_Canx_Error_System[CANx].Its_EPV = 0;
}
//存在错误警告[小于95就不告警了]
if (hcan->Instance->ESR & CAN_ESR_EWGF)
{
if (g_Canx_Error_System[CANx].Its_EWG < CANx_ERRx_MAX_TIME)
{
g_Canx_Error_System[CANx].Its_EWG++;
}
else
{
//告警
//拒绝发送&接收
g_Canx_Error_System[CANx].Its_TX_ERR_FLAG = CAN_FUNC_ERR;
g_Canx_Error_System[CANx].Its_RX_ERR_FLAG = CAN_FUNC_ERR;
}
}
else
{
g_Canx_Error_System[CANx].Its_EWG = 0;
}
///检测发送邮箱错误
if ((hcan->Instance->TSR & CAN_TSR_TERR0) >> CAN_TSR_TERR0_Pos)// 发送邮箱0
{
if (g_Canx_Error_System[CANx].Its_TX_MAILBOX_TX_ERR[0] < CANx_ERRx_MAX_TIME)
{
g_Canx_Error_System[CANx].Its_TX_MAILBOX_TX_ERR[0]++;
}
else
{
//告警
//拒绝发送
g_Canx_Error_System[CANx].Its_TX_ERR_FLAG = CAN_FUNC_ERR;
}
}
else
{
g_Canx_Error_System[CANx].Its_TX_MAILBOX_TX_ERR[0] = 0;
}
if ((hcan->Instance->TSR & CAN_TSR_TERR1) >> CAN_TSR_TERR1_Pos)// 发送邮箱1
{
if (g_Canx_Error_System[CANx].Its_TX_MAILBOX_TX_ERR[1] < CANx_ERRx_MAX_TIME)
{
g_Canx_Error_System[CANx].Its_TX_MAILBOX_TX_ERR[1]++;
}
else
{
//告警
//拒绝发送
g_Canx_Error_System[CANx].Its_TX_ERR_FLAG = CAN_FUNC_ERR;
}
}
else
{
g_Canx_Error_System[CANx].Its_TX_MAILBOX_TX_ERR[1] = 0;
}
if ((hcan->Instance->TSR & CAN_TSR_TERR2) >> CAN_TSR_TERR2_Pos)// 发送邮箱2
{
if (g_Canx_Error_System[CANx].Its_TX_MAILBOX_TX_ERR[2] < CANx_ERRx_MAX_TIME)
{
g_Canx_Error_System[CANx].Its_TX_MAILBOX_TX_ERR[2]++;
}
else
{
//告警
//拒绝发送
g_Canx_Error_System[CANx].Its_TX_ERR_FLAG = CAN_FUNC_ERR;
}
}
else
{
g_Canx_Error_System[CANx].Its_TX_MAILBOX_TX_ERR[2] = 0;
}
/
///检测发送邮箱仲裁错误
if ((hcan->Instance->TSR & CAN_TSR_ALST0) >> CAN_TSR_ALST0_Pos)// 发送邮箱0
{
if (g_Canx_Error_System[CANx].Its_TX_MAILBOX_ARB_ERR[0] < CANx_ERRx_MAX_TIME)
{
g_Canx_Error_System[CANx].Its_TX_MAILBOX_ARB_ERR[0]++;
}
else
{
//告警
//拒绝发送
g_Canx_Error_System[CANx].Its_TX_ERR_FLAG = CAN_FUNC_ERR;
}
}
else
{
g_Canx_Error_System[CANx].Its_TX_MAILBOX_ARB_ERR[0] = 0;
}
if ((hcan->Instance->TSR & CAN_TSR_ALST1) >> CAN_TSR_ALST1_Pos)// 发送邮箱1
{
if (g_Canx_Error_System[CANx].Its_TX_MAILBOX_ARB_ERR[1] < CANx_ERRx_MAX_TIME)
{
g_Canx_Error_System[CANx].Its_TX_MAILBOX_ARB_ERR[1]++;
}
else
{
//告警
//拒绝发送
g_Canx_Error_System[CANx].Its_TX_ERR_FLAG = CAN_FUNC_ERR;
}
}
else
{
g_Canx_Error_System[CANx].Its_TX_MAILBOX_ARB_ERR[1] = 0;
}
if ((hcan->Instance->TSR & CAN_TSR_ALST2) >> CAN_TSR_ALST2_Pos)// 发送邮箱2
{
if (g_Canx_Error_System[CANx].Its_TX_MAILBOX_ARB_ERR[2] < CANx_ERRx_MAX_TIME)
{
g_Canx_Error_System[CANx].Its_TX_MAILBOX_ARB_ERR[2]++;
}
else
{
//告警
//拒绝发送
g_Canx_Error_System[CANx].Its_TX_ERR_FLAG = CAN_FUNC_ERR;
}
}
else
{
g_Canx_Error_System[CANx].Its_TX_MAILBOX_ARB_ERR[2] = 0;
}
/
//检测接收FIFOx上溢出
if ((hcan->Instance->RF0R & CAN_RF0R_FOVR0) >> CAN_RF0R_FOVR0_Pos)// 接收FIFO0
{
if (g_Canx_Error_System[CANx].Its_RX_FIFOx_OVR[0] < CANx_ERRx_MAX_TIME)
{
g_Canx_Error_System[CANx].Its_RX_FIFOx_OVR[0]++;
}
else
{
//告警
//拒绝接收
g_Canx_Error_System[CANx].Its_RX_ERR_FLAG = CAN_FUNC_ERR;
}
}
else
{
g_Canx_Error_System[CANx].Its_RX_FIFOx_OVR[0] = 0;
}
if ((hcan->Instance->RF1R & CAN_RF1R_FOVR1) >> CAN_RF1R_FOVR1_Pos)// 接收FIFO1
{
if (g_Canx_Error_System[CANx].Its_RX_FIFOx_OVR[1] < CANx_ERRx_MAX_TIME)
{
g_Canx_Error_System[CANx].Its_RX_FIFOx_OVR[1]++;
}
else
{
//告警
//拒绝接收
g_Canx_Error_System[CANx].Its_RX_ERR_FLAG = CAN_FUNC_ERR;
}
}
else
{
g_Canx_Error_System[CANx].Its_RX_FIFOx_OVR[1] = 0;
}
/
///检测接收邮箱满
if ((hcan->Instance->RF0R & CAN_RF0R_FULL0) >> CAN_RF0R_FULL0_Pos)// 接收FIFO0
{
if (g_Canx_Error_System[CANx].Its_RX_FIFOx_FULL[0] < CANx_ERRx_MAX_TIME)
{
g_Canx_Error_System[CANx].Its_RX_FIFOx_FULL[0]++;
}
else
{
//告警
//拒绝接收
g_Canx_Error_System[CANx].Its_RX_ERR_FLAG = CAN_FUNC_ERR;
}
}
else
{
g_Canx_Error_System[CANx].Its_RX_FIFOx_FULL[0] = 0;
}
if ((hcan->Instance->RF1R & CAN_RF1R_FULL1) >> CAN_RF1R_FULL1_Pos)// 接收FIFO1
{
if (g_Canx_Error_System[CANx].Its_RX_FIFOx_FULL[1] < CANx_ERRx_MAX_TIME)
{
g_Canx_Error_System[CANx].Its_RX_FIFOx_FULL[1]++;
}
else
{
//告警
//拒绝接收
g_Canx_Error_System[CANx].Its_RX_ERR_FLAG = CAN_FUNC_ERR;
}
}
else
{
g_Canx_Error_System[CANx].Its_RX_FIFOx_FULL[1] = 0;
}
/
hcan->Instance->MSR = CAN_MSR_ERRI; //清除错误中断
}