2016-01-09 79 views
3

我想使用Arduino作爲i2c從機。但是我要求Arduino通過註冊多個i2c地址來充當多個設備。Arduino作爲具有多個i2c地址的從機

這可能不是一個通常會做的,但這裏是我的理由這樣做:

我想用一個Arduino作爲遙測傳感器,用於遙測的Spektrum。遙測接收器有幾個i2c插頭,它們連接到多個傳感器(電流爲0x02,電壓爲0x03,空速爲0x11等),每個傳感器都有遙測接收器預期的固定I2C地址。

我想使用其中一個 Arduino作爲所有這些設備充當所有這些設備註冊自己的所有上述地址,並作出適當的閱讀迴應。

我可以使用一個Arduino每個傳感器,這看起來很愚蠢,因爲我可以用一個Arduino pro-mini執行所有這些讀取。

我知道你可以使用

Wire.begin(0x02); 

註冊Arduino的,但我需要一些類似的(僞代碼)

Wire.begin(0x02, 0x03, 0x11); 

而在收到請求時,我需要知道什麼解決了Arduino的問題。

例如(僞碼)

void receiveEvent(byte address, int bytesReceived){ 
    if(address == 0x02){ 
    // Current reading 
    } 
    else if(address == 0x03){ 
    // Voltage reading 
    } 
    else if(address == 0x11){ 
    // Airspeed reading 
    } 
} 

任何建議,將不勝感激。

+0

除了原始的Arduino是一種選擇,ATxmegaA1設備帶有4個I2C接口,並且在github上有一個名爲Xmegaduino的[Arduino的ATxmega分支](https://github.com/Xmegaduino)。 – vega8

回答

5

由於Wire.begin()只允許通過一個從地址,所以不可能通過使用Wire庫使Arduino監聽多個從地址。


即使在其最Arduinos基於愛特梅爾的ATmega微控制器僅允許其硬件的2線串行接口(TWI)通過它的2線地址寄存器TWAR被設置爲單個7位地址。然而,可以通過使用TWI地址掩碼寄存器TWAMR掩蔽一個或多個地址位來解決該限制,如在(例如,簡單地)文件中所記錄的(稍微簡單地))。這ATmega datasheet部分22.9.6:

TWAMR可以加載一個7位Salve(sic!)地址掩碼。 TWAMR中的每個位都可以屏蔽(禁用)TWI地址寄存器(TWAR)中相應的地址位。如果屏蔽位設置爲1,則地址匹配邏輯會忽略傳入地址位與TWAR中對應位之間的比較。

所以,我們首先要建立基於我們要應對所有的I2C地址中用OR他們右移,以匹配TWAMR寄存器佈局的屏蔽位(TWAMR持有第7位掩碼:1,位0未使用):

TWAMR = (sensor1_addr | sensor2_addr | sensor3_addr) << 1; 

從這裏將是找出哪些特定的I2C地址被查詢的主要問題(我們只知道這是一個相匹配的地址掩碼)。 如果我解釋第22.5節。3正確,說明

TWDR包含要發送的地址或數據字節或接收到的地址或數據字節。

我們應該能夠從TWDR寄存器中檢索未屏蔽的I2C地址。

ATmega TWI操作是基於中斷的,更具體地說,它利用一箇中斷向量來處理TWSR狀態寄存器中由狀態代碼指示的大量不同的TWI事件。 在TWI中斷服務程序中,我們將不得不

  1. 確保如此,我們已經進入了ISR是因爲我們一直在質疑的原因。這可以通過檢查TWSR中狀態碼0xA8自己的SLA + R已收到
  2. 決定基於什麼I2C地址通過檢查的最後一個字節實際上查詢傳送回主傳感器數據進行巴士在TWDR

的ISR的這部分可能看起來像這樣(未經):

if (TWSR == 0xA8) { // read request has been received 
    byte i2c_addr = TWDR >> 1; // retrieve address from last byte on the bus 
    switch (i2c_addr) { 
    case sensor1_addr: 
     // send sensor 1 reading 
     break; 
    case sensor2_addr: 
     // send sensor 2 reading 
     break; 
    case sensor3_addr: 
     // send sensor 3 reading 
     break; 
    default: 
     // I2C address does not match any of our sensors', ignore. 
     break; 
    } 
} 

感謝您提出這個有趣的問題!

+0

Thankyou @ vega8,你的回答很具描述性!如果它能正常工作,我會嘗試更新。 – trojanc

+0

很好的答案。一個問題;有沒有限制你的地址數量(除了7位地址)?是否可以專門做6個地址?如:(0x28 | 0x29 | 0x2A | 0x2B | 0x2C | 0x2D)<< 1'。我想這樣做是爲了能夠從電路板上的特定傳感器獲取數據,還是在實際請求之前向電路板寫一個地址以指定我想要查詢的傳感器更好? –

4

我真的很喜歡vega8的答案,但是我還想提一提,如果你的I2C主控器不會快速設置時鐘速度,那麼使用基於軟件的I2C實現也是可行的,併爲你提供你想要的自由。

如果粗略計算顯示在TWI ISR中花費的時間太長,並且中斷可能開始重疊,您可能需要考慮該方法。

+1

好評,thx!這意味着要實現硬件中已有的大部分功能(包括增加的程序大小+額外的測試)。當然更多的靈活性,典型的權衡情況。 – vega8

1
void setup() 
{ 
    Wire.begin(0x11 | 0x12);  // Adr 11 and 12 are used for Alt and Speed by Spectrum DX 
    Wire.onRequest(requestEvent); // register callback function 
    TWAMR = (0x11 | 0x12) << 1; // set filter for given adr 
} 
+1

歡迎來到SO。請記得在您的代碼中添加4位縮進以便正確顯示。另外,我建議添加一些註釋。 – YakovL

1
void requestEvent() { 
    int adr = TWDR >> 1; // move 1 bit to align I2C adr 
    if (adr == 0x12)  // check for altitude request at adr 12 
     Wire.write(tmpSpektrumDataAlt, 16); // send buffer 
    if (adr == 0x11)  // check for speed request at adr 11 
     Wire.write(tmpSpektrumDataSpd, 16); // send buffer 
} 

這工作與遙測模塊頻譜DX8。 Spectrum界面已在Sectrums主頁上公開。技術文件。

+0

歡迎來到SO。請記得在您的代碼中添加4位縮進以便正確顯示。 – YakovL

0

I2C總線上可能有其他設備,TWAMR應設置儘可能少的位。所以我認爲,更好的辦法來計算面膜:

AddrOr = Addr1 | Addr2 | Addr3 | Addr4 ... 
AddrAnd = Addr1 & Addr2 & Addr3 & Addr4 ... 
TWAMR = (AddrOr^AddrAnd) << 1 

而TWAR可以設置爲任意AddrOr或AddrAnd 這樣如果使用的平臺,我們可以限制地址衝突的可能性最小