极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 22548|回复: 5

【教程】Arduino IIC/I2C 实验示例补充

[复制链接]
发表于 2015-4-5 03:39:36 | 显示全部楼层 |阅读模式
本帖最后由 tsaiwn 于 2015-4-5 15:49 编辑

关于 IIC/I2C 的通讯, 较完整的要算以下这:
   http://www.geek-workshop.com/thread-421-1-1.html

但是该篇主要用 老版本 Arduino-0018 IDE 编程,
我这边用官方网站最新范例作补充 :-)

以下这示范例子其实就在 Arduino 官网:

  http://arduino.cc/en/Tutorial/MasterReader

材料:
  两张 Arduino 开发板 + 4 条电导线
  Master 主人      僕人 SLAVE
  GND      --------  GND
   A4      --------  A4   (SDA, data)
   A5      --------  A5   (SCL, clock)
   5V      --------  Vin
*** 最后这第四条是当你 Slave 僕人板子没有自己的电池或USB供电才需要 !
    就是说如果 Slave 用电池供电, 那就不必从 Master 的 5V 连接到 Slave 的 Vin.
http://arduino.cc/en/uploads/Tutorial/Master_Sender_bb.png
  


注意图片中没有把 Master 的 5V 连接到 Slave 的 Vin 是假设 Slave 有电池供电 !
这样就可以测试了 !
一张板为 Master 主人, 另一张板为 Slave 僕人 !
注意, IIC (I2C) 规定每个 Slave 要有一个编號 (address)!
现在我们假设第二张板子(Slave)的编號为 2 號!

Master 主人程序码如下:
  1. #include <Wire.h>

  2. void setup()
  3. {
  4.   Wire.begin();        // join i2c bus (我是主人, 不必报告 IIC 號码)
  5.   Serial.begin(9600);  // 串口输出
  6. }

  7. void loop()
  8. {
  9.   Wire.requestFrom(2, 6);    // 要求 2號僕人 透过 Wire 送 6 char 过来!

  10.   while(Wire.available())    // 如果Wire上还有 char 等我读取
  11.   {
  12.     char c = Wire.read(); // 从 Wire 读取一个 char
  13.     Serial.print(c);      // 送到串口监视器查看
  14.   }

  15.   delay(5500);  // 等 5.5秒
  16.   Serial.println( ); // 故意换到下一行方便查看
  17. } // loop(
复制代码



接著来看 Slave 僕人的程序码:

  1. #include <Wire.h>

  2. void setup()
  3. {
  4.   Wire.begin(2);   // 报告大家, 我是 2 號 IIC 设备喔, 在此等待服务主人
  5.   Wire.onRequest(ggyy); // 註册 ! 如果主人给我命令, 就调用函数 ggyy( )
  6. }

  7. void loop()
  8. {
  9.   // 我是僕人, 平常没事做
  10. }

  11. // 这函数必须在 setup( ) 內用 onRequest( ) 註册!
  12. void ggyy()
  13. {
  14.   Wire.write("Hello "); // 送出 6 个 char 给 IIC 上的主人
  15. } // loop(
复制代码



只有一部 PC 要如何测试 ?
(1)PC 先用 USB 连接 第二个 Arduino 板子 (Slave 僕人)
   把 Slave 僕人的程序码 上载进第二个 Arduino 板子(Slave 僕人)


(2)拔掉 Slave Arduino 板子,
   PC 改连接 Master 板子,

   把 Master 主人程序上载到第一 Arduino 板子 (主人, Master)

(3)把四条线连接好:
  Master 主人      僕人 SLAVE
  GND      --------  GND
   A4      --------  A4   (SDA, data)
   A5      --------  A5   (SCL, clock)
   5V      --------  Vin

  *** 最后这第四条是当你 Slave 僕人板子没有自己的电池或USB供电才需要 !
    就是说如果 Slave 用电池供电, 那就不必从 Master 的 5V 连接到 Slave 的 Vin.

(4)开启串口监视器, 可敲入 CTRL_Shift_M

必要时按板子上的 Reset (复位键)


----------------------------------------------------------

另外官网还有一个简单的范例:

   http://arduino.cc/en/Tutorial/MasterWriter
好了, 测试过范例之后, 我们来稍微讲解一下:
(1)要在 setup( ) 內用 Wire.begin( ) 加入 IIC 通讯
   (A)Master  只要这样 Wire.begin( );   
   (B)Slave 要用一个 1 到 127 的整数当作参数, 代表 Slave 的 address,
      例如  Wire.begin(2);  // 我是 2 號
(2)要由 Master 送命令给 Slave,例如:
      Wire.requestFrom(2, 6);    // 要求 2號僕人 透过 Wire 送 6 char 过来!
     但是, 请注意, 这里的 6 其实只是一个 byte 的命令, 是要求2號僕人 透过 Wire 送 6 char 过来 !
  但是Slave 可能不听话只送出 3 char 就结束通信 !  !
  因为..
     Wire.requestFrom( ); 只是送个命令(一个 byte)给某个 Slave,
  然后等著(注意会等著不立即往下一句做喔!),
  直到至少一个 char 送过来或 time out 才会往下做下一行!
  所以, 这时 Master 在这句下方要用 Wire.read( ) 读取资料!
  那怎知是 timeout 呢?
  都没 Wire.available( ) 就是没资料啊!
  不过, 其实 Wire.requestFrom( ); 会回传一个整数, 可以这样:
    int kkk = Wire.requestFrom(2, 6);
  然后检查 kkk 是否为 0, 是表示 time out 都没收到任何 byte !
(3)至於 Slave 应该如何回应主人Master的命令呢 ? (请注意命令只有一个 byte)
   官网的范例根本不管 Master 送过来是啥, 直接用 requestEvent() 函数送回 6 bytes!
      本来, 比较正確的方法应该是 Slave 要先把命令收下(一个 byte),
   然后检查该 Byte 內容, 至於是啥意思则由 Master 和 Slave 写程序的人自己定义,
   所以, Wire.requestFrom(2, 6);  的 6 其实是主人一厢情愿希望Slave给它 6 char,
   但 Slave 可能不听话只送出 3 char 就结束通信 !
   因为TWI/IIC的缓存区只有32bytes, 所以最多只可以要求 32 bytes;   如果你写  int kkk = Wire.requestFrom(2, 33);  则会立即返回且 kkk 得到 0;
   因为目前的 .requestFrom( )调用 twi_readFrom( ) 之后检查第二个参数如果超过 32 就不做事 !!
   如果Slave不管主人送啥过来(一个 byte內容)是啥, Slave 都是做自己的事,,
   那就可以照该官网的范例写的方式:
       http://arduino.cc/en/Tutorial/MasterReader
   否则如果Master 送过来的一个 Byte 有意义,
   那Slave必须类似以下这样写:
///Slave arduino
//...const  int  MY_ADDRESS = 38;   // 我位址编號是 38
volatile  char what = 0;  // 接收命令 byte
void setup() {
   Wire.begin (MY_ADDRESS);   // can be 1,2, .. 127
   Wire.onReceive (ggaaa);   // receiveEvent interrupt handler
   Wire.onRequest (yybbb);   // requestEvent interrupt handler
   //...
}
void loop( ) {
  //...
}
void ggaaa(int haha) {
   what = Wire.read( ); // 读取 Mater 送来的命令 byte
}
void yybbb( ) {  // 里面不可用  Serial.print 不然会来不及 !
   switch(what) {
     case 23:  Wite.write("Hello "); break;  // 表示送 6 char欢迎 (故意!)
     case 2:  sendA0( ); break;  // 读取 A0 並送往 Master ( 2 bytes)
     case 15:  // 送 15 char
        // 注意只可有一句 Wire.write( ), 所以要先把资讯准备在一个 char 的 Array
        break;  // 每个 case 都要记得 break;
     case 18:
       //...
        break;

    default:
Wite.write("HaHa!"); break;  //其他 case
   }//switch(
} // yybbb(
void sendA0( ) { // 读取 A0 並送往 Master, 注意 0~1023 会用2 byte
   int val = analogRead (A0);
   byte buf [2];
   buf [0] = val >> 8;   // 取左边 byte
   buf [1] = val & 0xFF;  // 右边的 byte
   Wire.write (buf, 2);   // 只可用一次 Wire.write( ); 所以必须先准备到 Array
}  // sendA0(
/// Master 那边要如何读取这送过去的 A0  值?
/// int ans = Wire.read( ) * 256 + Wire.read( );
(4)I2cScanner 看看系统有没有连接 IIC/I2C 装置(Slave Device)
   在 Arduino 官网有人提供了一个 I2cScanner (I2C 扫描器),
   顾名思义, 就是可以帮忙找出系统上所有的 IIC Slave 僕人装置
     http://playground.arduino.cc/Main/I2cScanner
   这个程序码其实很简单, 就是用 Loop 把 address 从 1 找到 126
   对每个 address 都做以下两句:
     Wire.beginTransmission(address);
     int  error = Wire.endTransmission();
   然后就检查 error 是否为 0 ?
   只有 0 才表示真的有个 Slave Device 的位址编號是 address   不是 0 则表示有错, 目前可辨別四种错误(1,2,3,4),
   详细可以参考官方网站:
      http://arduino.cc/en/Reference/WireEndTransmission


参考:
   http://www.gammon.com.au/i2c
   http://www.gammon.com.au/i2c-summary
也可看看这篇:
      http://tronixstuff.com/2010/10/20/tutorial-arduino-and-the-i2c-bus/

-----------------------------------------------------------------------

通常 Slave 是一些支援 IIC (I2C) 的模块,
如果你要了解更多,
可以下载一些支援 IIC 模块的库来解压缩偷看其源代码 !


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2015-4-5 09:33:31 | 显示全部楼层
谢谢分享学习一下
回复 支持 反对

使用道具 举报

发表于 2015-4-5 10:38:11 | 显示全部楼层
谢谢收藏了。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-5 15:51:50 | 显示全部楼层


通常 Arduino 都是当 IIC/I2C/TWI 的 Master(主人),
如果你是想用 Arduino 模仿 IIC Slave Device / 传感器,可以参考以下这两篇:

  http://www.gammon.com.au/forum/?id=10896

  http://dsscircuits.com/articles/arduino-i2c-slave-guide
回复 支持 反对

使用道具 举报

发表于 2015-4-5 17:45:56 | 显示全部楼层
写的很有意思嘛,收下了
回复 支持 反对

使用道具 举报

发表于 2015-4-6 12:50:13 | 显示全部楼层
写的不错,留个记号找时间实践下
回复 支持 反对

使用道具 举报

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

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-18 20:36 , Processed in 0.043596 second(s), 23 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

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