步驟1:您需要什么:
我們假設(shè)您具有以下部分:
兩個Arduino UNO
一些公對母電線
一些公對公電線
一個旋轉(zhuǎn)電位計
一個面包板
步驟2:I2C的工作方式
I2C是一種通信協(xié)議,使您可以在微控制器和某些傳感器等電路之間進(jìn)行通信。它僅使用兩根線(如此高效?。5谝痪€是時鐘線,通常在文檔中寫為SCL。第二根線是數(shù)據(jù)線,通常寫為SDA。
I2C總線上的設(shè)備可以是“主機(jī)”或“從機(jī)”。僅主機(jī)控制時鐘線上的電壓,而主機(jī)和從機(jī)都可以操縱數(shù)據(jù)線上的電壓。通過仔細(xì)輪流,網(wǎng)絡(luò)上的所有設(shè)備都可以共享信息。
為了將信息發(fā)送到正確的位置,每個從站都有一個唯一的地址號碼,就像每個電話都有一個唯一的號碼一樣。
當(dāng)我看到I2C器件時,他們有文檔說:“該電路希望接收N字節(jié)表示ABC的數(shù)據(jù),并發(fā)送回M字節(jié)表示DEF的數(shù)據(jù)?!比绻徺I的設(shè)備不包含此信息,則不要購買。
有關(guān)I2C通信內(nèi)部工作的更多詳細(xì)信息,請查看以下鏈接:
http://www.robot-electronics.co.uk/i2c-tutorial
http://www.i2c-bus.org/結(jié)果
https://en.wikipedia.org/wiki/I%C2%B2C
步驟3:設(shè)置
上圖中的設(shè)備使用引腳A4和A5進(jìn)行I2C通信。每種類型的arduino和Wire庫的I2C引腳說明如下:
https://www.arduino.cc/zh/Reference/Wire
主設(shè)置看起來像這樣:
#include
void setup() {
// note that begin() has no parameter.
Wire.begin();
}
從站設(shè)置看起來像這樣:
#include
void setup() {
// note that begin() has a parameter.
// Any number from 0.。..127 will work.
Wire.begin(1);
}
如果您要在該網(wǎng)絡(luò)上使用第二個從站,則需要除#1外的地址,因為該地址已被使用。這意味著只能通過仔細(xì)計劃來添加和刪除網(wǎng)絡(luò)上的設(shè)備。許多使用I2C的設(shè)備都將帶有一個帶撥碼開關(guān)(小光開關(guān))的PCB,可以將其撥動以更改地址。便宜的型號將有裸露的接觸。要翻轉(zhuǎn)這些開關(guān),必須觸摸裸觸點(diǎn)。
第4步:發(fā)送數(shù)據(jù)
與之交談的人,然后發(fā)送信息,然后說“我完成了?!?/p>
void loop() {
Wire.beginTransmission(1);
Wire.write(“hello, ”);
Wire.endTransmission();
}
從站僅需發(fā)送信息。每個人都假定從服務(wù)器正在與主機(jī)通信。
void loop() {
Wire.write(“world!”);
}
Wire.write()具有三個版本:一個用于單個數(shù)字,一個用于字符串,以及一個用于數(shù)據(jù)塊。您必須告訴Wire數(shù)據(jù)塊有多長時間。
步驟5:接收數(shù)據(jù)
主機(jī)可以使用
Wire.read()
從網(wǎng)絡(luò)獲取單個字節(jié)的數(shù)據(jù),而不管是誰發(fā)送的。
Wire.read()是阻塞操作-您的Arduino在讀取一個字節(jié)之前不會做其他任何事情。如果沒有要讀取的字節(jié),則可能要等待很長時間!為避免此問題,還有
Wire.available()
將返回等待讀取的字節(jié)數(shù)。
將兩者放在一起,
while(Wire.available()) {
char c = Wire.read();
// do something with c
// maybe count how much we received,
// do something when we get the whole message.
}
// do other stuff while we wait for the whole message.
第6步:請求/接收
您已經(jīng)擁有運(yùn)行I2C網(wǎng)絡(luò)所需的一切,但是我想讓您了解另外一項功能,這有點(diǎn)棘手,所以請忍受我。實際上,我會說這完全是不需要,但是我將其包括在內(nèi)是為了徹底。也許表明有很多方法可以完成相同的工作,有些方法比其他方法更好。
您已經(jīng)知道,在C代碼中,有諸如setup()和loop()之類的方法。您也可以創(chuàng)建自己的方法并按名稱調(diào)用它們。您是否知道可以將方法名稱作為參數(shù)發(fā)送給另一個方法?通常用于稱為回調(diào)的東西。在這種情況下,我們將告訴線庫(I2C)當(dāng)從站從網(wǎng)絡(luò)接收數(shù)據(jù)時調(diào)用哪種方法。
// a master is calling and requesting something.
void requestEvent() {
// definitely send something back.
Wire.write(2); // one byte as an example.
}
// a master has sent something.
// Might not be requesting anything.
// Might not be all the data that was sent (yet)
void receiveEvent(int bytes) {
int i;
for(i=0;i char c = Wire.read();
// do something with c.
}
// maybe send something back
}
void setup() {
Wire.begin(1); // slave address = 1
Wire.onRequest(requestEvent);
Wire.onReceive(receiveEvent);
}
void loop() {
// do nothing!
}
此處的一些注意事項:
requestEvent()不會收到數(shù)字,說明主機(jī)期望多少字節(jié)。
據(jù)我所知,這些事件是中斷-無論loop()中發(fā)生了什么,它們都會盡快發(fā)生。如果時間和代碼正確,那么無論循環(huán)做什么,都可能會嚴(yán)重混亂。由于很難重新創(chuàng)建導(dǎo)致問題的條件,因此很難診斷出它為什么混亂。
因此,正如我所說的,盡管您可以使用這些工具,但我不建議您這樣做
第7步:雙向通信
現(xiàn)在讓我們將它們放在一起。
主代碼:
#include
#define TO_MASTER_SIZE 3
#define TO_SLAVE_SIZE 4
#define START_NODE 1 // The starting I2C address of slave nodes
#define END_NODE 2 // last node to probe +1
#define NODE_READ_DELAY 100 // Some delay between I2C node reads
byte messageToMaster[TO_MASTER_SIZE];
byte messageToSlave[TO_SLAVE_SIZE];
void setup() {
Serial.begin(9600);
Serial.println(“MASTER”);
Wire.begin(); // Activate I2C link
}
void loop() {
for (int address = START_NODE; address 《 END_NODE; address++) {
sendToSlave(address);
readFromSlave();
}
delay(NODE_READ_DELAY);
}
void sendToSlave(int address) {
// message is 0123
for(int i = 0; i 《 SEND_SIZE; i++) {
messageToSlave[i] = (byte)i;
}
Wire.beginTransmission(address);
Wire.write(messageToSlave, TO_SLAVE_SIZE);
Wire.endTransmission();
}
void readFromSlave() {
// if data size is available from nodes
if(Wire.available() == TO_MASTER_SIZE) {
for (int i = 0; i 《 TO_MASTER_SIZE; i++) {
messageToMaster[i] = Wire.read(); // get data
}
int fromAddress = messageToMaster[0];
int value = ((int)messageToMaster[1] 《《 8 ) | (int)messageToMaster[2];
Serial.print(“Slave ”);
Serial.print(fromAddress);
Serial.print(“ says ”);
Serial.print(value);
}
}
從站代碼:
#include
// Change this unique address for each I2C slave node
#define NODE_ADDRESS 1
// matches values on master side.
#define TO_MASER_SIZE 3
#define TO_SLAVE_SIZE 4
#define NODE_READ_DELAY 100
byte messageToMaster[TO_MASTER_SIZE];
byte nodeReceive[TO_SLAVE_SIZE];
void setup() {
Serial.begin(9600);
Serial.print(“SLAVE #”);
Serial.println(NODE_ADDRESS);
Wire.begin(NODE_ADDRESS); // Activate I2C network
}
void loop() {
delay(NODE_READ_DELAY);
if(Wire.avaialable() == TO_SLAVE_SIZE) {
readFromMaster();
sendToMaster();
}
}
void readFromMaster() {
for(int i = 0; i 《 TO_SLAVE_SIZE; i ++){
nodeReceive[i] = Wire.read();
}
Serial.print(“Master says ”);
for(int i = 0; i 《 TO_SLAVE_SIZE; i ++){
Serial.print(nodeReceive[i]);
}
Serial.println();
}
void sendToMaster() {
int x = analogRead(A0);
messageToMaster[0] = NODE_ADDRESS;
messageToMaster[1] = (x0》》8) & 0xff; // the top byte of x
messageToMaster[2] = (x0 ) & 0xff; // the bottom byte of x
Wire.write(messageToMaster,TO_MASTER_SIZE);
Serial.print(“Sensor value: ”);
Serial.println(x);
}
有趣的一點(diǎn)是,總線(網(wǎng)絡(luò))上的任何人都可以收聽雙向通信。從理論上講,可以添加一個靜默設(shè)備,其唯一的工作就是監(jiān)視網(wǎng)絡(luò)。
第8步:最終想法
單個I2C網(wǎng)絡(luò)可能有多個主機(jī),但這是多余的棘手的問題–主機(jī)之間必須進(jìn)行協(xié)商以避免彼此之間的交談,這會導(dǎo)致混亂。
責(zé)任編輯:wv
-
aduino
+關(guān)注
關(guān)注
0文章
3瀏覽量
3445
發(fā)布評論請先 登錄
相關(guān)推薦
評論