Arduino mit Analogsensoren, BUS-Verbindung und I2C Display friert ein

Hi, ich lese seit einer Weile still mit.
Seit einer Weile bastle ich schon mit dem Arduino.
Das aktuelle Projekt ist das Messen von Motoröldruck und -temperatur in meinem BMW E39.
Hierfür habe ich einen Widerstandstemperatursensor und einen Drucksensor. Dazu ein i2C Display und nicht zuletzt einen MCP2025 um die Daten auf den I-BUS vom Wagen einzuspeisen (und da wieder auszulesen und in der "I-BUS App" anzuzeigen). Angeschlossen an einem Arduino Nano (Nachbau von AZ Delivery).

Von Anfang an habe ich sporadisch das Problem, dass das Display einfriert oder gar kryptische Zeichen bringt. Nur ein Reset/Neustart erweckt das das "System" wieder zum Leben. Mal nur einen Augenblick, mal läuft es über Stunden.
Spannung bekommt der Nano vom MCP2025 und der wiederum via 12V vom Wagen. Seit geraumer Zeit funktioniert das parallel nicht mehr - ich speise nun zusätzlich via USB Spannung ein. Nur wenn beides dran ist lebt das Ganze. Sicher muss ich auch hier auf Spuren suche gehen.
Das Nano habe ich bereits mehrfach gegen andere getauscht - das Problem bleibt.

Für mich ist nun die Frage, ob ich mir Störungen über die Leitungen oder das I2C einfange - dazu las ich erst heute morgen, dass man die beiden Signal-Leitungen SDA / SCL mit je 4,7kOhm gegen 5V up-pullen soll? Kann es das schon sein? Ich meine mich zu erinnern, dass das System auch mit abgestecktem Display einfriert. (Is länger her aber schnell zu testen).
Dazu kam der Hinweis, dass man auch am Analog-Eingang einen Pull-Up setzen soll? Macht das Sinn.

Letztlich die Frage, ob man "Fehler" am Analog-Eingang nicht im Code abfangen kann. Wobei ich aktuell keine Idee für einen Fehler, außer einem Kurzschluss vorstellen kann.

Auch hatte ich die BUS Übertragung mal als Fehler auf dem Schirm. Aber auch dessen Auskommentierung brachte keinen Effekt.

Einen Schaltplan/Fritzing muss ich euch noch schuldig bleiben. Aber den Code hänge ich mal an.

PS: Aktuell plane ich die beiden Sensoren gegen den BOSCH PST-F1 zu tauschen, der bereits bereits liegt. Dafür möchte ich aber, dass das System stabil läuft.

int analogPin6 = A6; // Analog-Input Pin6 => Öldruck als 5V-Signal
int analogPin7 = A7; // Analog-Input Pin7 => Öltemperatur als  Widerstand
float R1 = 5.14; //Wert des bekannten Widerstands, ehemals 107000 Ohm => R "/1000" nun entfallen da nun in kOhm 
float R; //Widerstand des Temperaturfühlers
float SpannungR2; //Spannung über dem zu messenden Widerstand
float oiltemp; // Öltemperatur
float oilpressure; // Öldruck
float Tmittel=0; // gemittelte Öltemperatur
float pmittel=0; //gemittelter Öldruck
unsigned long last_oil_send = 0;
unsigned long last_oled_send = 0;
int sendTime = 2000;

#include <U8g2lib.h>
U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);   // Adafruit ESP8266/32u4/ARM Boards + FeatherWing OLED

#include <IbusTrx.h> // include the IbusTrx library
IbusTrx ibusTrx; // create a new IbusTrx instance

#define WAKE_PIN 13
#define wake_set(...) digitalWrite(WAKE_PIN, __VA_ARGS__)

void setup(void) {
  u8g2.begin();
  ibusTrx.begin(Serial); // begin listening for messages
  pinMode(WAKE_PIN, OUTPUT);
  wake_set(HIGH);
}

void loop()
{
  //Berechung Widerstand Temperaturfühler
  SpannungR2 = 5 / 1023.0 * analogRead(analogPin7);
  R = R1 * (SpannungR2 / (5 - SpannungR2));

  //Umrechnung Widerstand in Temperatur
  if (R > 45) {
    oiltemp = 0.00479709*pow(R, 2) - 1.00497778*R + 61.07424494;
  }
  else {
    oiltemp = 0.0000001326*pow(R, 6) - 0.0000236053*pow(R, 5) + 0.0016840356*pow(R, 4) - 0.0620097366*pow(R, 3) + 1.2759648324*pow(R, 2) - 15.504389816*R + 138.9049501569;
  }

  //Berechnung Öldruck
  if ((analogRead(analogPin6) / 1023.00 * 5) * 1.379 - 0.69 <= 0.05) {
    oilpressure = 0;
  }
  else {
    oilpressure = (analogRead(analogPin6) / 1023.00 * 5) * 1.379 - 0.69;
  }

  //gleitenden Mittelwert bilden
  Tmittel = 0.95*Tmittel + 0.05*oiltemp;  
  pmittel = 0.95*pmittel + 0.05*oilpressure;

  //Temp auf 0,5er Schritte runden
  Tmittel = trunc(Tmittel * 2 + 0.5) / 2;

  // an I2C-Display senden alle 200 ms
  int sendTimeOLED = 200;
  if (millis() - last_oled_send > sendTimeOLED) {
    last_oled_send = millis();
    u8g2.clearBuffer();
    //u8g2.setFont(u8g2_font_8x13B_tf);
    //u8g2.setFont(u8g2_font_10x20_tf); //16px hoch
    u8g2.setFont(u8g2_font_fur20_tf); //20px hoch
    u8g2.setFontRefHeightExtendedText();
    u8g2.setDrawColor(1);
    u8g2.setFontPosTop();
    u8g2.setFontDirection(0);
    u8g2.setCursor(0, 1);
    u8g2.print(pmittel, 2);
    u8g2.setCursor(72, 1);
    if (Tmittel<100) {u8g2.print(Tmittel, 1);
    }
    else 
    {u8g2.print(Tmittel, 0);
    }
    u8g2.setFont(u8g2_font_5x7_tf);
    u8g2.drawUTF8(0, 25, "Öldruck bar");
    u8g2.drawUTF8(72, 25, "Öltemp. C");
    u8g2.sendBuffer();
  }

  // auf I-BUS senden alle 2000 ms
  if (ibusTrx.available()) { // receive and write to I-BUS
    IbusMessage m = ibusTrx.readMessage(); // grab incoming messages and clear read buffer
    if (millis() - last_oil_send > sendTime) {
      last_oil_send = millis();
      uint8_t oil[6] = {
        0xAA, // sender ID (diagnostic interface)
        0x05, // length of the message payload (including destination ID and checksum)
        0xAB, // destination ID (body control module)
        0xBB, // the type of message (IO manipulation)
        byte(pmittel * 10), // "oilpressure"
        byte(Tmittel) // "oiltemp"
      };
      ibusTrx.write(oil); // write message in tx buffer
    }
  }
}



Hier ein paar Bilder und der grundlegende Plan für die BUS-Kommunikation.

Im KFZ entstehen u.a. durch den Motor sehr hohe Störpegel. Diese können durchaus den I2C-Bus zum Absturz bringen. Die Pullup-Widerstände am I2C-Bus müssen zwingend sein, aber alleine helfen die bei den Problemen nicht.
Da kann nur eine genaue Untersuchung und Messung am Besten mit einem Oszilloskop helfen. Auch eine passende Abschirmung (Kabel und kompl. Projekt) sowie kurze Kabelwege ist hilfreich.

Wie lang ist die I,2C Leitung ?

Danke Dir, Pull-Up Widerstände also in der Art zw. VCC und SDA/SCL!?

An den beiden Analog-Sensoren aber nicht?

Die "Sensorleitung" zum Motor vor ist ein geschirmtes Kabel von ca. 3m Länge. Ich muss aber offen gestehen, dass ich prüfen muss, ob ich den Schirm auf Karosse gelegt habe.

@fony die I2C Leitung ist ca. 70cm lang und geht vom Handschuhfach zur Mitte hinter Radio/Klimabedienteil. Unterwegs sind je zwei 4 polige Stecker.

Ich lese also raus, dass Störungen auf dem I2C BUS durchaus stören können? Sprich wenn ich das Display mal aus kommentiere (und abklemme ?) könnte das das Problem evtl. lösen?

Ja, das ist def. so, muss aber nicht zwingend auch über die Leitungen des I2C reinkommen.
Störungen im KFZ suchen sich immer ihren Weg.
Du solltest alles abschirmen und immer wieder testen.
Und deine 70cm Kabellänge sind def. zu lang. I2C ist für eine "Onboard Platinen Nutzung" entwickelt worden. Daher für andere Verwendung def. sehr anfällig auf Störungen.

Die Pullup sind so richtig gezeichnet und in deinem Fall nur für I2C gedacht.

Wobei sehr häufig auf den Modulen die I2C PullUps schon verbaut sind. Zu viele darf es auch nicht geben. Entweder nachmessen ob schon einer da ist oder im Schaltplan nachsehen.

Es hat schon seinen Grund warum in Kfz CAN-BUS und nicht der I2C-Bus verwendet werden.

CAN-BUS funktioniert sogar dann noch wenn eine Busleitung Masseschluss hat.

Ich würde das LCD wirklich unmittelbarst neben den Microcontroller setzen
Besser nur 1 cm Busleitung als 5 cm.

Wenn das nicht geht würde ich ein anderes Display ein Dotmartrix Display mit serieller Schnittstelle in Erwägung ziehen
evtl. geht auch ein Dot-Matrix-Display, dass nicht I2C-Bus hat sondern die 4-Bit Schnittstelle.
oder
einen zweiten Microcontroller bei dem du dann das OLED-Display wirklich in unmittelbarer Nähe platzieren kannst.
hat denn dein restliches Armaturenbrett lauter digitale Anzeigen?
Sonst wäre vielleicht auch so was hier schick

I
Danke für den Tipp. Ich meine hier zwei 4,7kOhm Wiederstände (R3 und R4) zw. SDA/SCL und VCC erkennen zu können?
Das zusätzlich noch an der anderen Seite (also am Arduino) zu machen ist sicher Unfug!?

Also wäre das eher nicht die Lösung?
Das Display habe ich vorhin nur mal abgesteckt, so bekomme ich die Werte "nur" via I-BUS in die App und da gezeigt (leider mit deutlich langsamerem Refresh um den BUS nicht zu zu müllen).
Jedenfalls lief das Arduino so 20min ohne Störung.
Schön und schade zu gleich.

Hast Du mal im stromlosen Zustand den Widerstand zwischen SCL/SDA und Vcc (5V) gemessen? Dann siehst Du, ob welche auf der Platine sind. Meist sind die so um die 5 kOhm. Dann könntest Du jeweils erst mal 4k7 parallel schalten und so den PullUp-Widerstand verkleinern, was den Störabstand verringert. Das geht aber nicht beliebig. Bei ca. 1k5 Gesamtwiderstand ist Schluss.

Gruß Tommy

Danke für die Info - muss ich noch messen.

Habe heute auf der Fahrt wieder das Display abgezogen gelassen, es sind also nur ca. 10cm Kabel mit Stecker am Arduino. Und es lief ohne Probleme 45min durch.
Das Board direkt hinter das Display setzen wird schwer bzw mag ich da gern ran kommen (um im Zweifel Reset zu drücken - ohne mit dafür eine Extra Kabel mit Taster zu bauen) - das wäre dann hinter Radio/Klimabedienteil und da kommt man nicht mal eben ran.

Würde es Sinn machen den Pull-Up Widerstand wie von Dir beschrieben zu verringern - oder am Arduino zusätzliche Pull-Ups zu setzen?
Dazu hatte ich zu dem Thema I2C Verdrahtung die zwei Themen gefunden:

Hier sind auch längere Leitungen als "on Board" genutzt worden.

Das ist leider nicht so pauschal zu beantworten. In jedem KFZ ist es anders sowie auch der Montageplatz wirkt sich unterschiedlich auf die Störungen ein. Auch eine Abschirmung des Kabels kann sich negativ bemerkbar machen. Das sind einfach Dinge, die man am Objekt messen oder testen muß. Wie dir Tommy schon schrieb, kannst du die Pullup-Widerstände durchaus noch verkleinern, also 4k7 parallel schalten.
Das kann durchaus eine Verbesserung bringen.

Danke.
Die müsste ich dann parallel zu R3 und R4 auf der Rückseite vom Display einlöten, korrekt?
Zusätzliche Pull-Ups am Arduino selbst wären falsch!? (Da käme ich aktuell einfacher ran)

Da es ein BUS ist, kannst du die auch am Arduino unterbringen.

Die Stifte am Display bitten sich auch an.

Die Lötanschlüsse am Display?
Ja, aber da komme ich nicht ran ohne alles auszubauen. :stuck_out_tongue:
Das Arduino liegt im Handschuhfach (isoliert und mit Zugsicherung der Leitungen!).
Aber danke für den Tipp

Dann löte die zusätzlichen Pullup-Widerstände am Arduino an.
Und wenn du abgescirmtes Kabel für das Display verwenden möchtest, dann den Schirm nur einseitig auf GND löten. Und das am Arduino.

Vielen Dank.
Ich habe nun auch am Arduino für den I²C Port je einen 4,7kOhm Widerstand zw. SDA <=> 5V und SCL <=> 5V. Gestern auf der Fahrt fast eine Stunde und mehrfache Starts keinerlei Probleme oder "Freezes" gehabt. Ich beobachte weiter, bin aber zuversichtlich.

Vielen Dank.