CAN 是 Controller Area Network 的缩写(以下称为 CAN),是 ISO 国际标准化的串行通信
协议。异步半双工。
ISO11898:123kbps~1Mbps。
ISO11519:125kbps
特点:
帮助记忆:显“0”。多点线与机制,一个是0全是0,所有1才为1。类似于上拉。
差分信号:抗干扰,双绞线(相互抵消电磁干扰),电压差值不变。
1bit,显性电平。
1位,分为4个段,每个段分为若干个Tq。
当同样的电平持续 5 位时则添加一个位的反型数据。
发送单元的工作:
在发送数据帧和遥控帧时,SOF~CRC 段间的数据,相同电平如果持续 5 位,在下一个位(第 6 个位)则要插入 1 位与前 5 位反型的电平。
接收单元的工作:
在接收数据帧和遥控帧时,SOF~CRC 段间的数据,相同电平如果持续 5 位,需要删除下一个位(第 6 个位)再接收。如果这个第 6 个位的电平与前 5 位相同,将被视为错误并发送错误帧。
硬件同步(帧起始同步);
再同步(发慢收快,延长相位缓冲段1;发快收慢,缩短相缓2)。
同步规则:
STM32F1 自带的是 bxCAN,即基本扩展 CAN。它支持 CAN 协议 2.0A 和 2.0B。 CAN2.0A
只能处理标准数据帧,扩展帧的内容会识别错误; CAN2.0B Active 可以处理标准数据帧和扩展
数据帧;而 CAN2.0B passive 只能处理标准数据帧,扩展帧的内容会忽略。 它的设计目标是,
以最小的 CPU 负荷来高效处理大量收到的报文。它也支持报文发送的优先级要求(优先级特性
可软件配置)。
为了过滤出一组标识符,应该设置过滤器组工作在屏蔽位模式。
为了过滤出一个标识符,应该设置过滤器组工作在标识符列表模式。应用程序不用的过滤器组,应该保持在禁用状态。
优先级:32位>16位,标识符列表>屏蔽位,过滤号小的优先级高。
举例说明:过滤器组0工作在:1个32位过滤器-标识符屏蔽模式,CAN_F0R1=0XFFFF0000,CAN_F0R2=0XFF00FF00,
程序选择 1 个空置的邮箱(TME=1) →设置标识符(ID),数据长度和发送数据→设置 CAN_TIxR 的 TXRQ 位为 1,请求发送→邮箱挂号(等待成为最高优先级) →预定发送(等待总线空闲) →发送→邮箱空置。
FIFO 空→收到有效报文→挂号_1(存入 FIFO 的一个邮箱,这个由硬件控制,我们不需要理会) →收到有效报文→挂号_2→收到有效报文→挂号_3→收到有效报文溢出。
通过查询 CAN_RFxR 的 FMP 寄存器来得到,只要 FMP不为 0,我们就可以从 FIFO 读出收到的报文。
- HAL_StatusTypeDef HAL_CAN_Init(CAN_HandleTypeDef *hcan);
-
-
- typedef struct __CAN_HandleTypeDef
- {
- CAN_TypeDef *Instance; /* CAN 控制寄存器基地址 */
- CAN_InitTypeDef Init; /* 初始化参数结构体 */
- __IO HAL_CAN_StateTypeDef State; /* CAN 通讯状态 */
- __IO uint32_t ErrorCode; /* CAN 通讯结果编码 */
- } CAN_HandleTypeDef;
-
- typedef struct
- {
- uint32_t Prescaler; /* 分频值, 可以配置为 1~1024 间的任意整数 */
- uint32_t Mode; /* can 操作模式,有效值参考 CAN_operating_mode 的描述 */
- uint32_t SyncJumpWidth; /* CAN 硬件的最大超时时间 */
- uint32_t TimeSeg1; /* CAN_time_quantum_in_bit_segment_1 */
- uint32_t TimeSeg2; /* CAN_time_quantum_in_bit_segment_2 */
- FunctionalState TimeTriggeredMode; /* 启用或禁用时间触发模式 */
- FunctionalState AutoBusOff; /* 禁止/使能软件自动断开总线的功能 */
- FunctionalState AutoWakeUp; /* 禁止/使能 CAN 的自动唤醒功能 */
- FunctionalState AutoRetransmission; /* 禁止/使能 CAN 的自动传输模式 */
- FunctionalState ReceiveFifoLocked; /* 禁止/使能 CAN 的接收 FIFO */
- FunctionalState TransmitFifoPriority; /* 禁止/使能 CAN 的发送 FIFO */
- } CAN_InitTypeDef;
- HAL_StatusTypeDef HAL_CAN_ConfigFilter(CAN_HandleTypeDef *hcan,
- CAN_FilterTypeDef *sFilterConfig)
-
- typedef struct
- {
- uint32_t FilterIdHigh; /* 过滤器标识符高位 */
- uint32_t FilterIdLow; /* 过滤器标识符低位 */
- uint32_t FilterMaskIdHigh; /* 过滤器掩码号高位(列表模式下,也是属于标识符) */
- uint32_t FilterMaskIdLow; /* 过滤器掩码号低位(列表模式下,也是属于标识符) */
- uint32_t FilterFIFOAssignment; /* 与过滤器组管理的 FIFO */
- uint32_t FilterBank; /* 指定过滤器组, 单 CAN 为 0~13, 双 CAN 可为 0~27 */
- uint32_t FilterMode; /* 过滤器的模式 标识符屏蔽位模式/标识符列表模式 */
- uint32_t FilterScale; /* 过滤器的位宽 32 位/16 位 */
- uint32_t FilterActivation; /* 禁用或者使能过滤器 */
- uint32_t SlaveStartFilterBank; /* 双 CAN 模式下,规定 CAN 的主从模式的过滤器分配 */
- } CAN_FilterTypeDef;
HAL_CAN_Start 函数
HAL_StatusTypeDef HAL_CAN_Start(CAN_HandleTypeDef *hcan);
HAL_CAN_ActivateNotification 函数
- HAL_StatusTypeDef HAL_CAN_ActivateNotification(CAN_HandleTypeDef *hcan,
- uint32_t ActiveITs);
HAL_CAN_AddTxMessage 函数
- HAL_StatusTypeDef HAL_CAN_AddTxMessage(CAN_HandleTypeDef *hcan,
- CAN_TxHeaderTypeDef *pHeader, uint8_t aData[], uint32_t *pTxMailbox)
-
- typedef struct
- {
- uint32_t StdId; /* 标准标识符 11 位 范围:0~0x7FF */
- uint32_t ExtId; /* 扩展标识符 29 位 范围:0~0x1FFFFFFF */
- uint32_t IDE; /* 标识符类型 CAN_ID_STD / CAN_ID_EXT */
- uint32_t RTR; /* 帧类型 CAN_RTR_DATA / CAN_RTR_REMOTE */
- uint32_t DLC; /* 帧长度 范围:0~8byte */
- FunctionalState TransmitGlobalTime; /* 时间戳是否在开始时捕获 */
- } CAN_TxHeaderTypeDef;
HAL_CAN_GetRxMessage 函数
- HAL_StatusTypeDef HAL_CAN_GetRxMessage(CAN_HandleTypeDef *hcan,
- uint32_t RxFifo, CAN_RxHeaderTypeDef *pHeader, uint8_t aData[])
-
-
- typedef struct
- {
- uint32_t StdId; /* 标准标识符 11 位 范围:0~0x7FF */
- uint32_t ExtId; /* 扩展标识符 29 位 范围:0~0x1FFFFFFF */
- uint32_t IDE; /* 标识符类型 CAN_ID_STD / CAN_ID_EXT */
- uint32_t RTR; /* 帧类型 CAN_RTR_DATA / CAN_RTR_REMOTE */
- uint32_t DLC; /* 帧长度 范围:0~8byte */
- uint32_t Timestamp; /* 在帧接收开始时开始捕获的时间戳 */
- uint32_t FilterMatchIndex; /* 过滤器匹配序号 */
- } CAN_RxHeaderTypeDef;
1.CAN参数初始化
can_init(CAN_SJW_1TQ, CAN_BS2_8TQ, CAN_BS1_9TQ, 4, CAN_MODE_LOOPBACK);//500Kbps
2.开启CAN和对应管脚时钟,配置CAN_TX和CAN_RX的复用功能输出
3.设置过滤器
4.CAN数据接收和发送
- /**
- * @brief CAN 发送一组数据
- * @note 发送格式固定为: 标准 ID, 数据帧
- * @param id : 标准 ID(11 位)
- * @retval 发送状态 0, 成功; 1, 失败;
- */
- uint8_t can_send_msg(uint32_t id, uint8_t *msg, uint8_t len)
- {
- uint32_t TxMailbox = CAN_TX_MAILBOX0;
- g_canx_txheader.StdId = id; /* 标准标识符 */
- g_canx_txheader.ExtId = id; /* 扩展标识符(29 位) */
- g_canx_txheader.IDE = CAN_ID_STD; /* 使用标准帧 */
- g_canx_txheader.RTR = CAN_RTR_DATA; /* 数据帧 */
- g_canx_txheader.DLC = len;
- if (HAL_CAN_AddTxMessage(&g_canx_handler, &g_canx_txheader,
- msg, &TxMailbox) != HAL_OK) /* 发送消息 */
- {
- return 1;
- }
- /* 等待发送完成,所有邮箱为空(3 个邮箱) */
- while (HAL_CAN_GetTxMailboxesFreeLevel(&g_canx_handler) != 3);
- return 0;
- }
-
- /**
- * @brief CAN 接收数据查询
- * @note 接收数据格式固定为: 标准 ID, 数据帧
- * @param id : 要查询的 标准 ID(11 位)
- * @param buf : 数据缓存区
- * @retval 接收结果
- * @arg 0 , 无数据被接收到;
- * @arg 其他, 接收的数据长度
- */
- uint8_t can_receive_msg(uint32_t id, uint8_t *buf)
- {
- if (HAL_CAN_GetRxFifoFillLevel(&g_canx_handler, CAN_RX_FIFO0) != 1)
- {
- return 0;
- }
- if (HAL_CAN_GetRxMessage(&g_canx_handler, CAN_RX_FIFO0, &g_canx_rxheader,
- buf) != HAL_OK)
- {
- return 0;
- }
- /* 接收到的 ID 不对 / 不是标准帧 / 不是数据帧 */
- if (g_canx_rxheader.StdId!= id || g_canx_rxheader.IDE != CAN_ID_STD ||
- g_canx_rxheader.RTR != CAN_RTR_DATA)
- {
- return 0;
- }
- return g_canx_rxheader.DLC;
- }
1、为什么用CAN?
汽车的电子控制单元逐渐增多。各电控单元之间的信号交换导致汽车线束的级数增加。大大减少了汽车的线束。可靠性下降。增加了重量。
2、如何减少波特率的误差带来的通信错误?
CAN总线规定信号的跳变沿时刻进行同步,将误差累计限制在两个跳变沿。 当发送数据出现都为0或者1的时候,同样不跳变造成误差累计怎么办? 采用填充位在连续5个相同位后插入一个相反位,产生跳变沿,用于同步。
3、终端电阻的作用
4、需要在接收数据的时候用一个标志来判断当前发送的数据是真正的命令还是干扰,用一个特殊的值来做为接收指令的开始,这里选用0XA5做为数据的开始,为什么选0xA5呢?
因为0xA5的 二进制数位 1010 0101 刚好是一个1一个0,间隔开,用这个数字做为开始可以很大程度上的避免干扰信号,因为干扰信号一般不会是这种高低高低很有规律的信号。于是协议就改为 0xA5 为第一个数据,做为上位机发送命令的标志。
5、CAN物理层常见故障(CAN示波器)
(1)CAN节点供电正常,CAN工具上就是接收不到CAN报文数据或者报错,可能是什么原因?
首先确定CAN器件程序有bug;终端电阻不匹配;CAN收发器的影响。
(2)测试CAN物理波形,发现报文出现严重的振铃和反射现象?
缩短引线长度;加粗到线、印制铜箔的宽度;减小信号的传输距离;采用引线电感小的元器件;阻抗匹配
(3)通信错误会不会是CAN收发器故障引脚,如何判断收发器的好坏?
可以在ECU上电的CAN总线空闲情况下,测量CANH和CANL对地的电压是否在2.5V左右,如果出现0V或5V之类的,可考虑收发器故障问题。
(4)来自想用厂家的两个CAN节点又可以正常通信,为什么两个不同厂家的CAN节点连接通信时好时坏,甚至不能正常通信?
不同的厂家使用不用的采样点,也有可能造成通信不良。
(5)所有在测ECU节点CAN功能单独测试正常,装车后CAN功能失常,CAN错误频发,特别是新能源车上?
电磁干扰:选择性能好的隔离收发器;增加CAN双绞程度;布线尽量远离;感性防护器件。