Проблема с использованием выводов A4 и A5 для ввода и вывода I2C

Хардаре используется: Arduino nano ( старый загрузчик ) Монохромный Oled-дисплей ( 4 контакта, 128 x 32 ) MPU 6050

Как дисплей, так и MPU используют A4 и A5 в качестве протокола связи I2C, они мешают, так как MPU используется в 2 направлениях, а дисплей в 1 направлении.

  1. Как я могу изменить эти 2 контакта( не имеет значения, какой дисплей/датчик )
  2. Может ли этот метод ( тот, который вы предлагаете ) быть использован для большего числа подобных случаев? ( например, 3 датчика )

Вот что я пробовал до сих пор:

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels

#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    #include "Wire.h"
#endif
MPU6050 mpu;

#define OUTPUT_READABLE_YAWPITCHROLL
#define OUTPUT_READABLE_REALACCEL

// MPU control/status vars
bool dmpReady = false;  // set true if DMP init was successful
uint8_t mpuIntStatus;   // holds actual interrupt status byte from MPU
uint8_t devStatus;      // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize;    // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount;     // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer

// orientation/motion vars
Quaternion q;           // [w, x, y, z]         quaternion container
VectorInt16 aa;         // [x, y, z]            accel sensor measurements
VectorInt16 aaReal;     // [x, y, z]            gravity-free accel sensor measurements
VectorInt16 aaWorld;    // [x, y, z]            world-frame accel sensor measurements
VectorFloat gravity;    // [x, y, z]            gravity vector
float euler[3];         // [psi, theta, phi]    Euler angle container
float ypr[3];           // [yaw, pitch, roll]   yaw/pitch/roll container and gravity vector

#define INTERRUPT_PIN 2  // use pin 2 on Arduino Uno & most boards
volatile bool mpuInterrupt = false;
void dmpDataReady() {
  mpuInterrupt = true;
}

void setup() {
  volatile bool mpuInterrupt = false;     // indicates whether MPU interrupt pin has gone high

  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
   for(;;); // Don't proceed, loop forever
  }

  // Clear the buffer
  display.clearDisplay();

  delay(150);

  #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
        Wire.begin();
        Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
    #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
        Fastwire::setup(400, true);
    #endif

    Serial.println(F("Initializing I2C devices..."));
    mpu.initialize();
    pinMode(INTERRUPT_PIN, INPUT);

    // verify connection
    Serial.println(F("Testing device connections..."));
    Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));

    delay(50);
    
    // load and configure the DMP
    Serial.println(F("Initializing DMP..."));
    devStatus = mpu.dmpInitialize();

  if (devStatus == 0) {
        // Calibration Time: generate offsets and calibrate our MPU6050
        mpu.CalibrateAccel(6);
        mpu.CalibrateGyro(6);
        mpu.PrintActiveOffsets();
        // turn on the DMP, now that it's ready
        Serial.println(F("Enabling DMP..."));
        mpu.setDMPEnabled(true);

        // enable Arduino interrupt detection
        Serial.print(F("Enabling interrupt detection (Arduino external interrupt "));
        Serial.print(digitalPinToInterrupt(INTERRUPT_PIN));
        Serial.println(F(")..."));
        attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
        mpuIntStatus = mpu.getIntStatus();

        // set our DMP Ready flag so the main loop() function knows it's okay to use it
        Serial.println(F("DMP ready! Waiting for first interrupt..."));
        dmpReady = true;

        // get expected DMP packet size for later comparison
        packetSize = mpu.dmpGetFIFOPacketSize();
    } else {
        // ERROR!
        // 1 = initial memory load failed
        // 2 = DMP configuration updates failed
        // (if it's going to break, usually the code will be 1)
        Serial.print(F("DMP Initialization failed (code "));
        Serial.print(devStatus);
        Serial.println(F(")"));
    }

    
  
  Serial.begin(9600);
}

void loop() {
  if (!dmpReady) return;
    // read a packet from FIFO
    if (mpu.dmpGetCurrentFIFOPacket(fifoBuffer)) { // Get the Latest packet 
        
        #ifdef OUTPUT_READABLE_YAWPITCHROLL
            // display Euler angles in degrees
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetGravity(&gravity, &q);
            mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
            /*
            data.gyro_data[0] = ypr[0] * 180/M_PI;
            data.gyro_data[1] = ypr[1] * 180/M_PI;
            data.gyro_data[2] = ypr[2] * 180/M_PI;
            */
        #endif

        #ifdef OUTPUT_READABLE_REALACCEL
            // display real acceleration, adjusted to remove gravity
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetAccel(&aa, fifoBuffer);
            mpu.dmpGetGravity(&gravity, &q);
            mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
            /*
            data.acc_data[0] = aaReal.x;
            data.acc_data[1] = aaReal.y;
            data.acc_data[2] = aaReal.z;
            */
        #endif
    }
    
    display.print(String(ypr[0] * 180/M_PI));
    display.print('/');
    display.print(String(ypr[1] * 180/M_PI));
    display.print('/');
    display.print(String(ypr[2] * 180/M_PI));
    display.print("\n\n");
    display.print(String(aaReal.x));
    display.print('/');
    display.print(String(aaReal.y));
    display.print('/');
    display.print(String(aaReal.z));
    

    //display.print(String(data.id));
    display.display();
    
    
    delay(500);
}

Теперь я знаю, что это похоже на кучу кода, собранного вместе с надеждой на работу, но он состоит из 2 других моих кодов отдельно для MPU и дисплея, они отлично работают.

, 👍0

Обсуждение

-Они мешают, так как MPU используется 2-полосным способом, а Дисплей-1-полосным. - Нет, это чепуха. Независимо от этого, I2C является двунаправленным полудуплексом. Даже если вы думаете, что используете только одно направление, на самом деле вы всегда используете оба. Вы описали все, кроме реальной проблемы, Вы говорите, что они "мешают", но на самом деле не говорите нам, как, по вашему мнению, они мешают друг другу или каковы симптомы на самом деле., @Majenko

Несколько устройств могут совместно использовать шину I2C, если только они не имеют одного и того же адреса (что маловероятно с дисплеем и MPU)., @PMF

Есть много аспектов вашего кода, которые не имеют никакого смысла. Такие вещи, как вся система прерываний (которая, по-видимому, вообще ничего не делает)., @Majenko

#включить "I2Cdev.h" #include "MPU6050_6Axis_MotionApps20.h" позаботьтесь о связи с MPU, и в предыдущих тестах вывод прерывания` стабилизирует ось z. Я использовал [this](https://howtomechatronics.com/tutorials/arduino/arduino-and-mpu6050-accelerometer-and-gyroscope-tutorial/) в качестве ориентира. Тогда под помехами я подразумеваю то, что обычно дисплей показывает **0.00/0.00/0.00** на двух строках, ( так как данных нет). Но с добавлением MPU он просто показывает несколько случайных пикселей., @Drogon Blue


1 ответ


Лучший ответ:

1

Поэтому после повторных тестов я обнаружил несколько проблем, программных и аппаратных.

  1. Кабели, которые я использовал на макете, были обращены друг к другу. Металлические части, к которым прикасаются ( из-за дефекта кабелей ). Повернул их на 90*.

  2. Oled-дисплей не был инициализирован должным образом. При использовании display.write() или display.print() сначала необходимо поместить курсор в (0;0) с помощью display.setCursor(0,0). Кроме того, для большей совместимости в Setup(){} вам необходимо добавить display.setTextSize(1) и display.SetTextColor(БЕЛЫЙ).

  3. Контроль мощности. Я нашел лучшее, либо добавив конденсатор на линии VCC и GND при их использовании для одновременного питания 2 датчиков, либо объявив задержку в 5 мл в первой функции. delay(5)

,