• 正文
    • 一、物理層深度剖析
    • 二、數(shù)據(jù)鏈路層全解析(幀結(jié)構(gòu)+仲裁機(jī)制)
    • 三、數(shù)據(jù)鏈路層核心機(jī)制
    • 四、CANopen協(xié)議深度實戰(zhàn)
    • 五、J1939協(xié)議核心要點(diǎn)
    • 六、STM32HAL庫實戰(zhàn)進(jìn)階
    • 七、工業(yè)級應(yīng)用案例解析
    • 八、調(diào)試與優(yōu)化技巧
    • 九、擴(kuò)展學(xué)習(xí)資源
  • 相關(guān)推薦
申請入駐 產(chǎn)業(yè)圖譜

手把手教你玩轉(zhuǎn)CAN總線 從原理到STM32實戰(zhàn)

04/11 11:32
717
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

一、物理層深度剖析

1.1 差分信號的本質(zhì)

CAN總線采用雙線差分傳輸,核心原理圖解:

markdown

CAN_H ────── ? ? ? /───────── ?
 ? ? ? ? ? ? ? ? / ?
 ? ? ? ? ? ? ___/ ?
CAN_L ──────/ ? ? ───────── ?
  • 顯性狀態(tài)(Dominant):CAN_H電壓 ≥ 2.5V,CAN_L ≤ 1.5V → 差值≥1V

  • 隱性狀態(tài)(Recessive):CAN_H/CAN_L均為2.5V → 差值≈0V

物理層參數(shù)對照表

參數(shù) 標(biāo)準(zhǔn)值 測試方法
終端電阻 120Ω ±1% 萬用表直接測量
最大傳輸距離 10km @ ≤5Kbps 示波器+時延測試儀
波特率容差 ±1% 專用CAN分析儀
共模電壓抑制 ±2V 隔離示波器測量

1.2 波特率計算公式

markdown

位時間 = 同步段 + 傳播時間段 + 相位緩沖段1 + 相位緩沖段2 ?
總位數(shù) = 同步段(SJW) + 時間段1(TS1) + 時間段2(TS2)

STM32配置示例(500Kbps):

hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ; ? ?// 同步跳轉(zhuǎn)寬度=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)=500Kbps

1.3 終端電阻調(diào)試技巧

  • 錯誤現(xiàn)象:總線波形畸變、通信不穩(wěn)定

  • 檢測方法:

    1. 斷電測量總線兩端電阻(應(yīng)為120Ω±5%)

    2. 上電后用示波器觀察終端反射波形

  • 解決方案:

    # 終端電阻計算公式(單位Ω)
    def calc_termination_resistance(length):
     ? ?# 每米電纜約60Ω特性阻抗
     ? ?return 120 - (length * 60) / 1000 ?
    # 示例:總線長度40m → 120 - 24 = 96Ω → 需補(bǔ)48Ω電阻

二、數(shù)據(jù)鏈路層全解析(幀結(jié)構(gòu)+仲裁機(jī)制)

2.1 CAN幀類型對比表

幀類型 標(biāo)識符長度 用途 DLC最大值
標(biāo)準(zhǔn)幀 11位 普通數(shù)據(jù)傳輸 8字節(jié)
擴(kuò)展幀 29位 復(fù)雜設(shè)備通信 8字節(jié)
遠(yuǎn)程幀 11/29位 請求數(shù)據(jù) -
錯誤幀 - 錯誤通知 -

2.2 經(jīng)典仲裁過程演示

場景:三個節(jié)點(diǎn)同時發(fā)送數(shù)據(jù)

markdown

節(jié)點(diǎn)A: ID=0x100 (0b000100000000)
節(jié)點(diǎn)B: ID=0x200 (0b001000000000)
節(jié)點(diǎn)C: ID=0x080 (0b000010000000)

仲裁過程

  1. 第一位:全顯性 → 繼續(xù)比較

  2. 第二位:A=0, B=0, C=1 → C失去仲裁權(quán)

  3. 后續(xù)位比較后,A勝出總線使用權(quán)

STM32仲裁配置要點(diǎn)

// 使能自動重傳功能(默認(rèn)開啟)
hcan1.Init.AutoRetransmission = ENABLE;
// 設(shè)置重試次數(shù)(最大16次)
hcan1.Init.RetryCount = 3;

2.3 錯誤檢測機(jī)制詳解

五級錯誤防護(hù)體系

  1. CRC校驗:15位循環(huán)冗余校驗

  2. 位填充:每5個相同電平插入相反電平

  3. ACK校驗:接收節(jié)點(diǎn)必須發(fā)送顯性確認(rèn)

  4. 幀格式校驗:7個保留位必須為隱性

  5. 總線監(jiān)控:持續(xù)檢測總線邏輯電平

錯誤計數(shù)器動態(tài)調(diào)整算法

markdown

當(dāng)檢測到錯誤時:
TEC += 8(發(fā)送錯誤)或 REC += 1(接收錯誤)
當(dāng)TEC > 127時:進(jìn)入總線關(guān)閉狀態(tài)

2.4 位時間同步技術(shù)

同步機(jī)制

  • 硬同步:在幀起始位強(qiáng)制對齊

  • 重新同步:通過調(diào)整時間段2補(bǔ)償時鐘偏差

STM32時間參數(shù)配置示例

// 配置同步跳轉(zhuǎn)寬度為1個時間量子
hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
?
// 時間段分配(假設(shè)系統(tǒng)時鐘16MHz)
CAN_BtrTypeDef sCanBtr;
sCanBtr.SyncJumpWidth = CAN_SJW_1TQ;
sCanBtr.TimeSeg1 = CAN_BS1_9TQ; ?// 傳播延遲補(bǔ)償
sCanBtr.TimeSeg2 = CAN_BS2_4TQ; ?// 相位緩沖

三、數(shù)據(jù)鏈路層核心機(jī)制

3.1 CAN協(xié)議棧全景圖

應(yīng)用層CANopen/J1939)
 ? ↓
網(wǎng)絡(luò)層(路由/錯誤處理)
 ? ↓
數(shù)據(jù)鏈路層(幀結(jié)構(gòu)/仲裁)
 ? ↓
物理層(差分信號/終端電阻)

3.2 幀結(jié)構(gòu)深度拆解

標(biāo)準(zhǔn)幀格式(11位ID)

| 仲裁場(11b) | 控制場(6b) | 數(shù)據(jù)場(0-8B) | CRC場(15b) | ACK場(1b) | 幀結(jié)束(7b) |
  • 仲裁場:包含節(jié)點(diǎn)ID和幀類型標(biāo)識

  • 控制場:DLC(數(shù)據(jù)長度碼) + IDE(擴(kuò)展標(biāo)識符)

  • CRC場:15位循環(huán)冗余校驗(生成多項式:x1?+x1?+...+1)

STM32 CRC配置示例

// CAN1 CRC初始化
hcan1.Instance->CRCD = 0xFFFF; ? ?// 初始值
hcan1.Instance->CRCSA = 0x0000; ? // 起始地址

3.3 仲裁機(jī)制詳解

29位擴(kuò)展幀仲裁過程

優(yōu)先級位 → 源地址 → 參數(shù)組號(PGN)
  • 優(yōu)先級計算:ID31-ID26位決定(數(shù)值越小優(yōu)先級越高)

  • 源地址沖突檢測:同一網(wǎng)絡(luò)內(nèi)節(jié)點(diǎn)地址必須唯一

仲裁時序仿真

def can_arbitration(id_list):
 ? ?sorted_ids = sorted(id_list, key=lambda x: bin(x).count('1'))
 ? ?return sorted_ids[0]
?
# 示例:三個節(jié)點(diǎn)同時發(fā)送
nodes = [0x18FEF100, 0x18FEF200, 0x18FEF300]
winner = can_arbitration(nodes) ?# 輸出0x18FEF100

四、CANopen協(xié)議深度實戰(zhàn)

4.1 對象字典(Object Dictionary)

OD結(jié)構(gòu)示例

索引 ? ? ?  類型 ? ? ?  描述
0x2000 ? ? ARRAY ? ? ? 電機(jī)控制參數(shù)
0x2000[0]  UINT16 ? ?  目標(biāo)轉(zhuǎn)速(rpm)
0x2000[1]  FLOAT ? ? ? 加速度(m/s2)
0x2001 ? ? RECORD ? ?  故障代碼
0x2001[0]  BITFIELD ?  故障標(biāo)志位

STM32 SDO傳輸實現(xiàn)

// SDO客戶端上傳數(shù)據(jù)
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網(wǎng)絡(luò)管理

狀態(tài)遷移圖

INIT → PRE-OPERATIONAL → OPERATIONAL → STOPPED
 ? ↑ ? ? ?  ↑ ? ? ? ? ? ? ? ? ?  ↓
 ? └──RESET←───────────────────┘

心跳報文配置

// 心跳生產(chǎn)者配置
CO_NMT_HeartbeatConfig(0x01, 0x00, 500); ?// 節(jié)點(diǎn)ID=1,周期500ms

五、J1939協(xié)議核心要點(diǎn)

5.1 參數(shù)組號(PGN)編碼規(guī)則

PGN = PF(8b) << 8 | PS(8b)
PF: 參數(shù)組功能(0-255)
PS: 參數(shù)組子功能(0-255)

典型PGN解析

PGN PF PS 描述
0xFEFC 0xFE 0xFC 發(fā)動機(jī)轉(zhuǎn)速請求
0xFEF0 0xFE 0xF0 冷卻液溫度
0xFECA 0xFE 0xCA 車輛位置報告

5.2 多包數(shù)據(jù)傳輸

傳輸流程

請求 → 確認(rèn) → 數(shù)據(jù)包1 → 數(shù)據(jù)包2 → ... → 結(jié)束符

STM32多包發(fā)送實現(xiàn)

// 多包數(shù)據(jù)發(fā)送(最大12字節(jié)/包)
void CAN_Send_MultiPacket(uint8_t *data, uint16_t length) {
 ? ?uint8_t packets[6][8] = {0};
 ? ?uint8_t packet_count = (length + 7) / 8;
 ? ?
 ? ?for (int i=0; i<packet_count; i++) {
 ? ? ? ?packets[i][0] = 0x00; ?// 流控制字段
 ? ? ? ?memcpy(&packets[i][1], &data[i*8], 8);
 ? ? ? ?CAN_TransmitPacket(packets[i]);
 ?  }
}

六、STM32HAL庫實戰(zhàn)進(jìn)階

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 數(shù)據(jù)收發(fā)實戰(zhàn)

// 數(shù)據(jù)發(fā)送(PDO模擬)
void CAN_Send_PDO(uint8_t node_id, uint16_t position) {
 ?CAN_TxHeaderTypeDef TxHeader = {0};
 ?uint8_t TxData[8] = {0};
 ?
 ?TxHeader.StdId = 0x200 + node_id; ?// PDO ID
 ?TxHeader.IDE = CAN_ID_STD;
 ?TxHeader.DLC = 2;
 ?
 ?TxData[0] = (position >> 8) & 0xFF;
 ?TxData[1] = position & 0xFF;
 ?
 ?HAL_CAN_AddTxMessage(&hcan1, &TxHeader, TxData, &TxMailbox);
}
?
// 接收回調(diào)(帶錯誤檢測)
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) {
 ?CAN_RxHeaderTypeDef RxHeader;
 ?uint8_t RxData[8] = {0};
 ?
 ?if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, RxData) == HAL_OK) {
 ? ?if (RxHeader.DLC != 2) {
 ? ? ?// 數(shù)據(jù)長度異常處理
 ? ? ?return;
 ?  }
 ? ?uint16_t value = (RxData[0] << 8) | RxData[1];
 ? ?Process_Sensor_Data(value);
  }
}

七、工業(yè)級應(yīng)用案例解析

7.1 電動汽車三電系統(tǒng)

通信拓?fù)?/span>

BMS → CAN → MCU → CAN → 電機(jī)控制器
 ? ? ? ? ? ↑↓
 ? ? ? ? 充電樁

7.2 智能倉儲機(jī)器人

  • 多機(jī)協(xié)同:50+臺AGV通過CAN總線同步路徑規(guī)劃

  • 實時監(jiān)控:電量/故障狀態(tài)實時上報

  • 抗干擾方案:

    • 雙絞線屏蔽層接地

    • 隔離收發(fā)器(如ADuM1201)

    • 冗余幀重傳機(jī)制

八、調(diào)試與優(yōu)化技巧

1.示波器觀察

  • 檢查CAN_H/CAN_L差分波形(正常應(yīng)為方波

  • 波特率驗證(500Kbps對應(yīng)周期2μs)

2.錯誤分析

  • 錯誤幀計數(shù):HAL_CAN_GetError(&hcan1)

  • 總線負(fù)載率:CAN總線分析儀檢測

3.性能優(yōu)化

  • 使用CAN FD(Flexible Data Rate)提升帶寬

  • 優(yōu)化過濾器配置減少CPU開銷

  • 采用環(huán)形緩沖區(qū)處理高頻率數(shù)據(jù)

九、擴(kuò)展學(xué)習(xí)資源

  • 經(jīng)典CAN vs CAN FD:帶寬從1Mbps提升至5Mbps

  • AUTOSAR架構(gòu):標(biāo)準(zhǔn)化汽車軟件架構(gòu)

  • TSN時間敏感網(wǎng)絡(luò)工業(yè)4.0通信新標(biāo)準(zhǔn)

相關(guān)推薦