Несколько РАЗРЫВОВ I2C с подтягивающими резисторами не работают

[ОБНОВЛЕНИЕ] Теперь он работает нормально, но как только я добавляю модуль GY-521 (аппаратное, а не программное обеспечение), он начинает отправлять мне дрянную информацию

В проекте используются:

Arduino Pro Mini в качестве мозга

FTDI как программатор

Гироскоп GY-521/ускорение

MPL3115A2 баро/высотомер

DS3231 часы реального времени

Адаптер карты Micro SD для регистрации данных

В GY-521, MPL3115A2 и DS3231 используется I2C, и они являются пробойными платами, поэтому они включают в себя подтягивающие резисторы на плате. Теперь GY-521 и MPL3115A2 отлично работают вместе, но как только я добавляю DS3231, все это освобождается. Мой код в порядке, и я в этом уверен.

Теперь моя теория заключается в том, что все эти подтягивающие резисторы вызвали какую-то проблему в цепи. Я знаю, что для обычного I2C требуются подтягивающие резисторы на 4,7 К Ом. Теперь я СЧИТАЮ, что GY-521 использует подтягивающие резисторы 4,7 К, MPL3115A2 использует подтягивающие резисторы 10 К, а DS3231 также использует подтягивающие резисторы 10 К.

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

Вот код:

Вкладка 1: ОСНОВНЫЕ

  //==================================================

#include <SPI.h>                        //include the SPI library
#include <SD.h>                         //include the SD card library
#include <Wire.h>                       //include I2C library
#include "I2Cdev.h"                     //include another I2C library
#include "Wire.h"                       //include another I2C library (yes, again)
#include "MPU6050_6Axis_MotionApps20.h" //include the MPU6050 library
#include "SparkFunMPL3115A2.h"          //include the MPL3115A2 library
#include <DS3231.h>                     //include the DS3231 library

//==================================================

#define testtest           //*** COMMENT THIS LINE BEFORE UPLOADING OFFICIAL CODE TO FINAL PROJECT ***

#define chipSelect 10      //pin for the CS/SS
#define led 2              //led and/or buzzer

volatile bool mpuInterrupt = false; //just one of those bools

bool ledState     = false; //state of the led and/or buzzer
bool dmpReady     = false; //state of the mpu6050

int yprInt[3];             //gyro data in a integer because the extra precision of the float is total bullshit
int altitude;              //altitude above takeoff point in meters
int altitudeCalibration;   //calibration for the altimeter
int temperature;           //temperature in degrees Celcius

float counter = 0;         //time counter, a somewhat internal clock that starts when the module starts dataloging

uint8_t mpuIntStatus;      //holds actual interrupt status byte from MPU
uint8_t devStatus;         //return status after each device operation (0 = success, !0 = error)
uint8_t fifoBuffer[64];    //FIFO storage buffer

uint16_t packetSize;       //expected DMP packet size (default is 42 bytes)
uint16_t fifoCount;        //count of all bytes currently in FIFO

String day;                //day of the week
String ymd;                //date: year,month,day
String hms;                //time: hour,minute,second

MPU6050 mpu;               //MPU6050 object declaration as mpu
Quaternion q;              //quaternion container
VectorFloat gravity;       //gravity vector

MPL3115A2 myPressure;      //MPL3115A2 object declaration as myPressure
DS3231  rtc(SDA, SCL);     //DS3231 object declaration as rtc

//==================================================

void setup()
{
  generalSetup();

  gyroSetup();
  baroSetup();

  dataSetup();
}

//==================================================

void loop()
{
  gyro();      //read angles
  baro();      //read altitude and temperature
  timeClock(); //read day, date, time

  dataPrint();   //serial print the information

  dataLog();   //write data in sd card

  timer();     //time delay and led flash
}

Вкладка 2: НАСТРОЙКА

//==================================================

void generalSetup()
{
  Serial.begin(115200); //start serial communication
  Wire.begin();         //start I2C communication
  rtc.begin();          //start DS3231

  pinMode(led, OUTPUT); //led or buzzer; used to easily find a lost device
}

//==================================================

void dmpDataReady() {
  mpuInterrupt = true;
}

void gyroSetup()
{
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
  TWBR = 24;
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
  Fastwire::setup(400, true);
#endif
  //while (!Serial);
  mpu.initialize();
  devStatus = mpu.dmpInitialize();
  mpu.setXGyroOffset(220);
  mpu.setYGyroOffset(76);
  mpu.setZGyroOffset(-85);
  mpu.setZAccelOffset(1788);

  if (devStatus == 0)
  {
    mpu.setDMPEnabled(true);
    attachInterrupt(0, dmpDataReady, RISING);
    mpuIntStatus = mpu.getIntStatus();
    dmpReady = true;
    packetSize = mpu.dmpGetFIFOPacketSize();
  }

  else
  {
    return;
  }
}

//==================================================

void baroSetup()
{
  myPressure.begin();             //start MPL3115A2 communication 
  myPressure.setModeAltimeter();
  myPressure.setOversampleRate(7);
  myPressure.enableEventFlags();
  altitudeCalibration = myPressure.readAltitude(); //read altitude
}

//==================================================

void dataSetup()
{
  if (SD.begin());
}

//==================================================

Вкладка 3: ФУНКЦИИ

//==================================================

void gyro()
{
  float yprFlo[3]; //gyro data in a float

  mpu.resetFIFO();
  mpuInterrupt = false;
  mpuIntStatus = mpu.getIntStatus();
  fifoCount = mpu.getFIFOCount();

  if (mpuIntStatus & 0x02)
  {
    while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
    mpu.getFIFOBytes(fifoBuffer, packetSize);
    fifoCount -= packetSize;
    mpu.dmpGetQuaternion(&q, fifoBuffer);
    mpu.dmpGetGravity(&gravity, &q);
    mpu.dmpGetYawPitchRoll(yprFlo, &q, &gravity);

    for (int i = 0; i < 3; i++)
    {
      yprFlo[i] = yprFlo[i] * 180 / M_PI; //simplify the variable for serial printing and dataloging
    }

    for (int i = 0; i < 3; i++)
    {
      yprInt[i] = yprFlo[i]; //changing the variable from a float to a int
    }
  }
}

//==================================================

void baro()
{
  altitude = myPressure.readAltitude() - altitudeCalibration; //read altitude
  temperature = myPressure.readTemp();  //read temperature
}

//==================================================

void dataPrint() //serial print all the data
{
  Serial.print(day);
  Serial.print(" ");
  Serial.print(ymd);
  Serial.print(" -- ");
  Serial.print(hms);
  Serial.print(", ");
  Serial.print(counter);
  Serial.print(", ");
  Serial.print(yprInt[0]);
  Serial.print(", ");
  Serial.print(yprInt[1]);
  Serial.print(", ");
  Serial.print(yprInt[2]);
  Serial.print(", ");
  Serial.print(altitude);
  Serial.print(" ,");
  Serial.print(temperature);
  Serial.println();
}

//==================================================

void dataLog()//wirte all the data in a note file on the sd card
{
  if (altitude > 1) //if the device is higher then 1m, then we sstart recording everything
  {
    File dataFile = SD.open("datalog.txt", FILE_WRITE);

    if (dataFile)
    {
      dataFile.print(day);
      dataFile.print(" ");
      dataFile.print(ymd);
      dataFile.print(" -- ");
      dataFile.print(hms);
      dataFile.print(", ");
      dataFile.print(counter);
      dataFile.print(", ");
      dataFile.print(yprInt[0]);
      dataFile.print(", ");
      dataFile.print(yprInt[1]);
      dataFile.print(", ");
      dataFile.print(yprInt[2]);
      dataFile.print(", ");
      dataFile.print(altitude);
      dataFile.print(" ,");
      dataFile.print(temperature);
      dataFile.println();
      dataFile.close();
    }
  }
}

//==================================================

void timeClock()
{
  day = rtc.getDOWStr();
  ymd = rtc.getDateStr();
  hms = rtc.getTimeStr();
}

//==================================================

void timer()
{
  counter = counter + 0.5;

  #ifndef testtest
  ledState = !ledState;
  digitalWrite(led, ledState);
  #endif

  delay(500);
}

//==================================================

, 👍0

Обсуждение

Если проблема является общей, вызванной съемными резисторами, подключение одной из плат *без* попыток поговорить с ней все равно вызовет проблемы при общении с другими. Вы также можете проверить теорию подтягивания, добавив несколько дополнительных параллельно - если она все еще работает с одной из плат, замененных другим набором резисторов 2,2 К, это, вероятно, не проблема с резисторами. Проблема с адресом не повлияет на другие устройства с уникальными адресами. Строго говоря, разные платы могут иметь разную восприимчивость к чрезмерно жесткому подтягиванию шины от нескольких параллельных резисторов., @Chris Stratton

В вашей функции ISR "dmpDataReady" вы устанавливаете "mpuInterrupt = true;" - эта переменная должна быть объявлена " изменчивой`., @Nick Gammon

`как только я добавлю DS3231, все это исчезнет " - можете ли вы кое-что уточнить? Вы добавляете оборудование, и оно зависает, или вы *изменяете код*, а также добавляете оборудование?, @Nick Gammon

Программное обеспечение не меняется. Я еще не тестировал volatile, но я знаю, что в примере скетча они использовали volatile для этого. В этом может быть проблема. Когда я добавляю DS3231 в смысле аппаратного обеспечения. Программа запускает MPL3115A2 + GY-521 = НОРМАЛЬНО. MPL3115A2 + DS3231 = ОТЛИЧНО. GY-521 + DS3231 = ПРОБЛЕМА. Речь идет об оборудовании., @Dat Ha

Вы не можете правильно выполнить тесты, которые, как вы утверждаете, есть, не изменив программное обеспечение - оставив программное обеспечение, которое пытается разговаривать с чипом, которого там нет, *вызовет проблемы, как минимум замедление, если будет реализован тайм-аут, но неясно, что есть, и в этом случае программа может зависнуть., @Chris Stratton


3 ответа


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

1

На самом деле MPU-6050 на GY521 и DS3231 оба используют адрес I2C 0x68. Если бы вы посмотрели на источник заголовочных файлов, которые вы включили для каждого, это было бы очевидно.

Сверившись с паспортом данных для каждого чипа, вы, скорее всего, найдете способ либо изменить адрес I2C, изменив контакт конфигурации, либо потенциально включить/отключить чип, изменив его с помощью GPIO. Однако это, вероятно, потребует хирургической модификации несущей платы.

Вы также можете переместить любое устройство, к которому вы ожидаете получить доступ, по меньшей мере, на отдельную "мягкую" шину I2C, битую на других выводах GPIO. Никакого одобрения не подразумевается, но первая такая библиотека, которая появилась в веб-поиске, была:

http://playground.arduino.cc/Main/SoftwareI2CLibrary

вероятно, вы можете найти для себя другие варианты или потенциально можете создать свой собственный.

В семействе MPU-6050 также есть другие чипы, которые говорят на SPI вместо или так же, как на I2C, однако они, как правило, дороже.

,

2

По моим расчетам, общее подтягивание составляет:

1 / (1/10 + 1/10 + 1/4.7) = 2.423 k

Как я показываю на своей странице о I2C, подтягивающий резистор 2,2 К дает достаточно хороший сигнал:

2.2k pullup

Таким образом, я не думаю, что проблема в резисторах. И я не вижу, как добавление большего количества "немного успокоит все созвездие I2C".

,

Хорошо, мне придется проверить это еще раз. Спасибо!, @Dat Ha

Я думаю, что есть столкновение между DS3231 и GY-521. Если я удалю любой из них, код будет нормально работать с MPL3115A2. Но если они будут выполняться вместе, с MPL3115A2 или без него, программа не будет иметь предсказанного конечного результата. Если вы хотите, я мог бы включить код в редактирование моего вопроса., @Dat Ha

Было бы полезно добавить код к вашему вопросу., @Nick Gammon

Код был добавлен!, @Dat Ha

GY-521 имеет 2k2 или 10k подтягиваний в зависимости от игровой площадки Arduino. http://playground.arduino.cc/Main/MPU-6050, @Mikael Patel


2

Когда параллельно добавляются дополнительные резисторы, что происходит при добавлении новых устройств I2C на шину I2C, общий резистор снижается. Это может вызвать проблему с устройствами, которые не могут обеспечить достаточный ток при низком сопротивлении подтягиванию. Следовательно, устройство не будет хорошо функционировать, когда сопротивление подтягивания ниже определенного значения. Чтобы устранить проблему, я рекомендую удалить все параллельные подтягивающие резисторы и просто держать по одному на каждой линии, чтобы получить хорошее значение резистора примерно 4,7 К-Ом.

,