本例程使用的是快恢复,一旦发生canbusoff后立刻重新初始化can。
ac7811官方例程中写的比较全面,有快恢复和慢恢复,可参考。
typedef struct
{
unsigned char Data[8];
unsigned long int ID;
unsigned char DataLength;
}MCU_CAN_MSG;
//做个循环队列
#define CANBuffMaxLength 8 //CAN接收队列长度
MCU_CAN_MSG g_MCU_CAN_RXBuff[CANBuffMaxLength];
uint8_t g_MCU_CAN_RXFull = 0; //0-CAN接收队列未满 1-CAN接收队列已满
uint8_t g_MCU_CAN_RXFront = 0; //接收缓冲区队头
uint8_t g_MCU_CAN_RXRear = 0; //接收缓冲区队尾
/**
* 描述 CAN帧出队
* 输入 CAN帧数据地址
* 返回 1 正常
* 0 队列无数据
*/
uint8_t CAN_Receive(MCU_CAN_MSG *data)
{
if ((g_MCU_CAN_RXFull == 0) && (g_MCU_CAN_RXRear == g_MCU_CAN_RXFront))
{
return 0;//队列已空,没有数据
}
*data = g_MCU_CAN_RXBuff[g_MCU_CAN_RXFront];//数据出列队
g_MCU_CAN_RXFront++;
if (g_MCU_CAN_RXFront >= CANBuffMaxLength)
{
g_MCU_CAN_RXFront = 0;
}
g_MCU_CAN_RXFull = 0; //队列未满
return 1;
}
/**
* 描述 CAN帧入队
* 输入 CAN帧数据
* 返回 1 正常
* 0 队列已满
*/
uint8_t CAN_AddRxData(MCU_CAN_MSG data)
{
if (g_MCU_CAN_RXFull == 1)
{
return 0; //队列已满
}
g_MCU_CAN_RXBuff[g_MCU_CAN_RXRear] = data; //数据入队列
g_MCU_CAN_RXRear++;
if (g_MCU_CAN_RXRear >= CANBuffMaxLength)
{
g_MCU_CAN_RXRear = 0;
}
if (g_MCU_CAN_RXRear == g_MCU_CAN_RXFront)
{
g_MCU_CAN_RXFull = 1; //队列满
}
return 1;
}
/**
* @prototype CAN1_IRQnCallBack(uint32_t event, uint32_t wparam, uint32_t lparam)
*
* @param[in] ...
* @return ...
*
* @brief CAN1 module interrupt handler.
* CAN1中断处理函数.
*/
int32_t CAN1_IRQnCallBack(uint32_t event, uint32_t wparam, uint32_t lparam)
{
MCU_CAN_MSG CAN_RxData;
if (event & CAN_EVENT_BUSERROR) /* 发生错误后,打印错误消息,仅用于调试 */
{
// printf("CAN[%d]e: wparam: %x lparam: %x\r\n", event, wparam, lparam);
}
if (event & CAN_EVENT_RECVMSG)
{
if(CAN_IsMsgInReceiveBuf((CAN_Type*)lparam))
{
CAN_MessageRead((CAN_Type*)lparam, &g_recvCANMsgInfo);
if((g_recvCANMsgInfo.ID == 0x200)
||(g_recvCANMsgInfo.ID == 0x201)
||(g_recvCANMsgInfo.ID == 0x202)
||(g_recvCANMsgInfo.ID == 0x18aabbcc))
{
CAN_RxData.ID = g_recvCANMsgInfo.ID;
CAN_RxData.DataLength = g_recvCANMsgInfo.DLC;
memcpy(CAN_RxData.Data, &g_recvCANMsgInfo.Data[0], 8);
CAN_AddRxData(CAN_RxData); //软件层实现can队列
}
}
}
else if (event & CAN_EVENT_ERROR)
{
if (CAN1->BIT.BUSOFF & 0x01)//BUS OFF
{
CAN1_Config();//快恢复,重新初始化can1
}
}
return 1;
}
void CAN1_Config(void)
{
CAN_Config canConfig = {0};
CAN_BaudrateConfig canBandrateConfig = {0};
GPIO_SetFunc(CAN1_TX, GPIO_FUNC_2);//设置CAN1引脚复用功能
GPIO_SetFunc(CAN1_RX, GPIO_FUNC_2);
// GPIO_SetDir(GPIO_PD5, GPIO_OUTPUT);//设置CAN1收发器控制为IO控制 有的项目需要,根据自己实际情况来
// do{GPIO_ResetPinBits(GPIO_PD5);}while(0);
/*
设置波特率为500K,采样点为81.25%.
tSeg1 = (S_SEG_1 + 2); tSeg2 = (S_SEG_2 + 1).
BandRate = (48M / (S_PRESC + 1) / ((S_SEG_1 + 2) + (S_SEG_2 + 1)))
SamplePoint = (tSeg1 / (tSeg1 + tSeg2)).
在已经知道波特率与采样点的情况下,经过计算后:tSeg1 = 13,tSeg2 = 3.
*/
canBandrateConfig.S_PRESC = 5;//分频后时钟为8M.
canBandrateConfig.S_SEG_1 = 11;
canBandrateConfig.S_SEG_2 = 2;
canBandrateConfig.S_SJW = 2;//满足S_SJW <= tSeg2即可.
/*
16个过滤器中,可随意选择使用哪个,并制定其过滤模式,制定其过滤ID的类型.
如果一个过滤器只需要接收一个ID,直接可将其设置CODE模式,然后根据ID类型设置过滤类型.
如果一个过滤器需要接收多个ID,将其设置为MASK模式,并根据这几个ID的实际类型设置过滤ID类型,如果既有STD又有EXT,则应选择FILTER_IDE_STD_EXT_BOTH.
此处加宏是为了更清楚的说明各种设置是否有效,在实际应用中,可将各种组合放在一起使用.
*/
CAN_SetFilterParam(0, 1, CAN_FILTER_CODE_MODE, FILTER_IDE_STD_ONLY,0x200);//使用CODE模式只接收STD帧
CAN_SetFilterParam(1, 1, CAN_FILTER_CODE_MODE, FILTER_IDE_STD_ONLY, 0x201);//使用CODE模式只接收STD帧
CAN_SetFilterParam(2, 1, CAN_FILTER_CODE_MODE, FILTER_IDE_STD_ONLY, 0x202);//使用CODE模式只接收STD帧
CAN_SetFilterParam(3, 1, CAN_FILTER_CODE_MODE, FILTER_IDE_EXT_ONLY, 0x18aabbcc);//使用CODE模式只接收EXT帧
canConfig.interruptEnable = TRUE;//使能中断
canConfig.canMode = CAN_MODE_NORMAL;
canConfig.autoReset = FALSE;//禁止自动复位,自动恢复正常.....................注意此处
canConfig.filterList = g_canFilterTab;//赋值过滤器设置list
CAN_SetEventCallBack(CAN1, CAN1_IRQnCallBack);
CAN_Initialize(CAN1, &canConfig, &canBandrateConfig);
}
CAN_FilterControl g_canFilterTab[CAN_MAX_FILTER_NUM] =
{
{ 0, 0, 0x00000000, 0x00000000},
{ 1, 0, 0x00000000, 0x00000000},
{ 2, 0, 0x00000000, 0x00000000},
{ 3, 0, 0x00000000, 0x00000000},
{ 4, 0, 0x00000000, 0x00000000},
{ 5, 0, 0x00000000, 0x00000000},
{ 6, 0, 0x00000000, 0x00000000},
{ 7, 0, 0x00000000, 0x00000000},
{ 8, 0, 0x00000000, 0x00000000},
{ 9, 0, 0x00000000, 0x00000000},
{10, 0, 0x00000000, 0x00000000},
{11, 0, 0x00000000, 0x00000000},
{12, 0, 0x00000000, 0x00000000},
{13, 0, 0x00000000, 0x00000000},
{14, 0, 0x00000000, 0x00000000},
{15, 0, 0x00000000, 0x00000000},
};
uint32_t g_canFilterMask[3] = {0x5FFFFFFF, 0x7FFFFFFF, 0x1FFFFFFF};//只接收标准帧 只接收扩展帧 接收两种数据帧
/**
* @prototype CAN_SetFilterParam(uint8_t filterNum, uint8_t filterEn, CAN_FilterMode_TypeDef filterMode, CAN_FilterMask_TypeDef filterMask, uint32_t ID)
*
* @param[in] filterNum:过滤器编码,0到15可用.
* @param[in] filterEn:过滤器使能状态,1使能,0禁能
* @param[in] filterMode:CAN_FilterMode_TypeDef已定义.
* @param[in] filterMask:参考CAN_FilterMask_TypeDef.
* @param[in] ID
* @return void
*
* @brief Initalize CAN filter.
* 初始化CAN过滤器,当filterMode选择FILTER_CODE_MODE时,每个过滤器过滤一个ID,否则,使用MASK模式,过滤的多个ID的组合.
*/
void CAN_SetFilterParam(uint8_t filterNum, uint8_t filterEn, CAN_FilterMode_TypeDef filterMode, CAN_FilterMask_TypeDef filterMask, uint32_t ID)
{
g_canFilterTab[filterNum].enable = filterEn;
g_canFilterTab[filterNum].code = ID;
if (filterMode == CAN_FILTER_MASK_MODE)
{
g_canFilterTab[filterNum].mask = (g_canFilterMask[filterMask] & ~ID);//进行掩码屏蔽
}
else
{
g_canFilterTab[filterNum].mask = (g_canFilterMask[filterMask] & CAN_CLEAR_ALL_ID_BIT);//进行ID屏蔽,就是ID必须与设置的ID一模一样,才接收
}
}
/*****进行can报文处理***/
while(0x1 == CAN_Receive(&receive1_msg))//can1 标准帧和扩展帧
{
can1_receive_ID = receive1_msg.ID;
can1_rx_data[0] = receive1_msg.Data[0];
can1_rx_data[1] = receive1_msg.Data[1];
can1_rx_data[2] = receive1_msg.Data[2];
can1_rx_data[3] = receive1_msg.Data[3];
can1_rx_data[4] = receive1_msg.Data[4];
can1_rx_data[5] = receive1_msg.Data[5];
can1_rx_data[6] = receive1_msg.Data[6];
can1_rx_data[7] = receive1_msg.Data[7];
if(can1_receive_ID == 0x200)
{
}