STM32 CAN配置

STM32 CAN 配置

  • 使用工具:CubeMX
  • 硬件:STM32F105RBT6
1.概述 STM32F105x双can,CAN1为主,CAN2为从,使用CAN2必须使能CAN1的时钟,CAN1/CAN2使用共同的筛选器,总计28组。
  • CAN2作为CAN1的从站,CAN1复位是否会影响CAN2?
  • CAN总线关闭之后一定要自主恢复,自动脱离Bus-off状态,重复启动
  • CAN总线错误分析
2.CubeMX配置 1.配置CAN1为500K
STM32 CAN配置
文章图片

2.配置CAN接收中断
STM32 CAN配置
文章图片

3.配置GPIO
STM32 CAN配置
文章图片

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 必须处于正常模式。
STM32 CAN配置
文章图片

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总线发送就会出现这种情况

    推荐阅读