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