
作者 | 糊涂振
出品 | 汽車電子與軟件
在AUTOSAR架構的汽車電子開發中,CAN通信是最基礎、最核心的功能之一。很多初學者在理解了COM、PduR、CanIf、CanDrv等模塊的層次架構后,仍然對"代碼到底怎么跑"感到困惑:一個車速信號從應用層發出,經歷了哪些函數調用?網絡管理報文又是如何喚醒和維持網絡的?
今天,我們就扒開AUTOSAR的外衣,沿著CAN應用報文和網管報文兩條主線,完整追蹤它們從發送到接收的全過程。
01
AUTOSAR通信棧
的總體視圖
在深入細節之前,我們先建立整體認知,如下所示為基于AUTOSAR架構的CAN通訊棧:

由圖可知,AUTOSAR通信棧從上到下依次為:
- Application Layer(應用層):運行SWC(軟件組件),產生或消費信號;
- RTE(運行時環境):連接應用層與底層BSW的橋梁;
- COM:信號與PDU(協議數據單元)的打包/解包層;
- PduR(PDU路由器):PDU的路由分發中心;
- CanIf(CAN接口):屏蔽不同CAN控制器的硬件差異;
- CanDriver(CAN驅動):直接操作CAN控制器寄存器;
- MCAL(微控制器抽象層):硬件底層驅動;
- CAN收發器:物理層電平轉換。
此外,網絡管理相關的模塊包括ComM(通信管理器)、Nm(網絡管理)、CanNm(CAN網絡管理)和CanSM(CAN狀態管理器),它們共同控制通信棧的狀態切換。
整個通信棧的設計哲學是分層解耦 + 路由轉發。每一層只負責自己的職責,通過標準化的接口與上下層交互,上層永遠不需要關心下層的具體實現。
02
CAN應用報文發送過程:
從SWC到總線
假設我們需要發送一個車速信號,值為100 km/h。應用層的SWC中只有一行看似簡單的代碼:
Com_SendSignal(ComConf_ComSignal_VehicleSpeed, &VehicleSpeed);
但這行代碼背后,整個AUTOSAR通信棧開始高效運轉。
2.1 COM層:信號到PDU的轉換
COM模塊收到`Com_SendSignal`請求后,內部會經過多個子函數調用:
Com_SendSignal()
→ Com_SendSignalInternal()
→ Com_UpdateShadowSignal()
→ Com_TriggerIPDUSend()
那么調用這些函數做了什么事情,總結起來COM層主要完成四件事:
1. 信號更新:將新的信號值寫入影子緩沖區;
2. 字節打包:按照配置的起始位、長度、字節順序,將多個信號組裝到PDU中;
3. 大小端轉換:如果信號字節序與PDU要求不一致,進行轉換;
4. 觸發發送:當該PDU的所有信號都更新完畢,或達到發送觸發條件時,調用下層發送接口。

Source:https://geekli.blog.csdn.net/article/details/142671389
對于車速信號(uint16類型,值120 = 0x0078),假設PDU中Byte0和Byte1分別存放低字節和高字節,則打包結果為:Byte0 = 0x78,Byte1 = 0x00。
打包完成后,COM調用PduR的接口:PduR_ComTransmit(PduIdType id, const PduInfoType* info)。
2.2 PduR層:PDU路由中心
很多新人覺得PduR沒有存在感,但在AUTOSAR通信棧中,它是最重要的路由轉發中心。PduR內部維護了一張路由配置表,記錄了每個PDU ID對應的目標模塊。

Source:https://blog.csdn.net/geek_liyang/article/details/142745460
收到`PduR_ComTransmit`請求后,PduR根據PDU ID查找配置:
- 如果目標是CanIf,調用`CanIf_Transmit()`;
- 如果目標是LinIf,調用`LinIf_Transmit()`;
- 如果目標是多個模塊(網關場景),則逐個轉發。
這個過程就像快遞分揀中心:收到包裹,掃描標簽,決定發往哪個分揀口。PduR的存在使得上層模塊完全不需要知道下層是CAN、LIN還是ETH。
2.3 CanIf層:硬件抽象與發送校驗
CanIf(CAN Interface)的核心職責是屏蔽不同CAN控制器的硬件差異。無論下面使用的是TC397、S32K還是RH850,上層永遠調用統一的`CanIf_Transmit()`接口,應用層代碼無需任何修改。CanIf內部典型的發送流程包括:
CanIf_Transmit()
→ CanIf_CheckTxPdu() // 檢查PDU配置是否有效
→ CanIf_ControllerModeCheck() // 檢查CAN控制器狀態
→ Can_Write() // 調用驅動層接口
CanIf還會根據配置選擇發送模式:
- 立即發送:直接調用驅動發送;
- 存儲轉發:將PDU存入發送隊列,由后臺任務處理;
- 周期發送:根據周期配置自動觸發。

2.4 CanDrv層:驅動CAN控制器
終于來到最底層。CanDrv(CAN Driver)是真正操作硬件的地方:
Can_Write()
→ Can_lWrite() // 底層寫入函數
→ Can_HwTransmit() // 硬件發送觸發
→ 操作寄存器(如TC397的MCMCAN_TXBAR)

Source: https://geekli.blog.csdn.net/article/details/144489173
此時驅動開始操作CAN控制器的寄存器:
- 找到空閑的發送郵箱(Mailbox);
- 將PDU的ID、DLC、數據寫入郵箱;
- 設置發送請求位,觸發硬件發送。
這里注意一個重要概念:`Can_Write()`執行完成不代表報文已經發送到總線。它只是將發送請求提交給了CAN控制器,真正的發送過程由CAN控制器硬件獨立完成。
2.5 硬件發送與發送確認
CAN控制器獲得發送請求后,自動完成以下流程:
1. 仲裁:監聽總線,等待空閑,參與ID仲裁
2. 發送:逐位發送SOF、ID、控制場、數據場、CRC
3. 應答:等待接收節點發送ACK顯性位
4. 完成:發送結束,硬件置位發送完成標志
發送完成后,CAN控制器產生發送完成中斷。

Source:https://blog.csdn.net/monkea123/article/details/102880891
中斷服務程序觸發回調鏈:
Can_IsrTx()
→ CanIf_TxConfirmation(PduIdType PduId)
→ PduR_TxConfirmation(PduIdType id)
→ Com_TxConfirmation(PduIdType id)
Com收到發送確認后,可以:
- 清除發送緩沖區;
- 觸發上層回調通知應用層;
- 處理下一個等待發送的PDU。
因此,通過上述這個發送過程,我們可以總結下發送方向完整調用鏈:
Application (SWC)
↓ (RTE生成代碼調用)
Com_SendSignal()
↓ (COM內部打包)
Com_TriggerIPDUSend()
↓ (PduR路由)
PduR_ComTransmit()
↓ (CanIf接口)
CanIf_Transmit()
↓ (硬件校驗)
CanIf_ControllerModeCheck()
↓ (驅動調用)
Can_Write()
↓ (操作寄存器)
CAN Controller (硬件發送)
↓ (發送完成中斷)
Can_IsrTx()
↓ (確認回掉)
CanIf_TxConfirmation() → PduR_TxConfirmation() → Com_TxConfirmation()
↓ (可選)
Rte_ComTxConfirmation() → Application

Source: https://mp.weixin.qq.com/s/k5p5zgl-MwRQu0ELFJBfuw
03
CAN應用報文接收過程:
從總線到應用
接收過程與發送過程正好相反,觸發源是CAN控制器的接收中斷。
3.1 硬件接收與驅動層
當CAN總線上的報文經過濾波匹配后,CAN控制器接收該報文并產生接收中斷:
Can_IsrRx() // 中斷服務程序
→ Can_Read() // 讀取CAN控制器接收郵箱
→ 提取ID、DLC、數據
驅動層將讀取到的數據包裝成PDU結構,調用上層指示接口:
CanIf_RxIndication(Can_HwHandleType hrh, const Can_PduType* pduInfo)
3.2 CanIf層:ID到PDU映射
CanIf收到驅動層的接收指示后,需要完成ID到PDU句柄的映射。由于不同CAN控制器的硬件句柄格式不同,CanIf負責將這些差異屏蔽掉,統一調用:
PduR_CanIfRxIndication(PduIdType id, const PduInfoType* info)
3.3 PduR層:接收路由
PduR在接收方向同樣扮演路由中心角色。根據PDU ID查找配置,決定將PDU轉發給哪個上層模塊:
- 如果是一般應用報文,轉發給COM
- 如果是診斷報文,轉發給DCM(診斷通信管理)
- 如果是網絡管理報文,轉發給Nm
對于應用報文,調用`Com_RxIndication(PduIdType id, const PduInfoType* info)`。
3.4 COM層:PDU到信號的解包
COM收到接收指示后,內部執行:
Com_RxIndication()
→ 查找PDU對應的信號配置列表;
→ Com_UnpackSignal() // 根據信號位置、長度、字節序解析;
→ 信號值寫入對應的信號緩沖區;
→ 觸發信號回調(如果配置了);
解包過程需要考慮:
- 大小端:信號在PDU中的字節順序;
- 符號擴展:有符號信號的符號位擴展;
- 物理值轉換:原始值通過因子和偏移量計算物理值。
解包完成后,COM通過RTE將信號值傳遞給對應的SWC應用層:Rte_Write\_\\_\(&SignalValue)

由此不難總結CAN報文接收方向完整調用鏈,即:
CAN Bus
↓ (物理層傳輸)
CAN Transceiver
↓ (CAN_H/L差分信號轉邏輯電平)
CAN Controller (硬件接收、濾波)
↓ (接收中斷)
Can_IsrRx()
↓ (驅動讀取)
Can_Read()
↓ (CanIf指示)
CanIf_RxIndication()
↓ (PduR路由)
PduR_CanIfRxIndication()
↓ (COM指示)
Com_RxIndication()
↓ (COM解包)
Com_UnpackSignal()
↓ (RTE寫入)
Rte_Write()
↓ (SWC端口接收)
Application (SWC)
04
網絡管理報文收發:
喚醒與保持網絡
網絡管理報文與普通應用報文的處理流程有相似之處,但也有獨特之處。網絡管理的核心是協調網絡中所有節點的休眠和喚醒,優化整車功耗。
4.1 AUTOSAR網絡管理架構
AUTOSAR采用分布式直接網絡管理(類似OSEK NM的直接網絡管理),核心模塊包括:
- ComM:通信管理器,負責協調多個通信通道的狀態,是應用層請求通信的主入口
- Nm:網絡管理抽象層,實現狀態機、重復消息請求、總線休眠管理
- CanNm:CAN網絡管理實現,封裝/解析NM PDU,負責具體的NM報文收發
- CanSM:CAN狀態管理器,控制CAN控制器和收發器的上下電

Source:https://blog.csdn.net/qq_41908302/article/details/131904857
4.2 網絡管理報文發送過程
網絡管理報文發送的場景主要有兩種:主動發送和被動發送。

Source:https://blog.csdn.net/zhangkaidewd/article/details/146923733
場景一:應用請求網絡通信
應用層需要發送數據前,首先請求網絡通信:
ComM_RequestComMode(ComM_Channel_Can, COMM_FULL_COMMUNICATION)
ComM收到請求后:
1. 檢查當前通信狀態;
2. 如果網絡當前處于休眠狀態,調用Nm接口請求網絡:
Nm_NetworkRequest(NetworkHandleType network)
Nm模塊收到請求后,狀態機切換到重復消息狀態(Repeat Message State),并調用下層接口:CanNm_NetworkRequest(NetworkHandleType channel)
CanNm模塊負責構造NM PDU,內容包括:
- 源節點ID:本節點的地址;
- 用戶數據:可選的應用數據;
- 控制位:重復消息請求位、活動位等。
CanNm調用PduR發送NM PDU:PduR_CanNmTransmit(PduIdType id, const PduInfoType* info)
之后的路徑與普通應用報文完全一致:
PduR → CanIf → CanDrv → CAN Controller → CAN Bus
場景二:周期性發送NM報文
一旦網絡進入正常工作狀態(Normal Operation State),CanNm需要按照配置周期(如100ms)主動發送NM報文,以告知其他節點本節點仍然在線。這個周期性發送由CanNm內部的周期任務觸發,不需要上層的顯式請求,發送路徑與上面相同。

Source:https://blog.csdn.net/zhangkaidewd/article/details/146923733
4.3 網絡管理報文接收過程
網絡管理報文的接收路徑與普通應用報文在前半部分一致,直到PduR層發生路由分化。
當CAN總線上的NM報文被接收,經過CanDrv → CanIf → PduR后,PduR根據PDU ID識別出這是NM報文,調用:Nm_RxIndication(NetworkHandleType network, const Nm_PduInfoType* info),Nm模塊收到指示后,執行狀態機邏輯:
1. 解析NM PDU:提取源節點ID和控制位;
2. 狀態更新:
- 如果當前處于休眠狀態,收到NM報文會喚醒網絡;
- 如果進入重復消息狀態,設置重復消息請求標志;
- 正常工作狀態下,更新該節點的存活時間戳。
3. 觸發Nm回調:通知ComM網絡已被激活;
ComM收到網絡激活通知后,會進一步通知CanSM控制CAN收發器進入正常工作模式,準備收發應用報文。
4.4 網絡休眠過程
當所有節點都不再需要通信時,網絡進入休眠過程:
1. 應用層調用:`ComM_RequestComMode(Channle, COMM_NO_COMMUNICATION)`;
2. ComM請求Nm釋放網絡:`Nm_NetworkRelease()`;
3. Nm啟動休眠計時器:等待其他節點可能發送的NM報文;
4. 計時超時后,Nm通知CanNm進入休眠準備:CanNm_PassiveStartup();
5. CanNm停止發送NM報文,并通知CanSM關閉CAN控制器:CanSM_RequestBusOffMode(Channel) → Can_Disable();
6. CanSM進一步控制收發器進入休眠或斷電。

Source:https://blog.csdn.net/zhangkaidewd/article/details/146923733
05
應用報文與網管報文
的交互場景
在實際系統中,應用報文和網管報文是協同工作的。以喚醒后發送CAN報文的完整流程為例:
1. 總線喚醒(被動或主動)
- 主動喚醒:應用調用ComM請求通信 → ComM調用Nm請求網絡 → CanNm發送NM報文 → 總線喚醒;
- 被動喚醒:收到NM報文觸發接收中斷 → Nm喚醒網絡 → ComM通知應用。
2. 等待網絡穩定
- Nm進入重復消息狀態;
- Nm持續發送NM報文(如10條);
- 其他節點看到NM報文后,知道網絡正在建立。
3. 應用開始發送數據
- 網絡進入正常工作狀態后;
- ComM回調RTE,允許SWC發送數據;
- 應用調用`Com_SendSignal()`,報文經過PduR→CanIf→CanDrv發出。
4. 周期性保活
- 應用持續發送數據期間;
- CanNm定時器周期性觸發,發送NM報文;
- 其他節點收到NM報文,重置各自的休眠計時器。
5. 停止通信與休眠
- 應用發送完成,調用ComM釋放網絡;
- Nm啟動休眠計時(如2秒);
- 2秒內如果收到其他節點NM報文,重置計時器;
- 計時超時,Nm停止發送NM報文,關閉CAN控制器和收發器。
06
小 結
以Vector MICROSAR為例,一個普通CAN信號從`Com_SendSignal()`到真正發出,通常經過10~20個函數調用。如果包含網關路由、診斷通信、TP分包、安全認證等高級功能,調用深度可能達到30個以上。這也是為什么新人第一次調試AUTOSAR時,單步跟蹤會感覺"永遠跟不到頭"。
但理解了每一層的職責和數據流向,這些復雜性就變得有條理起來。AUTOSAR通信棧本質上是一條層層轉發的數據流水線,而不是幾個獨立模塊的簡單堆疊。當你能夠獨立追蹤一條信號從應用到總線的完整路徑,并理解網絡管理如何在幕后協調整車的通信狀態,你就真正掌握了AUTOSAR通信的精髓。
總的來說,AUTOSAR通信棧的核心不在于記住每個模塊的名字,而在于理解數據如何在COM的打包、PduR的路由、CanIf的抽象、CanDrv的驅動和Nm的狀態機之間層層流轉,最終完成從應用到總線的完整閉環。
