[gelöst] Pro Micro & MPU6050 funktioniert immer nur das erste Mal nach Upload

Hallo,

Ich habe einen Beschleunigungssensor GY-521 (MPU6050) an einem Arduino Pro Micro. Damit möchte ich eine LED anschalten, wenn der Sensor bewegt wird.

Nach etwas Ausprobieren funktioniert es soweit, allerdings nur direkt nach dem Hochladen des Sketches. Trenne ich das USB-Kabel und verbinde es wieder, funktioniert nichts mehr :slightly_frowning_face: . Lade ich den Sketch erneut hoch funktioniert es wieder bis zum nächsten Trennen der Stromversorgung. Dann wieder nicht mehr.
Andere kleine Sketches ohne den GY-521 funktionieren auch nach dem trennen/wiederherstellen der Stromversorgung, daher vermute ich, dass es an meinem Code (wahrscheinlich dem I²C?) liegt. Was mache ich falsch?

#include <Wire.h>

#define MPU6050_ADRESS 0x68

const int ACCEL_OFFSET   = 200;
const int GYRO_OFFSET    = 151;  // 151
const int GYRO_SENSITITY = 131;  // 131 is sensivity of gyro from data sheet
const float GYRO_SCALE   = 0.5; //  0.02 by default - tweak as required
const float LOOP_TIME    = 0.1; // 0.1 = 100ms

int accValue[3], accAngle[3], gyroValue[3], temperature, accCorr;
float gyroAngle[3], gyroCorr;

float beschlmittel;
int zaehler;
int LEDb = 8;

void setup()
{
  Wire.begin();
  Wire.beginTransmission(MPU6050_ADRESS); // Begins a transmission to the I2C slave (GY-521 board)
  Wire.write(0x6B); // PWR_MGMT_1 register
  Wire.write(0); // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);

  zaehler = 1;
  pinMode(LEDb, OUTPUT);  // Set LED 8 (blau) as an output

  Serial.begin(9600);
  Serial.flush();
}

void loop()
{
  Wire.beginTransmission(MPU6050_ADRESS);
  Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false); // the parameter indicates that the Arduino will send a restart. As a result, the connection is kept active.
  Wire.requestFrom(MPU6050_ADRESS, 7*2, true); // request a total of 7*2=14 registers

  // "Wire.read()<<8 | Wire.read();" means two registers are read and stored in the same variable
  for(byte i=0; i<3; i++) {
    accValue[i] = Wire.read()<<8 | Wire.read(); // reading registers: ACCEL_XOUT, ACCEL_YOUT, ACCEL_ZOUT
  }

  for(byte i=0; i<3; i++) {
    accCorr = accValue[i] - ACCEL_OFFSET;
    accCorr = map(accCorr, -16800, 16800, -90, 90);
    accAngle[i] = constrain(accCorr, -90, 90);
  }

  //Mittelwertbildung über Zeitabschnitt & vergleich des Deltas zum vorangehenden Zeitabschnitt
  beschlmittel = beschlmittel + accAngle[1];
  zaehler = zaehler + 1;
  if (zaehler > 60) {
    zaehler = 1;
    beschlmittel = beschlmittel / 60;
    if (abs(accAngle[1] - beschlmittel)>3) {
      digitalWrite(LEDb, HIGH);   // set the LED 8 ON
    }
    else {
        digitalWrite(LEDb, LOW);    // set the LED 8 OFF
      }
    beschlmittel = 0;
  }
  delay(LOOP_TIME * 10);
}

PS: Den Sketch habe ich von hier kopiert und selbst modifiziert.

microdave:
PS: Den Sketch habe ich von hier kopiert und selbst modifiziert.

Dann schau, wo Du Änderungen gemacht hast - fang ggegefls wieder von vorn an und mach es Schrittweise, bis der Effekt wieder auftritt.

Fange schon mal hiermit an:

const float LOOP_TIME    = 0.1; // 0.1 = 100ms

  delay(LOOP_TIME * 10);
}

(deleted)

Im Setup fehlt:

while(!Serial);

HotSystems:
Im Setup fehlt:

while(!Serial);

Nicht unbedingt!

while(!Serial);
Wartet darauf, dass die serielle Schnittstelle geöffnet wird.
Es verhindert also, dass das Programm weiter- bzw. losläuft.
Das resultierende Verhalten ist kontraproduktiv, wenn das Programm auch ohne seriellen Monitor laufen soll.

Ich dachte Serial.flush(); wartet bis das setup an den Sensor übertragen wurde, aber damit liege ich wohl falsch. Wenn ich Serial.flush(); weglasse macht das aber keinen Unterschied ...

Aha, wenn ich den seriellen Monitor am PC starte läuft es wieder. Ja, dann ist jetzt die Frage wie ich das ganze ohne Seriellen Monitor hinbekommen kann?

combie:
Nicht unbedingt!

while(!Serial);
Wartet darauf, dass die serielle Schnittstelle geöffnet wird.
Es verhindert also, dass das Programm weiter- bzw. losläuft.
Das resultierende Verhalten ist kontraproduktiv, wenn das Programm auch ohne seriellen Monitor laufen soll.

danke....ok ich werds mir merken. hoffe ich. :wink:

microdave:
Ich dachte Serial.flush(); wartet bis das setup an den Sensor übertragen wurde, aber damit liege ich wohl falsch.

Nee, nee. Ist schon richtig: Die Funktion kommt dann zurück, wenn alle zur Aussendung anstehenden Bytes auch wirklich gesendet wurden. Das kann je nach Baudrate auch mal einen Moment dauern.

Wenn ich Serial.flush(); weglasse macht das aber keinen Unterschied ...

Das ist dann auch nicht zu erwarten.

Aha, wenn ich den seriellen Monitor am PC starte läuft es wieder.

Das liegt vermutlich daran, dass Du damit einen Reset auslöst.

Das eigentliche Problem ist m.E. ein anderes: Du fordert 14 Byte an, liest aber nur sechs:

...
  Wire.requestFrom(MPU6050_ADRESS, 7*2, true); // request a total of 7*2=14 registers

  for(byte i=0; i<3; i++) {
    accValue[i] = Wire.read()<<8 | Wire.read(); // reading registers: ACCEL_XOUT, ACCEL_YOUT, ACCEL_ZOUT
  }
...

wno158:
Das eigentliche Problem ist m.E. ein anderes: Du fordert 14 Byte an, liest aber nur sechs:

OK, da hast du recht, habs korrigiert.
Leider funktioniert es damit immer noch nur direkt nach dem Upload und nach trennen und wiederverbinden der Stromversorgung (USB) nicht mehr.

 Wire.requestFrom(MPU6050_ADRESS, 3*2, true); // request a total of 3*2=6 registers

  for(byte i=0; i<3; i++) {
    accValue[i] = Wire.read()<<8 | Wire.read(); // reading registers: ACCEL_XOUT, ACCEL_YOUT, ACCEL_ZOUT
  }

Kann es sein, dass es etwas mit den beiden Serial-Ports des Micro Pro zu tun hat?
Auf Sparkfun ist zu Serial und Serial1 folgendes zu lesen:

That "1" makes a huge difference. Think of the Pro Micro having two separate serial ports. The one without the "1" is for communication to and from the computer over USB; this is what is visible in the Serial Monitor. The Serial1 port is a bonafide, hardware UART, where your Pro Micro can talk to any serial-enabled piece of hardware.

Du fordert 14 Byte an, liest aber nur sechs:

Die Frage ist die: Wie viele werden überhaupt geliefert?
Immerhin würde ja Wire.requestFrom() auch gerne die Anzahl erhaltener Byte abliefern.
Hat nur nicht die Chance.

Kann es sein, dass es etwas mit den beiden Serial-Ports des Micro Pro zu tun hat?

Ich denke nicht. Serial benutzt Du so wie mit jedem anderen Arduino (Leonardo oder Micro), Serial1 wie jede andere Schnittstelle (z.B. I2C oder SPI oder einen digitalen Pin) wenn die Applikation es erfordert.

Anmerkung: delay() (am Ende Deiner Loop) erwartet ein unsigned long in Millisekunden. Du übergibst ein float. Das solltest Du korrigieren.

Zwei Fragen habe ich noch:
Was hast Du in der IDE als Board eingestellt?
Funktioniert es, wenn Du alles mit 'Serial' im Sketch stilllegst?

wno158:
...Anmerkung: delay() (am Ende Deiner Loop) erwartet ein unsigned long in Millisekunden...

Danke, ist korrigiert.

wno158:
Zwei Fragen habe ich noch:
Was hast Du in der IDE als Board eingestellt?
Funktioniert es, wenn Du alles mit 'Serial' im Sketch stilllegst?

  1. SparkFun Pro Micro - ATmega32U4 (5V, 16MHz)
  2. Kein Unterschied ob mit oder ohne "Serial.begin(9600);" und "Serial.flush();"
    Ergänzung zur ersten Frage: Ich habe ein "Arduino Pro Micro kompatibles Board ATmega32U4" also nicht das Original von SparkFun.

(deleted)

Wenn es für den Sparkfun in der IDE keinen eigenen Eintrag gibt (was bei mir der Fall ist) wären die nächsten originalen Verwandten der Leonardo oder der Micro (ATmega 32U4).
Arduini Pro oder Pro Mini sind beides ATmega 328er.

Hast Du zufällig noch ein direkt von der IDE unterstützes Derivat rumliegen (ein Original-Leonardo z.B.) und kannst es damit mal probieren?

Bitte nicht falsch verstehen, habe mir die Board-Files für den SparkFun in die IDE geladen. Dann kann ich als Board "SparkFun Pro Micro - ATmega32U4 (5V, 16MHz)" auswählen.

Soll ich nun versuchen mit der Einstellung für "Leonardo" hochzuladen?

Habe leider momentan kein anderes Board da. Das letzte Mal Arduino ist schon 2 Jahre her und ich finde das alte Zeugs nicht mehr.

Schaltplan bin ich dran, dauert noch kurz...

Nee, wenn es von Sparkfun ein Boardfile gibt, sollte das ja das richtige sein. So tief hatte ich da auf deren Seite nicht gebohrt - Tschuldigung!

...zeige mal ein Schaltplan von deinem Testaufbau...

Anbei der Schaltplan und zwei Fotos von meinem Aufbau.

zweites Foto:

Back to the roots. Ich habe nun versucht meinen Code aufs Wesentliche zu reduzieren, damit die Fehlersuche einfacher wird.

Grundfunktion: Wenn der GY-521 Sensor bewegt wird, leuchtet die LED. Wenn nicht geht die LED aus.

#include <Wire.h>

#define MPU6050_ADRESS 0x68

int accValue, LEDb = 8;
float vorher;

void setup()
{
  Wire.begin();
  Wire.beginTransmission(MPU6050_ADRESS); // Begins a transmission to the I2C slave (GY-521 board)
  Wire.write(0x6B); // PWR_MGMT_1 register
  Wire.write(0); // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);

  pinMode(LEDb, OUTPUT);
}

void loop()
{
  Wire.beginTransmission(MPU6050_ADRESS);
  Wire.write(0x3D); // starting with register 0x3D (ACCEL_YOUT_H)
  Wire.endTransmission(false); // the parameter indicates that the Arduino will send a restart. As a result, the connection is kept active.
  Wire.requestFrom(MPU6050_ADRESS, 2, true); // request a total of 2 registers (ACCEL_YOUT_H & ACCEL_YOUT_L)

  accValue = Wire.read()<<8 | Wire.read(); //"Wire.read()<<8 | Wire.read();" means two registers are read and stored in the same variable

  //Wenn aktueller Wert accValue zu stark vom vorherigen Wert abweicht leuchtet die LED
  if (abs(accValue-vorher)>400) {
    digitalWrite(LEDb, HIGH);
    delay(1000);
  }
  else {
        digitalWrite(LEDb, LOW);
  }
  vorher = accValue;
}

Soeben ausprobiert, der Code funktioniert.

Nur nach Trennen und Wiederverbinden des USB-Kabels funktioniert es leider nicht mehr.
Nach erneutem Hochladen funktioniert es wieder, nach Trennen und Wiederverbinden wieder nicht mehr.

An was könnte es noch liegen, dass nach Unterbrechen der Stromversorgung nichts mehr geht?

JAAAA, ES GEEEEHT. :smiley: :smiley: :smiley: :smiley: :smiley:

Leute, ich hab's.

Der MPU6050 lieferte nach einem Trennen und Wiederverbinden des USB-Kabels keinen Wert mehr zurück. Vermutlich läuft das Setup des Arduino schon ab, bevor der MPU6050 bereit ist oder überhaupt mit Strom versorgt wird.
Nun habe ich im "void setup" als erstes ein delay(1000); eingefügt und siehe da der MPU6050 liefert auch nach Wiederverbinden Werte zurück und es funktioniert.

Sowohl der reduzierte Code im vorherigen Beispiel als auch der Code in meinem ersten Post funktionieren mit einem delay(1000); am Anfang vom Setup.

...
void setup()
{
  delay(1000);
  Wire.begin();
  Wire.beginTransmission(MPU6050_ADRESS);
...

Danke euch für eure Hilfeversuche, ich habe dadurch auch wieder einiges dazugelernt. =)