Arduino主从机之间的I2C通讯实验

通信设计应用

65人已加入

描述

  I2C简介

  I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。主器件用于启动总线传送数据,并产生时钟以开放传送的器件,此时任何被寻址的器件均被认为是从器件.在总线上主和从、发和收的关系不是恒定的,而取决于此时数据传送方向。如果主机要发送数据给从器件,则主机首先寻址从器件,然后主动发送数据至从器件,最后由主机终止数据传送;如果主机要接收从器件的数据,首先由主器件寻址从器件.然后主机接收从器件发送的数据,最后由主机终止接收过程。在这种情况下.主机负责产生定时时钟和终止数据传送。

  I2C工作原理

  SDA(串行数据线)和SCL(串行时钟线)都是双向I/O线,接口电路为开漏输出.需通过上拉电阻接电源VCC.当总线空闲时.两根线都是高电平,连接总线的外同器件都是CMOS器件,输出级也是开漏电路.在总线上消耗的电流很小,因此,总线上扩展的器件数量主要由电容负载来决定,因为每个器件的总线接口都有一定的等效电容.而线路中电容会影响总线传输速度.当电容过大时,有可能造成传输错误.所以,其负载能力为400pF,因此可以估算出总线允许长度和所接器件数量。

  主器件用于启动总线传送数据,并产生时钟以开放传送的器件,此时任何被寻址的器件均被认为是从器件.在总线上主和从、发和收的关系不是恒定的,而取决于此时数据传送方向。如果主机要发送数据给从器件,则主机首先寻址从器件,然后主动发送数据至从器件,最后由主机终止数据传送;如果主机要接收从器件的数据,首先由主器件寻址从器件.然后主机接收从器件发送的数据,最后由主机终止接收过程。在这种情况下.主机负责产生定时时钟和终止数据传送。

  2C总线特点

  (1)在硬件上,12C总线只需要一根数据线和一根时钟线两根线,总线接口已经集成在芯片内部,不需要特殊的接口电路,而且片上接口电路的滤波器可以滤去总线数据上的毛刺.因此I2C总线简化了硬件电路PCB布线,降低了系统成本,提高了系统可靠性。因为12C芯片除了这两根线和少量中断线,与系统再没有连接的线,用户常用IC可以很容易形成标准化和模块化,便于重复利用。

  (2)I2C总线是一个真正的多主机总线,如果两个或多个主机同时初始化数据传输,可以通过冲突检测和仲裁防止数据破坏,每个连接到总线上的器件都有唯一的地址,任何器件既可以作为主机也可以作为从机,但同一时刻只允许有一个主机。数据传输和地址设定由软件设定,非常灵活。总线上的器件增加和删除不影响其他器件正常工作。

  (3)I2C总线可以通过外部连线进行在线检测,便于系统故障诊断和调试,故障可以立即被寻址,软件也利于标准化和模块化,缩短开发时问。

  (4)连接到相同总线上的IC数量只受总线最大电容的限制,串行的8位双向数据传输位速率在标准模式下可达100Kbit/s,快速模式下可达400Kbit/s,高速模式下可达3.4Mbit/s。

  (5)总线具有极低的电流消耗.抗高噪声干扰,增加总线驱动器可以使总线电容扩大10倍,传输距离达到15m;兼容不同电压等级的器件,工作温度范围宽。

  Arduino主从机之间的I2C通讯实验

  I2C总线是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送,最高传送速率100kbps。各种被控制电路均并联在这条总线上,但就像电话机一样只有拨通各自的号码才能工作,所以每个电路和模块都有唯一的地址,在信息的传输过程中,I2C总线上并接的每一模块电路既可以是主控器(或被控器),又可以是发送器(或接收器),这取决于它所要完成的功能。

Arduino

  Arduino通讯命令见网址:http://www.arduino.cc/en/Reference/Wire,我通过这次IIC通讯实验把这10个I2C通讯命令全部应用到了。

Arduino

  我现在采用老版本A rduino-0018编程,老版本I2C通讯的发送数据命令是send(),接受数据命令是receive(),最新版本Arduino 1.0的发送数据的命令是write(),接受数据的命令是read(),这一点要注意啊,看清楚自己下载应用的是什么版本的Arduino编程软件。Arduino程序下载地址:http://arduino.cc/en/Main/Software

Arduino

  I2C实验说明: 主机向从机循环发送字符串“light is ”和字节x,x为1或0,从机接收后,把数据显示在它的串口监视器中,如上图。然后当主机通知从机向它上传数据时,会把x值再上传回主机,然后赋值给变量c。当主机程序判断c为1,则点亮主机数字端口13相连的LED,否则熄灭LED。

  通过这个实验把主从机之间的双向通讯都诠释出来了。

  实验全景图:

  把双Arduino控制器的SCL和SDA以及GND三根引脚用杜邦线相连,如果不是两个Arduino分别独立供电,您就要把双Arduino控制器的VCC也连一起,它们共用一个电源。这次实验就是把这四根线SCL和SDA以及GND、VCC都互连起来了。Arduino的SCL引脚位于模拟端口5,SDA引脚位于模拟端口4。

  Arduino控制器源于DFRobot官方网址:http://item.taobao.com/item.htm?spm=1101*r1F.1-1mJ7T.3-1MYgQs&id=3136612323

  注意:由于“单三角括号”里的内容,博客里显示不出来,所以我把头文件声明命令“被迫”进行了修改,以便在博客里看到头文件,例如改成“#include 《Wire.h》”。

  Arduino主机程序:(包括与I2C通讯相关的命令)

  /*主机向从机循环发送字符串“light is ”和字节x,x为1或0

  从机接收到主机发来的数据后,当主机通知从机向它上传数据时

  会把x值再上传回主机,然后赋值给变量c。

  当主机程序判断c为1,则点亮LED,否则熄灭LED。*/

  #include 《Wire.h》//声明I2C库文件

  #define LED 13

  byte x = 0;//变量x决定LED的亮灭

  //初始化

  void setup()

  {

  Wire.begin(); // 加入 i2c 总线,作为主机

  pinMode(LED,OUTPUT);//设置数字端口13为输出

  }

  //主程序

  void loop()

  {

  Wire.beginTransmission(4); //发送数据到设备号为4的从机

  Wire.send(“light is ”); // 发送字符串“light is ”

  Wire.send(x); // 发送变量x中的一个字节

  Wire.endTransmission(); // 停止发送

  x++;//变量x加1

  if(x==2)//如果变量x的值为2,则把x值转为0

  x=0;

  delay(1000);//延时1s

  Wire.requestFrom(4, 1); //通知4号从机上传1个字节

  while(Wire.available()》0) // 当主机接收到从机数据时

  {

  byte c = Wire.receive(); //接收一个字节赋值给c

  //判断c为1,则点亮LED,否则熄灭LED。

  if(c==1)

  {digitalWrite(LED,LOW);}

  else

  {digitalWrite(LED,HIGH);}

  }

  delay(1000);//延时1s

  }

  Arduino从机程序:(包括与I2C通讯相关的命令)

  /*循环接收主机发送来的数据包,同时显示在串口监视器上

  把数据包的最后一个字节,再上传回主机

  */

  #include 《Wire.h》//声明I2C库文件

  int x;//变量x值决定主机的LED是否点亮

  //初始化

  void setup()

  {

  Wire.begin(4); // 加入 i2c 总线,设置从机地址为 #4

  Wire.onReceive(receiveEvent); //注册接收到主机字符的事件

  Wire.onRequest(requestEvent); // 注册主机通知从机上传数据的事件

  Serial.begin(9600); //设置串口波特率

  }

  //主程序

  void loop()

  {

  delay(100);//延时

  }

  // 当从机接收到主机字符,执行该事件

  void receiveEvent(int howMany)

  {

  while( Wire.available()》1) // 循环执行,直到数据包只剩下最后一个字符

  {

  char c = Wire.receive(); // 作为字符接收字节

  Serial.print(c); // 把字符打印到串口监视器中

  }

  //接收主机发送的数据包中的最后一个字节

  x = Wire.receive(); // 作为整数接收字节

  Serial.println(x); //把整数打印到串口监视器中,并回车

  }

  //当主机通知从机上传数据,执行该事件

  void requestEvent()

  {

  //把接收主机发送的数据包中的最后一个字节再上传给主机

  Wire.send( x); // 响应主机的通知,向主机发送一个字节数据

  }

  我通过这次I2C通讯实验把这10个Arduino的I2C通讯命令全部应用到了,仔细看实验程序注释,并实践一次,就可以了解这Arduino控制器的I2C命令如何应用了。

  在数字通信各种协议中,相对Ethernet, USB, SATA, PCI-Express等传输速度达数百上千兆字节每秒的总线,I2C和SPI常称为“小”协议。但是,我们不能忘记的是各种总线的用途是什么。“大”协议是用于系统外的整个系统之间通信的,“小”协议是用于系统内各芯片间的通信,没有迹象表明“大”协议有必要取代“小”协议。I2C和SPI的存在和流行体现了“够用就好”的哲学。

  推荐阅读:arduino读取I2C总线上连接设备的地址

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分