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, и в нем я сказал, что мне удалось успешно считывать данные с датчика, но позже я узнал, что это были номера мусора. :(
@Tobias Guo, 👍3
Обсуждение3 ответа
Лучший ответ:
Из карты регистра MPU-6000/MPU-6050 и описаний:
Раздел 4.28, Регистрация 107 – Управление питанием 1 PWR_MGMT_1, страницы 40-41:
Примечание:
При использовании интерфейса SPI пользователь должен использовать DEVICE_RESET (регистр 107), а также SIGNAL_PATH_RESET (регистр 104), чтобы убедиться, что сброс выполнен правильно. Используемая последовательность должна быть:- Установить DEVICE_RESET = 1 (зарегистрировать PWR_MGMT_1)
- Подождите 100 мс
- Установить GYRO_RESET = ACCEL_RESET = TEMP_RESET = 1 (зарегистрировать SIGNAL_PATH_RESET)
- Подождите 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();
}
В следующем коде я написал:
Изменено
readGyro ()
, чтобы реализовать 3 состояния (Запрос, ожидание и чтение) и возвращать значениеtrue
, когда из MPU-6050 было считано 6 байт.Добавлено Мигание без задержки в
loop ()
, чтобы увидеть, зависает ли MCU, для чего требуется изменить вывод ADO с вывода 13 (встроенный светодиод) на другой вывод, т. Е. вывод 12.Добавлено несколько
последовательных инструкций.print()
для отладки, чтобы увидеть, где что-то идет не так.Изменил код в ответ на комментарии.
#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 В:
6.4 Электрические характеристики, Продолжение
Для этого потребуются переключатели уровней сигналов между 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
Некоторое время назад, выясняя свои собственные трудности с 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
Я использовал 5 В от моего Arduino для питания MPU6050, и все было в порядке. Проверьте: https://www.instructables. com/How-to-Make-a-Robot-Car-Drive-Straight-and-Turn-Ex/ с очень похожим кодом.
Кроме того, я обычно избегаю контакта 13, так как он выполняет какую-то особую дополнительную функцию, в отличие от контактов 2–12.
- Изменение адреса I2C MPU-6050
- Использование MPU-6050 без I2C
- Почему Wire.write дважды?
- Мультиплексор Adafruit MPU-6050 и adafruit I2C
- Несколько устройств I2C, подключенных к одному Arduino Uno?
- запрос члена "X" в чем-то, кроме структуры или союза
- MPU-6050 с Arduino – вскрытие
- Код показывает одинаковые углы для всех трех осей гироскопа MPU
Было бы хорошо дать ссылку на вопросы, по которым вы перепробовали все решения, чтобы люди точно знали, чего не следует повторять. Если вы можете, проверьте сигналы с помощью оптического прицела. Одной из потенциальных разниц между сканером I2C и библиотеками является запрашиваемая тактовая частота., @timemage