CAN BUS ON STM32

前言

控制器區域網路 (Controller Area Network,簡稱CAN或者CAN bus) 是一種功能豐富的車用匯流排標準。被設計用於在不需要主機(Host)的情況下,允許網路上的單晶片和儀器相互通信。 它基於訊息傳遞協定,設計之初在車輛上採用復用通信線纜,以降低銅線使用量,後來也被其他行業所使用。
在碩士班論文底下有使用dsPIC30F4011(Microchip)晶片來實作CAN bus系統,如今因客戶需求開始研究起STM32 Can Bus的操作
這邊會介紹接線與Can Bus範例程式等等操作

Can Bus接線

閉環匯流排網路
開環匯流排網路
  • CAN 物理層的形式主要有兩種,左圖中的 CAN 通訊網路是一種遵循 ISO11898 標準的高速、短距離「閉環網路」,它的匯流排最大長度為 40m,通訊速度最高為 1Mbps,匯流排的兩端各要求有一個「120 歐」的電阻
  • 右圖中的是遵循 ISO11519-2 標準的低速、遠距離「開環網路」,它的最大傳輸距離為 1km,最高通訊速率為 125kbps,兩根匯流排是獨立的、不形成閉環,要求每根匯流排上各串聯有一個「2.2千歐」的電阻

PS:這邊硬體接線請注意必加電阻CAN transceiver ,千萬不要傻傻的MCU的Can腳位直接接出來!!!!

MESSAGE TRANSFER(CAN通訊的資料格式)

CAN2.0有兩種版本,CAN2.0A(Standard),CAN2.0B(Extended)。

  • Start of Frame(SOF):送出1位元dominant(0),用來同步。
  • Arbitration Field:表示節點的優先權,用來判別優先權。若多個節點同時傳送,在仲裁欄位逐一比對優先權,
    位元為dominant(0)可優先傳送。長度有兩種11bits(Standard identifier)和29bits(Extended Identifier)。
  • RTR :為優先判斷與資料接收與否的識別
    RTR=dominant(0),表資料要傳出,RTR=recessive(1),表要接收資料。
  • IDE: 標準格式(Standard identifier)為dominant(0);延伸格式(Extended Identifier)為 recessive(1)。
  • R0:保留

CAN Bus上的傳輸圖解

可以看到下圖分別有3個傳輸裝置分別是A、B、C會把資料同時放到Bus線路上這邊只要留意每個裝置傳輸時候給予微小delay時間即可避免資料傳輸重疊衝突

STM32cubeMX設置與範例程式

怎麼設定波特率呢?

例子1:我們要設定成500KHz,那麼我們這樣設定(公式如下)

Fpclk1/((CAN_BS1+CAN_BS2+1)*CAN_Prescaler)=42M/(4+2+1)/12=500kHz

Basic Parameter設置

  • Timer Triggered Communication Mode:否使用時間觸發功能 (ENABLE/DISABLE),時間觸發功能在某些CAN 標準中會使用到。
  • Automatic Bus-Off Management:用於設定是否使用自動離線管理功能 (ENABLE/DISABLE),
    使用自動離線管理可以在出錯時離線後適時自動恢復,不需要軟體干預。
  • Automatic Wake-Up Mode:用於設定是否使用自動喚醒功能 (ENABLE/DISABLE),
    使能自動喚醒功能後它會在監測到匯流排活動後自動喚醒。
  • Automatic Retransmission:用於設定是否使用自動重傳功能 (ENABLE/DISABLE),
    使用自動重傳功能時,會一直傳送報文直到成功為止。
  • Receive Fifo Locked Mode:用於設定是否使用鎖定接收 FIFO(ENABLE/DISABLE),
    鎖定接收 FIFO 後,若FIFO 溢位時會丟棄新資料,否則在 FIFO 溢位時以新資料覆蓋舊資料。
  • Transmit Fifo Priority:用於設定傳送報文的優先順序判定方法 (ENABLE/DISABLE),使能時,以報文存入傳送郵箱的先後順序來傳送,否則按照報文 ID 的優先順序來傳送。

中斷種類

  • RX0,RX1中斷:STM32有2個3級深度的接收緩衝區:FIFO0和FIFO1,每個FIFO都可以存放3個完整的報文,它們完全由硬體來管理。
    如果是來自FIFO0的接收中斷,則用CAN1_RX0_IRQn中斷來處理。
    如果是來自FIFO1的接收中斷,則用CAN1_RX1_IRQn中 斷來處理
  • SCE中斷:status chanege error,錯誤和狀態變化中斷

範例程式與涵式庫

這邊以F4系列為例子其他可以參考各系列的User_manual

開啟CAN Bus(必加)

HAL_CAN_Start(&hcan1);

Send Data

uint8_t bsp_can1_send_msg(uint32_t id_type,uint32_t basic_id,uint32_t ex_id,uint8_t *data,uint32_t data_len)
{
    uint8_t index = 0;
    uint32_t *msg_box;
	uint8_t send_buf[8] = {0};
    CAN_TxHeaderTypeDef send_msg_hdr;
    send_msg_hdr.StdId = basic_id;
    send_msg_hdr.ExtId = ex_id;
    send_msg_hdr.IDE = id_type;
    send_msg_hdr.RTR = CAN_RTR_DATA;
    send_msg_hdr.DLC = data_len;
	send_msg_hdr.TransmitGlobalTime = DISABLE;
	for(index = 0; index < data_len; index++)
          send_buf[index] = data[index];
 
    HAL_CAN_AddTxMessage(&hcan1,&send_msg_hdr,send_buf,msg_box);
    return BSP_CAN_OK;
}

Get Data

uint8_t bsp_can1_polling_recv_msg(uint32_t *basic_id,uint32_t *ex_id,uint8_t *data,uint32_t *data_len)
{
	uint8_t index = 0;
	uint8_t recv_data[8];
    CAN_RxHeaderTypeDef header;
 
  while (HAL_CAN_GetRxFifoFillLevel(&hcan1, CAN_RX_FIFO0) != 0)
  {
    if (__HAL_CAN_GET_FLAG(&hcan1, CAN_FLAG_FOV0) != RESET)
      printf("[CAN] FIFO0 overrun!\n");
   
    HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &header, recv_data);
	if(header.IDE == CAN_ID_STD)
	{
              printf("StdId ID:%d\n",header.StdId);
	}
	else
	{
              printf("ExtId ID:%d\n",header.ExtId);
	}
	printf("CAN IDE:0x%x\n",header.IDE);
	printf("CAN RTR:0x%x\n",header.RTR);
	printf("CAN DLC:0x%x\n",header.DLC);
	printf("RECV DATA:");
	for(index = 0; index < header.DLC; index++)
	{
              printf("0x%x ",recv_data[index]);
	}
	printf("\n");
  }
}

其他涵式庫

PS:舊版的會有HAL_CAN_Transmit和HAL_CAN_Receive較新的MCU都替換成新涵式庫可以看下圖

Leave a Comment

Your email address will not be published. Required fields are marked *

Shopping Cart