极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 4684|回复: 9

Arduino 板子之间的 i2c 通讯问题

[复制链接]
发表于 2014-11-18 11:15:37 | 显示全部楼层 |阅读模式
本帖最后由 Super169 于 2014-11-18 11:17 编辑

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

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

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



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

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


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

  3. void setup() {  

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

  7.         Wire.begin();         // join I2C bus as a Master
  8.   
  9.         Serial.begin(57600);
  10.         Serial.println("Enter <target><data> to send:");
  11. }

  12. void loop() {
  13.         char slave = 0;
  14.         int slave_target = 0;  
  15.         char data = 0;

  16.         if (Serial.available()) {
  17.                 slave = Serial.read();
  18.                 delay(1);
  19.                 slave_target = slave - '0';
  20.                 if ((slave_target >= 0) && (slave_target < 10)) {
  21.                         Serial.print("Send to slave ");
  22.                         Serial.println(slave_target);
  23.                         Wire.beginTransmission(slave_target);
  24.                         while(Serial.available()) {
  25.                                 data = Serial.read();
  26.                                 Wire.write(data);
  27.                                 delay(1);
  28.                         }
  29.                         // add LF for better display in slave side
  30.                         Wire.write(10);
  31.                         Wire.endTransmission();
  32.                 } else {
  33.                         Serial.println("Invalid target");
  34.                         // clean up serial buffer
  35.                         while (Serial.available()) {
  36.                                 Serial.read();
  37.                                 delay(1);
  38.                         }
  39.                 }
  40.         }
  41. }
复制代码



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


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

  3. const int SLAVE_ADDRESS = 1;
  4. char incomingByte = 0;

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

  9.         Wire.begin(SLAVE_ADDRESS);    // join I2C bus as a slave with address 1
  10.         Wire.onReceive(receiveEvent); // register event
  11.   
  12.         Serial.begin(57600);
  13.         Serial.println("Received data:");
  14. }

  15. void loop() {
  16. }

  17. void receiveEvent(int howMany)
  18. {
  19.         while (Wire.available())
  20.         {
  21.                 incomingByte = Wire.read();
  22.                 Serial.print(incomingByte);
  23.         }
  24. }
复制代码
回复

使用道具 举报

发表于 2014-11-18 13:00:07 | 显示全部楼层
是不是没有共地之类的导致的?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-11-18 13:50:16 | 显示全部楼层
zoologist 发表于 2014-11-18 13:00
是不是没有共地之类的导致的?


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

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

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

使用道具 举报

 楼主| 发表于 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 而导致整个系统出问题.

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

使用道具 举报

发表于 2014-11-18 14:36:06 | 显示全部楼层
Super169 发表于 2014-11-18 13:50
如果不共地, 本身就已经不可以通讯了.

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

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

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

使用道具 举报

 楼主| 发表于 2014-11-18 16:41:40 | 显示全部楼层
zoologist 发表于 2014-11-18 14:36
如果这样的话,我觉得应该考虑是否是因为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
反覆测试, 发觉只要 把有问题的一片完全移走, 好像不需要重启 master, i2c 通讯也可以自动复原, 不知是否 ...

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

使用道具 举报

发表于 2014-11-19 08:39:37 | 显示全部楼层
用光耦隔离下试试?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-11-19 09:05:14 | 显示全部楼层
darkorigin 发表于 2014-11-19 08:39
用光耦隔离下试试?

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

使用道具 举报

发表于 2018-7-14 17:31:39 | 显示全部楼层
提出了一个很好的问题,有助于提高
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊 ( 浙ICP备09023225号 )

GMT+8, 2019-3-22 23:17 , Processed in 0.051445 second(s), 24 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表