我正在尝试将2个I2C模块连接到arduino uno。 GY86(HMC5883L,MS5611,MPU6050)和BMP085或任何其他I2C模块。当我单独测试每一个时它工作正常,但当两者都连接到I2C总线端口时,每件事都会破坏。当我连接BMP模块时,GY86开始输出错误的数字。我还用DS1307模块测试了我的GY86。同样的事情发生了,当我连接它们时,DS开始输出错误的随机输出。我试图为SDA和SCL应用一个上拉电阻但是没有工作。问题是什么?
答案 0 :(得分:4)
每个I2C总线由两个信号组成:SCL和SDA。 SCL是时钟信号,SDA是数据信号。时钟信号总是由当前总线主机产生;一些从设备可能有时迫使时钟低,以延迟主设备感测更多数据。
与UART或SPI连接不同,I2C总线驱动器是“开漏”,这意味着它们可以将相应的信号拉低,但不能将其驱动为高电平。因此,没有总线争用,其中一个设备试图将线路驱动为高电平而另一个设备试图将其拉低,从而消除了驱动器损坏或系统中过度功耗的可能性。每条信号线上都有一个上拉电阻,当没有器件将其置为低电平时,将信号恢复为高电平。
电阻选择因总线上的器件而异,但一个好的经验法则是以4.7k开始并向下调整。
由于总线上的器件实际上并未将信号驱动为高电平,因此I2C允许在连接具有不同I / O电压的器件时具有一定的灵活性。通常,在一个设备处于比另一个设备处于更高电压电平的系统中,可以通过I2C连接这两个设备,而在它们之间没有任何电平转换电路。诀窍是将pull_up电阻连接到两个电压中较低的一个。这仅适用于某些情况,两个系统电压中的较低者超过较高电压系统的高电平输入电压 - 例如,5V Arduino和3.3V加速度计。
通过I2C进行通信比使用UART或SPI解决方案更复杂。信令必须遵守总线上设备的特定协议,才能将其识别为有效的I2C通信。
消息分为两种类型的帧:一个地址帧,其中主设备指示发送消息的从设备,以及一个或多个数据帧,它们是从主设备传送到从设备的8位数据消息或相反亦然。 SCL变为低电平后,数据置于SDA线上,并在SCL线变为高电平后进行采样。时钟边沿和数据读/写之间的时间由总线上的器件定义,并且因芯片而异。
要启动地址帧,主器件将SCL保持为高电平并将SDA拉低。这使得所有从设备都注意到传输即将开始。如果两个主设备希望一次获得总线的所有权,那么无论哪个设备将SDA拉低,首先都会赢得比赛并获得对总线的控制权。可以发出重复启动,启动新的通信序列,而不必将总线控制权交给其他主站。
地址帧始终是任何新通信序列中的第一个。对于7-地址,地址首先输出最高有效位(MSB),然后是R / W位,指示这是读(1)还是写(0)操作。 帧的第9位是NACK / ACK位。所有帧(数据或地址)都是这种情况。 一旦发送了8位帧,接收设备就可以控制SDA。如果接收设备在第9个时钟脉冲之前没有将SDA线拉低,则可以推断出接收设备要么没有接收到数据,要么不知道如何解析消息。在这种情况下,交易所停止,由系统主人决定如何继续。
发送地址帧后,可以开始传输数据。主器件将以规则的间隔继续生成时钟脉冲,数据将由主器件或从器件置于SDA上,具体取决于R / W位是指示读操作还是写操作。数据帧的数量是任意的,并且大多数从器件将自动递增内部寄存器,这意味着后续的读取或写入来自下一个寄存器。
一旦发送了所有数据帧,主设备将生成停止条件。停止条件由SCL上0-> 1转换后的0-> 1(低到高)转换定义,SCL保持高电平。在正常数据写入操作期间,当SCL为高电平时,SDA上的值不会发生变化,以避免停止状态。
答案 1 :(得分:1)
我认为有些设备具有相同的地址。这就是你收到不良数据的原因。通常I2C器件有额外的引脚来设置addr的低位。这样做并且不要忘记更改相应的软件定义。
更新:
MPU6050有输入引脚,它指定I2C地址的LSB。您需要将此引脚连接到高电平3.3V。否则MPU6050将具有与DS1307相同的地址。我肯定知道这一点,因为与两个IC一起工作很多。要做到这一点,你需要在MPU6050和Gnd的第9针之间断线。并通过> 3k至3.3V的电阻器将其焊接。或者不使用DS1307。从内存中有ds1302 rtc模块。
您应该找到您使用的所有IC的数据表,并检查它们的I2C地址。该板由三部分组成,因此您必须知道这3个地址。