Использование 2 GY521(mpu6050) с Arduino Uno R3

Я работаю над созданием датчика движения на базе интерфейса Arduino и MPU6050. Хочу переделать свой код так, чтобы он мог считывать данные с двух устройств mpu6050. Помимо определения адреса 0x69 и установки AD0 в высокий уровень на одном устройстве и AD0 в низкий уровень на другом, какие ещё изменения мне нужно внести в код? Исходный код я выложил ниже. Заранее спасибо!

//Базовый код для настройки и чтения необработанных значений из mpu6050
//matt_m 7-9-2017


#include <Wire.h>

// Регистры: акселерометр, температура, гироскоп
#define ACCEL_XOUT_H 0x3B
#define ACCEL_XOUT_L 0x3C
#define ACCEL_YOUT_H 0x3D
#define ACCEL_YOUT_L 0x3E
#define ACCEL_ZOUT_H 0x3F
#define ACCEL_ZOUT_L 0x40
#define TEMP_OUT_H 0x41
#define TEMP_OUT_L 0x42
#define GYRO_XOUT_H 0x43
#define GYRO_XOUT_L 0x44
#define GYRO_YOUT_H 0x45
#define GYRO_YOUT_L 0x46
#define GYRO_ZOUT_H 0x47
#define GYRO_ZOUT_L 0x48

#define PWR_MGMT_1 0x6B
#define PWR_MGMT_2 0x6C

#define MPU6050 0x68 // Адрес устройства
#define ACCEL_CONFIG 0x1C // Адрес конфигурации акселерометра
#define GYRO_CONFIG 0x1B // Адрес конфигурации гироскопа




//Масштабирование выходного сигнала датчика
#define accSens 0 // 0 = 2g, 1 = 4g, 2 = 8g, 3 = 16g
#define gyroSens 1 // 0 = 250 рад/с, 1 = 500 рад/с, 2 1000 рад/с, 3 = 2000 рад/с


int16_t  AcX, AcY, AcZ, Tmp, GyX, GyY, GyZ;

void setup() {
 Serial.begin(115200);
 angle_setup();
}

void loop() {
  read_mpu6050();
  Serial.println(AcX);  //значение для отображения
}

//настройка MPU6050
void angle_setup()
{
  Wire.begin();
  delay (100);
  writeTo(MPU6050, PWR_MGMT_1, 0); //выход из спящего режима
  writeTo(MPU6050, ACCEL_CONFIG, accSens << 3); // Указание масштабирования выходных данных
  of accelerometer
  writeTo(MPU6050, GYRO_CONFIG, gyroSens << 3); // Указание масштабирования выходных данных
  of gyroscope
  delay (100);
}

void read_mpu6050()
{
  // считать необработанные измерения ускорения/гироскопа с устройства
  Wire.beginTransmission(MPU6050);
  Wire.write(0x3B);                  // начиная с регистра 0x3B
(ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU6050, 14, true);  // запросить всего 14 регистров
  AcX = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C
(ACCEL_XOUT_L)
  AcY = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E
(ACCEL_YOUT_L)
  AcZ = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40
(ACCEL_ZOUT_L)
  Tmp = Wire.read() << 8 | Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42
(TEMP_OUT_L)
  GyX = Wire.read() << 8 | Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44
(GYRO_XOUT_L)
  GyY = Wire.read() << 8 | Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46
(GYRO_YOUT_L)
  GyZ = Wire.read() << 8 | Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48
(GYRO_ZOUT_L)
}

void writeTo(byte device, byte toAddress, byte val) {
  Wire.beginTransmission(device);  
  Wire.write(toAddress);        
  Wire.write(val);        
  Wire.endTransmission();
 }

*редактирование: Ниже представлен код с моим лучшим предположением о том, как реализовать 2 датчика. Увы, вывод на мой последовательный монитор продолжает выдавать ошибочные значения -1 и 0

#include <Wire.h>

// Регистры: акселерометр, температура, гироскоп
#define ACCEL_XOUT_H 0x3B
#define ACCEL_XOUT_L 0x3C
#define ACCEL_YOUT_H 0x3D
#define ACCEL_YOUT_L 0x3E
#define ACCEL_ZOUT_H 0x3F
#define ACCEL_ZOUT_L 0x40
#define TEMP_OUT_H 0x41
#define TEMP_OUT_L 0x42
#define GYRO_XOUT_H 0x43
#define GYRO_XOUT_L 0x44
#define GYRO_YOUT_H 0x45
#define GYRO_YOUT_L 0x46
#define GYRO_ZOUT_H 0x47
#define GYRO_ZOUT_L 0x48

#define PWR_MGMT_1 0x6B
#define PWR_MGMT_2 0x6C


#define MPU60501 0x68 // Адрес устройства №1
#define MPU60502 0x69 // Адрес устройства №2
#define ACCEL_CONFIG 0x1C // Адрес конфигурации акселерометра
#define GYRO_CONFIG 0x1B // Адрес конфигурации гироскопа




//Масштабирование выходного сигнала датчика
#define accSens 0 // 0 = 2g, 1 = 4g, 2 = 8g, 3 = 16g
#define gyroSens 1 // 0 = 250рад/с, 1 = 500рад/с, 2 1000рад /с, 3 = 2000рад/с


int16_t  AcX1, AcY1, AcZ1, Tmp1, GyX1, GyY1, GyZ1;
int16_t  AcX2, AcY2, AcZ2, Tmp2, GyX2, GyY2, GyZ2;
void setup() {
 pinMode(0, OUTPUT);
 digitalWrite(0, HIGH);
 pinMode(1, OUTPUT);
 digitalWrite(1,LOW);
 Serial.begin(115200);
 angle_setup1();
 angle_setup2();
}

void loop() {
  read_mpu60501();
  Serial.println(AcX1);  //значение для отображения
  read_mpu60502();
  Serial.println(AcX2);  //значение для отображения


}

//настройка MPU60501
void angle_setup1()
{
  Wire.begin();
  delay (100);
  writeTo(MPU60501, PWR_MGMT_1, 0); //выход из спящего режима
  writeTo(MPU60501, ACCEL_CONFIG, accSens << 3); // Указание вывода
scaling of accelerometer
  writeTo(MPU60501, GYRO_CONFIG, gyroSens << 3); // Указание выходных данных
scaling of gyroscope
  delay (100);
}

void read_mpu60501()
{
  // считать необработанные измерения ускорения/гироскопа с устройства
  Wire.beginTransmission(MPU60501);
  Wire.write(0x3B);                  // начиная с регистра 0x3B
(ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU60501, 14, true);  // запросить всего 14 регистров
  AcX1 = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C
(ACCEL_XOUT_L)
  AcY1 = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E
(ACCEL_YOUT_L)
  AcZ1 = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40
(ACCEL_ZOUT_L)
  Tmp1 = Wire.read() << 8 | Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42
(TEMP_OUT_L)
  GyX1 = Wire.read() << 8 | Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44
(GYRO_XOUT_L)
  GyY1 = Wire.read() << 8 | Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46
(GYRO_YOUT_L)
  GyZ1 = Wire.read() << 8 | Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48
(GYRO_ZOUT_L)
}

//настройка MPU60502
void angle_setup2()
{
  Wire.begin();
  delay (100);
  writeTo(MPU60502, PWR_MGMT_1, 0); //выход из спящего режима
  writeTo(MPU60502, ACCEL_CONFIG, accSens << 3); // Указание вывода
scaling of accelerometer
  writeTo(MPU60502, GYRO_CONFIG, gyroSens << 3); // Указание выходных данных
scaling of gyroscope
  delay (100);
 }
void read_mpu60502()
 {
  // считать необработанные измерения ускорения/гироскопа с устройства
  Wire.beginTransmission(MPU60502);
  Wire.write(0x3B);                  // начиная с регистра 0x3B
(ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU60502, 14, true);  // запросить всего 14 регистров
  AcX2 = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C
(ACCEL_XOUT_L)
  AcY2 = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E
(ACCEL_YOUT_L)
  AcZ2 = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40
(ACCEL_ZOUT_L)
  Tmp2 = Wire.read() << 8 | Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42
(TEMP_OUT_L)
  GyX2 = Wire.read() << 8 | Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44
(GYRO_XOUT_L)
  GyY2 = Wire.read() << 8 | Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46
(GYRO_YOUT_L)
  GyZ2 = Wire.read() << 8 | Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48
(GYRO_ZOUT_L)
}

void writeTo(byte device, byte toAddress, byte val) {
  Wire.beginTransmission(device);  
  Wire.write(toAddress);        
  Wire.write(val);        
  Wire.endTransmission();
}

`

, 👍0

Обсуждение

Вы дважды используете Wire.begin(). Думаю, это может сработать, но это некрасивое программирование. Ваш код может работать, но повторение одного и того же кода дважды очень затрудняет обнаружение ошибки. Хороший программист использует код, который выполняет определённую задачу только один раз. Вы можете использовать функцию с адресом I2C в качестве параметра или класс для MPU-6050 (как уже написал @CodeGorilla)., @Jot


1 ответ


1

Когда вы начинаете рассматривать множество объектов, вам следует думать о классах и структурах, которые позволяют это делать.

Если вы написали класс:

class MPU6050
{
public:
    // Конструктор класса
    MPU6050 (const byte& address = 0x68)
      :m_Address(address)
    {
    }

    // Деструктор класса
    ~MPU6050()
    {}

    //настройка MPU60501
    void angle_setup (void)
    {
      // Wire.begin(); // Этот метод следует вызывать в основной настройке.
      delay (100);
      writeTo(MPU60501, PWR_MGMT_1, 0); //выход из спящего режима
      writeTo(MPU60501, ACCEL_CONFIG, accSens << 3); // Указание масштабирования выходных данных акселерометра
      writeTo(MPU60501, GYRO_CONFIG, gyroSens << 3); // Указание масштабирования выходного сигнала гироскопа
      delay (100);
    }

    void read_mpu6050(void)
    {
      // считать необработанные измерения ускорения/гироскопа с устройства
      Wire.beginTransmission(MPU60501);
      Wire.write(0x3B);                  // начиная с регистра 0x3B (ACCEL_XOUT_H)
      Wire.endTransmission(false);
      Wire.requestFrom(MPU60501, 14, true);  // запросить всего 14 регистров
      AcX1 = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
      AcY1 = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
      AcZ1 = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
      Tmp1 = Wire.read() << 8 | Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
      GyX1 = Wire.read() << 8 | Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44(GYRO_XOUT_L)
      GyY1 = Wire.read() << 8 | Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
      GyZ1 = Wire.read() << 8 | Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (ГИРО_ZOUT_L)
    }

    // Элемент данных, который может быть закрытым и иметь функции доступа, но...
    int16_t     AcX1;
    int16_t     AcY1;
    int16_t     AcZ1;
    int16_t     Tmp1;
    int16_t     GyX1;
    int16_t     GyY1;
    int16_t     GyZ1;

private:
    byte m_Address;
};

Затем вы можете иметь любое количество датчиков, выполнив следующие действия:

MPU6050  SensorOne;  // Адрес необязателен и по умолчанию равен 68.
MPU6050  SensorTwo (0x69);

Чтобы получить доступ к данным или функциям в них:

SensorOne.angle_setup();
Serial.println(SensorOne.AcX1);

Можно поместить датчик в массив, а затем использовать циклы везде, но для двух экземпляров экономия невелика.

,