文章目录

一、CAN 简介

1、CAN 总线

CAN(Controller Area Network,控制器局域网),是一种串行、异步、差分、多主、高可靠现场总线,专为复杂电磁环境、多设备组网通信设计,是车载电子、工业控制、机器人、智能家居的核心通信总线。
不同于UART/SPI/IIC板内短距离通信,CAN支持远距离、抗干扰强、多设备无主组网、自动仲裁容错,是唯一可用于工业和车载恶劣环境的低速总线。

2、CAN 核心硬件特点

差分信号传输:CAN_H、CAN_L 差分电压传输,抗电磁干扰能力极强。
多主架构:无固定主机从机,任意节点均可主动发送数据。
总线仲裁机制:多节点同时发数据时,ID优先级自动仲裁,无数据冲突。
自带错误容错:硬件自动重发、错误计数、离线保护。
远距离通信:125Kbps下可通信1000米,远超其他串口。
总线广播机制:一发多收,全网节点均可监听数据。

3、CAN 物理信号线详解

闭环总线网络
  在这里插入图片描述

开环总线网络:
  在这里插入图片描述
CAN_H:总线高位差分线。
CAN_L:总线低位差分线。
120Ω、2.2kΩ终端电阻:总线首尾节点必须并联,用于阻抗匹配、防止信号反射。
正常工作电平:显性电平(CAN_H高、CAN_L低,差分压差)、隐性电平(双线电平近似相等,压差为0)。

4、CAN 两大协议标准

CAN 2.0A(标准帧):11位ID,设备少、简单组网使用。
CAN 2.0B(扩展帧):29位ID,海量设备组网、车载设备标配。

5、典型应用场景

车载电子:汽车仪表、电机控制、车身组网、自动驾驶外设。
工业控制:PLC通信、工业传感器、伺服电机组网。
机器人:多舵机、多控制器协同通信。
楼宇智能、无人设备、恶劣电磁环境数据传输。

二、CAN 模块详解

1、CAN功能框图

  在这里插入图片描述

该芯片内置两路 CAN2.0B 控制器:

CAN1(主):拥有完整硬件资源(发送邮箱、接收 FIFO、28 组验收筛选器),具备筛选器主控权;
CAN2(从):无独立筛选器,复用 CAN1 的验收筛选器,仅自带控制状态寄存器、收发缓存;
两者共用一片 512Byte 片内 SRAM 作为报文存储区,由存储器访问控制器统一调度。

① 控制 / 状态配置寄存器组(CAN1 主 + CAN2 从两套独立)

每套 CAN 都拥有独立寄存器,功能完全一致:
  主控制:使能 CAN、睡眠模式、软件复位、自动重发、时间触发模式开关。
  主状态:总线空闲 / 发送忙 / 接收忙、总线错误、离线状态标记。
  发送状态:3 个发送邮箱空满、发送完成、发送失败标记。
  接收 FIFO 0/1 状态:FIFO 满、FIFO 溢出、新报文到达标志。
  中断使能:发送完成、接收报文、错误、总线离线中断开关。
  错误状态:发送错误计数 TEC、接收错误计数 REC、错误类型位。
  位定时:配置波特率、采样点、同步跳转宽度 BS1/BS2。
  筛选器专属寄存器(仅 CAN1 有效):筛选器主模式、单 / 双 32 位模式、FIFO 分配、筛选器激活开关。
主从差异:
  CAN2 无筛选器配置寄存器,所有报文过滤规则全部由 CAN1 统一配置。

② 发送邮箱模块(主 CAN1 + 从 CAN2 各 3 个发送邮箱)

CAN1:主发送邮箱 0/1/2;CAN2:从发送邮箱 0/1/2;
每个邮箱存储一帧完整 CAN 报文(ID + 数据长度 + 8 字节数据);
内置传输调度程序:硬件自动仲裁 3 个邮箱优先级,按 ID 优先级顺序发送;
发送流程:CPU 填充邮箱 → 置位发送请求 → 调度器竞争总线 → 总线发送完成置中断标志。

③ 主接收 FIFO0 / FIFO1(仅 CAN1 拥有双 FIFO)

两路独立先进先出接收缓冲区,硬件自动分流匹配报文:
  FIFO0:分配低序号筛选器报文;FIFO1:分配高序号筛选器报文;
  每个 FIFO 内置 3 级缓存,支持连续接收多帧不丢失;
  报文匹配筛选器后,硬件自动存入对应 FIFO,产生接收中断;
  读取报文后 CPU 释放缓存空间,FIFO 自动移位。

④ 验收筛选器组(CAN1 独占,共 28 组:主 0~27、从 0~27)

核心报文过滤硬件,CAN2 完全复用此模块,是双 CAN 架构核心:
总计 28 个筛选器单元,支持两种模式:
  32 位模式:单个筛选器匹配标准 ID + 扩展 ID + 掩码;
  16 位双筛选:一个单元拆为两组短 ID 筛选;
每个筛选器可绑定分配到 FIFO0 或 FIFO1;
报文流程:总线接收报文 → 筛选器匹配校验 → 匹配成功送入对应 FIFO,匹配丢弃;
CAN1 为主控,可开启 / 关闭、配置所有筛选器;CAN2 无配置权限,仅共享过滤规则。

⑤ 共享 512Byte SRAM & 存储器访问控制器

存储资源:整片 512 字节 SRAM 由 CAN1、CAN2 共同占用,存放所有发送邮箱、接收 FIFO、筛选器掩码 / ID 表;
存储器访问控制器:硬件仲裁 CPU/CAN1/CAN2 的读写请求,避免 SRAM 访问冲突;
资源分配规则:
  CAN1 占用大部分缓存;CAN2 仅占用自身 3 个发送邮箱缓存;
  筛选器表、CAN1 接收 FIFO 固定占用 SRAM 前段空间。

2、CAN基本结构

1.基本功能框图

  在这里插入图片描述

2. 接收流程

CAN 总线差分信号 → CAN 内核位同步 → 报文帧接收 → 筛选器匹配校验 → 匹配成功存入CAN1 FIFO0/FIFO1 → CPU 读取 FIFO 数据。
  在这里插入图片描述

3. 发送流程

CPU 填充 CAN1/CAN2 发送邮箱(主 / 从邮箱)→ 传输调度程序仲裁发送顺序 → 存储器控制器读取 SRAM 报文 → CAN 内核编码输出到 CAN 总线。
  在这里插入图片描述

4.发送和接收配置位

NART:
  置1,关闭自动重传,CAN报文只被发送1次,不管发送的结果如何(成功、出错或仲裁丢失);置0,自动重传,CAN硬件在发送报文失败时会一直自动重传直到发送成功。
TXFP:
  置1,优先级由发送请求的顺序来决定,先请求的先发送;置0,优先级由报文标识符来决定,标识符值小的先发送(标识符值相等时,邮箱号小的报文先发送)。
RFLM:
  置1,接收FIFO锁定,FIFO溢出时,新收到的报文会被丢弃;置0,禁用FIFO锁定,FIFO溢出时,FIFO中最后收到的报文被新报文覆盖

3、标识符过滤器

1.过滤器能功框图

  在这里插入图片描述

每个过滤器的核心由两个32位寄存器组成:R1[31:0]和R2[31:0]。
FSCx:位宽设置
  置0,16位;置1,32位。
FBMx:模式设置
  置0,屏蔽模式;置1,列表模式。
FFAx:关联设置
  置0,FIFO 0;置1,FIFO 1。
FACTx:激活设置
  置0,禁用;置1,启用。

2.过滤顺配置示例

  在这里插入图片描述

4、测试模式

1.静默模式

用于分析CAN总线的活动,不会对总线造成影响。
  在这里插入图片描述

2.环回模式

用于自测试,同时发送的报文可以在CAN_TX引脚上检测到。
  在这里插入图片描述

3.环回静默模式

用于热自测试,自测的同时不会影响CAN总线。
  在这里插入图片描述

5、工作模式

  在这里插入图片描述

初始化模式: 用于配置CAN外设,禁止报文的接收和发送。
正常模式: 配置CAN外设后进入正常模式,以便正常接收和发送报文。
睡眠模式: 低功耗,CAN外设时钟停止,可使用软件唤醒或者硬件自动唤醒。
AWUM: 置1,自动唤醒,一旦检测到CAN总线活动,硬件就自动清零SLEEP,唤醒CAN外设;置0,手动唤醒,软件清零SLEEP,唤醒CAN外设。

6、位时间特性

1.时钟来源

STM32F103 的 CAN 外设挂载 APB1 总线。
系统时钟 SYSCLK=72MHz,APB1 预分频器 = 2 → PCLK1 = 36MHz(工程最常用)。
APB1 预分频 = 1 时,PCLK1=72MHz。

2.单时间TQ时长

TQ = Prescaler/PCLK1。Prescaler:CAN 分频器(CubeMX 参数 Prescaler for Time Quantum)

3.1位总TQ个数

CAN 一位分为 4 段:SYNC_SEG (固定 1TQ) + BS1 + BS2
(TotalTQ = 1 + BS1 + BS2)

4.波特率计算

BaudRate = PCLK1/Prescaler/(1+BS1+BS2)

5.常用波特率配置

目标波特率 Prescaler BS1 BS2 TotalTQ 采样点
1000 kbps 2 13 2 16 87.5%
750 kbps 3 13 2 16 87.5%
500 kbps 4 13 2 16 87.5%
250 kbps 8 13 2 16 87.5%
125 kbps 16 13 2 16 87.5%
50 kbps 40 13 2 16 87.5%
20 kbps 100 13 2 16 87.5%

6.位时序图

  在这里插入图片描述
SS = 1Tq。
BS1 = 1~16Tq。
BS2 = 1~8Tq。
SJW=1~4Tq。
波特率 = APB1时钟频率 / 分频系数 / 一位的Tq数量
   = 36MHz / (BRP[9:0]+1) / (1 + (TS1[3:0]+1) + (TS2[2:0]+1))

7、中断

  在这里插入图片描述

CAN外设占用4个专用的中断向量:
  发送中断:发送邮箱空时产生。
  FIFO 0中断:收到一个报文/FIFO 0满/FIFO 0溢出时产生。
  FIFO 1中断:收到一个报文/FIFO 1满/FIFO 1溢出时产生。
  状态改变错误中断:出错/唤醒/进入睡眠时产生。

8、时间触发通信

  在这里插入图片描述

TTCM: 置1,开启时间触发通信功能;置0,关闭时间触发通信功能。
CAN外设内置一个16位的计数器,用于记录时间戳。
TTCM置1后,该计数器在每个CAN位的时间自增一次,溢出后归零。
每个发送邮箱和接收FIFO都有一个TIME[15:0]寄存器,发送帧SOF时,硬件捕获计数器值到发送邮箱的TIME寄存器,接收帧SOF时,硬件捕获计数器值到接收FIFO的TIME寄存器。
发送邮箱可配置TGT位,捕获计数器值的同时,也把此值写入到数据帧数据段的最后两个字节,为了使用此功能,DLC必须设置为8。

9、错主处理和离线恢复

  在这里插入图片描述

TEC和REC根据错误的情况增加或减少。
ABOM:
  置1,开启离线自动恢复,进入离线状态后,就自动开启恢复过程;
  置0,关闭离线自动恢复,软件必须先请求进入然后再退出初始化模式,随后恢复过程才被开启。

10、CAN 与 UART/SPI/IIC 核心区别

通信总线 CAN UART SPI IIC
传输方式 差分异步 单端异步 单端同步 单端同步
组网方式 多主多从、无冲突仲裁 一对一 一主多从(片选) 一主多从(地址)
抗干扰 极强(差分传输)
传输距离 最远1000米 几十米 板内短距离 板内短距离
容错能力 硬件自动容错重发 无硬件容错 无硬件容错 无硬件容错

三、CubeMX 标准 CAN 配置

1、基础配置

  在这里插入图片描述

Parameter Settings 位时序 & 基础参数(工业标准 500kbps,PCLK1=36M)

Bit Timings Parameters

参数 标准配置 说明
Prescaler (for Time Quantum) 4 时钟分频
Time Quanta in Bit Segment 1 13 BS1,保证高采样点
Time Quanta in Bit Segment 2 2 BS2
ReSynchronization Jump Width(SJW) 1 同步宽度

Basic Parameters(工程推荐全开容错)

Time Triggered Communication Mode:Disable。
Automatic Bus-Off Management:Enable(总线短路自动恢复)。
Automatic Wake-Up Mode:Disable。
Automatic Retransmission:Enable(发送失败自动重发)。
Receive Fifo Locked Mode:Disable。
Transmit Fifo Priority:Disable(硬件按 ID 仲裁优先级)。

Advanced Parameters

Test Mode:
  Normal(正常总线模式)
  Loopback:内部自测;
  Silent:仅监听不发送

2、关键模式说明

Normal 正常模式:真实总线收发,工程正式使用。
Loopback 回环模式:内部自收自发,无需外接设备,纯代码调试。
Silent 静默模式:只接收不发送,总线监听专用。

3、配置注意事项

总线两端必须焊接120Ω终端电阻,否则通信乱码、丢包。
所有CAN节点波特率、时序参数必须完全一致。
未配置过滤器或过滤器屏蔽错误,会接收不到数据。
调试优先使用回环模式,无需外接硬件即可验证代码。

四、CAN编程模块

1、CAN结构

1.CAN_HandleTypeDef 外设句柄(顶层总控)

		typedef struct
		{
		  CAN_TypeDef                 *Instance;        // CAN寄存器基地址(CAN1/CAN2)
		  CAN_InitTypeDef             Init;             // 时序、工作模式配置
		  CAN_FilterTypeDef           FilterConfig;      // 过滤器配置缓存
		  HAL_LockTypeDef             Lock;             // 互斥锁,多任务防冲突
		  __IO HAL_StateTypeDef       State;             // 外设运行状态
		  __IO uint32_t               ErrorCode;        // 硬件错误标志
		} CAN_HandleTypeDef;

2.CAN_InitTypeDef 初始化时序结构体

		对应框图位定时、总线基础功能开关
		typedef struct
		{
		  uint32_t Prescaler;              // 波特率分频TQ
		  uint32_t Mode;                   // 工作模式:正常/自测/监听
		  uint32_t SyncJumpWidth;          // SJW同步跳转宽度
		  uint32_t TimeSeg1;               // BS1时间段
		  uint32_t TimeSeg2;               // BS2时间段
		  FunctionalState TimeTriggeredMode; // TTCAN时间触发关闭/开启
		  FunctionalState AutoBusOff;      // 总线离线自动恢复
		  FunctionalState AutoWakeUp;      // 总线唤醒睡眠
		  FunctionalState AutoRetransmission; // 发送失败自动重发
		  FunctionalState ReceiveFifoLocked; // FIFO满锁定不覆盖旧数据
		  FunctionalState TransmitFifoPriority; // 邮箱ID优先级发送
		} CAN_InitTypeDef;

3.CAN_FilterTypeDef 过滤器结构体(框图过滤器核心)

		HAL_CAN_ConfigFilter() 入参,对应硬件 0~27 组 Filter Bank
		typedef struct
		{
		  uint32_t FilterBank;             // 过滤器编号0~27
		  uint32_t FilterMode;             // 模式:掩码匹配/列表匹配
		  uint32_t FilterScale;            // 位宽:32位(单ID)/16位(双ID)
		  uint32_t FilterIdHigh;           // ID寄存器高16位
		  uint32_t FilterIdLow;            // ID寄存器低16位
		  uint32_t FilterMaskHigh;         // 掩码寄存器高16位
		  uint32_t FilterMaskLow;          // 掩码寄存器低16位
		  uint32_t FilterFIFOAssignment;   // 匹配报文送入FIFO0/FIFO1
		  uint32_t FilterActivation;       // 过滤器使能/关闭
		  uint32_t SlaveFilterBank;        // 双CAN时分配给CAN2的过滤器段
		} CAN_FilterTypeDef;

4.CAN_TxHeaderTypeDef 发送报文头(对应 3 个发送邮箱)

		填充后调用HAL_CAN_AddTxMessage()写入发送邮箱
		typedef struct
		{
		  uint32_t StdId;       // 标准ID 0~0x7FF
		  uint32_t ExtId;       // 扩展ID 0~0x1FFFFFFF
		  uint32_t IDE;         // 帧类型:标准帧CAN_ID_STD / 扩展帧CAN_ID_EXT
		  uint32_t RTR;         // 远程帧CAN_RTR_REMOTE / 数据帧CAN_RTR_DATA
		  uint32_t DLC;         // 数据长度0~8字节
		  FunctionalState TransmitGlobalTime; // 时间触发时间戳
		} CAN_TxHeaderTypeDef;

5.CAN_RxHeaderTypeDef 接收报文头(对应 FIFO 缓存)

		HAL_CAN_GetRxMessage() 读取 FIFO 报文输出参数
		typedef struct
		{
		  uint32_t StdId;       // 接收报文标准ID
		  uint32_t ExtId;       // 接收报文扩展ID
		  uint32_t IDE;         // 标准/扩展帧标识
		  uint32_t RTR;         // 数据帧/远程帧标识
		  uint32_t DLC;         // 接收数据长度
		  uint32_t FilterMatchIndex; // 匹配的过滤器编号
		} CAN_RxHeaderTypeDef;

2、HAL_CAN_API

1.初始化 / 反初始化类

		HAL_CAN_Init(CAN_HandleTypeDef *hcan):根据句柄 Init 配置初始化 CAN 外设时序与模式。
		HAL_CAN_DeInit(CAN_HandleTypeDef *hcan):复位 CAN 外设,清空运行状态。
		HAL_CAN_MspInit(CAN_HandleTypeDef *hcan):底层 MSP 初始化,开启时钟、配置 TX/RX 引脚复用。
		HAL_CAN_MspDeInit(CAN_HandleTypeDef *hcan):释放 CAN 底层资源,关闭外设时钟、恢复 GPIO。

2.过滤器配置专用

		HAL_CAN_ConfigFilter(CAN_HandleTypeDef *hcan, CAN_FilterTypeDef *sFilterConfig):配置 ID 过滤器,设置匹配规则与绑定 FIFO。

3.外设启停控制

		HAL_CAN_Start(CAN_HandleTypeDef *hcan):使能 CAN 内核,退出睡眠,进入正常收发状态。
		HAL_CAN_Stop(CAN_HandleTypeDef *hcan):关闭 CAN 内核,进入睡眠,停止总线收发。

4.报文发送操作

		HAL_CAN_AddTxMessage(CAN_HandleTypeDef *hcan, CAN_TxHeaderTypeDef *pTxHeader, const uint8_t *pData, uint32_t *pTxMailbox):填充空闲发送邮箱,载入待发报文,返回使用的邮箱号。
		HAL_CAN_AbortTxRequest(CAN_HandleTypeDef *hcan, uint32_t TxMailbox):取消指定邮箱未发送报文,释放邮箱缓存。
		HAL_CAN_GetTxMailboxesFreeLevel(CAN_HandleTypeDef *hcan):查询当前空闲发送邮箱数量(0~3)。
		HAL_CAN_IsTxMessagePending(CAN_HandleTypeDef *hcan, uint32_t TxMailbox):查询指定邮箱是否存在待发送报文。

5.报文接收操作

		HAL_CAN_GetRxMessage(CAN_HandleTypeDef *hcan, uint32_t RxFifo, CAN_RxHeaderTypeDef *pRxHeader, uint8_t *pData):从指定 FIFO 读取一帧完整接收报文。
		HAL_CAN_GetRxFifoFillLevel(CAN_HandleTypeDef *hcan, uint32_t RxFifo):查询 FIFO 内缓存的未读报文数量(0~3)。
		HAL_CAN_ClearRxFifoOverrunFlag(CAN_HandleTypeDef *hcan, uint32_t RxFifo):清除 FIFO 报文溢出标志,代表存在丢帧。

6.中断管理

		中断开关:
			HAL_CAN_ActivateNotification(CAN_HandleTypeDef *hcan, uint32_t ActiveITs):开启指定 CAN 中断(接收 / 发送 / 故障)。
			HAL_CAN_DeactivateNotification(CAN_HandleTypeDef *hcan, uint32_t InactiveITs):关闭指定 CAN 中断
		中断底层入口:
			HAL_CAN_IRQHandler(CAN_HandleTypeDef *hcan):CAN 中断服务总入口,解析中断标志并分发对应回调
		发送完成回调(用户重写):
			void HAL_CAN_TxMailbox0CompleteCallback(CAN_HandleTypeDef *hcan):邮箱 0 报文发送完成回调。
			void HAL_CAN_TxMailbox1CompleteCallback(CAN_HandleTypeDef *hcan):邮箱 1 报文发送完成回调。
			void HAL_CAN_TxMailbox2CompleteCallback(CAN_HandleTypeDef *hcan):邮箱 2 报文发送完成回调。
		FIFO 接收回调(用户重写):
			void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan):FIFO0 收到新报文中断回调。
			void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan):FIFO1 收到新报文中断回调。
		FIFO 状态异常回调(用户重写):
			void HAL_CAN_RxFifo0FullCallback(CAN_HandleTypeDef *hcan):FIFO0 缓存已满中断回调。
			void HAL_CAN_RxFifo1FullCallback(CAN_HandleTypeDef *hcan):FIFO1 缓存已满中断回调。
			void HAL_CAN_RxFifo0OverrunCallback(CAN_HandleTypeDef *hcan):FIFO0 报文溢出丢帧回调。
			void HAL_CAN_RxFifo1OverrunCallback(CAN_HandleTypeDef *hcan):FIFO1 报文溢出丢帧回调。
		总线故障回调(用户重写):
			void HAL_CAN_BusOffCallback(CAN_HandleTypeDef *hcan):总线离线 BusOff 严重故障回调。
			void HAL_CAN_ErrorCallback(CAN_HandleTypeDef *hcan):通用硬件错误中断回调(位错 / 仲裁丢失等)。

7.状态 / 错误查询

		HAL_StateTypeDef HAL_CAN_GetState(CAN_HandleTypeDef *hcan):获取 CAN 外设当前运行状态(就绪 / 忙 / 错误)。
		uint32_t HAL_CAN_GetError(CAN_HandleTypeDef *hcan):读取 CAN 硬件错误标志位。
		HAL_StatusTypeDef HAL_CAN_ResetError(CAN_HandleTypeDef *hcan):清除硬件错误计数 TEC/REC 与错误标志。

8.低功耗睡眠模式

		HAL_CAN_EnterSleepMode(CAN_HandleTypeDef *hcan):控制 CAN 进入低功耗睡眠模式。
		HAL_CAN_WakeUpFromSleepMode(CAN_HandleTypeDef *hcan):软件唤醒睡眠中的 CAN 外设,恢复通信。

五、CAN 应用实例

1、CubeMX配置

  在这里插入图片描述

1.Bit Timings Parameters(工业标准 500kbps,PCLK1=36M)

参数 标准配置 说明
Prescaler (for Time Quantum) 4 时钟分频
Time Quanta in Bit Segment 1 13 BS1,保证高采样点
Time Quanta in Bit Segment 2 2 BS2
ReSynchronization Jump Width(SJW) 1 同步宽度

2.Basic Parameters(工程推荐全开容错)

Time Triggered Communication Mode:Disable(TTCAN 时间触发模式)
Automatic Bus-Off Management:Enable(总线短路自动恢复)
Automatic Wake-Up Mode:Disable(总线自动唤醒)
Automatic Retransmission:Enable(发送失败自动重发)
Receive Fifo Locked Mode:Disable(FIFO 满锁定)
Transmit Fifo Priority:Disable(硬件按 ID 仲裁优先级)

3.Advanced Parameters

Test Mode:
  Normal(正常总线模式)
  Loopback(内部自测)
  Silent(仅监听不发送)

4.NVIC 中断配置(中断接收必备)

  在这里插入图片描述

5.配置完成在代码生成后使能CAN

		//使能CAN
		HAL_StatusTypeDef HAL_CAN_Start(CAN_HandleTypeDef *hcan);

2、发送代码参考

	CAN_TxHeaderTypeDef can_Tx;
	uint8_t sendBuf[5] = {"hello"};
	uint32_t box;
	
	int main(void)
	{
	    HAL_Init();
	    SystemClock_Config();
	    MX_GPIO_Init();
	    MX_CAN_Init();
	
	    HAL_CAN_Start(&hcan);
	  
	    can_Tx.StdId = 0x123;
	    can_Tx.ExtId = 0;
	    can_Tx.IDE = CAN_ID_STD;
	    can_Tx.RTR = CAN_RTR_DATA;
	    can_Tx.DLC = 5;
	    can_Tx.TransmitGlobalTime = DISABLE;
	
	    while (1)
	    {
			HAL_CAN_AddTxMessage(&hcan, &can_Tx, sendBuf, &box);
			HAL_Delay(100);
	    }
	}

3、过滤器配置代码参考

	//1.配置为CAN总线上所有的报文都会被接收,并存入FIFO0中。
	CAN_FilterTypeDef can_Filter = {0};
	can_Filter.FilterIdHigh = 0;
	can_Filter.FilterIdLow = 0;
	can_Filter.FilterMaskIdHigh = 0;
	can_Filter.FilterMaskIdLow = 0;
	can_Filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
	can_Filter.FilterBank = 0;
	can_Filter.FilterMode = CAN_FILTERMODE_IDMASK;
	can_Filter.FilterScale = CAN_FILTERSCALE_32BIT;
	can_Filter.FilterActivation = CAN_FILTER_ENABLE;

	HAL_CAN_ConfigFilter(&hcan, &can_Filter);

	//2.配置仅接收标准ID为0x0的数据帧和遥控帧,并存入FIFO0中。
	/*
	CAN_FilterTypeDef can_Filter = {0};

	can_Filter.FilterIdHigh = 0;
	can_Filter.FilterIdLow = 0;
	can_Filter.FilterMaskIdHigh = 0;
	can_Filter.FilterMaskIdLow = 2;
	can_Filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
	can_Filter.FilterBank = 0;
	can_Filter.FilterMode = CAN_FILTERMODE_IDLIST;
	can_Filter.FilterScale = CAN_FILTERSCALE_32BIT;
	can_Filter.FilterActivation = CAN_FILTER_ENABLE;

	HAL_CAN_ConfigFilter(&hcan, &can_Filter);
	*/

4、接收代码参考

使能CAN外设中断函数:
  HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
实例代码:

	#include <stdio.h>
	
	CAN_RxHeaderTypeDef can_Rx;
	uint8_t recvBuf[8];
	
	uint8_t uartBuf[64];
	
	int main(void)
	{
	    HAL_Init();
	    SystemClock_Config();
	    MX_GPIO_Init();
	    MX_CAN_Init();
	    MX_USART1_UART_Init()
	
	    CAN_FilterTypeDef can_Filter = {0};
	    
	    can_Filter.FilterIdHigh = 0;
	    can_Filter.FilterIdLow = 0;
	    can_Filter.FilterMaskIdHigh = 0;
	    can_Filter.FilterMaskIdLow = 0;
	    can_Filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
	    can_Filter.FilterBank = 0;
	    can_Filter.FilterMode = CAN_FILTERMODE_IDMASK;
	    can_Filter.FilterScale = CAN_FILTERSCALE_32BIT;
	    can_Filter.FilterActivation = CAN_FILTER_ENABLE;
	    HAL_CAN_ConfigFilter(&hcan1, &can_Filter);
	    
	    HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
	    
	    HAL_CAN_Start(&hcan);
	
	    while (1)
	    {
	
	    }
	}
	
	void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
	{
	    uint16_t len = 0;
	    
	    HAL_CAN_GetRxMessage(&hcan, CAN_RX_FIFO0, &can_Rx, recvBuf);
	
	    if(can_Rx.IDE == CAN_ID_STD)
	    {
	        len += sprintf((char *)&uartBuf[len], "标准ID:%#X; ", can_Rx.StdId);
	    }
	    else if(can_Rx.IDE == CAN_ID_EXT)
	    {
	        len += sprintf((char *)&uartBuf[len], "扩展ID:%#X; ", can_Rx.ExtId);
	    }
	    
	    if(can_Rx.RTR == CAN_RTR_DATA)
	    {
	        len += sprintf((char *)&uartBuf[len], "数据帧; 数据为:");
	        
	        for(int i = 0; i < can_Rx.DLC; i ++)
	        {
	            len += sprintf((char *)&uartBuf[len], "%X ", recvBuf[i]);
	        }
	        
	        len += sprintf((char *)&uartBuf[len], "\r\n");
	        HAL_UART_Transmit(&huart, uartBuf, len, 100);        
	    }
	    else if(can_Rx.RTR == CAN_RTR_REMOTE)
	    {
	        len += sprintf((char *)&uartBuf[len], "遥控帧\r\n");
	        HAL_UART_Transmit(&huart, uartBuf, len, 100);        
	    }    
	}

5、实验结果

  在这里插入图片描述

六、CAN 核心要点与避坑大全

1、核心知识点

CAN为差分异步多主总线,抗干扰强、支持远距离组网。
ID越小优先级越高,硬件自动仲裁,无总线冲突。
总线首尾必须120Ω终端电阻,是通信成功的前提。
单帧最大8字节数据,超长数据需分包传输。
必须配置过滤器,否则无法正常接收总线数据。
支持自动重发、错误计数、总线离线保护。

2、高频坑点

未接120Ω终端电阻,导致信号反射、乱码、丢包严重。
多设备波特率、时序参数不统一,总线通信失败。
忘记配置过滤器或过滤器屏蔽全部ID,接收不到数据。
单帧发送数据超过8字节,触发传输错误。
总线干扰严重导致报错、离线,未开启自动恢复。
混淆标准帧与扩展帧ID,数据收发不匹配。

3、工程最佳实践

调试阶段使用回环模式,快速验证代码逻辑。
正式工程开启自动重发、自动总线离线恢复。
统一使用500Kbps标准波特率,设备兼容性最强。
采用中断方式接收,实时响应总线数据。
超长数据自定义分包协议,规避8字节单帧限制。
增加总线错误检测与重连机制,提升工业稳定性。

4、一句话总结

CAN是差分异步多主现场总线,依靠CAN_H/CAN_L差分传输实现强抗干扰,通过ID优先级硬件仲裁避免总线冲突,自带错误容错与自动重发机制,支持多设备远距离组网,是车载与工业控制的核心通信总线。

七、全篇总结

CAN 是嵌入式工业与车载领域的核心总线,区别于普通板级通信总线,具备高抗干扰、多主组网、硬件容错、远距离传输的核心优势。
掌握 CAN 时序原理、仲裁机制、过滤器配置、CubeMX工程配置、中断收发实战代码,即可独立完成工业组网、车载设备、机器人多机通信项目开发,是嵌入式高薪进阶的必备核心技能。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐