Display und MPU6050 I2C Probleme

Hallo Forum,

ich betreibe einen Uno R4 mit MPU6050 und einen Oled Display an einen I2C Bus.
Nach ca. 1 Stunde hängt sich der I2C Bus auf bzw. funktioniert nicht mehr.

Ein reset des Arduino hilft nichts, nur ein Stromlos machen startet alles neu und hilft.
Warum ist das so?

Hat das Problem noch jemand bzw. eine Lösung für mich?

#include <SPI.h>
#include <SD.h>
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include <Wire.h>
#include <MPU6050.h>
#include <U8g2lib.h>         

// Pins für die SD-Karte
#define CHIP_SELECT  10 // Ändern Sie dies, wenn Sie einen anderen Pin verwenden


// Erstellen Sie Objekte für GPS und SD
TinyGPSPlus gps;
File logFile;
File config;

SoftwareSerial ss(8, 7);
const int schalterPin = 2;
int schalterZustand = 1;
const int ledPinFehler = 3;
const int ledPinOk = 4;
int gpsSignal = 0;

float latitude = 0;
float longitude = 0;

bool headerFirma = false;
bool headerPrivat= false;
bool stop = false;

const int threshold = 25000;
int bewegung = 0;
int zaehlerStopp = 0;
int stoppVerzoegerung = 60;

int zaehlerAzBeginn = 0;
int azBeginnVerzoegerung = 60;

unsigned long azTimeMillis = 0;
unsigned long azPerviousTimeMillis = 0;

float lastLat = 0.0, lastLon = 0.0;  // Vorherige Koordinaten für die Berechnung der Entfernung
float totalDistance = 0.0;  // Gesamte zurückgelegte Strecke
float totalDistanceAlt = 0.0;

unsigned long myTime = 0;
unsigned long myPreviousTime = 0;
const long interval = 3000;         // 3000 Millisekunden = 3 Sekunden
int currentPage = 0;

bool startAz = false;
int azAufzeichnungGestartet = 0; 

int startZeitStunde = 0;
int startZeitMinute = 0;
int endZeitStunde = 0;
int endZeitMinute = 0;
int arbeitsZeit = 0;
int arbeitsZeitVorher = 0;

int currentTimeHour = 0;
int currentTimeMinute = 0;
int currentDateYear = 0;
int currentDateMonth = 0;
int currentDateDay = 0;

const unsigned long RESET_INTERVAL = 300000;  // 5 Minuten in Millisekunden
unsigned long lastResetTime = 0;

MPU6050 mpu;

U8G2_SH1106_128X64_NONAME_F_HW_I2C oled(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

void setup() {

  pinMode(10, OUTPUT);
  pinMode(schalterPin, INPUT);
  pinMode (ledPinFehler, OUTPUT);
  pinMode (ledPinOk, OUTPUT);
  
  

  digitalWrite (ledPinFehler, LOW);
  digitalWrite (ledPinOk, LOW);

  Serial.begin(9600);
  Wire.begin();
  mpu.initialize();

  if (mpu.testConnection()) {
    Serial.println("MPU-521 verbunden");
  } else {
    Serial.println("MPU-521 Verbindung fehlgeschlagen");
  }

  ss.begin(9600); // GPS Serial Port

  // Initialisieren der SD-Karte
  while (!SD.begin(CHIP_SELECT)) {
    Serial.println("SD-Karte konnte nicht initialisiert werden!");
    digitalWrite (ledPinFehler, HIGH);
  }
   
  readConfig();

  stoppVerzoegerung = stoppVerzoegerung / 2;
  Serial.println(stoppVerzoegerung);
  Serial.println(azBeginnVerzoegerung);

  // Erstellen oder Öffnen der GPS-Datei
  while (!logFile) {
    logFile = SD.open("log.txt", FILE_WRITE);
    digitalWrite (ledPinFehler, HIGH);
  }

  digitalWrite (ledPinFehler, LOW); 
  
  oled.setBusClock(75000);
  //Wire.setClock(75000);


 if (!oled.begin()) {  
    Serial.println(F("OLED nicht gefunden"));
  }
  oled.clearBuffer();
  oled.setFont(u8g2_font_t0_12b_tr) ;  // choose a suitable font
  oled.drawStr(27,10, "Hallo, Floki!");
  oled.drawStr(8,20, "Der Logger sucht ein");
  oled.drawStr(45,33, "Signal!");
  oled.sendBuffer();
  
}

void loop() {

  while (ss.available() > 0) {     

  unsigned long I2CMillis = millis();
  if (I2CMillis - lastResetTime >= RESET_INTERVAL) {
    // Wenn 5 Minuten vergangen sind, setze den I2C-Bus zurück
    //i2c_reset();
    lastResetTime = I2CMillis;  // Setze den Zeitpunkt des letzten Resets
  }

    schalterZustand = digitalRead(schalterPin);
    int16_t ax, ay, az;
    mpu.getAcceleration(&ax, &ay, &az);
    long acceleration = abs(ax) + abs(ay) + abs(az);
  
    if (acceleration > threshold) {
        bewegung = 1;
        azTimeMillis = millis();
        azPerviousTimeMillis = azTimeMillis;
        
    } else {
      bewegung = 0;
    }  

    if (bewegung == 0 && startAz == false){
      azTimeMillis = millis();
      

      if (azTimeMillis - azPerviousTimeMillis >= (azBeginnVerzoegerung * 1000)) {
        azPerviousTimeMillis = azTimeMillis;  // Speichere den aktuellen Zeitpunkt
        startAz = true;
        Serial.println ("AZ Beginn"); 
      }    

    }

    

    if ((zaehlerStopp + 1 > stoppVerzoegerung) && (stop == false)){
      digitalWrite (ledPinFehler, HIGH);
      totalDistanceAlt = totalDistance;
      headerFirma = false;
      headerPrivat = false;
      totalDistance = 0.0;
      stop = true;
      
    }
  
    if (bewegung == 1){
      digitalWrite (ledPinFehler, LOW);
      zaehlerStopp = 0;
      stop = false;
      if (azAufzeichnungGestartet == 1){
        arbeitsZeitVorher = arbeitsZeit;
      }
      arbeitsZeit = 0;
      startAz = false;  
      azAufzeichnungGestartet = 0; 
    }
   
    gps.encode(ss.read());

    if(gps.location.isUpdated()){
      gpsSignal = 1;
    }
    else{
      gpsSignal = 0;
    }

    if(gpsSignal == 1){

      currentTimeHour = gps.time.hour() ;
      currentTimeMinute = gps.time.minute();
      currentDateYear = gps.date.year();
      currentDateMonth = gps.date.month();
      currentDateDay = gps.date.day();   
      endZeitStunde = gps.time.hour();
      endZeitMinute = gps.time.minute();

      // GPS-Daten abrufen
      latitude = gps.location.lat();
      longitude = gps.location.lng();
     
      if (startAz == true && azAufzeichnungGestartet == 0){
        startZeitStunde = gps.time.hour();
        startZeitMinute = gps.time.minute();
        Serial.print(startZeitStunde);
        Serial.print(startZeitMinute);
        azAufzeichnungGestartet = 1;
      }
      printDisplay();  
    }

    if (gpsSignal == 1 && (zaehlerStopp < stoppVerzoegerung) ) {   
      
      if (lastLat == 0){
        lastLat = latitude;
        lastLon = longitude;
      }          
  
      // Berechnung der Strecke mit Haversine
      float distance = haversine(lastLat, lastLon, latitude, longitude);
      totalDistance += distance;  // Gesamte zurückgelegte Strecke

      // Aktualisiere lastLat und lastLon mit den aktuellen GPS-Werten
      lastLat = latitude;
      lastLon = longitude;

      digitalWrite (ledPinOk, HIGH);

      if (gps.date.day() < 1){
        delay (2000);
      }
      else {
        if(schalterZustand == 1){    
              
          if (!headerFirma){
            logFile.println();
            logFile.println();
            logFile.print("Firma ");              
            logFile.print(gps.date.year());
            logFile.print(".");
            logFile.print(gps.date.month());
            logFile.print(".");
            logFile.print(gps.date.day());
            logFile.print(", ");
            logFile.print(" ");
            logFile.print((gps.time.hour() + 1));
            logFile.print(":");
            logFile.print(gps.time.minute());
            logFile.print("  ");
            headerFirma = true;
            headerPrivat = false;
          }
        }
        else{
          if (!headerPrivat){
            logFile.println();
            logFile.println();
            logFile.print("Privat ");              
            logFile.print(gps.date.year());
            logFile.print(".");
            logFile.print(gps.date.month());
            logFile.print(".");
            logFile.print(gps.date.day());
            logFile.print(", ");
            logFile.print(" ");
            logFile.print((gps.time.hour() + 1));
            logFile.print(":");
            logFile.print(gps.time.minute());
            logFile.print("  ");
            headerPrivat = true;
            headerFirma = false;
          }
        }
        
        // GPS-Tracelog schreiben
        logFile.print(latitude, 6); // 6 Dezimalstellen
        logFile.print(" ");
        logFile.print(longitude, 6); // 6 Dezimalstellen
            
        if ((logFile.print(", ")) < 1){
          digitalWrite (ledPinFehler, HIGH);
        }
       
        // Daten im Serial Monitor ausgeben
        Serial.print("Lat: ");
        Serial.print(latitude, 6);
        Serial.print(" Lon: ");
        Serial.println(longitude, 6);
        
        // Daten auf SD Karte schreiben
        logFile.flush();

        if (bewegung == 0){
          zaehlerStopp = zaehlerStopp + 1;
        }
            
        Serial.println(zaehlerStopp);         
        
    delay(2000);
            
      }     
    }
    else{
      digitalWrite (ledPinOk, LOW);
    }
    if(startAz == true){
    arbeitsZeit = timeDifference (startZeitStunde, startZeitMinute, endZeitStunde, endZeitMinute);
    }
  }
}


float haversine(float lat1, float lon1, float lat2, float lon2) {
  const float R = 6371.0;  // Erdradius in km
  float phi1 = toRadians(lat1);
  float phi2 = toRadians(lat2);
  float deltaPhi = toRadians(lat2 - lat1);
  float deltaLambda = toRadians(lon2 - lon1);

  float a = sin(deltaPhi / 2) * sin(deltaPhi / 2) +
  cos(phi1) * cos(phi2) *
  sin(deltaLambda / 2) * sin(deltaLambda / 2);
  float c = 2 * atan2(sqrt(a), sqrt(1 - a));
  return R * c;  // Entfernung in km
}


// Hilfsfunktion, um Grad in Radiant zu konvertieren
float toRadians(float degrees) {
  return degrees * 3.141592653589793 / 180.0;
}


void printDisplay (){

  myTime = millis();

  if (myTime - myPreviousTime >= interval) {
    myPreviousTime = myTime;  // Speichere den aktuellen Zeitpunkt

    // Nächste Seite anzeigen
    currentPage = (currentPage + 1) % 2;  // Wechselt zwischen 0, 1 und 2
  }

  oled.clearBuffer();   
 
  switch (currentPage){
    case 0:

      oled.setFont(u8g2_font_t0_12b_tr) ;

      oled.drawStr(27,10, "Hallo, Floki!");
      oled.drawStr(12,23, "Signal gefunden");
      oled.setCursor(0,36);
      oled.print(currentTimeHour + 1);
      oled.setCursor(12,36);
      oled.print(":");
      oled.setCursor(18,36);
      oled.print(currentTimeMinute);
      oled.setCursor(35,36);
      oled.print(currentDateDay);
      oled.setCursor(47,36);
      oled.print(".");
      oled.setCursor(53,36);
      oled.print(currentDateMonth);
      oled.setCursor(65,36);
      oled.print(".");
      oled.setCursor(71,36);
      oled.print(currentDateYear);
      oled.setCursor(0, 49);
      oled.print("Strecke: ");
      oled.print(totalDistance, 3);
      oled.setCursor(0, 62);
      oled.print("Strecke vorher: ");
      oled.print(totalDistanceAlt, 3);

      break;
    
    case 1:

      oled.setFont(u8g2_font_t0_16b_tr) ;

      int differenzStunden = arbeitsZeit / 60;
      int differenzRestMinuten = arbeitsZeit % 60;
      int differenzStundenVorher = arbeitsZeitVorher / 60;
      int differenzRestMinutenVorher = arbeitsZeitVorher % 60;

      char azStunden[3];
      sprintf(azStunden, "%02d", differenzStunden);
      char azMinuten[3];
      sprintf(azMinuten, "%02d", differenzRestMinuten);
      char azStundenVorher[3];
      sprintf(azStundenVorher, "%02d", differenzStundenVorher);
      char azMinutenVorher[3];
      sprintf(azMinutenVorher, "%02d", differenzRestMinutenVorher);

      oled.setCursor(0, 18);
      oled.print("AZ lfd: ");
      oled.print(azStunden);
      oled.print(":");
      oled.print(azMinuten);
      oled.setCursor(0, 36);
      oled.print("AZ letzte: ");
      oled.print(azStundenVorher);
      oled.print(":");
      oled.print(azMinutenVorher);


      break;
  }
  oled.sendBuffer();
}


int timeDifference (int startHour, int startMinute, int endHour, int endMinute) {
 
  int startInMinuten = startHour * 60 + startMinute;
  int endInMinuten = endHour * 60 + endMinute;
  int differenzInMinuten = 0;

  // Berechnung der Differenz in Minuten
  differenzInMinuten = endInMinuten - startInMinuten;

  // Wenn die Differenz negativ ist (Endzeit liegt vor Startzeit), einen neuen Tag annehmen
  if (differenzInMinuten < 0) {
     differenzInMinuten += 24 * 60;  // 24 Stunden in Minuten
  }
    
  return differenzInMinuten;  
}


void readConfig (){

  config = SD.open("config.txt");

  if (!config) {
    Serial.println("Fehler beim Öffnen der Config Datei.");
    return;
  }
  String line = "";
  while (config.available()) {
    char c = config.read(); // Zeichenweise lesen
    if (c == '\n' || c == '\r') { 
      // Wenn eine Zeile endet, prüfen, ob sie "Stoppzeit: " enthält
      if (line.startsWith("Stoppzeit in Sekunden: ")) {
        // Entferne "Zeit: " und konvertiere den restlichen Text in eine Zahl
        String zahlString = line.substring(23); // Ab der 23. Position (nach "Zeit: ")
        stoppVerzoegerung = zahlString.toInt(); // String in Integer umwandeln
        // Verlasse die Schleife, nachdem die Zahl gefunden wurde
      }
      if (line.startsWith("Arbeitszeit Verzoegerung in Sekunden: ")) {
        // Entferne "Zeit: " und konvertiere den restlichen Text in eine Zahl
        String zahlStringAz = line.substring(38); // Ab der 38. Position (nach "Zeit: ")
        azBeginnVerzoegerung = zahlStringAz.toInt(); // String in Integer umwandeln
        break; // Verlasse die Schleife, nachdem die Zahl gefunden wurde
      }
      line = ""; // Leere die Zeile für die nächste Zeile
    } else {
      line += c; // Zeileninhalt aufbauen
    }
  }
  config.close();
}


void i2c_reset() {
    Wire.beginTransmission(0x68); // MPU 6050 Adresse
    Wire.write(0x6B);  // Power Management Register
    Wire.write(0x40);  // Versetzt den Sensor in den Schlafmodus
    Wire.endTransmission();
    Wire.end();     // Schließt die aktuelle I2C-Verbindung
    delay(500);     // Kurze Pause, um den Bus freizugeben
    Wire.begin();   // Startet den I2C-Bus neu
    Serial.println("I2C reset");
    Wire.beginTransmission(0x68); // MPU 6050 Adresse
    Wire.write(0x6B);  // Power Management Register
    Wire.write(0x00);  // Aktiviert den Sensor
    Wire.endTransmission();
    


}

Der Endliche Automat des Slaves steht in einem von der Lib unerwarteten Zustand.
Manchmal hilft "I2C freitakten."

Ursache oft hier: [Bericht] I2C Pullup

Du weißt, dass dir die Methode eine Fehlermeldung liefern kann, aber du liest sie nicht aus-
Schade eigentlich.....

Wire.endTransmission() wir nicht aufgerufen, war mal zum Testen, half aber nichts.

Was meinst du mit "freitakten" ?

Sollte es aber, denn das startet die eigentliche Übertragung.

https://docs.arduino.cc/language-reference/en/functions/communication/wire/endTransmission/

Warum machst du das?
Der MPU laut der Lib will mit 400kHz arbeiten, habe noch nie bei SH1106 I²C Bus Clock runtergesetzt.
Was sagt I²C Scanner wen OLED und MPU am Bus hängen?

SH1106 Datenblatt sagt der kann 400kHz

Du hast mich evtl. falsch verstanden.
Die Meldung könnte dir sagen, was falsch läuft, zumindest einen Hinweis liefern.
Sicherlich behebt die Meldung keine Fehler, aber sie könnte dich etwas schlauer machen.

Ähm...
Sachte ich das nicht?
Den im Slave eingebauten Automaten wieder auf die Beine bringen
Tipp: I2C freitakten - Google Search
Du darfst auch nach "I2C Bus Recovery " suchen.

So Problem mal gelöst denke ich.
Hab den ClockSpeed wieder auf 400000 gestellt und funktioniert. Reduziert hab ich ihn, weil ich irgendwo gelesen habe das sowas das Problem sein kann, anscheinend nicht :slight_smile:

So jetzt anderes Problem wo ich Hilfe benötige:
Habe das Ding über den PC mit der USB C buchse versorgt und lief einwandfrei. Hab es dann im Auto probiert, ebenfalls an der eigenen USB C buchse, lief auch.
Nur schaltet sich diese ab und das will ich nicht.

Plan B: Billiges Dings an Zigarettenanzünder das USB C hat, Display bleibt wieder hängen.
Ok Plan C: Den Arduino mit 12V vom Zigarettenanzünder über die Buchse, selbiges Spiel, Display bleibt hängen.

So und jetzt?
Hat das schon jemand mal probiert oder gemacht?
Ich denke der Arduino funktioniert weiter nur der Bus hängt sich auf.
Ich verstehe schon das es keine saubere Spannung ist, aber was ist die Lösung für mein Problem.

Hoffe es kann mir jemand helfen.

MFG

Und was genau heißt das?

Um das genau aufzuklären, solltest du ein Schaltbild posten.

Habe schon im #5 geschrieben :wink:

Die meisten Wandler mit Zigarettenanzünderstecker sind nicht geeignet als Versorgung für Empfindliche Geräte, die sind vorgesehen als "Ladekabel" intern nicht entstört dadurch kommt auf dem Ausgang zwar 5V raus nur das ist weit entfernt von Gleichspannung

Was meinst du?

Genau das, was ich geschrieben habe.

So, hab einen Caddy 2024, der hat in der Mittelkonsole 2 USB C dosen für Handy laden und zb Android Auto. Stecke ich dort den Arduino an, funktioniert er normal, soweit ich gesehen habe.

Die müssen, sollten der USB Norm entsprechen, ist bei meinem (Nicht VW) auch der Fall, Direkt über USB tuts alles über Zigarettenanzünder kann ich dafür mit höheren Strom laden,

Ja eh alles verständlich, löst aber mein Problem nicht. Was kann ich dagegen tun?

Dann wäre mein Tipp, das mit genügent Verständnis selbsbauen.
In dem Verlinkten Beitrag gibt es alle nötigen Informationen.

Hab das kurz überflogen, eigentlich steht da beim schnellen lesen viele Widersprüche und das es ws nicht gut funktioniert. Oder lese ich es falsch?

Ok, dann scheint der Selbstbau nichts für dich zu sein.
Bei fertigen Teilen kann ich keine Tipps geben, da fehlt die Erfahrung.

Schade, bin ja ned der erste der so ein Teil im Auto betreiben will oder?

Da muss es ja irgendwas geben oder?

Naja, der Abend ist ja noch lang. :wink:
Da wird sich schon noch jemand hier melden, der dir praktische Tipps geben kann.