如今,任何一輛普通汽車都包含大約 60 到 100 個傳感器單元,用于傳感和交換信息。隨著汽車制造商不斷通過自動駕駛、安全氣囊系統、胎壓監測、巡航控制系統等功能使他們的汽車更加智能,這個數字只會越來越高。與其他傳感器不同,這些傳感器處理關鍵信息,因此來自這些傳感器的數據應使用標準汽車通信協議進行通信。例如,速度、油門位置等巡航控制系統數據是發送到電子控制單元 (ECU)的重要值為了決定汽車的加速水平,此處的錯誤通信或數據丟失可能導致嚴重故障。因此,與 UART、SPI或I2C等標準通信協議不同,設計人員使用更可靠的汽車通信協議,如 LIN、CAN、FlexRay 等。
在本文中,我們將再次研究基礎知識,最后我們還將使用 CAN 通信在兩個 Arduino 之間交換數據。
CAN簡介
CAN aka Controller Area Network是一種串行通信總線,專為工業和汽車應用而設計。它是一種基于消息的協議,用于多個設備之間的通信。當多個 CAN 設備如下圖所示連接在一起時,連接形成一個網絡,就像我們的中樞神經系統一樣,允許任何設備與節點中的任何其他設備通話。
CAN 網絡將僅包含兩條線CAN High 和 CAN Low,用于雙向數據傳輸,如上所示。通常,CAN 的通信速度范圍從 50 Kbps 到 1Mbps,距離范圍可以從 1Mbps 的 40 米到 50kpbs 的 1000 米。
CAN報文格式:
在 CAN 通信中,數據以特定的消息格式在網絡中傳輸。這種消息格式包含許多段,但兩個主要段是標識符和有助于在 CAN 總線中發送和響應消息的數據。
標識符或 CAN ID:標識符也稱為 CAN ID 或也稱為 PGN(參數組編號)。它用于識別 CAN 網絡中存在的 CAN 設備。根據使用的 CAN 協議類型,標識符的長度為 11 位或 29 位。
標準 CAN:0-2047(11 位)
擴展 CAN:0-2 29 -1(29 位)
數據:這是必須從一個設備發送到另一個設備的實際傳感器/控制數據。大小數據的長度可以是 0 到 8 個字節。
數據長度代碼 (DLC):0 到 8 表示存在的數據字節數。
CAN中使用的電線:
CAN 協議由兩條線組成,即CAN_H 和 CAN_L,用于發送和接收信息。兩條線都充當差分線,這意味著 CAN 信號(0 或 1)由 CAN_L 和 CAN_H 之間的電位差表示。如果差為正且大于某個最小電壓,則為 1,如果差為負,則為 0。
通常使用雙絞線電纜進行 CAN 通信。如圖所示,CAN 網絡的兩端通常使用一個 120 歐姆的電阻,這是因為線路需要平衡并連接到相同的電位。
CAN over SPI 和 I2C 的比較
既然我們已經學會了如何使用SPI 和 Arduino和IIC 和 Arduino,讓我們比較一下 SPI 和 I2C 和 CAN 的特性
CAN 協議應用
由于 CAN 協議的穩健性和可靠性,它們被用于汽車、工業機械、農業、醫療設備等行業。
由于 CAN 中的布線復雜性降低,它們主要用于汽車等汽車應用。
實施成本低,硬件組件價格也較低。
易于添加和刪除 CAN 總線設備。
如何在 Arduino 中使用 CAN 協議
由于 Arduino 不包含任何內置 CAN 端口,因此使用了一個名為MCP2515的 CAN 模塊。該 CAN 模塊通過 SPI 通信與 Arduino 連接。讓我們詳細了解 MCP2515 以及它如何與 Arduino 接口。
MCP2515 CAN 模塊:
MCP2515 模塊有一個 CAN 控制器 MCP2515,它是高速 CAN 收發器。MCP2515 與 MCU 之間通過 SPI 連接。因此,很容易與任何具有 SPI 接口的微控制器連接。
對于想要學習 CAN Bus 的初學者來說,這個模塊將是一個好的開始。此 CAN SPI 板非常適合工業自動化、家庭自動化和其他汽車嵌入式項目。
MCP2515的特性和規格:
使用高速CAN收發器TJA1050
尺寸:40×28mm
用于擴展多 CAN 總線接口的 SPI 控制
8MHZ晶振
120Ω終端電阻
支持 1 Mb/s CAN 操作
低電流待機操作
最多可連接112個節點
MCP2515 CAN 模塊的引腳排列:
在本教程中,讓我們看看如何通過 CAN總線模塊 MCP2515從 Arduino Nano 向 Arduino Uno 發送濕度和溫度 (DHT11) 傳感器數據。
所需組件
Arduino UNO
阿杜諾納米
DHT11
16x2 液晶顯示器
MCP2515 CAN 模塊 – 2
10k 電位器
面包板
連接電線
MCP2515 Arduino電路圖
CAN Transmitter 端的連接:
CAN接收器側的電路連接:
兩個 MCP2515 CAN 模塊之間的連接
完成所有連接后,我的硬件如下所示
為 CAN 通信編程 Arduino
首先,我們必須在 Arduino IDE 中安裝 CAN 庫。通過使用以下庫,將 MCP2515 CAN 模塊與 Arduino 連接變得更加容易。
在本教程中,編碼分為兩部分,一是CAN 發送器代碼(Arduino Nano),另一部分是CAN 接收器代碼(Arduino UNO),兩者均可在本頁底部找到。其說明如下。
在編寫發送和接收數據的程序之前,請確保您已經按照上述步驟安裝了庫,并且 CAN 模塊 MCP2515 在您的程序中初始化如下。
初始化 MCP2515 CAN 模塊:
要創建與 MCP2515 的連接,請執行以下步驟:
1.設置SPI CS連接的管腳號(默認10)
MCP2515 mcp2515(10);
2.設置波特率和振蕩器頻率
mcp2515.setBitrate(CAN_125KBPS, MCP_8MHZ);
可用波特率:
CAN_5KBPS、CAN_10KBPS、CAN_20KBPS、CAN_31K25BPS、CAN_33KBPS、CAN_40KBPS、CAN_50KBPS、CAN_80KBPS、CAN_83K3BPS、CAN_95KBPS、CAN_100KBPS、CAN_125KBPS、CAN_200KBPS、CAN_250KBPS、CAN_500KBPS、CAN_1000KBPS。
可用時鐘速度:
MCP_20MHZ、MCP_16MHZ、MCP_8MHZ
3. 設置模式。
mcp2515.setNormalMode(); mcp2515.setLoopbackMode(); mcp2515.setListenOnlyMode();
CAN發射端代碼說明(Arduino Nano)
在發射器部分,Arduino Nano 通過 SPI 引腳與 MCP2515 CAN 模塊接口,DHT11 將溫度和濕度數據發送到 CAN 總線。
首先包括所需的庫,用于使用 SPI 通信的 SPI 庫、用于使用 CAN 通信的 MCP2515 庫和用于將 DHT 傳感器與 Arduino 一起使用的 DHT 庫。我們之前將 DHT11 與 Arduino 接口。
#include#include #include
現在定義了與 Arduino Nano 的 A0 相連的 DHT11(OUT 引腳)的引腳名稱
#define DHTPIN A0
而且,DHTTYPE被定義為 DHT11。
#define DHTTYPE DHT11
用于存儲 CAN 消息格式的canMsg結構數據類型。
結構 can_frame canMsg;
設置 SPI CS 連接的管腳號(默認為 10)
MCP2515 mcp2515(10);
此外,DHT 類的對象 dht 與 Arduino Nano 和 DHT 類型為 DHT11 的 DHT 引腳被初始化。
DHT dht(DHTPIN, DHTTYPE);
接下來在 void setup() 中:
使用以下語句開始 SPI 通信
SPI.開始();
然后使用以下語句開始接收來自 DHT11 傳感器的溫度和濕度值。
dht.begin();
接下來,使用以下命令重置 MCP2515
mcp2515.reset();
現在 MCP2515 的速度設置為 500KBPS 和 8MHZ 作為時鐘
mcp2515.setBitrate(CAN_500KBPS,MCP_8MHZ);
并且 MCP2525 設置為正常模式
mcp2515.setNormalMode();
在無效循環()中:
以下語句獲取濕度和溫度值并存儲在整數變量 h 和 t 中。
int h = dht.readHumidity(); int t = dht.readTemperature();
接下來,CAN ID 為 0x036(根據選擇),DLC 為 8,我們將 h 和 t 數據分配給data[0] 和data[1] ,并將所有數據保留為 0。
canMsg.can_id = 0x036; canMsg.can_dlc = 8; canMsg.data[0] = h; //更新[0]中的濕度值 canMsg.data[1] = t; //更新[1]中的溫度值 canMsg.data[2] = 0x00; //全部用 0 休息 canMsg.data[3] = 0x00; canMsg.data[4] = 0x00; canMsg.data[5] = 0x00; canMsg.data[6] = 0x00; canMsg.data[7] = 0x00;
畢竟,要將消息發送到 CAN BUS,我們使用以下語句。
mcp2515.sendMessage(&canMsg);
所以現在溫度和濕度數據作為消息發送到 CAN 總線。
CAN接收端代碼說明(Arduino UNO)
在接收器部分,Arduino UNO 與 MCP2515 和16x2 LCD 顯示器連接。在這里,Arduino UNO 從 CAN 總線接收溫度和濕度,并在 LCD 中顯示接收到的數據。
首先包括所需的庫,用于使用 SPI 通信的 SPI 庫、用于使用 CAN 通信的 MCP2515 庫和用于將 16x2 LCD 與 Arduino 一起使用的 LiquidCrsytal 庫。
#include#include
接下來定義用于連接 Arduino UNO 的 LCD 引腳。
const int rs = 3, en = 4, d4 = 5, d5 = 6, d6 = 7, d7 = 8; LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
聲明了一個結構數據類型用于存儲CAN 消息格式。
結構 can_frame canMsg;
設置 SPI CS 連接的管腳號(默認為 10)
MCP2515 mcp2515(10);
在 void setup() 中:
首先將 LCD 設置為 16x2 模式并顯示歡迎信息。
lcd.開始(16,2); lcd.setCursor(0,0); lcd.print("電路文摘"); lcd.setCursor(0,1); lcd.print("CAN ARDUINO"); 延遲(3000); lcd.clear();
使用以下語句開始 SPI 通信。
SPI.開始();
接下來,使用以下命令重置 MCP2515。
mcp2515.reset();
現在將 MCP2515 設置為 500KBPS 的速度和 8MHZ 作為時鐘。
mcp2515.setBitrate(CAN_500KBPS,MCP_8MHZ);
MCP2525 設置為正常模式。
mcp2515.setNormalMode();
接下來在 void loop() 中:
以下語句用于接收來自 CAN 總線的消息。如果收到消息,則進入if條件。
if (mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK)
在if條件下,數據被接收并存儲在 canMsg中,具有濕度值的數據 [0] 和具有溫度值的數據 [1]。這兩個值都存儲在整數 x 和 y 中。
int x = canMsg.data[0]; int y = canMsg.data[1];
收到數值后,溫度和濕度值使用以下語句顯示在 16x2 LCD 顯示屏上。
lcd.setCursor(0,0); lcd.print("濕度:"); lcd.print(x); lcd.setCursor(0,1); lcd.print("溫度:"); lcd.print(y); 延遲(1000); lcd.clear();
Arduino中CAN通信的工作
硬件準備好后,將 CAN 發送器和 CAN 接收器的程序(完整程序如下)上傳到各自的 Arduino 板上。通電后,您應該注意到 DHT11 讀取的溫度值將通過 CAN 通信發送到另一個 Arduino,并顯示在第二個Arduino 的 LCD 上,如下圖所示。我還使用交流遙控器檢查液晶顯示屏上顯示的溫度是否接近實際室溫。
CAN 發射器代碼(Arduino Nano):
#include
#include
#include
#define DHTPIN A0
#define DHTTYPE DHT11
結構 can_frame canMsg;
MCP2515 mcp2515(10);
DHT dht(DHTPIN, DHTTYPE); //使用STM32的DHT引腳和DHT類型為DHT11的DHT類初始化對象dht
void setup()
{
while (!Serial);
序列號.開始(9600);
SPI.開始();//開始 SPI 通信
dht.begin(); //開始讀取溫濕度傳感器值
mcp2515.reset();
mcp2515.setBitrate(CAN_500KBPS,MCP_8MHZ); //將 CAN 設置為速度 500KBPS 和時鐘 8MHz
mcp2515.setNormalMode();
}
void loop()
{
int h = dht.readHumidity(); //獲取濕度值
int t = dht.readTemperature(); //獲取溫度值
canMsg.can_id = 0x036; //CAN id 為 0x036
canMsg.can_dlc = 8; //CAN數據長度為8
canMsg.data[0] = h; //更新[0]中的濕度值
canMsg.data[1] = t; //更新[1]中的溫度值
canMsg.data[2] = 0x00; //全部用 0 休息
canMsg.data[3] = 0x00;
canMsg.data[4] = 0x00;
canMsg.data[5] = 0x00;
canMsg.data[6] = 0x00;
canMsg.data[7] = 0x00;
mcp2515.sendMessage(&canMsg); //發送CAN報文
delay(1000);
}
CAN接收器代碼(Arduino UNO):
#include
#include
#include
const int rs = 3, en = 4, d4 = 5, d5 = 6, d6 = 7, d7 = 8;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7); //定義LCD顯示引腳RS,E,D4,D5,D6,D7
結構 can_frame canMsg;
MCP2515 mcp2515(10); // SPI CS 引腳 10
void setup() {
lcd.begin(16,2); //設置 LCD 為 16x2 類型
lcd.setCursor(0,0); //顯示歡迎信息
lcd.print("CIRCUIT DIGEST");
lcd.setCursor(0,1);
lcd.print("CAN ARDUINO");
延遲(3000);
lcd.clear();
SPI.開始();//開始SPI通信
Serial.begin(9600); //以 9600 波特率開始串行通信
mcp2515.reset();
mcp2515.setBitrate(CAN_500KBPS,MCP_8MHZ); //將 CAN 設置為 500KBPS 和 8MHz 時鐘
mcp2515.setNormalMode(); //將CAN設置為正常模式
}
void loop()
{
if (mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK) // 接收數據(輪詢讀取)
{
int x = canMsg.data[0];
int y = canMsg.data[1];
lcd.setCursor(0,0); //顯示在 16x2 LCD 上接收到的溫度和濕度值
lcd.print("Humidity : ");
lcd.print(x);
lcd.setCursor(0,1);
lcd.print("溫度:");
lcd.print(y);
延遲(1000);
lcd.clear();
}
}
-
CAN
+關注
關注
57文章
2754瀏覽量
463721 -
MCP2515
+關注
關注
0文章
23瀏覽量
15818 -
Arduino
+關注
關注
188文章
6469瀏覽量
187093
發布評論請先 登錄
相關推薦
評論