基于arduino的IIC扩展同时读取八个MPU6050的数据

一、系统设计需求

       应项目要求,对于某项目利用“4*4”的MPU6050形成阵列,同时采集到这么多个MPU6050的数据进行一种新的姿态解算的算法。本人利用简单的MCU和TCA9548便完成了IIC拓展,可在串口上读取这些数据,可惜没有一拓16路的IIC模块,要不然只需一块就可完成。

二、设计思路

        对于MPU6050芯片的信号处理,由于MPU6050是由IIC和上位机进行通讯,但又因为一个MPU6050的IIC通讯地址只有0x68和0x69(由MPU6050上的9号引脚AD0控制的,接GND即为0x68,VCC为0x69,注意这里的VCC为3.3V)。当有多个相同的IIC从机器件且从机的器件地址相同要和IIC主机器件进行通信,若也挂在IIC两根总线上进行通信将会变得紊乱,所以我们使用了TCA9845A芯片扩展IIC接口,TCA9845A能有效的解决这种情况的出现,可以使八个IIC从机地址相同的器件和IIC主机进行有效的通信。我们扩展八路IIC接口来解决16个MPU6050的通信问题。

       上面只是理想情况,先实现MPU6050的AD0全接地的情况下,实现一拓八路的情况吧。

三、硬件设计

3.1 MCU

       采用市面上常用的arduino板子。由于是姿态解算有新的算法,我们只需要取到四元数就可,交由其他人进行姿态解算即可。

3.2 TCA9548a

       就是一个i2c的多路多路开关,可以把最多8个地址相同的i2c设备分别接在TCA9548APWR芯片上,通过i2c命令对TCA9548APWR芯片进行设置,即选择接通一个chanel,这样也就是选择了8个i2c设备中的一个设备。

       既然TCA9548APWR芯片是一个i2c设备,那么一定有i2c设备地址,如下图所示,7位地址的低3位取决于外接电平状态。

      当然,对于不同的地址,不用外接A0,A1,A2,用程序控制软件控制切换即可。

3.3 MPU6050

      我们这里使用的MPU6050,肯定不是市面上的模块,仅仅利用MPU6050芯片,我这边还需要对其设计外围电路,参考芯片手册如下。

       AD0默认是接地的,如有需求,可接3.3V拉高改变其通信地址,这里我们引出每个芯片的SDA和SCL即可,别忘了他们有4.7kΩ的上拉电阻,设计的AD原理接线图如下:

       没办法,没有现成的1拓16路的芯片,所以只能两块TCA9548a来实现对16路MPU6050的数据读取了。对于TCA9548a,我们只需要把SDA和SCL接上arduino板子上的A4,A5即可,接线很简单的。

四、软件设计

       在使用如下程序之前,要先安装这样的库。

代码如下:


#include "MPU6050_6Axis_MotionApps20.h"

MPU6050 Mpu6050;
#define TCAADDR 0x70
#define MPU6050_NUMS  7  //传感器数量
#define DELAY_TIME  200     //延迟时间
int16_t ax, ay, az, gx, gy, gz;  

void tcaselect(uint8_t i) {

  if (i > 7) return;
  Wire.begin();
  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();
}

void setup()
{
  Serial.begin(9600);
  for (int i = 0; i < MPU6050_NUMS; i++) {
    tcaselect(i);
    delay(400);
    Mpu6050.initialize();      //初始化MPU6050
    delay(100);
    Serial.println(i);
  }

}

void loop()
{
  for (int i = 0; i < MPU6050_NUMS; i++) {
    tcaselect(i);
    Mpu6050.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
    Serial.print("#");
    Serial.print(i);
    Serial.print("  AX:");
    Serial.print(ax);
    Serial.print("|");
    Serial.print("AY:");
    Serial.print(ay);
    Serial.print("|");
    Serial.print("AZ:");
    Serial.print(az);
    Serial.print("|");
    Serial.print("GX:");
    Serial.print(gx);
    Serial.print("|");
    Serial.print("GY:");
    Serial.print(gy);
    Serial.print("|");
    Serial.print("GZ:");
    Serial.print(gz);
    Serial.print("|");
    Serial.println();
  }
  delay(DELAY_TIME);
}

        只需要修改上面的传感器数量,接上相应的SDA和SCL就可以在串口中读出,我这里测试了七个,因为SDA8断开了,手动调节了传感器的数量为7,接线无误情况下测试效果如下:

       由于我的接口没有进行焊接,所以测试的时候,前三路完全一样的原因可能是接触不好或者是那个位置的MPU6050芯片有问题,因为我试过了如果后面的MPU6050没有接或者检测到,就会打印前一个的数据,可以肯定的是,没一个MPU6050数据会完全一样,但也足以验证程序的正确性,在传感器正常和接线正常的情况下肯定能够读出数据。

五、改进计划

        1、需要姿态解算的小伙伴自行开发。

        2、鄙人能力有限,不能利用MPU6050的AD0引脚的拉高拉低来完成仅用一个TCA9548a完成16路MPU6050的读取,有能力者做出可告我一声。

很抱歉,作为AI语言模型,我没有实际的编程能力,无法编写代码。但是,我可以提供一些提示和建议,帮助您开始编写代码。 首先,您需要确保每个MPU6050都连接到Arduino板上,可以使用I2C通信协议进行通信。您需要确定每个MPU6050的I2C地址,并在代码中设置相应的地址。 然后,您需要使用Wire库,该库提供了I2C通信所需的函数。您需要使用Wire.begin()初始化I2C通信,并使用Wire.requestFrom()函数从每个MPU6050读取数据。 您还需要定义变量来存储每个MPU6050数据。您可以使用结构体来存储数据,并使用数组来存储每个MPU6050数据。 最后,您需要编写一个循环来读取每个MPU6050数据,并将其存储在相应的变量中。您可以使用for循环来遍历每个MPU6050,并使用Wire.requestFrom()函数从每个MPU6050读取数据。 下面是一个简单的示例代码,可以帮助您开始编写代码: #include <Wire.h> struct MPU6050Data { int16_t ax; int16_t ay; int16_t az; int16_t gx; int16_t gy; int16_t gz; }; const uint8_t MPU6050_ADDRESSES[] = {0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F}; const uint8_t NUM_MPU6050 = 8; MPU6050Data mpu6050Data[NUM_MPU6050]; void setup() { Wire.begin(); Serial.begin(9600); } void loop() { for (uint8_t i = 0; i < NUM_MPU6050; i++) { Wire.beginTransmission(MPU6050_ADDRESSES[i]); Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H) Wire.endTransmission(false); Wire.requestFrom(MPU6050_ADDRESSES[i], 14, true); // request a total of 14 registers mpu6050Data[i].ax = Wire.read() << 8 | Wire.read(); mpu6050Data[i].ay = Wire.read() << 8 | Wire.read(); mpu6050Data[i].az = Wire.read() << 8 | Wire.read(); mpu6050Data[i].gx = Wire.read() << 8 | Wire.read(); mpu6050Data[i].gy = Wire.read() << 8 | Wire.read(); mpu6050Data[i].gz = Wire.read() << 8 | Wire.read(); } // print data to Serial Monitor for (uint8_t i = 0; i < NUM_MPU6050; i++) { Serial.print("MPU6050 "); Serial.print(i); Serial.print(": ax="); Serial.print(mpu6050Data[i].ax); Serial.print(", ay="); Serial.print(mpu6050Data[i].ay); Serial.print(", az="); Serial.print(mpu6050Data[i].az); Serial.print(", gx="); Serial.print(mpu6050Data[i].gx); Serial.print(", gy="); Serial.print(mpu6050Data[i].gy); Serial.print(", gz="); Serial.println(mpu6050Data[i].gz); } delay(100); // wait a little bit before reading again } 请注意,此示例代码仅供参考,并且可能需要根据您的具体需求进行修改。同时,如果您没有经验,建议您查阅官方文档、教程和其他资源,以获取更详细的说明和指导。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值