STM32 CAN 配置
- 使用工具:CubeMX
- 硬件:STM32F105RBT6
- CAN2作为CAN1的从站,CAN1复位是否会影响CAN2?
- CAN总线关闭之后一定要自主恢复,自动脱离Bus-off状态,重复启动
- CAN总线错误分析
文章图片
2.配置CAN接收中断
文章图片
3.配置GPIO
文章图片
2.STM32CAN驱动程序 1.CAN1初始化
- can1筛选器使用0组,CAN2筛选器使用14组
- SlaveStartFilterBank从站使用筛选器组,CAN1->FMR.CAN2SB=14
/**
* @brief CAN1初始化
*/
void CAN1_Init(void)
{
CAN_FilterTypeDef sFilterConfig;
/*##-1- Configure the CAN peripheral #######################################*/
hcan1.Instance = CAN1;
/*< 预分频系数 */
hcan1.Init.Prescaler = 9;
/*< CAN工作模式 CAN_MODE_NORMAL:正常模式 CAN_MODE_LOOPBACK:回环模式
CAN_MODE_SILENT:静默模式 CAN_MODE_SILENT_LOOPBACK:静默回环模式*/
hcan1.Init.Mode = CAN_MODE_NORMAL;
/*< 同步时间 */
hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
/*< 相位缓冲段1 */
hcan1.Init.TimeSeg1 = CAN_BS1_5TQ;
/*< 相位缓冲段2 */
hcan1.Init.TimeSeg2 = CAN_BS2_2TQ;
/*< 时间触发通信模式 DISABLE:禁止时间触发通信模式 ENABLE:使能时间触发通信模式*/
hcan1.Init.TimeTriggeredMode = DISABLE;
/*< 自动的总线关闭管理 此位控制 CAN 硬件在退出总线关闭状态时的行为
DISABLE: 在软件发出请求后,一旦监测到 128 次连续 11 个隐性位,
并且软件将 CAN_MCR 寄存器的 INRQ 位先置 1 再清零,即退出总线关闭状态
ENABLE: 一旦监测到 128 次连续 11 个隐性位,即通过硬件自动退出总线关闭状态 */
hcan1.Init.AutoBusOff = ENABLE;
/*< 自动唤醒模式 此位控制 CAN 硬件在睡眠模式下接收到消息时的行为
DISABLE: 在软件通过将 CAN_MCR 寄存器的 SLEEP 位清零发出请求后,退出睡眠模式
ENABLE: 一旦监测到 CAN 消息,即通过硬件自动退出睡眠模式 */
hcan1.Init.AutoWakeUp = DISABLE;
/*< 自动重发送
DISABLE: 无论发送结果如何(成功、错误或仲裁丢失),消息均只发送一次
ENABLE: CAN 硬件将自动重发送消息,直到根据 CAN 标准消息发送成功 */
hcan1.Init.AutoRetransmission = DISABLE;
/*< 接收 FIFO 锁定模式
DISABLE: 接收 FIFO 上溢后不锁定。接收 FIFO 装满后,下一条传入消息将覆盖前一条消息
ENABLE: 接收 FIFO 上溢后锁定。接收 FIFO 装满后,下一条传入消息将被丢弃*/
hcan1.Init.ReceiveFifoLocked = DISABLE;
/*< 发送 FIFO 优先级
DISABLE: 优先级由消息标识符确定
ENABLE: 优先级由请求顺序(时间顺序)确定*/
hcan1.Init.TransmitFifoPriority = ENABLE;
if (HAL_CAN_Init(&hcan1) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}/*##-2- Configure the CAN Filter ###########################################*/
/*CAN1 CAN2共用筛选器组 CAN1使用0-13,CAN2使用14-27*/
/*< 使用的筛选器组 当前使用筛选器组为0,后续全部为配置此筛选器使用 */
sFilterConfig.FilterBank = 0;
/*< CAN_FILTERMODE_IDMASK 掩码模式 CAN_FILTERMODE_IDLIST 列表模式
掩码模式: 在掩码模式下,标识符寄存器与掩码寄存器关联,用以指示标识符的哪些位“必须匹配”,哪些位“无关”
列表模式: 在标识符列表模式下,掩码寄存器用作标识符寄存器。这时,不会定义一个标识符和一个掩码,而是指定两个标识符,
从而使单个标识符的数量加倍。传入标识符的所有位都必须与筛选器寄存器中指定的位匹配。*/
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
/*< 筛选器宽度为32位或16位 */
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
/* 掩码模式下,ID码会先与掩码寄存器相与,再判断与标识符寄存器是否相同
(ExtId || StdId)== FltMaskId & FltMask ?
列表模式下,掩码寄存器作为标识符寄存器,此时传入标识符所有为都必须要和筛选器寄存器中指定的位匹配
((ExtId || StdId) == (FltMask || FltMaskId) ? */
/*< 筛选器组 标识符寄存器 */
sFilterConfig.FilterIdHigh = 0x0000;
sFilterConfig.FilterIdLow = 0x0000;
/*< 筛选器组 掩码寄存器 */
sFilterConfig.FilterMaskIdHigh = 0x0000;
sFilterConfig.FilterMaskIdLow = 0x0000;
/*< 将通过筛选的消息存储在FIFO0或FIFO1 */
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
/*< 激活筛选器 CAN_FILTER_ENABLE 使能;
CAN_FILTER_DISABLE 关闭 */
sFilterConfig.FilterActivation = CAN_FILTER_ENABLE;
/*< 选择CAN2从实例的开始过滤器号 CAN2SB 复位值为14 */
sFilterConfig.SlaveStartFilterBank = 14;
if (HAL_CAN_ConfigFilter(&hcan1,&sFilterConfig) != HAL_OK)
{
/* Filter configuration Error */
Error_Handler();
}/*##-3- Start the CAN peripheral ###########################################*/
if (HAL_CAN_Start(&hcan1) != HAL_OK)
{
/* Start Error */
Error_Handler();
}/*##-4- Activate CAN RX notification #######################################*/
if (HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
{
/* Notification Error */
Error_Handler();
}/*##-5- Activate CAN BUSOFF notification ###################################*/
if (HAL_CAN_ActivateNotification(&hcan1, CAN_IT_BUSOFF) != HAL_OK)
{
/* Notification Error */
Error_Handler();
}
}
2.CAN2初始化
- CAN2为CAN1的从机
/**
* @brief CAN2初始化
*/
void CAN2_Init(void)
{
CAN_FilterTypeDef sFilterConfig;
/*##-1- Configure the CAN peripheral #######################################*/
hcan2.Instance = CAN2;
/*< 预分频系数 */
hcan2.Init.Prescaler = 9;
/*< CAN工作模式 CAN_MODE_NORMAL:正常模式 CAN_MODE_LOOPBACK:回环模式 CAN_MODE_SILENT:静默模式 CAN_MODE_SILENT_LOOPBACK:静默回环模式*/
hcan2.Init.Mode = CAN_MODE_NORMAL;
/*< 同步时间 */
hcan2.Init.SyncJumpWidth = CAN_SJW_1TQ;
/*< 相位缓冲段1 */
hcan2.Init.TimeSeg1 = CAN_BS1_5TQ;
/*< 相位缓冲段2 */
hcan2.Init.TimeSeg2 = CAN_BS2_2TQ;
/*< 时间触发通信模式 DISABLE:禁止时间触发通信模式 ENABLE:使能时间触发通信模式*/
hcan2.Init.TimeTriggeredMode = DISABLE;
/*< 自动的总线关闭管理 此位控制 CAN 硬件在退出总线关闭状态时的行为
DISABLE: 在软件发出请求后,一旦监测到 128 次连续 11 个隐性位,
并且软件将 CAN_MCR 寄存器的 INRQ 位先置 1 再清零,即退出总线关闭状态
ENABLE: 一旦监测到 128 次连续 11 个隐性位,即通过硬件自动退出总线关闭状态 */
hcan2.Init.AutoBusOff = ENABLE;
/*< 自动唤醒模式 此位控制 CAN 硬件在睡眠模式下接收到消息时的行为
DISABLE: 在软件通过将 CAN_MCR 寄存器的 SLEEP 位清零发出请求后,退出睡眠模式
ENABLE: 一旦监测到 CAN 消息,即通过硬件自动退出睡眠模式 */
hcan2.Init.AutoWakeUp = DISABLE;
/*< 自动重发送
DISABLE: 无论发送结果如何(成功、错误或仲裁丢失),消息均只发送一次
ENABLE: CAN 硬件将自动重发送消息,直到根据 CAN 标准消息发送成功 */
hcan2.Init.AutoRetransmission = DISABLE;
/*< 接收 FIFO 锁定模式
DISABLE: 接收 FIFO 上溢后不锁定。接收 FIFO 装满后,下一条传入消息将覆盖前一条消息
ENABLE: 接收 FIFO 上溢后锁定。接收 FIFO 装满后,下一条传入消息将被丢弃*/
hcan2.Init.ReceiveFifoLocked = DISABLE;
/*< 发送 FIFO 优先级
DISABLE: 优先级由消息标识符确定
ENABLE: 优先级由请求顺序(时间顺序)确定*/
hcan2.Init.TransmitFifoPriority = ENABLE;
if (HAL_CAN_Init(&hcan2) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}/*##-2- Configure the CAN Filter ###########################################*/
/*CAN1 CAN2共用筛选器组 CAN1使用0-13,CAN2使用14-27*/
/*< 使用的筛选器组 当前使用筛选器组为0,后续全部为配置此筛选器使用 */
sFilterConfig.FilterBank = 14;
/*< CAN_FILTERMODE_IDMASK 掩码模式 CAN_FILTERMODE_IDLIST 列表模式
掩码模式: 在掩码模式下,标识符寄存器与掩码寄存器关联,用以指示标识符的哪些位“必须匹配”,哪些位“无关”
列表模式: 在标识符列表模式下,掩码寄存器用作标识符寄存器。这时,不会定义一个标识符和一个掩码,而是指定两个标识符,
从而使单个标识符的数量加倍。传入标识符的所有位都必须与筛选器寄存器中指定的位匹配。*/
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
/*< 筛选器宽度为32位或16位 */
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
/* 掩码模式下,ID码会先与掩码寄存器相与,再判断与标识符寄存器是否相同
(ExtId || StdId)== FltMaskId & FltMask ?
列表模式下,掩码寄存器作为标识符寄存器,此时传入标识符所有为都必须要和筛选器寄存器中指定的位匹配
((ExtId || StdId) == (FltMask || FltMaskId) ? */
/*< 筛选器组 标识符寄存器 */
sFilterConfig.FilterIdHigh = 0x0000;
sFilterConfig.FilterIdLow = 0x0000;
/*< 筛选器组 掩码寄存器 */
sFilterConfig.FilterMaskIdHigh = 0x0000;
sFilterConfig.FilterMaskIdLow = 0x0000;
/*< 将通过筛选的消息存储在FIFO0或FIFO1 */
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
/*< 激活筛选器 CAN_FILTER_ENABLE 使能;
CAN_FILTER_DISABLE 关闭 */
sFilterConfig.FilterActivation = CAN_FILTER_ENABLE;
/*< 选择CAN2从实例的开始过滤器号 CAN2SB 复位值为14 */
sFilterConfig.SlaveStartFilterBank = 14;
if (HAL_CAN_ConfigFilter(&hcan2,&sFilterConfig) != HAL_OK)
{
/* Filter configuration Error */
Error_Handler();
}/*##-3- Start the CAN peripheral ###########################################*/
if (HAL_CAN_Start(&hcan2) != HAL_OK)
{
/* Start Error */
Error_Handler();
}/*##-4- Activate CAN RX notification #######################################*/
if (HAL_CAN_ActivateNotification(&hcan2, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
{
/* Notification Error */
Error_Handler();
}/*##-5- Activate CAN BUSOFF notification ###################################*/
if (HAL_CAN_ActivateNotification(&hcan2, CAN_IT_BUSOFF) != HAL_OK)
{
/* Notification Error */
Error_Handler();
}
}
3.CAN1/CAN2发送
typedef struct tagCANMESSAGE
{
CAN_TxHeaderTypeDef TxHeader;
uint8_t TxData[8];
uint32_t TxMailBox;
CAN_RxHeaderTypeDef RxHeader;
uint8_t RxData[8];
uint32_t RxMailBox;
}CANMESSAGE;
CANMESSAGE CAN_Message,CAN2_Message;
/**
* @brief CAN1发送
*/
void CAN1_Transmit(void)
{
uint8_t i;
CAN_Message.TxHeader.DLC = 8;
CAN_Message.TxHeader.RTR = CAN_RTR_DATA;
CAN_Message.TxHeader.IDE = CAN_ID_STD;
CAN_Message.TxHeader.StdId = 0x601;
for(i=0;
i<8;
i++)
{
CAN_Message.TxData[i] = i+1;
}HAL_CAN_AddTxMessage(&hcan1,&CAN_Message.TxHeader, CAN_Message.TxData, &CAN_Message.TxMailBox);
}/**
* @brief CAN2发送
*/
void CAN2_Transmit(void)
{
uint8_t i;
CAN2_Message.TxHeader.DLC = 8;
CAN2_Message.TxHeader.RTR = CAN_RTR_DATA;
CAN2_Message.TxHeader.IDE = CAN_ID_STD;
CAN2_Message.TxHeader.StdId = 0x601;
for(i=0;
i<8;
i++)
{
CAN2_Message.TxData[i] = i+1;
}HAL_CAN_AddTxMessage(&hcan2,&CAN2_Message.TxHeader, CAN2_Message.TxData, &CAN2_Message.TxMailBox);
}
3.CAN RXFIFO0接收处理回调函数
/**
* @brief RX FIFO0接收处理回调函数
*/
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
if(hcan->Instance==CAN1)
{
HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &CAN_Message.RxHeader, CAN_Message.RxData);
}
else if(hcan->Instance==CAN2)
{
HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &CAN2_Message.RxHeader, CAN2_Message.RxData);
}
else
{
;
}
}
4.错误异常回调函数
/**
* @brief 错误异常 接收处理回调函数
*/
void HAL_CAN_ErrorCallback(CAN_HandleTypeDef *hcan)
{
if(hcan->Instance==CAN1)
{
HAL_CAN_Stop(hcan);
CAN1_Init();
}
else if(hcan->Instance==CAN2)
{
HAL_CAN_Stop(hcan);
CAN2_Init();
}
else
{
;
}
}
3.CAN Bus LEC 错误管理
如 CAN 协议所述,错误管理完全由硬件通过发送错误计数器(CAN_ESR 寄存器中的 TEC 值)和接收错误计数器(CAN_ESR 寄存器中的 REC 值)来处理,这两个计数器根据错误 状况进行递增或递减。有关 TEC 和 REC 管理的详细信息,请参见 CAN 标准。
两者均可由软件读取,用以确定网络的稳定性。此外,CAN 硬件还将在 CAN_ESR 寄存器中 提供当前错误状态的详细信息。通过 CAN_IER 寄存器(ERRIE 位等),软件可以非常灵活 地配置在检测到错误时生成的中断。
总线关闭恢复
当 TEC 大于 255 时,达到总线关闭状态,该状态由 CAN_ESR 寄存器的 BOFF 位指示。在 总线关闭状态下,bxCAN 不能再发送和接收消息。
bxCAN 可以自动或者应软件请求而从总线关闭状态中恢复(恢复错误主动状态),具体取 决于 CAN_MCR 寄存器的 ABOM 位。但在两种情况下,bxCAN 都必须至少等待 CAN 标准 中指定的恢复序列完成(在 CANRX 上监测到 128 次 11 个连续隐性位)。
如果 ABOM 位置 1,bxCAN 将在进入总线关闭状态后自动启动恢复序列。
如果 ABOM 位清零,则软件必须请求 bxCAN 先进入再退出初始化模式,从而启动恢复序列。
注意:在初始化模式下,bxCAN 不会监视 CANRX 信号,因此无法完成恢复序列。要进行恢复, bxCAN 必须处于正常模式。
文章图片
LEC[2:0]:上一个错误代码 (Last error code)
该字段由硬件置 1,其中的代码指示 CAN 总线上检测到的上一个错误的错误状况。如果消息
成功传送(接收或发送)且未发生错误,该字段将清为“0”。
LEC[2:0] 位可由软件置为 0b111 值。这些位由硬件更新,以指示当前通信状态。
000:无错误
001:填充错误
010:格式错误
011:确认错误
100:位隐性错误
101:位显性错误
110:CRC 错误
111:由软件置 1
【STM32 CAN配置】主动发送错误ACK错误TEC最多到128,如未接入CAN总线发送就会出现这种情况