李旭昂 发表于 2025-4-10 11:03

【手把手教你玩转CAN总线】从原理到STM32实战

#申请原创# #技术资源#一、物理层深度剖析
1.1 差分信号的本质CAN总线采用双线差分传输,核心原理图解:CAN_H ──────\       /─────────
            \   /
             \___/
CAN_L ──────/   \─────────
[*]显性状态(Dominant):CAN_H电压 ≥ 2.5V,CAN_L ≤ 1.5V → 差值≥1V
[*]隐性状态(Recessive):CAN_H/CAN_L均为2.5V → 差值≈0V
物理层参数对照表:
参数标准值测试方法
终端电阻120Ω ±1%万用表直接测量
最大传输距离10km @ ≤5Kbps示波器+时延测试仪
波特率容差±1%专用CAN分析仪
共模电压抑制±2V隔离示波器测量
1.2 波特率计算公式markdown位时间 = 同步段 + 传播时间段 + 相位缓冲段1 + 相位缓冲段2
总位数 = 同步段(SJW) + 时间段1(TS1) + 时间段2(TS2)STM32配置示例(500Kbps):hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;    // 同步跳转宽度=1TQ
hcan1.Init.TimeSeg1 = CAN_BS1_9TQ;         // 时间段1=9TQ
hcan1.Init.TimeSeg2 = CAN_BS2_4TQ;         // 时间段2=4TQ
// 总位时间=1+9+4=14TQ → 时钟频率=8MHz → TQ=0.125μs → 波特率=1/(14 * 0.125μs)=500Kbps1.3 终端电阻调试技巧
[*]错误现象:总线波形畸变、通信不稳定
[*]检测方法:
[*]断电测量总线两端电阻(应为120Ω±5%)
[*]上电后用示波器观察终端反射波形

[*]解决方案:# 终端电阻计算公式(单位Ω)
def calc_termination_resistance(length):
    # 每米电缆约60Ω特性阻抗
    return 120 - (length * 60) / 1000
# 示例:总线长度40m → 120 - 24 = 96Ω → 需补48Ω电阻
二、数据链路层全解析(帧结构+仲裁机制)2.1 CAN帧类型对比表
帧类型标识符长度用途DLC最大值
标准帧11位普通数据传输8字节
扩展帧29位复杂设备通信8字节
远程帧11/29位请求数据-
错误帧-错误通知-
2.2 经典仲裁过程演示场景:三个节点同时发送数据markdown节点A: ID=0x100 (0b000100000000)
节点B: ID=0x200 (0b001000000000)
节点C: ID=0x080 (0b000010000000)仲裁过程:
[*]第一位:全显性 → 继续比较
[*]第二位:A=0, B=0, C=1 → C失去仲裁权
[*]后续位比较后,A胜出总线使用权
STM32仲裁配置要点:// 使能自动重传功能(默认开启)
hcan1.Init.AutoRetransmission = ENABLE;
// 设置重试次数(最大16次)
hcan1.Init.RetryCount = 3;2.3 错误检测机制详解五级错误防护体系:
[*]CRC校验:15位循环冗余校验
[*]位填充:每5个相同电平插入相反电平
[*]ACK校验:接收节点必须发送显性确认
[*]帧格式校验:7个保留位必须为隐性
[*]总线监控:持续检测总线逻辑电平
错误计数器动态调整算法:markdown当检测到错误时:
TEC += 8(发送错误)或 REC += 1(接收错误)
当TEC > 127时:进入总线关闭状态2.4 位时间同步技术同步机制:
[*]硬同步:在帧起始位强制对齐
[*]重新同步:通过调整时间段2补偿时钟偏差
STM32时间参数配置示例:// 配置同步跳转宽度为1个时间量子
hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;

// 时间段分配(假设系统时钟16MHz)
CAN_BtrTypeDef sCanBtr;
sCanBtr.SyncJumpWidth = CAN_SJW_1TQ;
sCanBtr.TimeSeg1 = CAN_BS1_9TQ;// 传播延迟补偿
sCanBtr.TimeSeg2 = CAN_BS2_4TQ;// 相位缓冲
三、数据链路层核心机制3.1 CAN协议栈全景图应用层(CANopen/J1939)
   ↓
网络层(路由/错误处理)
   ↓
数据链路层(帧结构/仲裁)
   ↓
物理层(差分信号/终端电阻)3.2 帧结构深度拆解标准帧格式(11位ID):| 仲裁场(11b) | 控制场(6b) | 数据场(0-8B) | CRC场(15b) | ACK场(1b) | 帧结束(7b) |
[*]仲裁场:包含节点ID和帧类型标识
[*]控制场:DLC(数据长度码) + IDE(扩展标识符)
[*]CRC场:15位循环冗余校验(生成多项式:x¹⁵+x¹⁴+...+1)
STM32 CRC配置示例:// CAN1 CRC初始化
hcan1.Instance->CRCD = 0xFFFF;    // 初始值
hcan1.Instance->CRCSA = 0x0000;   // 起始地址3.3 仲裁机制详解29位扩展帧仲裁过程:优先级位 → 源地址 → 参数组号(PGN)
[*]优先级计算:ID31-ID26位决定(数值越小优先级越高)
[*]源地址冲突检测:同一网络内节点地址必须唯一
仲裁时序仿真:def can_arbitration(id_list):
    sorted_ids = sorted(id_list, key=lambda x: bin(x).count('1'))
    return sorted_ids

# 示例:三个节点同时发送
nodes =
winner = can_arbitration(nodes)# 输出0x18FEF100
四、CANopen协议深度实战4.1 对象字典(Object Dictionary)OD结构示例:索引      类型      描述
0x2000   ARRAY       电机控制参数
0x2000UINT16      目标转速(rpm)
0x2000FLOAT       加速度(m/s²)
0x2001   RECORD      故障代码
0x2001BITFIELD    故障标志位STM32 SDO传输实现:// SDO客户端上传数据
void SDO_Upload(uint16_t index, uint8_t subindex) {
    CO_SDO_Req req;
    CO_SDO_ReqInit(&req);
    req.Cmd = CO_SDO_CMD_UPLOAD_REQ;
    req.Index = index;
    req.SubIndex = subindex;
   
    if (CO_SDO_Transmit(&req) == CO_SDO_OK) {
      Process_SDO_Response(req.Data);
    }
}4.2 NMT网络管理状态迁移图:INIT → PRE-OPERATIONAL → OPERATIONAL → STOPPED
   ↑      ↑                  ↓
   └──RESET←───────────────────┘心跳报文配置:// 心跳生产者配置
CO_NMT_HeartbeatConfig(0x01, 0x00, 500);// 节点ID=1,周期500ms
五、J1939协议核心要点5.1 参数组号(PGN)编码规则PGN = PF(8b) << 8 | PS(8b)
PF: 参数组功能(0-255)
PS: 参数组子功能(0-255)典型PGN解析:
PGNPFPS描述
0xFEFC0xFE0xFC发动机转速请求
0xFEF00xFE0xF0冷却液温度
0xFECA0xFE0xCA车辆位置报告
5.2 多包数据传输传输流程:请求 → 确认 → 数据包1 → 数据包2 → ... → 结束符STM32多包发送实现:// 多包数据发送(最大12字节/包)
void CAN_Send_MultiPacket(uint8_t *data, uint16_t length) {
    uint8_t packets = {0};
    uint8_t packet_count = (length + 7) / 8;
   
    for (int i=0; i<packet_count; i++) {
      packets = 0x00;// 流控制字段
      memcpy(&packets, &data, 8);
      CAN_TransmitPacket(packets);
    }
}
六、STM32HAL库实战进阶6.1 完整初始化流程// 1. GPIO配置(CubeMX生成)
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOB_CLK_ENABLE();

// CAN_RX/TX引脚配置
GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF9_CAN1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

// 2. CAN初始化(含过滤器配置)
void MX_CAN1_Init(void)
{
CAN_HandleTypeDef hcan1;

hcan1.Instance = CAN1;
hcan1.Init.Prescaler = 5;         // 500Kbps
hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
hcan1.Init.TimeSeg1 = CAN_BS1_9TQ;
hcan1.Init.TimeSeg2 = CAN_BS2_4TQ;
hcan1.Init.Mode = CAN_MODE_NORMAL;

if (HAL_CAN_Init(&hcan1) != HAL_OK) {
    Error_Handler();
}

// 滤波器配置(接收ID=0x100-0x1FF)
CAN_FilterTypeDef sFilterConfig = {0};
sFilterConfig.FilterBank = 0;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = 0x100 << 13;
sFilterConfig.FilterIdLow = 0x1FF << 13 | 0xFFFF;
HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig);
}6.2 数据收发实战// 数据发送(PDO模拟)
void CAN_Send_PDO(uint8_t node_id, uint16_t position) {
CAN_TxHeaderTypeDef TxHeader = {0};
uint8_t TxData = {0};

TxHeader.StdId = 0x200 + node_id;// PDO ID
TxHeader.IDE = CAN_ID_STD;
TxHeader.DLC = 2;

TxData = (position >> 8) & 0xFF;
TxData = position & 0xFF;

HAL_CAN_AddTxMessage(&hcan1, &TxHeader, TxData, &TxMailbox);
}

// 接收回调(带错误检测)
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) {
CAN_RxHeaderTypeDef RxHeader;
uint8_t RxData = {0};

if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, RxData) == HAL_OK) {
    if (RxHeader.DLC != 2) {
      // 数据长度异常处理
      return;
    }
    uint16_t value = (RxData << 8) | RxData;
    Process_Sensor_Data(value);
}
}
七、工业级应用案例解析7.1 电动汽车三电系统
[*]BMS电池管理:通过CAN总线监控单体电压/温度
[*]电机控制器:接收扭矩指令并反馈转速
[*]OBC车载充电机:与BMS通信实现充电保护
通信拓扑:BMS → CAN → MCU → CAN → 电机控制器
         ↑↓
         充电桩7.2 智能仓储机器人
[*]多机协同:50+台AGV通过CAN总线同步路径规划
[*]实时监控:电量/故障状态实时上报
[*]抗干扰方案:
[*]双绞线屏蔽层接地
[*]隔离收发器(如ADuM1201)
[*]冗余帧重传机制


八、调试与优化技巧
[*]示波器观察:
[*]检查CAN_H/CAN_L差分波形(正常应为方波)
[*]波特率验证(500Kbps对应周期2μs)

[*]错误分析:
[*]错误帧计数:HAL_CAN_GetError(&hcan1)
[*]总线负载率:CAN总线分析仪检测

[*]性能优化:
[*]使用CAN FD(Flexible Data Rate)提升带宽
[*]优化过滤器配置减少CPU开销
[*]采用环形缓冲区处理高频率数据


九、扩展学习资源
[*]经典CAN vs CAN FD:带宽从1Mbps提升至5Mbps
[*]AUTOSAR架构:标准化汽车软件架构
[*]TSN时间敏感网络:工业4.0通信新标准      
[*] @21小跑堂

515192147 发表于 2025-4-10 17:18

厉害

WK520077778 发表于 2025-4-10 20:20

厉害

dffzh 发表于 2025-4-11 09:33

阁下,请问以下拓扑结构能不能实现正常CAN通信?

coody 发表于 2025-4-11 11:41

很疑惑的问题:你又不在我身边,请告诉我,怎么手把手法?

arima 发表于 2025-4-12 08:54

谢谢分享,学习了。。。
页: [1]
查看完整版本: 【手把手教你玩转CAN总线】从原理到STM32实战