醬是創客的ESP32教學主題第20篇,以NodeMCU-32S(使用Arduino IDE)來實作教學,本篇教學Arduino透過SPI介面傳送/接收CAN bus通訊協議,來傳送接收Standard/Extended/Remote request Frame

以下是我們今天的目標

  • 傳送接收Standard/Extended/Remote request Frame
  • 了解CAN bus ID/DLC/DATA的關聯

設備:
安信可原廠/副廠NodeMCU-32S #露天拍賣 #蝦皮購物
醬是創客CAN bus模組 #露天拍賣 #蝦皮購物

CAN bus發送端接線方式:
NodeMCU-32S(GPIO5)–SPI訊號–醬是創客CAN bus模組(CS)
NodeMCU-32S(GPIO18)–SPI訊號–醬是創客CAN bus模組(SCK)
NodeMCU-32S(GPIO19)–SPI訊號–醬是創客CAN bus模組(SO)
NodeMCU-32S(GPIO23)–SPI訊號–醬是創客CAN bus模組(SI)
DC 5V(+)–醬是創客CAN bus模組(VCC)
DC 0V(-)–醬是創客CAN bus模組(GND)
發送端醬是創客CAN bus模組(H)-CAN訊號–接收端醬是創客CAN bus模組(H)
發送端醬是創客CAN bus模組(L)-CAN訊號–接收端醬是創客CAN bus模組(L)

CAN bus接收端接線方式:
NodeMCU-32S(GPIO5)–SPI訊號–醬是創客CAN bus模組(CS)
NodeMCU-32S(GPIO18)–SPI訊號–醬是創客CAN bus模組(SCK)
NodeMCU-32S(GPIO19)–SPI訊號–醬是創客CAN bus模組(SO)
NodeMCU-32S(GPIO21)–DI訊號–醬是創客CAN bus模組(INT)
NodeMCU-32S(GPIO23)–SPI訊號–醬是創客CAN bus模組(SI)
DC 5V(+)–醬是創客CAN bus模組(VCC)
DC 0V(-)–醬是創客CAN bus模組(GND)
發送端醬是創客CAN bus模組(H)-CAN訊號–接收端醬是創客CAN bus模組(H)
發送端醬是創客CAN bus模組(L)-CAN訊號–接收端醬是創客CAN bus模組(L)

Ai-Thinker安信可NodeMCU-32S的腳位圍(資料來源:安信可)

醬是創客CAN bus模組相關資料
CAN bus的速率是依靠晶片與振盪器而定,以MCP2515這顆晶片來說它理論可以達到1Mbps,這個前提是配合16MHz或20MHz振盪器,如果需要跑到1Mbps需求者,需自行將振盪器元件轉焊換成16MHz或20MHz,一般來說這個模組使用8MHz振盪器,速度會選用125Kbps,以我們做過的專案來說125Kbps其實就很夠用

Arduino IDE mcp2515.h 安裝說明:
1. 下載此ZIP檔案https://github.com/autowp/arduino-mcp2515/archive/master.zip
2. 打開Arduino IDE >> 草稿碼 >> 匯入程式庫 >> 加入.ZIP程式庫,並選擇剛剛下載的ZIP檔案
3. 安裝好後,關閉Arduino IDE,並再重新啟動Arduino IDE

Arduino CAN bus發送端範例程式碼如下,請注意程式碼中的 & 需自行轉換成&符號

//醬是創客 開發實作的好夥伴
#include "WiFi.h"
#include <SPI.h>
#include <mcp2515.h>

struct can_frame canMsg1;
struct can_frame canMsg2;
//定義使用GPIO5當SPI的CS
MCP2515 mcp2515(5);


void setup() {
  //standard frame
  canMsg1.can_id  = 0x0F6;
  canMsg1.can_dlc = 8;
  canMsg1.data[0] = 0x8E;
  canMsg1.data[1] = 0x87;
  canMsg1.data[2] = 0x32;
  canMsg1.data[3] = 0xFA;
  canMsg1.data[4] = 0x26;
  canMsg1.data[5] = 0x8E;
  canMsg1.data[6] = 0xBE;
  canMsg1.data[7] = 0x86;

  //extended frame
  canMsg2.can_id  = 0x12345678 | CAN_EFF_FLAG;
  canMsg2.can_dlc = 8;
  canMsg2.data[0] = 0x0E;
  canMsg2.data[1] = 0x00;
  canMsg2.data[2] = 0x00;
  canMsg2.data[3] = 0x08;
  canMsg2.data[4] = 0x01;
  canMsg2.data[5] = 0x00;
  canMsg2.data[6] = 0x00;
  canMsg2.data[7] = 0xA0;
  
  
  Serial.begin(115200);
  
  mcp2515.reset();
  //使用8MHz振盪器並搭配125Kbps速度
  mcp2515.setBitrate(CAN_125KBPS, MCP_8MHZ);
  //使用CAN bus NormalMode
  mcp2515.setNormalMode();
  
  Serial.println("Chosemaker: Write to CAN");
}

void loop() {
  //送出standard frame
  mcp2515.sendMessage(&amp;canMsg1);
  delay(1000);
  //送出extended frame
  mcp2515.sendMessage(MCP2515::TXB1,&amp;canMsg2);  
  delay(1000);
}

Arduino CAN bus接收端範例程式碼如下,請注意程式碼中的 &amp; 需自行轉換成&符號

//醬是創客 開發實作的好夥伴
#include "WiFi.h"
#include <SPI.h>
#include <mcp2515.h>

struct can_frame canMsg;
//定義CAN_INT使用GPIO21
#define CAN_INT 21
//定義使用GPIO5當SPI的CS
MCP2515 mcp2515(5);
char msgString[128]; 


void setup() {
  Serial.begin(115200);
  
  mcp2515.reset();
  //使用8MHz振盪器並搭配125Kbps速度
  mcp2515.setBitrate(CAN_125KBPS, MCP_8MHZ);
  //使用CAN bus NormalMode
  mcp2515.setNormalMode();
  //CAN_INT為INPUT模式
  pinMode(CAN_INT, INPUT);
  Serial.println("------- CAN Read ----------");
  Serial.println("ID  DLC   DATA");
}

void loop() {
  //CAN_INT低電位時開始收資料
  if(!digitalRead(CAN_INT))                         
  {
    //讀取CAN Frame資料
    mcp2515.readMessage(&amp;canMsg);      
    //判斷ID是standard (11 bits) frame還是extended (29 bits)frame
    if((canMsg.can_id &amp; 0x80000000) == 0x80000000)     
      sprintf(msgString, "Extended ID: 0x%.8lX  DLC: %1d  Data:", (canMsg.can_id &amp; 0x1FFFFFFF), canMsg.can_dlc);
    else
      sprintf(msgString, "Standard ID: 0x%.3lX       DLC: %1d  Data:", canMsg.can_id, canMsg.can_dlc);
  
    Serial.print(msgString);
    //判斷ID是否為remote request frame
    if((canMsg.can_id &amp; 0x40000000) == 0x40000000){    
      sprintf(msgString, " REMOTE REQUEST FRAME");
      Serial.print(msgString);
    } else {
      //取出frame資料
      for(byte i = 0; i<canMsg.can_dlc; i++){
        sprintf(msgString, " 0x%.2X", canMsg.data[i]);
        Serial.print(msgString);
      }
    }
        
    Serial.println();
  }


}

我們在發送端每隔一秒鐘持續發出standard frame和extended frame,在CAN bus設計中standard frame ID有11 bits,extended frame ID有29 bits,DLC代表著資料的長度,DATA的部分常用都是8組0~255

entry 0x400806ac
------- CAN Read ----------
ID  DLC   DATA
Extended ID: 0x12345678  DLC: 8  Data: 0x0E 0x00 0x00 0x08 0x01 0x00 0x00 0xA0
Standard ID: 0x0F6       DLC: 8  Data: 0x8E 0x87 0x32 0xFA 0x26 0x8E 0xBE 0x86