我自己的原文哦~? ? ? ?https://blog.51cto.com/whaosoft/14016935
一、CAN總線常見信號干擾問題
定位干擾原因
????當總線有干擾時,有經驗的工程師能夠迅速定位,但是對于新手來說卻很麻煩。
????造成總線干擾的原因有很多,比如通過電磁輻射耦合到通訊電纜中、屏蔽線接地沒處理好、隔離了通訊沒有隔離電源等。通過下圖我們可以推導出,現場的干擾不是通過電磁輻射進來,整車的網絡也沒有干擾,基本可以斷定干擾就是電機驅動器的CAN通訊沒隔離好。
圖1 定位干擾原因
消除延時誤差的方法
????為了減小延時,增加通訊距離和降低通訊錯誤率,我們可以采取以下措施:
- 采用磁隔離的CTM1051方案設計接口收發電路;
- 用較粗的導線代替細導線,標準為1.5線纜(延遲為5ns/m);
- 使用鍍金或鍍銀的線纜;
- 增加網橋中繼設備CANBridge延長通訊距離;
- 采用光纖傳輸,如致遠電子的CANHUB-AF1S1,同等波特率可延長1倍通訊距離。
信號地(CAN-GND)
1 信號地概念
????信號地也稱為隔離地,為使電子設備工作時有一個統一的參考電位,避免有害電磁場的干擾,使設備穩定可靠的工作,設備中的信號電路統一參考地,即CAN-GND。
2 信號地處理
????許多實際應用中,設計者常直接將每個節點的參考地接于本地的大地,作為信號的返回地,看似正常可靠的做法,卻存在極大的隱患!
????信號地(CAN-GND)正確的接法主要分為兩種:
????單屏蔽層線纜:如果線纜是單屏蔽層,信號地理想接法是使用專門的信號線將所有節點信號地連接,起到參考地的作用。但如果缺少信號地線,亦可將所有節點信號地都連接到屏蔽層,但這樣屏蔽效果亦差強人意。
????如下圖,帶有屏蔽層雙絞線。
??如下圖,含信號地線雙絞線連接方式。
?下圖,信號地與屏蔽層連接方式。
????雙屏蔽層線纜:當使用雙層屏蔽電纜時,需要將所有節點信號地連接到內屏蔽層,若使用非屏蔽線進行數據傳輸時,請保持信號地管腳懸空處理。
????下圖,是雙屏蔽層信號地處理方式。
????所有節點信號地接到屏蔽層或者雙屏蔽層的內層后,屏蔽層處理方式注意為單點接地,不可多點接地,否則會在信號地線上形成地環流。
????另外,單點接地時為了加大供電地和信號地之間的隔離電阻,阻止共地阻抗電路耦合產生的電磁干擾,注意采用隔離浮地設計,通過阻容方式將屏蔽層與外殼隔離。如下圖所示,未進行單點接地處理的報文受到電磁干擾。
二、CAN總線錯誤分析與解決
從實際工作中碰到的具體問題來分析一些常見的CAN總線錯誤和解決辦法。
CAN節點數據收發過程
我們知道,CAN總線上的每個節點往總線上發送數據的同時,會讀取總線上的數據,并與自己發送的數據作對比。
CAN信息發送成功后,在這個間隙內,接收節點可以準備要回復的信息,也就是把應答場填充為顯性0,在發送時其為隱性1。
應答過程可能如下:當信息傳輸到ACK前的Del時,可以認為信息已經傳輸完畢,接收節點也接收到了足夠的信息來檢測接收的信息是否正確。
這時接收節點就會檢測信號是否正確,如果正確,就將ACK置位為顯性0,注意這時,發送節點因為還在發送而接收節點又將ACK信息置位為1,所以它就會在回讀時檢測到ACK為0,判斷接收成功。
注意:這其中有個接收節點用顯性覆蓋隱性---覆蓋ACK位的過程,覆蓋+回讀。
ACK前后各加一個Del,就是為了考慮到時間誤差,讓接收節點有足夠的時間對ACK確認。這個過程說明,CAN發送是個雙向互動的過程,發送節點一邊發送,一邊對節點進行回收確認數據正確,而接收節點也時刻接收,并在正確的時間將ACK設置為1。
CAN總線錯誤
CAN總線錯誤分別有發送和接收錯誤計數,計數達到一定的累計以后就會產生CAN BUS OFF, 這說明CAN總線上出現了嚴重的錯誤。
如下圖CAN總線產生錯誤后的狀態轉換機制:
如果出現了BUS OFF,總線上的節點需要做一些動作,例如重啟CAN控制器或是重新上電,但是這些都只是一些補救措施,最根本的還是需要找到引起BUS OFF的根源。
CAN總線分析的一些工具和文檔:
- CAN分析儀或者邏輯分析儀
- 數字示波器
- 相關的軟件debug工具
- CAN控制器芯片數據手冊
- 硬件電路圖
- CAN協議文檔
CAN節點發送錯誤不成功
掛載在CAN總線上的一個節點向總線上發送數據不成功,用邏輯分析儀也看不到任何波形。
下面具體來看看怎么不成功。于是調試中斷查看 CAN_STATUS 即 CAN狀態寄存器顯示 0xE5, 查看CPU數據手冊:
CAN總線狀態直接進入了BUS OFF狀態,這意味著錯誤計數已經超限,查看CPU收發寄存器的收發錯誤計數顯示發送錯誤計數TEC達到248, 接收錯誤計數為0。這很明顯,數據壓根沒有發送到總線上。再進一步查看寄存器值LEC即LAST ERROR CODE 最后一個錯誤代碼, 顯示是BIT0 ERROR。?
查看上面的錯誤代碼表可知,BIT0 錯誤也就是在發送數據期間,雖然CAN節點設備想要發送一個顯性位,也就是邏輯0,但是CAN總線同時監聽到總線上的數據位為隱性位,即邏輯1。
這意味著CAN core往總線上發送的數據第一位就已經出錯了,壓根沒有將數據經過CAN收發器傳送到CAN總線上。
由于是新的CPU的開發所以在懷疑硬件的問題的同時也在排查軟件問題,但是經過一陣排查,沒有發現軟件上的問題。回頭再分析硬件,又經過一陣排查溯源,發現 CPU 的 CAN 收發線與 CAN 收發器的收發線接反了。
總結
CAN節點發送數據不成功,首先分析是不是CAN控制器本身的問題,查看CPU中的CAN core的狀態寄存器,分析是否有BUS OFF, 如果存在BUS OFF, 則進一步查看具體的錯誤信息。
是主動的錯誤還是被動的錯,發送錯誤計數有沒有超限,最后一次發生的錯誤狀態是什么,查看是位填充錯誤還是格式錯誤等其他錯誤,然后具體問題具體分析。
三、使用時出現的一次錯誤
最近負責的一個項目用的主控芯片是??STM32F407IGT6?
??,需要和幾個電機控制器進行通訊,有很多參數需要進行監控。
有一個問題一直無法解決。在開啟???CAN?
?的接收中斷,接收不到數據,問題卡了很久,下面簡單分享一下解決的過程和思路。
CAN總線
CAN總線是一種串行通信協議,用于在微控制器和其他設備之間傳輸數據。CAN總線通常用于汽車、工業自動化和機器人等領域。
CAN總線的硬件通常由以下幾個部分組成:
- 控制器區域:包括CAN控制器和CAN收發器;
- 總線電纜:用于連接CAN總線上的所有設備;
- 終端電阻:用于終止總線,以減少反射和信號干擾;
- 外部電源:用于為CAN總線提供電源;
CAN總線的控制器區域通常包括CAN控制器和CAN收發器。
- CAN控制器負責處理CAN總線上的數據傳輸,包括數據發送和接收、錯誤檢測和糾正等;
- CAN收發器則負責將CAN控制器的信號轉換為總線上的電信號,并將總線上的電信號轉換為CAN控制器可以理解的信號。
CAN控制器
主板上的芯片??STM32F407IGT6?
?中帶有兩路的CAN控制器,分別為??CAN1?
???和???CAN2?
?,具體如下圖所示;
CAN收發器
主板上使用的是芯片??SN65HVD230?
?,這是TI公司的一款性能強大且具體低功耗功能的CAN收發器,具體的典型應用電路如下所示;
調試過程
硬件排查
設備的調試過程中,首先要確保硬件鏈路上是否正常。最常見的方法就是直接用示波器進行檢查。具體如下所示;
- 檢查CAN控制器和CAN收發器之間是否正常;
- 檢查CAN收發器的差分信號是否正常,這里可能要了解一下CAN總線電平的顯性電平和隱性電平的特點,以及CAN底層協議的細節,會比較復雜;
個人比較推薦使用上述步驟檢查硬件鏈路是否存在問題,那如何對數據進行分析呢?當然可以對著示波器的波形一點一點進行分析,但是這樣是很低效的,這里我建議使用CAN分析儀進行數據抓包,下面我們繼續進行介紹。
CAN分析儀
至于數據傳輸是否正確,可以使用CAN盒進行數據監聽,下面是我使用的一款CAN分析儀,如圖;
將CAN分析儀的??CAN_H?
??和??CAN_L?
??分別并聯到CAN收發器的??CAN_H?
??和??CAN_L?
?上,然后打開CAN分析儀廠家提供的PC軟件,就可以對CAN總線的數據進行監聽;
- 將CAN分析儀接入到CAN總線;
- 將CAN分析儀連接到電腦(這里是USB接口),需要配置相同的波特率;
- 打開CAN分析儀配套的PC軟件,進行數據的收發;
- 進行到這里,我在項目中遇到的問題是,發送正常,但是?
?STM32F407?
??無法接收到連續的數據,可以接收到一次數據,后面便無法再進入中斷。這時候,只能再芯片端進行??Debug?
?了。
芯片CAN控制器調試
這里的代碼用的HAL庫,庫版本相對來說比較老,是??V1.7.10?
?版本的,如下圖所示;
當時我把項目升級到最新的HAL庫,發現CAN部分的驅動改動比較大,另外,下文都是基于??V1.7.10?
?版本的HAL庫。
CAN控制器的初始化代碼如下所示;
void MX_CAN_Init(void)
{CAN_FilterConfTypeDef sFilterConfig;/*CAN單元初始化*/hCAN.Instance = CANx; /* CAN外設 */hCAN.pTxMsg = &TxMessage;hCAN.pRxMsg = &RxMessage;hCAN.Init.Prescaler = 6; /* BTR-BRP 波特率分頻器 定義了時間單元的時間長度 42/(1+6+7)/6 = 500Kbps */hCAN.Init.Mode = CAN_MODE_NORMAL; /* 正常工作模式 */hCAN.Init.SJW = CAN_SJW_1TQ; /* BTR-SJW 重新同步跳躍寬度 1個時間單元 */hCAN.Init.BS1 = CAN_BS1_6TQ; /* BTR-TS1 時間段1 占用了6個時間單元 */hCAN.Init.BS2 = CAN_BS2_7TQ; /* BTR-TS1 時間段2 占用了7個時間單元 */hCAN.Init.TTCM = DISABLE; /* MCR-TTCM 關閉時間觸發通信模式使能 */hCAN.Init.ABOM = ENABLE; /* MCR-ABOM 自動離線管理 */hCAN.Init.AWUM = ENABLE; /* MCR-AWUM 使用自動喚醒模式 */hCAN.Init.NART = DISABLE; /* MCR-NART 禁止報文自動重傳 DISABLE-自動重傳 */hCAN.Init.RFLM = DISABLE; /* MCR-RFLM 接收FIFO 鎖定模式 DISABLE-溢出時新報文會覆蓋原有報文 */hCAN.Init.TXFP = DISABLE; /* MCR-TXFP 發送FIFO優先級 DISABLE-優先級取決于報文標示符 */HAL_CAN_Init(&hCAN);/*CAN過濾器初始化*/sFilterConfig.FilterNumber = 0; /* 過濾器組0 */sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; /* 工作在標識符屏蔽位模式 */sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; /* 過濾器位寬為單個32位。*//* 使能報文標示符過濾器按照標示符的內容進行比對過濾,擴展ID不是如下的就拋棄掉,是的話,會存入FIFO0。 */sFilterConfig.FilterIdHigh = 0x0000; //(((uint32_t)0x1314<<3)&0xFFFF0000)>>16; /* 要過濾的ID高位 */sFilterConfig.FilterIdLow = 0x0000; //(((uint32_t)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; /* 要過濾的ID低位 */sFilterConfig.FilterMaskIdHigh = 0x0000; /* 過濾器高16位每位必須匹配 */sFilterConfig.FilterMaskIdLow = 0x0000; /* 過濾器低16位每位必須匹配 */sFilterConfig.FilterFIFOAssignment = 0; /* 過濾器被關聯到FIFO 0 */sFilterConfig.FilterActivation = ENABLE; /* 使能過濾器 */ sFilterConfig.BankNumber = 14;HAL_CAN_ConfigFilter(&hCAN, &sFilterConfig);}
根據注釋,可以大概看懂,另外再簡單分析一下關鍵的幾點;
- 波特率設置為 500Kbps;
- 對報文不進行過濾,可以接收任何擴展ID的數據;
雖然不進行任何過濾,但是還是無法接收到CAN回傳的數據,無法進入的接收中斷;
從STM32F407的編程手冊里了解到;
不難發現,??CAN1?
??的??FIFO0?
?產生接收中斷需要滿足三個條件中的任意一個;
- ?
?FMPIE0?
??置??1?
???且???FMP0?
??置??1?
?;FIFO不為空會產生中斷 - ?
?FFIE0?
??置??1?
???且???FULL?
??置??1?
?;FIFO滿,會產生中斷 - ?
?FOVIE0?
??置??1?
???且???FOVR0?
??置??1?
?;FIFO溢出,會產生中斷
手冊里是這樣描述的,如下圖所示;
使用仿真器對芯片進行調試,設置斷點,發現??FMPIE0?
?被清空了,具體如下圖所示;?
??FMPIE0?
?這一位是FIFO0中有掛起的消息會產生中斷的中斷使能標志位;
所以到這里,問題有點明朗了,為什么無法進入中斷?是中斷使能位被清空了。
那么下面就是檢查代碼,看看是哪里把中斷給??disable?
?了。
繼續調試,發現在??ESR?
??寄存器中,??TEC?
??的值一直增加,然后??EWGF?
??被值??1?
?了;具體如下所示;
??TEC?
??和??REC?
?分別是發送錯誤計數器和接收錯誤計數器;
如 CAN 協議所述,錯誤管理完全由硬件通過發送錯誤計數器( CAN_ESR 寄存器中的 TEC 值)和接收錯誤計數器( CAN_ESR 寄存器中的 REC 值)來處理,這兩個計數器根據錯誤 狀況進行遞增或遞減。有關 TEC 和 REC 管理的詳細信息,請參見 CAN 標準。兩者均可由軟件讀取,用以確定網絡的穩定性。此外, CAN 硬件還將在 CAN_ESR 寄存器中 提供當前錯誤狀態的詳細信息。通過 CAN_IER 寄存器( ERRIE 位等),軟件可以非常靈活 地配置在檢測到錯誤時生成的中斷。
當??TEC?
?大于96的時候,硬件會將??EWGF?
??置??1?
?(錯誤警告標志位);在代碼中找到了相應的宏定義;這下問題越來越清晰了。
全文搜索這個宏定義,在??HAL_CAN_IRQHandler?
??中找到了??__HAL_CAN_DISABLE_IT(CAN_IT_FMP0)?
??,關閉了??FIFO0?
?的消息掛起中斷, 整體代碼如下;
/*** @brief Handles CAN interrupt request * @param hcan: pointer to a CAN_HandleTypeDef structure that contains* the configuration information for the specified CAN.* @retval None*/
void HAL_CAN_IRQHandler(CAN_HandleTypeDef* hcan)
{uint32_t tmp1 = 0U, tmp2 = 0U, tmp3 = 0U;uint32_t errorcode = HAL_CAN_ERROR_NONE;/* Check Overrun flag for FIFO0 */tmp1 = __HAL_CAN_GET_FLAG(hcan, CAN_FLAG_FOV0);tmp2 = __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_FOV0);if(tmp1 && tmp2){/* Set CAN error code to FOV0 error */errorcode |= HAL_CAN_ERROR_FOV0;/* Clear FIFO0 Overrun Flag */__HAL_CAN_CLEAR_FLAG(hcan, CAN_FLAG_FOV0);}/* Check Overrun flag for FIFO1 */tmp1 = __HAL_CAN_GET_FLAG(hcan, CAN_FLAG_FOV1);tmp2 = __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_FOV1);if(tmp1 && tmp2){/* Set CAN error code to FOV1 error */errorcode |= HAL_CAN_ERROR_FOV1;/* Clear FIFO1 Overrun Flag */__HAL_CAN_CLEAR_FLAG(hcan, CAN_FLAG_FOV1);}/* Check End of transmission flag */if(__HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_TME)){tmp1 = __HAL_CAN_TRANSMIT_STATUS(hcan, CAN_TXMAILBOX_0);tmp2 = __HAL_CAN_TRANSMIT_STATUS(hcan, CAN_TXMAILBOX_1);tmp3 = __HAL_CAN_TRANSMIT_STATUS(hcan, CAN_TXMAILBOX_2);if(tmp1 || tmp2 || tmp3) {tmp1 = __HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK0);tmp2 = __HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK1);tmp3 = __HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK2);/* Check Transmit success */if(tmp1 || tmp2 || tmp3){/* Call transmit function */CAN_Transmit_IT(hcan);}else /* Transmit failure */{/* Set CAN error code to TXFAIL error */errorcode |= HAL_CAN_ERROR_TXFAIL;}/* Clear transmission status flags (RQCPx and TXOKx) */SET_BIT(hcan->Instance->TSR, CAN_TSR_RQCP0 | CAN_TSR_RQCP1 | CAN_TSR_RQCP2 | \CAN_FLAG_TXOK0 | CAN_FLAG_TXOK1 | CAN_FLAG_TXOK2);}}tmp1 = __HAL_CAN_MSG_PENDING(hcan, CAN_FIFO0);tmp2 = __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_FMP0);/* Check End of reception flag for FIFO0 */if((tmp1 != 0U) && tmp2){/* Call receive function */CAN_Receive_IT(hcan, CAN_FIFO0);}tmp1 = __HAL_CAN_MSG_PENDING(hcan, CAN_FIFO1);tmp2 = __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_FMP1);/* Check End of reception flag for FIFO1 */if((tmp1 != 0U) && tmp2){/* Call receive function */CAN_Receive_IT(hcan, CAN_FIFO1);}/* Set error code in handle */hcan->ErrorCode |= errorcode;tmp1 = __HAL_CAN_GET_FLAG(hcan, CAN_FLAG_EWG);tmp2 = __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_EWG);tmp3 = __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_ERR);/* Check Error Warning Flag */if(tmp1 && tmp2 && tmp3){/* Set CAN error code to EWG error */hcan->ErrorCode |= HAL_CAN_ERROR_EWG;}tmp1 = __HAL_CAN_GET_FLAG(hcan, CAN_FLAG_EPV);tmp2 = __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_EPV);tmp3 = __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_ERR); /* Check Error Passive Flag */if(tmp1 && tmp2 && tmp3){/* Set CAN error code to EPV error */hcan->ErrorCode |= HAL_CAN_ERROR_EPV;}tmp1 = __HAL_CAN_GET_FLAG(hcan, CAN_FLAG_BOF);tmp2 = __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_BOF);tmp3 = __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_ERR); /* Check Bus-Off Flag */if(tmp1 && tmp2 && tmp3){/* Set CAN error code to BOF error */hcan->ErrorCode |= HAL_CAN_ERROR_BOF;}tmp1 = HAL_IS_BIT_CLR(hcan->Instance->ESR, CAN_ESR_LEC);tmp2 = __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_LEC);tmp3 = __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_ERR);/* Check Last error code Flag */if((!tmp1) && tmp2 && tmp3){tmp1 = (hcan->Instance->ESR) & CAN_ESR_LEC;switch(tmp1){case(CAN_ESR_LEC_0):/* Set CAN error code to STF error */hcan->ErrorCode |= HAL_CAN_ERROR_STF;break;case(CAN_ESR_LEC_1):/* Set CAN error code to FOR error */hcan->ErrorCode |= HAL_CAN_ERROR_FOR;break;case(CAN_ESR_LEC_1 | CAN_ESR_LEC_0):/* Set CAN error code to ACK error */hcan->ErrorCode |= HAL_CAN_ERROR_ACK;break;case(CAN_ESR_LEC_2):/* Set CAN error code to BR error */hcan->ErrorCode |= HAL_CAN_ERROR_BR;break;case(CAN_ESR_LEC_2 | CAN_ESR_LEC_0):/* Set CAN error code to BD error */hcan->ErrorCode |= HAL_CAN_ERROR_BD;break;case(CAN_ESR_LEC_2 | CAN_ESR_LEC_1):/* Set CAN error code to CRC error */hcan->ErrorCode |= HAL_CAN_ERROR_CRC;break;default:break;}/* Clear Last error code Flag */ hcan->Instance->ESR &= ~(CAN_ESR_LEC);}/* Call the Error call Back in case of Errors */if(hcan->ErrorCode != HAL_CAN_ERROR_NONE){/* Clear ERRI Flag */ hcan->Instance->MSR = CAN_MSR_ERRI; /* Set the CAN state ready to be able to start again the process */hcan->State = HAL_CAN_STATE_READY;/* Disable interrupts: *//* - Disable Error warning Interrupt *//* - Disable Error passive Interrupt *//* - Disable Bus-off Interrupt *//* - Disable Last error code Interrupt *//* - Disable Error Interrupt *//* - Disable FIFO 0 message pending Interrupt *//* - Disable FIFO 0 Overrun Interrupt *//* - Disable FIFO 1 message pending Interrupt *//* - Disable FIFO 1 Overrun Interrupt *//* - Disable Transmit mailbox empty Interrupt */__HAL_CAN_DISABLE_IT(hcan, CAN_IT_EWG |CAN_IT_EPV |CAN_IT_BOF |CAN_IT_LEC |CAN_IT_ERR |CAN_IT_FMP0|CAN_IT_FOV0|CAN_IT_FMP1|CAN_IT_FOV1|CAN_IT_TME);/* Call Error callback function */HAL_CAN_ErrorCallback(hcan);}
}
最后,找到無法進入接收中斷的原因,是CAN總線出現發送錯誤的情況,從而觸發了錯誤警告標志位??EWGF?
?,進而將關閉了消息掛起中斷。
總結
這里簡單介紹了在STM32F407上的CAN總線調試過程,項目中難免會遇到各種問題,解決之后,大家要及時做好總結和復盤,技術在于積累和沉淀,相互學習,共同進步。
四、用示波器排查CAN的各種錯誤幀
摘要:CAN的BusOff源于錯誤幀的積累,而錯誤幀這個東西,是一個接收節點 認為數據有誤 故意打斷通信,好讓發送節點感知到 并重發報文的設計。注意這里邊有個“我覺得你有病”的認知陷阱,讓CAN的診斷變得近似玄學。本文分享一種用CAN波形的幅度和脈寬信息來精確定位錯誤幀來源的方法,來自知乎的大燈。
我們先從基礎的講起。CAN節點的電路一般如下圖所示,MCU內置了CAN控制器用來將MCU的數據封裝為CAN幀格式,同時它也負責CAN幀的校驗和錯誤幀的處理。控制器封裝好的邏輯報文經TX RX送到CAN收發器,將邏輯信號轉變為真正的總線差分波形。
1、CAN物理層
也就是CAN收發器干了啥?
一個典型的雙節點CAN網絡的物理層等效電路如上圖,兩顆120Ω終端電阻并聯呈現總線電阻60Ω。黑框里是A、B兩個節點的CAN收發器(Transceiver),它只負責電平轉換。當總線靜默時,收發器內部的2.5V電源經15KΩ電阻把CAN-H和CAN-L都拉到2.5V,總線這個狀態稱之為隱性。當節點A想要驅動總線的時候(TX=0),它同時把內部的上下兩個MOS管導通,整個網絡的電流流向:節點A的5V電源經二極管、24Ω、兩顆終端電阻并聯、24Ω、二極管回到節點A的地,總線這個狀態稱之為顯性。CAN總線上的電壓實際上就是終端電阻的分壓。從節點B來看,CAN-H就變成3.5V,CAN-L變成1.5V,拉出了總線 H - L = 2V 的差分電壓,大于0.7V的判斷閾值,節點B就認為收到了一個顯性(RX=0)。大家可以算一下分壓值以增強記憶,后邊會用到。
反直覺知識點①:總線無人驅動時,也就是各個節點都隱性時,CAN標準定義這時的TX/RX邏輯電平為1;總線有節點驅動顯性,也就是主動拉開差分電壓的時候,對應TX/RX端邏輯電平0,這個1/0的反邏輯類似I2C等OC門的驅動邏輯,努力適應一下。這么做我猜有兩個原因:一是對地邏輯的抗擾能力強一些,NPN載流能力強&回流路徑短;二是為了數學上的嚴謹性:1x1x1x1...1x0 = 0,任意節點驅動顯性0,那總線就是顯性0;所有節點隱性1,總線才是隱性1。但這樣的反邏輯帶來一個問題是,電路設計時需要尤其注意上下電時序,上電/休眠/喚醒過程中千萬不要出現MCU已下電(TX拉低)但CAN收發器還供5V電的情況。如果實在難以避免,可以試試單3.3V的CAN收發器MAX3051,它不需要5V電源,邏輯電和驅動電共用同一路3.3V,肯定不會出現電源時序問題。
反直覺知識點②:理論上CAN_L短地,或 CAN_H短路12V,因60Ω終端電阻的存在,隱性時CAN-H與CAN-L之間基本還是重合的,顯性時也能正常拉開壓差,能維持正常通信,只不過丟包率可能會大一點。大家可以算算總線電壓,示波器很容易診斷這個問題。另外,如果你看到CAN的通信電壓不是以2.5V為中心對稱的,也有可能是多個CAN線交叉錯接,比如CAN1_L錯接到了CAN2_L上。
反直覺知識點③:一個CAN網絡里,120Ω終端電阻1~4顆都能工作,少了的話 離終端電阻遠的節點 抗擾度會差,多了的話 顯性差分電壓可能無法觸發閾值。
反直覺知識點④:除了線路的最遠端,任何稍長的CAN分支都可以加1K~4.7K的支線電阻,跑點電流來改善抗擾度。只要分支別太長,大致1Mbps以內的任何總線其終端電阻都是跑電流增強抗擾的,不涉及真正的阻抗或者反射抑制,雙絞的要求也不是特別嚴格。
2、CAN鏈路層
也就是CAN控制器干了啥?
回顧完物理層,咱來看鏈路層,CAN幀的標準格式。當發送節的MCU將TX由1變0的時候,CAN收發器將CAN-H拉高&CAN-L拉低,接收節點收到了H-L>0.7V的壓差后,接收節點的CAN收發器RX輸出由1變0。下圖是一個節點接收到CAN波形后解碼出的RX邏輯。
一幀報文里邊有比較關鍵的幾段:仲裁段、控制段 、 數據段、CRC段、ACK段。
仲裁段中的大部分是CAN報文的ID,起名為“仲裁”其實是因為這一段有優先級仲裁的功能:假設A、B兩個節點在同一時刻搶發報文,節點A要發二進制ID為001的報文,B要發010。當A、B節點都在發第一位的顯性0的時候,總線會同時被兩個節點驅動顯性,A、B節點回讀總線也都是顯性,相互之間還意識不到對方的存在。當節點A發到第二位的0,節點B發到第二位的1的時候,總線只有節點A驅動顯性0,節點B不驅動 卻發現總線被別人驅動了,此時節點B會認為CAN線上有比自己這幀010優先級更高的數據,節點B就會主動停發,讓節點A獨占總線發完。之后節點B懷揣著這幀數據再次參與總線優先級的仲裁。
反直覺知識點①:CAN作為一個對等網絡,沒有主從關系,報文全部廣播,節點本身也沒有優先級概念,只有報文ID的優先級。可以這么理解:CAN節點是“由事件驅動的”,比如剎車制動器,它能發高優先級的“剎車被踩下”的報文,也會發低優先級的“剎車油位正常”的報文,這些報文根據ID的大小在總線上自由競爭優先級,而不是剎車制動器這個節點的話語權一定高。這個特性就要求設計人員提前規劃好所有報文優先級和周期(即“通信矩陣”)才能保證整個CAN網絡如期運轉。如果你的CAN網絡有大量雷同節點,節點又只有一幀報文,那么ID數大(優先級低)的節點一定會在總線繁忙或干擾重發的時候"插不上話",可以試試把時間戳融合到ID里邊,確保各節點的新數據優先級最高,舊數據自然會被仲裁掉。
反直覺知識點②:在A、B節點同時驅動第一個顯性0的時候,總線被兩個節點同時驅動,電壓會顯著高于2V。示波器上會看到在仲裁段的頭部有明顯的電平凸臺,后續節點A搶占總線之后電壓會回歸正常的2V。
反直覺知識點③:各個節點的時鐘同步是把每個bit做16~20份的數字切片來實現的,這個切的份數不建議太多或太少。詳細機制請參閱 ZLG致遠電子的這篇:CAN同步機制,你真的了解嗎?
控制段中有幾個控制位,這里拿幾個常用的舉例。IDE位為擴展ID的指示。如果IDE位為隱性1,就會在后邊再續上18位的ID,共11+18=29位長度。比如0x9E就是個11位長度的ID,0x0151就是個29位的ID。R0位是CAN里邊的預留位,在CAN-FD里被用作FD幀格式的標志位FDF,這一位為隱性1就會按FD的幀格式解碼后續報文。DLC指示了后邊的數據段的長度,例如1000表示后續會有8個Byte長度的數據。CAN-FD協議只在數據段會切換成高速率,比如2Mbps/8Mbps,前后其他段的速率保持500kbps不變。
反直覺知識點①:CAN與CAN-FD除了數據段波特率的不同,幀格式也有區別,CAN-FD多了一些控制位。比如FDF(也叫EDL)位用來指示是否按FD幀格式解碼,BRS位用來指示是否需要切換高波特率,也就是說,一個FD幀可以全程500kbps不切速率的。
反直覺知識點②:CAN控制器的標準ISO11898-1里要求接收方不解讀R0位的顯隱性,所以CAN的控制器無法過濾FD幀。標準CAN網絡里邊一旦出現FD幀會因為多了BRS、ESI等控制位被認為是格式錯誤。同樣的,因為CAN 2.0時代R0/FDF幀無意義,也有一些設備把發送出去的CAN幀的R0位錯誤地置了隱性1,這樣的設備在CAN網絡里一切正常,但若進入CAN-FD網絡就會被解讀成FD幀,進而因為缺少BRS、ESI等控制位被認為是格式錯誤。所以,CAN-FD并不是真的向下兼容CAN,因為舊時代的CAN設備并沒有判別R0/FDF位的能力,一旦它進入FD網絡就會瘋狂地打斷通信。
反直覺知識點③:DLC的長度,在CAN標準里DLC可以是0000~1000之間的二進制值,可以用8421的算法直接計算出數據長度。而在CAN-FD中,1001~1111之間的值則被解讀為離散的12,16,20,24,32,48,64byte。
CRC段對于從幀頭到Data結束之間的數據,CAN協議使用了CRC15這個比較特別的多項式計算校驗,有興趣的可以手算CRC試試。CAN-FD根據數據長度的不同使用了CRC17和CRC21,這里暫不做展開。
ACK段是由收到該幀的CAN節點回復的確認(Acknowledge)。注意 發送節點在ACK位一定發的是隱性1,由接收節點回應顯性0,雙方無縫銜接才在總線上呈現出一個完整的CAN報文。
反直覺知識點①:總線上任何節點 只要認為這個幀的結構正確,都會在ACK位回顯性0,不管需不需要這一幀的ID和數據。為什么不需要的節點也會回ACK?因為等MCU算完會造成這一位的延遲,攪亂總線時序,不如只保障鏈路層本身的格式正確,純芯片數字邏輯實現無延遲。嗯,90年代的總線要求不要太高。
反直覺知識點②:發送節點若發現自己這一幀沒有ACK回應,它也會認為總線出錯,重發16次后進入Passive error狀態,有興趣的自行研究一下,這里不做展開。
3、真實CAN波形
來看一個兩節點案例:若節點A發送0x9E報文到總線,從節點B收到的總線波形和邏輯側波形如下:
黃線為CAN-H,綠線為CAN-L,藍線為節點B的邏輯側RX,紫線為節點B的邏輯側TX。可以看到,作為接收方的節點B,總線拉差分電壓拉出顯性的時候,收發器將RX拉0給到MCU。在節點B想要回應ACK的時候,MCU將TX拉0,CAN收發器在總線上拉出了一個歪斜的顯性(歪斜是因為測量點的寄生電感影響)。RX在ACK位置的0,是收發器TX=0驅動總線顯性之后 回讀到的0。
再看一個比較真實的車上波形,CAN網絡上大于4個節點:
黃色是CAN_H,高電平表示顯性0,綠色是我們掛示波器這個節點的邏輯側TX,低電平表示顯性0。箭頭A~D是一幀完整的CAN報文,箭頭A ~ B這個過程中,我們掛示波器的這個節點和另一個節點正在進行優先級仲裁,根據我們之前講到的物理層的分壓原理,兩個節點同時驅動電壓會高一截。在箭頭C這個bit 該節點想發隱性1但發現總線是顯性0,那就說明有另外的節點在發送更高優先級的報文,我們這個節點會主動退出發送,成為接收節點,并在箭頭D點校驗成功后回應ACK,等待報文結束后這個節點再次參與總線仲裁,成功搶占總線如E點所示。
注意波形高度,在箭頭A~B之間,差分電壓略高于2V,這是正常現象,說明有兩個節點同時驅動總線顯性,但從邏輯看,因為H-L>0.7V所以都為顯性0,純數字邏輯的CAN控制器在箭頭A~B之間還感知不到對方的存在,箭頭C點之后才感知得到;而在箭頭D點,因為除了發送節點之外的所有節點都在同時驅動ACK,所以總線電壓比箭頭A~B之間的雙節點驅動 電壓更高。
4、錯誤幀
終于到了錯誤幀,注意,錯誤幀不是由哪個節點發出的,而是由某個接收節點認為總線錯誤,才故意驅動總線打斷發送方,在總線上呈現為一個錯誤幀。也就是說錯誤幀 一定是由 一個發送節點和至少一個 認為發送方有錯的節點 共同形成的。
5、位填充
位填充規則是CAN協議的靈魂,簡單來講就幾個字:逢五補一。當發送節點想要發連續5個bit的顯性0的數據,會故意插入一個無意義的隱性1;當出現連續5個bit的隱性1,會故意插入一個無意義的顯性0,如下圖的紫色bit。如果發送節點漏填了這個0/1,或者這個0/1被干擾成了1/0,接收節點就會判定為“填充錯誤”,向總線上輸出“主動錯誤標志”——連續六個顯性0,故意破壞這一幀報文,發送節點感知到總線錯誤之后停止發送這一報文的后續部分。你說巧妙不巧妙?連續6個顯性0本身就是破壞“逢五補一”規則的,被拿來當錯誤標志回給發送節點。
假如原始數據是0x00,二進制0000 0000,發送節點發到0000 0的時候發送節點會先插一個1,再發后續的000,成為0000 01000,共9bit長度,接收節點也會在第5bit的0之后預期一個無效的1,解碼時摳掉。
假如原始數據是0000 0100,第六位自帶1,發送節點發到00000的時候也會先插一個1,再發后續的100,成為0000 01100,共9bit長度。
6、回讀確認
發送節點發送了0或1的時候,會回讀確認總線是否和自己的發送相符,比如在仲裁段搶優先級失敗就會等下一幀再發;如果發到了數據段,按理說此時總線應該只有自己,發著發著突然發現回讀的0/1與自己發的不同,比如受到了干擾,發送節點就會輸出“主動錯誤標志”——連續6bit顯性0,來主動拋棄后續報文,同時讓接收節點知道我這一幀有誤。
在這時,接收節點收到第6bit顯性0的時候,因違背逢五補一的位填充規則,也會往總線上輸出“主動錯誤標志”,所以會在總線上看到連續12bit的顯性0,前6個來自發送節點,后6個來自接收節點。
正常情況來說,總線上的顯性不應該>5bits=10us。那么用示波器設置>11us的脈寬觸發模式就很容易定位錯誤幀的位置,不一定要用解碼示波器。
7、升維打擊
CAN網絡的幅度和電流可以為我們提供更多維度的信息,此所謂升維打擊。
我們先來看一個正常幀,我們叫它節點A吧,它內部有終端電阻,藍線為H-L的差分電壓,紫線是我們節點A的CAN-H引腳電流,輸出為正,輸入為負。
先看藍色的總線電壓波形,從0x83到END之間是一幀正常波形,注意看幀頭有多級臺階,幀尾ACK位置也特別高,這是正常的,可以理解 當多個節點同時驅動總線就會導致60Ω終端電阻上的分壓高于2V。從這些臺階來看,可以判斷出網絡上至少有5個節點。為啥?先看報文中部的幅度,這肯定是只有一個節點搶占總線之后的波形,往前有兩級臺階,可以認為A、B、C三個節點同時搶占總線出現了第一個高臺,然后節點C優先級仲裁失敗退出總線,A、B節點繼續搶占出現了第二個臺階,之后節點A成功搶占到了總線優先級,發送中間的數據。最后的ACK位比3節點驅動的第一個bit更高,說明至少有4個節點在驅動ACK,再加上節點A,網絡上至少有5個節點。
再看紫色的電流波形,已知節點A自己有終端電阻,外邊有另一顆終端電阻。波形中部的數據區肯定是節點A在驅動總線,差分電壓流經外邊的終端電阻形成回路,所以我們在節點A的引腳上觀察到了輸出的正向電流;往前一個電壓臺階的位置,電流為0,是A、B兩個帶終端電阻的節點在驅動總線,所以總線電壓拉開了但電流仍是無進無出的;再往前一個臺階,A、B、C三個節點驅動,節點C的電流流入A、B的終端電阻,所以在節點A的引腳上測到了輸入的負向電流;然后幀尾的ACK位置,至少有4個節點同時驅動,流入終端電阻A和B的負向電流更大了。
8、錯誤幀實戰
這是一個兩節點網絡,一個節點發,另一個節點收,兩方都有終端電阻,發送節點用的是TJA1042,接收節點用的是單3.3V收發器MAX3051。在幀頭就發生了錯誤,這種錯誤幀一般源于時鐘偏差或采樣點過小。
我們將示波器的差分探頭和電流探頭掛在接收端,下圖黃色為H-L的差分電壓,藍色為接收節點的輸出電流,RX為收發器將H-L差分電壓轉換出的邏輯波形,MCU內部的CAN控制器會根據RX的0/1來解讀總線。TX為接收節點的發送邏輯,MCU將TX拉低的時候收發器會往總線上驅動顯性。
我們已知500kbps的每個bit寬2us,注意上圖紫線TX在2 ~ 4箭頭之間出現了連續2us * 6=12us的顯性0,說明我們掛示波器的這個接收節點在此刻往外輸出了一個“主動錯誤標志”,那一定是接收節點在此之前認為總線出現了錯誤。我們來往前看,箭頭1~2之間總線差分電壓和RX邏輯側都只有10us/2us=5bit的顯性0,幀前邊都是長隱性1,這能有什么錯?一個可能是我們碰到了傳說中的過載幀,這個東西本應該很少見了;另一個可能是接收節點把對方來的正確報文認成了錯的,這10us被接收節點認成了6bit,錯誤的采樣點+硬同步(幀頭對齊)做得稀爛的國產MCU更容易出現這樣的幀頭報錯。
不管哪種,我們推演一下看看是否符合我們的理論,在箭頭2~3之間發送節點應該是想發送一個隱性,但這時接收節點已經覺得不對開始發“主動錯誤標志”,將總線拉成了顯性。然后發送節點讀到這一bit自己想發送隱性但總線是顯性,所以。。。仲裁區搶優先級失敗退出總線,,,怎么可能,之前有6個連續顯性呢,所以發送節點因違反“逢五補一”在箭頭3~5也輸出“主動錯誤標志”。所以就成了黃色總線波形的7個bit的“凸”型,中間的凸臺的位置總線被兩個節點驅動,電壓高起一個臺階。
再注意一個細節,凸臺的左肩膀和右肩膀高度不一樣,左肩膀是接收節點MAX3051驅動的電平,它比 右肩膀TJA1042的驅動能力弱一些,總線電平低一點。這個特性可以用來區分總線上的不同設備。
藍色線,是接收節點的輸出電流。箭頭1~2之間的負向電流為發送節點驅動總線,差分電壓流經接收節點內部的終端電阻帶來的負電流;箭頭2~3之間的正電流是接收節點驅動的主動錯誤的第一個bit;后邊3~4的凸臺兩個節點都在驅動顯性 但對應的電流也是負的,這是因為發送節點的驅動能力強過接收節點,整個網絡電流還是由發送節點灌入接收節點;再往后4~5的負電流是發送端驅動接收節點的終端電阻的電流。
下圖我標出了兩個節點的輸出bit流,紅框是“主動錯誤標志”。
這一幀的DLC=0x01,也就是只有1byte數據,數據區之后就是CRC區,我們的“主動錯誤標志”就發生在這個區,觀察又沒有填充錯誤,那就是我們掛示波器這個接收節點認為發送節點出現了CRC錯誤。但我們看到黃線在“主動錯誤標志”中間出現了凹坑,意味著發送節點還是想繼續發隱性,并不認為自己有錯,直到發現這一位被“主動錯誤標志”覆蓋為顯性才感知到位錯誤后拋棄后續報文。
原因最后定位到:過小的采樣點+過大的再同步補償寬度SJW讓時鐘誤差逐步積累,這顆國產MCU的重同步又做得稀爛,把正常報文錯讀了一位導致算CRC錯誤。最后通過調整采樣點和SJW寬度減少了這種錯誤的出現頻次,得到正常波形如下:
錯誤發生在CRC區,我們放大一下,看看各節點都發生了啥:
從每一個臺階往前畫12us的方框,得到每個節點輸出的“主動錯誤標志”,分析可知:這是一幀節點B發送的報文,節點A認為它的CRC算錯了,節點C湊了個熱鬧,三者一起形成了這個12bits長的“主動錯誤標志”。那,節點A為什么會認為CRC有錯呢?大概率是因為之前的數據讀錯了一位。這么好的波形也能讀錯?是的,我們無法判斷節點A所在的位置波形有多差,可能分支上沒有終端電阻振鈴很大呢?我們只能相信節點A不會亂搞。另外,采樣點偏差會導致節點對噪聲額外地敏感。
9、CAN-FD錯誤排查
來看一個A B C三節點CAN-FD錯誤幀的案例,節點C發,節點A、B收:黃色是H-L的差分電壓,綠色是節點B的邏輯TX。0x0677和0x0176是兩個錯誤幀。FD區波特率設置為2Mbps。
放大0x0176幀的細節:
- 標尺A B之間時間長度約0.8us,由一個2Mbps FD bit的0.5us + 一個CAN-FD的TDC(300ns)組成。
- 之后出現了6個FD bit(0.5us*6=3000ns)的連續顯性位,電平高度與之前相同,之后有連續2usx6=12us的顯性。
- 在標尺B線后12us位置出現了一個電壓跌落的小小的下降臺階,見下下圖。
綜上三條,認為節點C所在位置干擾過大/分支線路過長,節點C自己回讀↓下圖↓框出的bit位失敗,自己往總線上輸出“主動錯誤標志”(連續6bit=2usx6=12us的顯性),其他設備在接收到第6個CAN-FD的bit=0.5usx6=3us的時候就讀到了錯誤(違反FD速率的“逢五補一”規則),也往總線上疊加2us*6=12us的主動錯誤標志。然后,12us時節點C的主動錯誤標志先結束,其他節點的主動錯誤在2usx6+0.5usx6=15us后結束。至此,錯誤幀形態完成。
“逢五補一”這條規則是跟隨波特率變化的,6個連續的高波特率0或1都會觸發填充錯誤。但填充錯誤之后輸出的“主動錯誤標志”是500kbps波特率的6bit,固定長度12us。
再來一個案例:CAN-FD采樣點設置出錯導致節點B把節點A發送的CAN-FD報文當CAN來解析出錯。
黃色CAN_H,綠色CAN_L,藍色L-H反向差分電壓,紫線為節點B邏輯RX,青線為節點B邏輯TX。
注意看0x00前后的數據段,這一段是CAN-FD的2Mbps速率,節點B因為采樣點設置錯誤讀錯了BRS這一波特率轉換標志,仍按照標準的500kbps去解析節點A的2Mbps速率的數據,對RX信號2us一個采樣我用黃色箭頭標出來了,可以看到這恰好是6個連續顯性0,違反“逢五補一”的規則,故而接收節點B在箭頭2~4之間發“主動錯誤標志”,打斷總線通信,告知發送節點你發錯了。箭頭2~3之間,發送節點A恰好也要發顯性,所以節點A此時還沒感覺到不對。箭頭3之后,節點A想要拉隱性,電壓出現一個坑,卻發現總線還是顯性,此時節點A判斷出現了“位錯誤”,開始輸出“主動錯誤標志”,想告知接收方放棄我這一幀報文。箭頭4的位置節點B釋放“主動錯誤標志”,箭頭5的位置節點A釋放“主動錯誤標志”。
如果數據比較巧,恰好能滿足逢五補一的規則,那這種錯誤形態會在發送很多數據之后才會出現,但最晚也會被CRC攔截:
補充知識:CAN-FD網絡各個節點的采樣點必須完全相同,高速率導致對時序敏感很多,這一點與CAN網絡容許一個范圍顯著不同。上邊這一幀的BRS位怎么讀錯的呢?再一次違反直覺:CAN-FD的采樣點影響發送節點的驅動波形!用示波器可以輕松量出FD的采樣點位置。
看下圖,CAN-FD報文的控制段中的BRS位(Bit Rate Switch)明顯是短于前邊的FDF、R0位的,采樣點不匹配的話很容易讀錯。因為-FD的速率翻轉是在這一bit的采樣點位置發生的。比如采樣點80%的2Mbps CAN-FD網絡,BRS這一位的寬度為2us80%+0.5us20%=1.7us,而不是2us。接收節點的采樣點如果設置大于85%就會錯過整個BRS位(2us*85%=1.7us),從而導致如上的BRS位讀錯的問題。
以上,就是示波器升維破解CAN錯誤幀/BusOff的經驗分享,總結一下:
- 結合已知ID是哪個節點發的先驗信息,逐個拔掉非終端節點,示波器觀察“主動錯誤標志”,就能模糊定位錯誤源頭;
- 如果能引出敏感設備的TX,哪個節點認為哪個節點出了什么錯就會非常清晰明了;
- 其次,測量CAN的輸出電流也能清楚地定位誰在驅動“錯誤標志”,進而找到故障點;
- 如果上述難以實現,以12us間隔拆分“錯誤標志”的電壓臺階,也能定位大部分錯誤原因;
- 額外關注單bit寬度的電壓臺階,能排除部分節點;
.
五、經典的CAN總線現場故障
1?CAN總線的常見故障
???當CAN總線出現故障或數據傳輸異常時,往往會出現多種奇怪的故障現象,如儀表板顯示異常,車輛無法啟動,啟動后無法熄滅,車輛動力性能下降,某些電控系統功能失等。這是因為相關數據或信息是通過CAN總線傳輸的,如果傳輸失敗,那么會產生多種連帶故障,甚至造成整個網絡系統癱瘓。????最為常見的故障癥狀是儀表板的顯示異常,如下圖所示。
在檢修過程中,首先應查看具體的故障癥狀,根據故障癥狀和網絡結構圖來初步分析有可能是哪些原因造成的,然后使用相關的診斷儀器進行診斷,根據診斷結果制訂相關檢修方案,做到心中有數,目標明確。
????接著查找具體的故障部位和原因,同時結合相應的檢測方法和測量結果找到故障點,從而徹底排除故障。
????由于CAN網絡采用多種協議,每個控制模塊的端口在正常的情況下都有標準電壓,因此電壓測量法可用于判斷線路是否有對地或電源短路、相線間短路等問題。
????為了確定CAN H 或CAN L 導線是否損壞或信號是否正常,可以測量其對地電壓(平均電壓)。測量點通常在OBD診斷接口處,如下圖所示。
????診斷接口的6號針腳連接CAN H 導線,14號針腳連接CAN L 導線。如果診斷接口上連接有兩組CAN總線,那么動力CAN總線使用6號和14號針腳,舒適總線使用3號和11號針腳。診斷接口的針腳含義如下圖所示。?
????正常情況下,當CAN總線喚醒后,CAN H 對地電壓約為2.656V,CAN L 對地電壓約為2.319V,而且兩者相加為4.975V??▼?
CAN故障通常的原因有CAN線短路、對電源短路、對地短路、相互接反。
2?CAN?H與 CAN L短路
????當CAN H 與CAN L 短路時,CAN網絡會關閉,無法再進行通信。會有相應的網絡故障碼。CAN H 與CAN L 短路的總線波形如下圖所示。
????當兩者相互短路之后,CAN電壓電位置于隱性電壓值(約2.5V)。實際測量兩條CAN導線的電壓,會發現始終在2.5V左右,基本不變化,如下所示。
?故障排除方法:通過插拔CAN總線上的控制模塊(節點),可以判斷是由節點引起的短路還是導線連接引起的短路。
????逐個斷開節點,若電壓恢復正常,則說明該節點有問題。若斷開所有節點后電壓還沒有變化,則說明線路短路。
3?CAN H對電源(正極)短路
????當出現CAN H 對電源(正極)短路這種故障時,根據CAN總線的容錯特性,可能出現整個CAN網絡無法通信的情況或產生相關故障碼。
????以對12V電源短路為例,此時CAN H 電壓電位被置于12V,CAN L 線的隱性電壓被置于大約12V。CAN H 對電源短路的總線波形如下圖所示。
????實際測量電壓,若CAN H 電壓為12V,CAN L 電壓被置于約為11V,則說明出現此類故障。CAN H 對電源短路的CAN H 電壓如下圖所示。
??故障原因:如果不是CAN H 導線對外部電源短路引起的,那么這種故障就有可能是控制模塊內部的CAN收發器損壞造成的。故障查找方法同上。
4?CAN H對地短路?
????當出現CAN H 對地短路這種故障時,根據CAN總線的容錯特性,可能出現整個CAN網絡無法通信的情況或產生相關故障碼。
??? CAN H 的電壓位于0V,CAN L 電壓也位于0V,可是在CAN L 導線上還能夠看到一小部分的電壓變化。CAN H 對地短路的總線波形如下圖所示。
????實際測量電壓,若CAN H 和CAN L 電壓均約為0V,且無斷路問題,則說明出現此類故障。CAN H 對地短路的CAN H 電壓如下圖所示。
?故障原因:如果不是CAN H 導線對外部地線短路引起的,那么這種故障就可能是控制模塊內部的CAN收發器損壞造成的。故障查找方法同上。
5?CAN L對地短路
????當出現CAN L 對地短路這種故障時,根據CAN總線的容錯特性,可能出現整個CAN網絡無法通信的情況或產生相關故障碼。
????但是對于某些車系,如海馬車系,其CAN L 對地短路的容錯特性較好,車輛基本能夠正常使用,即在客戶體驗層面上沒有明顯的異常現象,但從診斷方面來講,會影響網絡傳輸速度。
????此時CAN L 電壓約為0V。CAN H 線的隱性電壓被降至0V,但顯性電壓基本不變,因此波形被拉長,依然可以傳輸數據,由此可說明CAN L 對地短路的容錯特性較好原因。CAN L 對地短路的總線波形如下圖所示。
????實際測量CAN導線電壓,若CAN L 電壓為0V,CAN H 為1V左右,則說明出現此類故障。CAN L 對地短路的CAN L 電壓如下圖所示。
故障原因:如果不是CAN-L導線對外部地線短路引起的,那么這種故障是控制模塊內部的CAN收發器損壞造成的。故障查找方法同上。
6?CAN L對帶電源(正極)短路
????當出現CAN L 對電源(正極)短路這種故障時,根據CAN總線的容錯特性,可能出現整個CAN網絡無法通信的情況或產生相關故障碼。
????由于CAN L 對電源短路,因此CAN H 電壓也被置于12V。CAN L 對電源短路的總線波形如下圖所示。
????實際測量CAN導線的電壓,若CAN L 和CAN H 導線電壓都約為12V,則說明出現此類故障。CAN L 對電源短路的CAN L 電壓如下圖所示。?
故障原因:如果不是CAN L 導線對外部電源短路引起的,那么這種故障就有可能是控制模塊內部的CAN收發器損壞造成的。故障查找方法同上。
7?CAN H斷路
????當某個控制模塊CAN H 導線斷路時,會導致該控制模塊無法實現通信,但其他控制模塊的通信還是有的。在其他的控制模塊可能讀到此故障模塊的故障碼。如果多個控制模塊的CAN H 導線出現斷路。那么這些控制模塊的通信功能都會受到影響。CAN H 斷路的總線波形如下圖所示。
?如果出現故障的控制模塊帶有終端電阻,可以用電阻測量法來判斷。測量診斷接口的CAN H 與CAN L 之間的電阻,若變為120Ω,則說明有一個終端電阻斷路。如果出現故障的控制模塊不帶終端電阻,那么需要測量該控制模塊的CAN導線的導通性。
????替換有故障碼內容涉及的控制模塊,可以快速判斷故障是否由該控制模塊本身造成的。此外,要結合網絡圖來查找斷點,因為在整個網絡中會設置相應的總線集線器,斷點部位不同,受影響的部件也不同,同時也會決定診斷儀能夠進行診斷的控制模塊。CAN網絡與集線器分布如下圖所示。
8?CAN L 斷路
????當某個控制模塊CAN L 導線斷路時,會導致該控制模塊無法實現通信,但其他控制模塊的通信還是有的。在其他控制模塊可能讀到此故障模塊的故障碼。如果多個控制模塊的CAN L 導線出現斷路,那么這些控制模塊的通信功能都會受到影響。
????如果出現故障的控制模塊帶有終端電阻,可以用電阻測量法來判斷。測量診斷接口的CAN H 與CAN L 之間的電阻,若變為120Ω,則說明有一個終端電阻斷路。如果出現故障的控制模塊不帶終端電阻,那么需要測量該控制模塊的CAN導線的導通性。CAN L 斷路的總線波形如下圖所示。
????替換有故障碼內容涉及的控制模塊,可以快速判斷故障是否是由該控制模塊本身造成的。此外,要結合網絡圖來查找斷點,從而準確找到原因,排除故障。
9?CAN L 與 CAN H導線相互反接
????當出現CAN L 與CAN H 導線互相接反這種故障時,一般情況下,接錯的那個控制模塊將無法通信,其他控制模塊的通信則正常。CAN L 與CAN H 導線互相接反的示意圖如下圖所示。
????在懷疑有問題的控制模塊的CAN導線針腳處測量其電壓,驗證電壓是否正常。結合CAN網絡圖核對線路連接情況進行檢查,判斷是否存在這種故障。若存在,則對CAN網絡進行修復。替換有故障碼內容涉及的控制模塊,判斷故障是否是由該控制模塊造成的。?
六、CAN比UART更難嗎?
#1、CAN總線波特率
CAN總線屬于異步通信,因此就有通信波特率,而這個波特率發生器就位于CAN控制器內部。我們不需要了解它是如何產生的,但需要了解它的含義。這章節針對初學者講述以下兩點內容。
1、異步通信
在串行通信中,主要分異步通信和同步通信。
同步通信:通信設備之間通過同步信號(CLK時鐘)來實現數據傳輸的通信叫同步通信。如I2C、SPI這類通信中都具有一個時鐘信號,其實在STM32中USART也具有同步功能,只是我們大多數人都只用了它的異步功能。
異步通信:簡單來說,就是通信設備之間通過約定一樣的時間來收發數據。而這個時間就會決定本節說的波特率。
2、波特率
很多工程師一直都沒徹底搞明白什么是波特率,我這里還是結合UART波特率來簡述一下其含義。
在電子通信領域,波特(Baud)即調制速率,指的是有效數據信號調制載波的速率,即單位時間內載波調制狀態變化的次數。它是對符號傳輸速率的一種度量,1波特即指每秒傳輸1個符號。
UART每秒鐘傳送240個字符,而每個字符格式包含10位(1個起始位,1個停止位,8個數據位),這時的波特率為240Bd,比特率為10位*240個/秒=2400bps。
從上面的描述可以總結:
- 比特率:即單位時間內傳送的二進制位數
- 波特率:即單位時間內傳輸的符號個數
只有在每個符號只代表一個比特信息的情況下,波特率與比特率才在數值上相等,但是它們的意義并不相同。
#2、位時序
上面講述了波特率,而決定波特率大小的就是本節說的位時序。在CAN標準中一個位可分為4段:
- 同步段(SS)
- 傳播時間段(PTS)
- 相位緩沖段1(PBS1)
- 相位緩沖段2(PBS2)
這些段又由可稱為 Time Quantum(簡稱Tq)的最小時間單位構成。
1位分為4個段,每個段又由若干個Tq構成,這稱為位時序。
而在STM32參考手冊中,將位時序分為三段,但它將它傳播段和位段1合并在一起了,如下圖所示:
1位由多少個Tq構成、每個段又由多少個Tq構成等,可任意設定位時序。通過設定位時序,決定傳輸的波特率:
這幾個參數會在以后編程中進行配置,從而決定通信的波特率。
關于同步,還有硬件同步、再同步等操作。但初學者可以不必過多理解,掌握上面基礎內容就行了。更多關于位時序的內容可以參看 ISO 11898 標準。
#3、幀類型及格式說明
CAN總線是通過以下5種類型的幀進行通信:
- 數據幀:用于發送單元向接收單元傳送數據的幀
- 遙控幀:用于接收單元向具有相同 ID 的發送單元請求數據的幀
- 錯誤幀:用于當檢測出錯誤時向其它單元通知錯誤的幀
- 過載幀:用于接收單元通知其尚未做好接收準備的幀
- 幀間隔:用于將數據幀及遙控幀與前面的幀分離開來的幀
數據幀和遙控幀有標準格式和擴展格式兩種格式,標準格式有11個位的標識符ID,擴展格式有29個位的ID。
1、 數據幀
如上圖所示,數據幀由7個段構成:
- 幀起始:表示數據幀開始的段
- 仲裁段:表示該幀優先級的段
- 控制段:表示數據的字節數及保留位的段
- 數據段:數據的內容,可發送 0~8 個字節的數據
- CRC段:檢查幀的傳輸錯誤的段
- ACK段:表示確認正常接收的段
- 幀結束:表示數據幀結束的段
理解數據幀的含義,請從認真理解它的定義:用于發送單元向接收單元傳送數據的幀。
一般的CAN總線通信,總線上通信絕大部分時候都是數據幀。像在CANOpen協議中,用的最多的PDO過程數據對象就是通過數據幀進行的通信。
初學者可以先理解數據幀,然后其他就容易理解了。下面,我們再來講述一下數據幀7段的詳情。
幀起始:標準和擴展格式相同。表示幀開始的段,1個位的顯性位,如下圖所示:
總線上的電平有顯性電平和隱性電平兩種。總線上執行邏輯上的線“與”時,顯性電平的邏輯值為“0”,隱性電平為“1”。
“顯性”具有“優先”的意味,只要有一個單元輸出顯性電平,總線上即為顯性電平。并且,“隱性”具有“包容”的意味,只有所有的單元都輸出隱性電平,總線上才為隱性電平。(顯性電平比隱性電平更強)
仲裁段:標準格式和擴展格式在此的構成有所不同。仲裁段表示該幀優先級的段,擴展格式多了18位ID,如下圖所示:
RTR = 0代表數據幀,RTR = 1代表遠程幀。
為什么叫仲裁段,就是通過ID來判斷總線上哪一個節點具有優先發送的權利。ID越小(0代表顯性),優先級越高。
控制段:標準和擴展格式的構成有所不同。控制段由 6 個位構成,如下圖所示:
它們除了都有4位表示數據段長度代碼(DLC)外,標準幀有IDE(數值為0)位和r0保留位,擴展幀有r0和r1保留位。
保留位必須全部以顯性電平發送。但接收方可以接收顯性、隱性及其任意組合的電平。
數據段:標準和擴展格式相同。數據段表示傳輸數據的內容,從 MSB(最高位)開始輸出,可發送 0~8 個字節的數據,長度由前面控制段決定。
CRC段:標準和擴展格式相同。CRC段是檢查幀傳輸錯誤的幀,由 15 個位的 CRC 順序和 1 個位的 CRC 界定符(用于分隔的位)構成。
相比485這類通信,CAN控制器就已經把CRC校驗做了,不需要你的程序再次去計算,從而節約了處理器資源。
ACK段:標準和擴展格式相同。ACK段用來確認是否正常接收。由 ACK 槽(ACK Slot)和 ACK 界定符 2 個位構成。
A.?發送單元在 ACK 段發送 2 個位的隱性位。
B.?接收到正確消息的單元在 ACK 槽(ACK Slot)發送顯性位, 通知發送單元正常接收結束。這稱作“發送 ACK”或者“返回 ACK”。
幀結束:標準和擴展格式相同。幀結束是表示該該幀的結束的段。由 7 個位的隱性位構成。
2、遙控幀
和數據幀相比,遙控幀是接收單元向發送單元請求發送數據所用的幀。所以,遙控幀沒有數據段。因此,遙控幀由如下 6 個段組成:
- 幀起始(SOF):表示幀開始的段
- 仲裁段:表示該幀優先級的段。可請求具有相同ID的數據幀
- 控制段:表示數據的字節數及保留位的段
- CRC段:檢查幀的傳輸錯誤的段
- ACK段:表示確認正常接收的段
- 幀結束:表示遙控幀結束的段
這6個段和上面數據幀的內容基本一樣,這里就不一一講述了。下面,講一下遙控幀和數據幀的區別:
一是,遙控幀的 RTR 位為隱性位,沒有數據段;二是,沒有數據段的數據幀和遙控幀可通過 RTR 位區別開來。
問題一:遙控幀沒有數據段,數據長度碼該如何表示?
遙控幀的數據長度碼以所請求數據幀的數據長度碼表示。
問題二:沒有數據段的數據幀有何用途?
例如,可用于各單元的定期連接確認/應答、或仲裁段本身帶有實質性信息的情況下。
3、錯誤幀
用于在接收和發送消息時檢測出錯誤通知錯誤的幀。錯誤幀由錯誤標志和錯誤界定符構成。
(1) 錯誤標志
錯誤標志包括主動錯誤標志和被動錯誤標志兩種:
- 主動錯誤標志:6 個位的顯性位
- 被動錯誤標志:6 個位的隱性位
(2) 錯誤界定符
錯誤界定符由 8 個位的隱性位構成。
4、過載幀
過載幀是用于接收單元通知其尚未完成接收準備的幀。過載幀由過載標志和過載界定符構成:
過載標志:6 個位的顯性位,過載標志的構成與主動錯誤標志的構成相同。
過載界定符:8 個位的隱性位,過載界定符的構成與錯誤界定符的構成相同。
5、幀間隔
幀間隔是用于分隔數據幀和遙控幀的幀。數據幀和遙控幀可通過插入幀間隔將本幀與前面的任何幀(數據幀、遙控幀、錯誤幀、過載幀)分開。
過載幀和錯誤幀前不能插入幀間隔。
(1) 間隔
3 個位的隱性位。
(2) 總線空閑
隱性電平,無長度限制(0 亦可);本狀態下,可視為總線空閑,要發送的單元可開始訪問總線。
(3) 延遲傳送(發送暫時停止)
8 個位的隱性位,只在處于被動錯誤狀態的單元剛發送一個消息后的幀間隔中包含的段。