本帖最后由 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 主人程序码如下: - #include <Wire.h>
-
- void setup()
- {
- Wire.begin(); // join i2c bus (我是主人, 不必报告 IIC 號码)
- Serial.begin(9600); // 串口输出
- }
-
- void loop()
- {
- Wire.requestFrom(2, 6); // 要求 2號僕人 透过 Wire 送 6 char 过来!
-
- while(Wire.available()) // 如果Wire上还有 char 等我读取
- {
- char c = Wire.read(); // 从 Wire 读取一个 char
- Serial.print(c); // 送到串口监视器查看
- }
-
- delay(5500); // 等 5.5秒
- Serial.println( ); // 故意换到下一行方便查看
- } // loop(
复制代码
接著来看 Slave 僕人的程序码:
- #include <Wire.h>
-
- void setup()
- {
- Wire.begin(2); // 报告大家, 我是 2 號 IIC 设备喔, 在此等待服务主人
- Wire.onRequest(ggyy); // 註册 ! 如果主人给我命令, 就调用函数 ggyy( )
- }
-
- void loop()
- {
- // 我是僕人, 平常没事做
- }
-
- // 这函数必须在 setup( ) 內用 onRequest( ) 註册!
- void ggyy()
- {
- Wire.write("Hello "); // 送出 6 个 char 给 IIC 上的主人
- } // 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 模块的库来解压缩偷看其源代码 !
|