Super169 发表于 2014-11-18 11:15:37

Arduino 板子之间的 i2c 通讯问题

本帖最后由 Super169 于 2014-11-18 11:17 编辑

利用 Wire 库做了一个非常简单的 arduino 分工系统, 由一片主板 (master) 分别连上多片 arduino 板 (slave) 以 I2C 通讯发出指令操控.

个别测试时完全正常, 但在多板测试时, 出现了一个问题.
如果整个系统中, 其中一块 slave 板没电或出了问题, 在 master 发出 指令後, 整个 i2c 通讯就停了.
解决的方法, 必须向该片 slave 板通电, 或者完全移走, 并可能需要重启 master.

请问这个情形是否正常的?有方法可以避免因为一片 slave 而破坏整个 i2c 通讯网络吗?



以下为简化了的通讯程式以供参考:

master 程式 (只供测试 i2c address 0 - 9):


// i2c_master.ino
#include <Wire.h>

void setup() {

        // Optional, just make sure the internal pullup resistors on I2C pins are enabled
        digitalWrite(A4, HIGH);   // pullup for SDA
        digitalWrite(A5, HIGH);   // pullup for SCL

        Wire.begin();         // join I2C bus as a Master

        Serial.begin(57600);
        Serial.println("Enter <target><data> to send:");
}

void loop() {
        char slave = 0;
        int slave_target = 0;
        char data = 0;

        if (Serial.available()) {
                slave = Serial.read();
                delay(1);
                slave_target = slave - '0';
                if ((slave_target >= 0) && (slave_target < 10)) {
                        Serial.print("Send to slave ");
                        Serial.println(slave_target);
                        Wire.beginTransmission(slave_target);
                        while(Serial.available()) {
                                data = Serial.read();
                                Wire.write(data);
                                delay(1);
                        }
                        // add LF for better display in slave side
                        Wire.write(10);
                        Wire.endTransmission();
                } else {
                        Serial.println("Invalid target");
                        // clean up serial buffer
                        while (Serial.available()) {
                                Serial.read();
                                delay(1);
                        }
                }
        }
}



slave 程式 (修改 SLAVE_ADDRESS 使每块 slave 有独立的 i2c address, 否則亦可以同一指令發給多片 slave):


// i2c_slave.ino
#include <Wire.h>

const int SLAVE_ADDRESS = 1;
char incomingByte = 0;

void setup() {
        // Optional, just make sure the internal pullup resistors on I2C pins are enabled
        digitalWrite(A4, HIGH);   // pullup for SDA
        digitalWrite(A5, HIGH);   // pullup for SCL

        Wire.begin(SLAVE_ADDRESS);    // join I2C bus as a slave with address 1
        Wire.onReceive(receiveEvent); // register event

        Serial.begin(57600);
        Serial.println("Received data:");
}

void loop() {
}

void receiveEvent(int howMany)
{
        while (Wire.available())
        {
                incomingByte = Wire.read();
                Serial.print(incomingByte);
        }
}

zoologist 发表于 2014-11-18 13:00:07

是不是没有共地之类的导致的?

Super169 发表于 2014-11-18 13:50:16

zoologist 发表于 2014-11-18 13:00 static/image/common/back.gif
是不是没有共地之类的导致的?

如果不共地, 本身就已经不可以通讯了.

现在的情况, 在全部通电正常下, 是完全没有问题的.

问题只是在当其中一块 slave 断了电, 即使 master 不是向它发出指令, 也会出现整个通讯网络停了.好像是 master 不能传出指令似的.
只要再供电或移走该 slave, 有时可以即时回复正常, 有时要把 master 重启才可以.

Super169 发表于 2014-11-18 14:03:54

或者我再补充少少, 出现问题的经过.

整个系统本身是运作正常的, 接线是没问题, 全部共地的.接线很简单, 全部板子的 GND, SDA 及 SCL 分别也接通了.
我本来是想更换其中一片进行 hot swap 测试, 由於每片 slave 都是独立供电, 个别运作, 应该是可行的.我是想在不影响其他装置下, 更换其中一个单元.

我发觉如果我先把该片 slave 拔走 (既先甩掉 SDA, SCL, GND), 然後才拔掉它的电源, 整个系统都可以维持运作.

但如果我先把该 slave 的电源抆掉 (只是该片 slave, 其他的依然供电运作中, 即先甩掉 电源), 才抆走其他 (SDA, SCL, GND), 如果在拔走 SDA, SCL 及 GND 之前, master 发出指令的话 (对象并非该 slave), 也会出现整个 i2c 通讯坏掉.

即是说, 必须在供电情况下先移除该 slave, 才可以维持运作.
我是害怕将来万一当中一片出了问题, 可能坏掉了供电的部份, 就会因为一片 slave 而导致整个系统出问题.

所以, 想了解一下是否有方法可以避免, 令到断电的一片, 就如同完全离开了一样.

zoologist 发表于 2014-11-18 14:36:06

Super169 发表于 2014-11-18 13:50 static/image/common/back.gif
如果不共地, 本身就已经不可以通讯了.

现在的情况, 在全部通电正常下, 是完全没有问题的.


如果这样的话,我觉得应该考虑是否是因为SDA或者SCL没有正确拉高导致的。

是不是当断点或者损坏的时候这两个Pin也应该处于拉高的状态才能保证整个系统的I2C

Super169 发表于 2014-11-18 16:41:40

zoologist 发表于 2014-11-18 14:36 static/image/common/back.gif
如果这样的话,我觉得应该考虑是否是因为SDA或者SCL没有正确拉高导致的。

是不是当断点或者损坏的时候 ...

反覆测试, 发觉只要 把有问题的一片完全移走, 好像不需要重启 master, i2c 通讯也可以自动复原, 不知是否合理的结果.

如果可以自动复源, 影响已减低很多了, 最少不用重启系统.
但在移除之前, i2c 通讯无法进行, 还在测试是否有方法可以令没电源的 slave 被看成是不存在.

初步怀疑可能因为 GND, SDA 及 SCL 是接通的, 虽然该片 slave 没有正常供电, 但 GND 及 SDA/SCL 接通後, 总会有一定的电压存在, 那片 "没电" 的 slave 并不被看成是完全不存在, 影响了 i2c 的运作.

我可是硬小白一名, 不知是否有方法把它"变成"不存在.

林定祥 发表于 2014-11-18 17:00:26

Super169 发表于 2014-11-18 16:41 static/image/common/back.gif
反覆测试, 发觉只要 把有问题的一片完全移走, 好像不需要重启 master, i2c 通讯也可以自动复原, 不知是否 ...

现在总线是简单并接,是否需要隔离一下,使得某板断电后不至于影响总线.甚至于某板端口短路也不至于影响总线.

darkorigin 发表于 2014-11-19 08:39:37

用光耦隔离下试试?

Super169 发表于 2014-11-19 09:05:14

darkorigin 发表于 2014-11-19 08:39 static/image/common/back.gif
用光耦隔离下试试?

谢谢你的提议, 可惜我是硬小白一名.....请问光耦应该如果连接?

ziwei590 发表于 2018-7-14 17:31:39

提出了一个很好的问题,有助于提高
页: [1]
查看完整版本: Arduino 板子之间的 i2c 通讯问题