Wire.endTransmission(false) зависание программы после однократного запуска при использовании MPU6050

Для этого проекта я использовал Elegoo Car V3 и пытался добавить к нему гироскоп. Когда я запускаю код для автомобиля, мой код цикла повторяется один раз, и он всегда может считывать данные датчика. Но после этого программа начинает зависать. Я проследил проблему до строки Wire.endTransmission(false) в моем коде. По какой-то причине эта строка не была завершена во второй раз.

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

Спасибо, что нашли время помочь мне!

Это результат работы программы

RawX= 82
RawY= 241
RawZ= -1
-----------------------------------------
AngleX= 195.41
AngleY= 216.93
AngleZ= 200.14
-----------------------------------------

И это код


#include <Wire.h>

const int MPU_addr = 0x68;
int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;

int minVal = 265;
int maxVal = 402;

double x;
double y;
double z;
int c = 0;
 
//www.elegoo.com

//     Right motor truth table
//Here are some handy tables to show the various modes of operation.
//  ENB         IN3             IN4         Description  
//  LOW   Not Applicable   Not Applicable   Motor is off
//  HIGH        LOW             LOW         Motor is stopped (brakes)
//  HIGH        LOW             HIGH        Motor is on and turning forwards
//  HIGH        HIGH            LOW         Motor is on and turning backwards
//  HIGH        HIGH            HIGH        Motor is stopped (brakes)   

// define IO pin
#define ENA 5
#define ENB 6
#define IN1 7
#define IN2 8
#define IN3 9
#define IN4 11

//set car speed
#define CAR_SPEED 100
typedef unsigned char u8;  //Change the name of unsigned char to u8

void forward(u8 car_speed)
{
  analogWrite(ENA, car_speed);
  analogWrite(ENB, car_speed);
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, HIGH);
}


void back(u8 car_speed)
{
  analogWrite(ENA, car_speed);
  analogWrite(ENB, car_speed);
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
}


void left(u8 car_speed)
{
  analogWrite(ENA, 250);
  analogWrite(ENB, 250);
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);

  digitalWrite(IN3, LOW);
  digitalWrite(IN4, HIGH);
}

void right(u8 car_speed)
{
  analogWrite(ENA, 250);
  analogWrite(ENB, 250);
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
}

void stop()
{
  digitalWrite(ENA, LOW);
  digitalWrite(ENB, LOW);
}


int getGyroData() {
    Wire.beginTransmission(MPU_addr);
    Wire.write(0x3B);
    Wire.endTransmission(false);


    Wire.requestFrom(MPU_addr,6,true);
    AcX = Wire.read()<<8|Wire.read();
    AcY = Wire.read()<<8|Wire.read();
    AcZ = Wire.read()<<8|Wire.read();


    int xAng = map(AcX, minVal, maxVal,-90, 90);
    int yAng = map(AcY, minVal, maxVal,-90, 90);
    int zAng = map(AcZ, minVal, maxVal,-90, 90);

    x= RAD_TO_DEG * (atan2(-yAng, -zAng)+PI);
    y= RAD_TO_DEG * (atan2(-xAng, -zAng)+PI);
    z= RAD_TO_DEG * (atan2(-yAng, -xAng)+PI);

    Serial.print("AngleX= ");
    Serial.println(x);

    Serial.print("AngleY= ");
    Serial.println(y);

    Serial.print("AngleZ= ");
    Serial.println(z);
    Serial.println("-----------------------------------------");


}


void turn(int degrees) {
    int *originalData;
    originalData = getGyroData();
    int originalTurn = originalData[2];

    bool notDone = true;

    while (notDone) {
        
        int *newVal;
        newVal = getGyroData();
        int newTurn = newVal[2];

        int change = originalTurn - newTurn;
        Serial.println(change);
    }
}

void setup(){
  Wire.begin();
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x6B);
  Wire.write(0);
  Wire.endTransmission(true);
  pinMode(IN1, OUTPUT);//before useing io pin, pin mode must be set first 
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
  pinMode(ENA, OUTPUT);
  pinMode(ENB, OUTPUT);
  Serial.begin(9600);
  
}


void loop(){
    c++;
    
    Serial.println(c);
    Wire.beginTransmission(MPU_addr);
    Serial.println(c);
    Wire.write(0x43);
    Serial.println(c);
    Wire.endTransmission(false);

    Serial.println(c);
    Wire.requestFrom(MPU_addr,4,true);
    AcX = Wire.read()<<8|Wire.read();
    AcY = Wire.read()<<8|Wire.read();
    AcZ = Wire.read()<<8|Wire.read();
    Serial.println(c);

    Serial.print("RawX= ");
    Serial.println(AcX);

    Serial.print("RawY= ");
    Serial.println(AcY);

    Serial.print("RawZ= ");
    Serial.println(AcZ);
    Serial.println("-----------------------------------------");

    int xAng = map(AcX, minVal, maxVal,-90, 90);
    int yAng = map(AcY, minVal, maxVal,-90, 90);
    int zAng = map(AcZ, minVal, maxVal,-90, 90);

    x= RAD_TO_DEG * (atan2(-yAng, -zAng)+PI);
    y= RAD_TO_DEG * (atan2(-xAng, -zAng)+PI);
    z= RAD_TO_DEG * (atan2(-yAng, -xAng)+PI);

    Serial.print("AngleX= ");
    Serial.println(x);

    Serial.print("AngleY= ");
    Serial.println(y);

    Serial.print("AngleZ= ");
    Serial.println(z);
    Serial.println("-----------------------------------------");
    delay(500);
    
}

Это схема машины, которую я нашел

This is a schematic of the car I found

, 👍2


1 ответ


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

3

В комментариях ниже @chrisl делает что-то явное, чего я не делал в предыдущих правках. Прочтение его первым может облегчить интерпретацию нижеследующего:

Полезный факт о I2C на Arduino: Wire.endTransmission() - это функция, которая фактически выполняет связь I2C. До этого (все вызовы Wire.beginTransmission() и Wire.write()) никакие данные не будут проходить по шине, просто помещенные в буфер библиотек. Таким образом, повешение Wire.endTransmission() равен заблокированной шине I2C.


На UNO A4 и A5 - это SDA и SCL, те же сигналы, которые доступны рядом с AREF и контактом 13 на другой стороне платы.

Итак, к ультразвуковому дальномер на картинке прилагаются сигналы, которые необходимы для работы шины I2C ("Wire"), и могут легко мешать Wire.endTransmission (false). Один из сигналов I2C, вероятно, вызывает срабатывание пальца диапазона во время трафика I2C. После каждого триггера эхо-сигнал от дальномера будет мешать подключенному сигналу шины I2C.

Вы можете попробовать бит-бит I2C, используя библиотеку вместо родного I2C, который находится на A4 / A5, и использовать его для управления гироскопом. Согласно вашей диаграмме, A0-A3 не используются и, по-видимому, являются единственными сигналами, не используемыми UNO. Несмотря на то, что они являются "аналоговыми" штифтами, они также функционируют как цифровые штифты и должны отлично работать для бит-битинга. Однако добраться до них может быть непросто, так как щит, похоже, не делает их снова доступными в виде булавок.

Или же вы можете направить ультразвуковой датчик подальше от A4 / A5, либо не подключая его к коллектору на экране, а вместо этого направляя сигналы от штекера туда, где имеется неиспользуемый набор контактов (опять же A0, хотя A3), а затем соответствующим образом обновляя код. Другая возможность может заключаться в том, чтобы оставить его подключенным к щиту, но согнуть штифты A4 и A5 в сторону, чтобы они не входили в UNO ниже, и использовать перемычки, чтобы направить их от согнутых штифтов к какой-нибудь другой паре доступных штифтов; вы не сможете сгибать их взад и вперед больше, чем раз или два, так что я буду осторожен с этой попыткой.

,

Полезный факт о I2C на Arduino: "Wire.endTransmission()" - это функция, которая фактически выполняет связь I2C. До этого (все вызовы Wire.beginTransmission() и Wire.write()) никакие данные не будут проходить по шине, просто помещенные в буфер библиотек. Таким образом, висящий "Wire.endTransmission()" равен заблокированной шине I2C., @chrisl

Да, наверное, мне следовало бы сказать об этом прямо. Позже я отредактирую его, чтобы включить ваш комментарий., @timemage

@timemage Это сработало как заклинание! Удаление ультразвукового датчика позволило гироскопу функционировать. Спасибо, что ответили так быстро! Я просто хотел спросить вас, почему контакты A4 и A5 используются для контактов связи SDA и SCL. Могу ли я использовать какие-либо другие аналоговые контакты для гироскопа?, @Akash Dubey

Я могу попытаться обновить ответ, чтобы он был более четким. Контакт на AVR может иметь специальные функции, помимо простого входа GPIO (с возможностью digitalRead / digitalWrite) или подключения к аналого-цифровому преобразователю (с возможностью analogRead). I2C / TWI "Провод" - это специальная функция, найденная только на контактах A4 и A5 UNO. Для сравнения, ультразвуковой датчик использует только общие функции GPIO, которые можно использовать практически на любом выводе. Поэтому имеет смысл поставить гироскоп на A4 / A5 и переместить ультразвуковой датчик на A0-A3, когда это возможно., @timemage

Использование I2C / Wire без помощи встроенной поддержки чипа для I2C ** - это то, что по сути означает "битный стук"., @timemage

Чтобы уточнить, тот факт, что собственный функционал I2C / Wire существует на тех же контактах, что и некоторые функции аналогового входа, зависит от того, как был построен чип ATmega328P, а не от выбора дизайна для Arduino UNO., @timemage