MPU6050 не выдает выход

Мне нужна помощь, чтобы мой MPU 6050 действительно предоставил мне данные. На данный момент моя программа считывает только 0 с гироскопа, и когда я перемещаю его, все значения становятся равными -1, и программа просто останавливается, пока я не закрою и снова не открою последовательный монитор. Я знаю, что этот вопрос уже задавался несколько раз, но я уже рассматривал каждый из этих вопросов и перепробовал все исправления, перечисленные там, но ни одно из них не сработало. Сканер I2C действительно находит датчик на 0x68, но это единственное, что работает. Это все совершенно новые платы, которые я получил пару дней назад.

Я перепробовал все библиотеки и все примеры скетчей, которые смог найти. Я перешел на 2 новые платы. Я даже попытался просмотреть таблицу данных для MPU 6050 и напрямую прочитать/записать регистры, но все равно не получил никаких результатов. Последовательный монитор либо остается пустым, показывает только 0 или-1, либо просто выдает мне значения мусора, которые меняются случайным образом. Пожалуйста, помогите мне.

Я подключил датчик следующим образом (в настоящее время я использую Arduino Uno):

VCC ==> 5 В>
GND ==> GND
SCL ==> A5
ПДД ==> А4>
AD0 ==> цифровой 13 (установлен на НИЗКИЙ уровень)>

И код, который я использую, таков:

#include <Wire.h>

const int addressPin = 13;

int gyroX, gyroY, gyroZ;

void setup() {
  Wire.begin();
  Serial.begin(9600);

  //designating pins as I/O
  pinMode(addressPin, OUTPUT);

  //setting IMU address to 0x68 (LOW)
  digitalWrite(addressPin, LOW);

  initializeSensor();
}

void loop() {
  readGyro();

  Serial.print(gyroX);
  Serial.print("    ");
  Serial.print(gyroY);
  Serial.print("    ");
  Serial.println(gyroZ);
}

void initializeSensor() {
  //performing full device reset, disables temperature sensor, disables SLEEP mode
  Wire.beginTransmission(0x68);

  Wire.write(0x6B);
  Wire.write(0b10001000);

  Wire.endTransmission();

  //writing to gyro config register
  Wire.beginTransmission(0x68);

  Wire.write(0x1B);
  Wire.write(0b00001000);

  Wire.endTransmission();
}

void readGyro() {
  //requesting data from gyro data registers
  Wire.beginTransmission(0x68);

  Wire.write(0x43);
  
  Wire.endTransmission();

  Wire.requestFrom(0x68, 6);
  
  gyroX = Wire.read()<<8|Wire.read();
  gyroY = Wire.read()<<8|Wire.read();
  gyroZ = Wire.read()<<8|Wire.read();
}

P.S. Несколько недель назад я опубликовал вопрос об устройствах I2C, и в нем я сказал, что мне удалось успешно считывать данные с датчика, но позже я узнал, что это были номера мусора. :(

, 👍3

Обсуждение

Было бы хорошо дать ссылку на вопросы, по которым вы перепробовали все решения, чтобы люди точно знали, чего не следует повторять. Если вы можете, проверьте сигналы с помощью оптического прицела. Одной из потенциальных разниц между сканером I2C и библиотеками является запрашиваемая тактовая частота., @timemage


3 ответа


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

3

Из карты регистра MPU-6000/MPU-6050 и описаний:

  • Раздел 4.28, Регистрация 107 – Управление питанием 1 PWR_MGMT_1, страницы 40-41:

    Примечание:
    При использовании интерфейса SPI пользователь должен использовать DEVICE_RESET (регистр 107), а также SIGNAL_PATH_RESET (регистр 104), чтобы убедиться, что сброс выполнен правильно. Используемая последовательность должна быть:

    1. Установить DEVICE_RESET = 1 (зарегистрировать PWR_MGMT_1)
    2. Подождите 100 мс
    3. Установить GYRO_RESET = ACCEL_RESET = TEMP_RESET = 1 (зарегистрировать SIGNAL_PATH_RESET)
    4. Подождите 100 мс
  • Раздел 4.26, Регистр 104 – Сброс пути сигнала SIGNAL_PATH_RESET, страница 37:

    Примечание: Этот регистр не очищает регистры датчиков. Сброс также инициализирует последовательный интерфейс.

  • Раздел 3, Карта регистрации, страница 8:

    Значение сброса равно 0x00 для всех регистров, кроме приведенных ниже.

    • Регистрация 107: 0x40.
    • Регистрация 117: 0x68.

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

void initializeSensor()
{
  //
  // Perfrom full reset as per MPU-6000/MPU-6050 Register Map and Descriptions, Section 4.28, pages 40 to 41.
  //

  // performing full device reset, disables temperature sensor, disables SLEEP mode
  Wire.beginTransmission(0x68);  // Device address.
  Wire.write(0x6B);              // PWR_MGMT_1 register.
  Wire.write(0b10001000);        // DEVICE_RESET, TEMP_DIS.
  Wire.endTransmission();
  delay(100);                    // Wait for reset to complete.

  Wire.beginTransmission(0x68);  // Device address.
  Wire.write(0x68);              // SIGNAL_PATH_RESET register.
  Wire.write(0b00000111);        // GYRO_RESET, ACCEL_RESET, TEMP_RESET.
  Wire.endTransmission();
  delay(100);                    // Wait for reset to complete.

  // Disable SLEEP mode because the reset re-enables it. Section 3, PWR_MGMT_1 register, page 8.
  Wire.beginTransmission(IMUAddress);   // Device address.
  Wire.write(0x6B);                     // PWR_MGMT_1 register.
  Wire.write(0b00001000);               // SLEEP = 0, TEMP_DIS = 1.
  Wire.endTransmission();
}

В следующем коде я написал:

  1. Изменено readGyro (), чтобы реализовать 3 состояния (Запрос, ожидание и чтение) и возвращать значение true, когда из MPU-6050 было считано 6 байт.

  2. Добавлено Мигание без задержки в loop (), чтобы увидеть, зависает ли MCU, для чего требуется изменить вывод ADO с вывода 13 (встроенный светодиод) на другой вывод, т. Е. вывод 12.

  3. Добавлено несколько последовательных инструкций.print() для отладки, чтобы увидеть, где что-то идет не так.

  4. Изменил код в ответ на комментарии.

#include <Wire.h>

const byte IMUAddress = 0x68;   // Added for readability and maintainability.
const byte addressPin = 12;     // Changed from 13 to 12 because 13 is built-in LED.

int gyroX, gyroY, gyroZ;

void setup()
{
  Wire.begin();
  Serial.begin(115200);
  Serial.println(F("\n\nMPU-6050 Test\n"));

  // Designating pins as I/O.
  pinMode(addressPin, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);  // Added LED for heartbeat signal.

  // Setting IMU address to 0x68 (LOW).
  digitalWrite(addressPin, IMUAddress & 1);  // Added bit mask of bit 0.

  initializeSensor();
}

void loop()
{
  //
  // TASK 1: Blink without delay to indicate that MCU hasn't frozen.
  //
  const unsigned int INTERVAL = 250;
  unsigned long current_timestamp = millis();
  static unsigned long previous_timestamp = current_timestamp;
  static bool led_state = false;
  if (current_timestamp - previous_timestamp >= INTERVAL)
  {
    led_state = !led_state;
    digitalWrite(LED_BUILTIN, led_state);
    previous_timestamp += INTERVAL;
  }

  //
  // TASK 2: Read gyro.
  //
  if (readGyro())
  {
    Serial.print(gyroX);
    Serial.print(F("    "));
    Serial.print(gyroY);
    Serial.print(F("    "));
    Serial.println(gyroZ);
  }
}

void initializeSensor()
{
  //
  // Perform full reset as per MPU-6000/MPU-6050 Register Map and Descriptions, Section 4.28, pages 40 to 41.
  //

  Serial.print(F("Performing full reset of MPU-6050..."));

  Wire.beginTransmission(IMUAddress);   // Device address.
  Wire.write(0x6B);                     // PWR_MGMT_1 register.
  Wire.write(0b10001000);               // DEVICE_RESET, TEMP_DIS.
  Wire.endTransmission();
  delay(100);                           // Wait for reset to complete.

  Wire.beginTransmission(IMUAddress);   // Device address.
  Wire.write(0x68);                     // SIGNAL_PATH_RESET register.
  Wire.write(0b00000111);               // GYRO_RESET, ACCEL_RESET, TEMP_RESET.
  Wire.endTransmission();
  delay(100);                           // Wait for reset to complete.

  Serial.println(F(" Done."));

  // Disable SLEEP mode because the reset re-enables it. Section 3, PWR_MGMT_1 register, page 8.
  Serial.print(F("Disabling sleep mode of MPU-6050..."));
  Wire.beginTransmission(IMUAddress);   // Device address.
  Wire.write(0x6B);                     // PWR_MGMT_1 register.
  Wire.write(0b00001000);               // SLEEP = 0, TEMP_DIS = 1.
  Wire.endTransmission();
  Serial.println(F(" Done."));

  //
  // Writing to gyro config register.
  //
  Serial.print(F("Configuring gyro of MPU-6050..."));
  Wire.beginTransmission(IMUAddress);   // Device address.
  Wire.write(0x1B);                     // GYRO_CONFIG register.
  Wire.write(0b00001000);               // +/-500 deg/s.
  Wire.endTransmission();
  Serial.println(F(" Done."));
}

typedef enum State
{
  Request,
  Wait,
  Read
};

bool readGyro()
{
  static State state = State::Request;

  switch (state)
  {
    case State::Request:
      // Request data from gyro data registers.
      Serial.print(F("Requesting data from gyro..."));
      Wire.beginTransmission(IMUAddress);   // Device address.
      Wire.write(0x43);                     // GYRO_XOUT_H register.
      Wire.endTransmission(false);          // Restart connection, i.e. keep alive.
      Wire.requestFrom(IMUAddress, 6);      // GYRO_XOUT_H, GYRO_XOUT_L, GYRO_YOUT_H, GYRO_YOUT_L, GYRO_ZOUT_H, GYRO_ZOUT_L.
      Serial.println(F(" Done."));
      state = State::Wait;
      Serial.print(F("Waiting for data from gyro..."));
      break;

    case State::Wait:
      // Wait for data to arrive into buffer.
      if(Wire.available() < 6)
      {
        //Serial.print(F("."));
        Serial.print(F(" "));
        Serial.print(Wire.available());  // Added to show bytes received.
      }
      else
      {
        Serial.print(F(" "));
        Serial.print(Wire.available());  // Added to show bytes received.
        Serial.println(F(" Done."));
        state = State::Read;
      }
      break;

    case State::Read:
      // Read data from gyro registers.
      Serial.print(F("Reading gyro data..."));
      gyroX = Wire.read() << 8 | Wire.read();
      gyroY = Wire.read() << 8 | Wire.read();
      gyroZ = Wire.read() << 8 | Wire.read();
      Serial.println(F(" Done."));
      state = State::Request;
      return true;  // Indicate data was received.
      break;
  }

  return false;  // Indicate no data received yet.
}

Обновление основано на ответе Роуанпа

Сосредоточившись на проблемах программного обеспечения, я пропустил важную часть информации из другой спецификации (Спецификация продукта MPU-6000/MPU-6050), т. Е. Электрические характеристики в разделах 6.3 и 6.4 на страницах 14 и 15, показывающие диапазон Vdd от 2,375 В до 3,46 В:

Electrical Characteristics of MPU-6050 Vdd power supply of MPU-6050

6.4 Электрические характеристики, Продолжение Digital inputs and outputs of MPU-6050

Для этого потребуются переключатели уровней сигналов между 3,3 В MPU-6050 и 5 В Arduino.

,

Спасибо за помощь! Я просмотрел контрольный список, который дал мне Роуэн, и исправил все, что, по моему мнению, могло быть неправильным, включая переключение на вывод 3,3 В для питания Uno. Я также использовал ваш код, и, похоже, он по-прежнему выдает только 0 секунд, но когда я поворачиваю датчик вокруг оси y, код застревает в состоянии :: Ожидание и печатает только периоды (но индикатор сердцебиения не останавливается). У тебя есть какие-нибудь идеи, почему?, @Tobias Guo

@TobiasGuo, как уже говорили другие, чип может быть поврежден из-за питания 5 В. Хотя 5 В находится в пределах абсолютного максимального значения 6 В, это выходит за рамки рекомендуемого рабочего напряжения. У вас есть переключатели уровней на SCL, SDA и ADO? Попробуйте заменить печать периода на " Serial.println(Wire.available ());", чтобы узнать, сколько байтов ему удается прочитать., @tim

@TobiasGuo, вы также можете распечатать и проверить возвращаемое значение каждого [Wire.endTransmission()](https://www.arduino.cc/en/Reference/WireEndTransmission)., @tim

@TobiasGuo, у тебя получилось? Я заметил из вашего вопроса о значениях акселерометра , что вы изменили код, т. е. отключили СПЯЩИЙ режим без выполнения сброса, потому что сброс повторно включает СПЯЩИЙ режим (раздел 3, регистр PWR_MGMT_1, стр. 8), и использовали функцию keep-alive с " Wire.endTransmission(false)` перед запросом данных., @tim

Я еще не пробовал этого. Я работал над поиском некоторых переключателей уровней для подключения к другим контактам на MPU, поэтому я еще не смог протестировать код. Я отвечу другим комментарием, как только у меня будет, и дам вам знать, как идут дела! Еще раз спасибо за помощь!, @Tobias Guo

@TobiasGuo, вот [простой двунаправленный уровень shifter](https://www.falstad.com/circuit/circuitjs.html?ctz=CQAgjCAMB0l3BWcMBMcUHYMGZIA4UA2ATmIxAUgoqoQFMBaMMAKADMQ8AWPcDQzjxCYUIbKLDQkMSChYAnEBgSiRSlXwFUw8SApDEuXTQaPCMo7bpYB3TuPOjlqi1FvqXownl5q5dvEJjNUNg1z07UMdkfGi5ACUPE2dwFF4qKi4qbGhsKHyYBBZEqLB+U2MwNIKQLOoMqCl3FLKBbl5WtztvXmxsNqE+rXd2sX6Y3vG9AHNBSYHe7wKWAGcJ6J1YofyINgBDABsVulWQHrGBc7VtEH2jk4APM7BiYUJLrleiV8rRAGUAMIAGVYTx0Dm+yEInlqqRAgKBcieGBeBnIxDwSE2sJQxgAQgBLBgAEwJ8joAGMAC4EgD2ADtDgAdFYHOgANzoBxZKwAFgS2FS6PIWLTYUF8lkMfVYNJhLC8gjWGKPpLINKuNBSBjmAhvDxCBhIHkZHAIFQvGJ4cC5EA). Нажмите переключатели., @tim

Спасибо! Похоже, это решило проблему! Я также перешел на использование библиотеки I2Cdev, и это помогло упростить процесс связи с датчиками, но теперь мои MPU фактически выдают мне правильный вывод!, @Tobias Guo


3

Некоторое время назад, выясняя свои собственные трудности с I2C, я провел некоторое исследование и перечислил все режимы сбоев и методы тестирования, которые я мог придумать в отношении I2C. Смотрите, что протокол I2C работает неправильно. Сейчас я регулярно просматриваю список, чтобы отметить то, что мне нужно проверить, чтобы новое соединение I2C заработало, обычно это что-то простое (скрещенные пальцы). У вас есть доступ к осциллографу?

(Править) Этот старый пост, похоже, описывает аналогичную проблему (только получение нулей) MPU6050 не работает. Все пришли к единому мнению, что 3,3 В MPU6050 был подключен к 5 В UNO, сжигая чип MPU6050. Это очень похоже на вашу ситуацию.

,

Спасибо, что связали этот контрольный список. Я пробегусь по нему, чтобы посмотреть, не пропустил ли я что-нибудь или есть ли что-нибудь еще, что я могу сделать, чтобы исправить это. У меня сложилось впечатление, что вывод VCC на MPU 6050 был разработан для работы с источником питания 5 В, но, возможно, я ошибался. Я обязательно попробую переключиться на источник питания 3,3 В!, @Tobias Guo

Какой модуль вы используете? Я использую модуль DFRobots 6DOF (https://wiki.dfrobot.com/6_DOF_Sensor-MPU6050__SKU_SEN0142_) и он отлично работает с питанием 5 В. Вы также можете попробовать взглянуть на это (https://www.fpaynter.com/2019/10/basic-arduino-mpu6050-gy-521-test/) и соответствующие статьи о MP6050 на моем веб-сайте (fpaynter.com), @user3765883

Я вернулся и проверил свое последнее использование модуля MPU6050, и, несмотря на ссылку, которую я опубликовал в своем ответе, я согласен с @user3765883, модули, которые у меня были, также устойчивы к 5 В. У меня нет схемы, но при ближайшем рассмотрении модуля на борту есть регулятор мощности с маркировкой 4A20. В зависимости от конкретного модуля, который вы используете, я думаю, что предыдущая ссылка о чипе MPU6050 с напряжением 3,3 В может быть отвлекающим маневром!, @RowanP

Итак, есть свидетельства по крайней мере двух различных типов модулей, находящихся в обращении. Один с регулятором мощности от 5 до 3,3 В и один без. Видишь https://forum.arduino.cc/t/mpu6050-eagle-files-out-of-date/633197, @RowanP


2

Я использовал 5 В от моего Arduino для питания MPU6050, и все было в порядке. Проверьте: https://www.instructables. com/How-to-Make-a-Robot-Car-Drive-Straight-and-Turn-Ex/ с очень похожим кодом.

Кроме того, я обычно избегаю контакта 13, так как он выполняет какую-то особую дополнительную функцию, в отличие от контактов 2–12.

,