Arduino Mega - Probleme mit Serieller Schnittstellenausgabe

Guten Abend,

für unser Studienprojekt bauen wir ein Elektrokart.
Des Aufbau wo, indem unser Problemfall vorliegt, ist folgender:
BMS -> Serielle Schnittstelle 1 (2400 Baud) -> Arduino Mega 2560 -> Serielle Schnittstelle "0" (9600 Baud) -> Nextion NX8048P070-011

Das BMS nimmt Daten der Batterie auf, der Mega schickt diese weiter bzw. verarbeitet sie und das Display gibt diese aus.
Info, aber nicht relevant: Die Baudrate zwischen BMS und Mega ist deswegen so gering, weil bisher ansonsten Teilstücke der Nachrichten nicht richtig eingelesen werden und es zu Problemen führt.
Der Mega wird zum Steuern weiterer Funktionen am Kart benötigt und ist somit unumgänglich.
Es liest z.B. auch über den Hallsensor unsere Geschwindigkeit ein und steuert das Licht.

Problemstellung
Das Problem befindet sich zwischen dem Mega und dem Nextion.
Die Daten vom BMS empfangen, auswerten und weiterschicken funktioniert einwandfrei -> Daten gelangen richtig ans Display über die Switch Case Funktion.
Sobald aber lediglich eine Nachricht (im Code zu finden unter dem Switch Case hier Beispielhaft "Powermeter") außerhalb der Switch Case auf den Bus zum Display geschickt wird, kommt nur noch Müll am Display an.

Fragestellung
Wieso kann diese eine zusätzliche Botschaft, außerhalb der des Switch Case die Datenübertragung so durcheinander bringen und welche Abhilfe gibt es??
Wir benötigen zwingend die Ausgabe weiterer Daten an das Display, die z.B. nicht über das BMS eingespeist werden, sondern direkt vom Mega kommen (z.B. die Geschwindigkeit über Hallsensor, welcher direkt am Mega hängt).

Ich bin sehr gespannt auf euer konstruktive Meinung und hoffe dadurch wieder etwas dazuzulernen!

LG
Philipp

/*
Fehler: Sobald Botschaften innerhalb der Loop, aber außerhalt dem Switch Case auf die Serielle Schnittstelle zum Display gelegt werden, kommt es zu Problemen!
*/



//*********************************************************************************************************
// Bibliothek einbinden
#include "EasyNextionLibrary.h"

//*********************************************************************************************************
// Serielle Kommunikation festlegen
EasyNex myObject(Serial);

//*********************************************************************************************************
// Globale Variable definieren
  //Taster Display
  int flag_motor          = 0;
  int flag_sportansicht   = 0;
  int flag_ecoansicht     = 0;
  int flag_lightON        = 0;
  int flag_lightOFF       = 1;
  int flag_lightAUTO      = 0;

  //Hilfsvariablen
  int licht_relais        = 11;
  int motor_relais        = 12;
  int LED                 = 13;
  int eingang_fotodiode   = A0;
  int wert_fotodiode      = 0;
  byte eingang_hallsensor = 21;
  int anzahl_flanken      = 0;
  //char zeilenumbruch    = '\n';
  
  //Daten vom BMS
  int cell_temp1       = 0;
  int cell_temp2       = 0;
  int cell_temp3       = 0;
  int cell_temp4       = 0; 

  int cell_volt1       = 0;
  int cell_volt2       = 0;
  int cell_volt3       = 0;
  int cell_volt4       = 0;
  int cell_volt5       = 0;
  int cell_volt6       = 0;
  int cell_volt7       = 0;
  int cell_volt8       = 0;
  int cell_volt9       = 0;
  int cell_volt10      = 0;
  int cell_volt11      = 0;
  int cell_volt12      = 0;
  int cell_volt13      = 0;
  int cell_volt14      = 0;
  int cell_volt15      = 0;
  int cell_volt16      = 0;
  int cell_volt_min    = 0;
  int cell_volt_max    = 0; 
  int cell_volt_ges    = 0;

  int batterieschuetz  = 0; //0 = offen, 0 = geschlossen
  int powermeter       = 69; //0 = Off; 69 = Ready

  int ladezustand      = 0; 
  int ladenaktiv       = 0;

  //Kommunikation mit BMS
  int data = 0;
  String eingang_BMS          = "";
  String zwischenspeicher_BMS = "";
  int header_BMS              = 0;
  float botschaft_BMS         = 0.0;


  

//*********************************************************************************************************
//Funktionsdefinitionen

  //Motor Ein/Aus
  void motorsteuerung (int i)
  {
    if(i % 2 == 1)
    {
      digitalWrite(motor_relais, LOW);
    }
      
    else
    {
      digitalWrite(motor_relais, HIGH);
    }
  }

  //Lichtsteuerung
  void lichtsteuerung (int an, int aus, int automatik)
  {
     if(aus == 1)
     {
      digitalWrite(licht_relais, HIGH);
     }

     else if(an == 1)
     {
      digitalWrite(licht_relais, LOW);
     }

     else
     {
      wert_fotodiode = analogRead(eingang_fotodiode);
      if(wert_fotodiode > 250)
      {
        digitalWrite(licht_relais, LOW);
      }
      else
      {
        digitalWrite(licht_relais, HIGH);
      }
     }
  }

  //Flankenzaehler Hallsensor
  void flankenzaehler_hallsensor()
  {
    anzahl_flanken++;
  }

  //Drehzahlberechnung
  void drehzahlberechnung(int i)
  {
    i = i / 3; 
    //Serial.print("Drehzahl = ");
    //Serial.println(i); 
  }

  //Laden aktiv oder inaktiv
  void ladeansicht(int i)
  {
    if(i == ladenaktiv)
    {
    }
    else if(i == 0 & ladenaktiv == 1)
    {
      myObject.writeStr("page 0");
      ladenaktiv = 0;
    }
    else
    {
      myObject.writeStr("page 5");
      ladenaktiv = 1;
    }
  }
 
  //Schütze offen oder geschlossen
  /*void schuetzauswertung(int i)
  {
    if(i == batterieschuetz)
    {
    }
    else if(i == 1 & batterieschuetz == 0)
    {
      powermeter = 69;
      batterieschuetz = 1;
    }
    else if(i == 0 & batterieschuetz == 1)
    {
      powermeter = 0;
      batterieschuetz = 0;
    }
  }*/

    
//*********************************************************************************************************
void setup() 
{
  //Baudrate festlegen für Serielle Schnittstellen
  myObject.begin(9600);
  Serial1.begin(2400);

  //Eingänge festlegen
  pinMode(eingang_hallsensor,INPUT_PULLUP);
  
  //Ausgänge festlegen
  pinMode(motor_relais, OUTPUT);
  pinMode(licht_relais, OUTPUT);
  pinMode(LED, OUTPUT);

  //Interrupts aufrufen
  attachInterrupt(digitalPinToInterrupt(eingang_hallsensor), flankenzaehler_hallsensor, FALLING);

//  //Starte Interrupt Timer
//  TCCR0A=(1<<WGM01);    //Set the CTC mode   
//  OCR0A=0xF9; //Value for ORC0A for 1ms
// 
//  TIMSK0|=(1<<OCIE0A);   //Set the interrupt request
//  sei(); //Enable interrupt
// 
//  TCCR0B|=(1<<CS01);    //Set the prescale 1/64 clock
//  TCCR0B|=(1<<CS00);

}

//*********************************************************************************************************
void loop() 
{
  //Zyklische Abfrage vom Display
  myObject.NextionListen();

  //Funktionsaufrufe
  motorsteuerung(flag_motor);

  lichtsteuerung(flag_lightON, flag_lightOFF, flag_lightAUTO);

  drehzahlberechnung(anzahl_flanken);

  //Datenempfang und Verarbeitung vom BMS
  if(Serial1.available() > 0) 
  {
    data = Serial1.read(); 
    if (char(data) != '\n') 
    {
      eingang_BMS += char(data);
    }  
    else 
    {  
      zwischenspeicher_BMS = eingang_BMS;     
      eingang_BMS = "";

      header_BMS = zwischenspeicher_BMS.substring(0,2).toInt();
      botschaft_BMS = zwischenspeicher_BMS.substring(2).toFloat();
       
      switch(header_BMS)
      {
        //Spannung
        case  1: cell_volt1   = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ1.val", cell_volt1); break;
        case  2: cell_volt2   = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ2.val", cell_volt2); break;
        case  3: cell_volt3   = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ3.val", cell_volt3); break;
        case  4: cell_volt4   = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ4.val", cell_volt4); break;
        case  5: cell_volt5   = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ5.val", cell_volt5); break;
        case  6: cell_volt6   = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ6.val", cell_volt6); break;
        case  7: cell_volt7   = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ7.val", cell_volt7); break;
        case  8: cell_volt8   = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ8.val", cell_volt8); break; 
        case  9: cell_volt9   = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ9.val", cell_volt9); break;
        case 10: cell_volt10  = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ10.val", cell_volt10); break;
        case 11: cell_volt11  = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ11.val", cell_volt11); break;
        case 12: cell_volt12  = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ12.val", cell_volt12); break;
        case 13: cell_volt13  = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ13.val", cell_volt13); break;
        case 14: cell_volt14  = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ14.val", cell_volt14); break;
        case 15: cell_volt15  = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ15.val", cell_volt15); break;
        case 16: cell_volt16  = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ16.val", cell_volt16); break;           
        case 17: cell_volt14  = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ14.val", cell_volt14); break;
        case 18: cell_volt15  = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ15.val", cell_volt15); break;
        case 19: cell_volt16  = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ16.val", cell_volt16); break;     

        //Schütze 00=offen; 01=geschlossen
        //case 20: schuetzauswertung((int)botschaft_BMS); break;

        //Ladezustand
        case 21: ladezustand  = ((int)botschaft_BMS); myObject.writeNum("Ladelevel.val", ladezustand); 
                                                      myObject.writeNum("Ladezustand.val", ladezustand); break;

        //Ladesituation
        case 25: ladeansicht((int)botschaft_BMS); break;

        //Temperatur
        case 30:  cell_temp1   = ((int)(botschaft_BMS*100)); myObject.writeNum("TZ1.val", cell_temp1); break;
        case 31:  cell_temp2   = ((int)(botschaft_BMS*100)); myObject.writeNum("TZ2.val", cell_temp2); break;
        case 32:  cell_temp3   = ((int)(botschaft_BMS*100)); myObject.writeNum("TZ3.val", cell_temp3); break;
        case 33:  cell_temp4   = ((int)(botschaft_BMS*100)); myObject.writeNum("TZ4.val", cell_temp4); break;

        default: break; 
       }       
    }
  }

  //Powermeter
    //Fehlend: Gaspedal einlesen + auswerten und Wert an Display schicken. 
    //Falls Schütze geschalten -> Wert + Powermeter
    //Falls Schütze offen -> Powermeter darf keinen Wert übermitteln
  //myObject.writeNum("PM.val", powermeter); 

}


//*********************************************************************************************************
//Triggersignale vom Display
void trigger0()   //Motor
{
  flag_motor = flag_motor + 1;
}

void trigger1()   //Sportansicht
{
  //BMS Rückmelden das Sportmodus aktiv ist 
}

void trigger2()   //Ecoansicht
{
  //BMS Rückmelden das Ecomodus aktiv ist 
}

void trigger3()   //Light ON
{
  flag_lightON    = 1;
  flag_lightOFF   = 0;
  flag_lightAUTO  = 0;
}

void trigger4()   //Light OFF
{
  flag_lightON    = 0;
  flag_lightOFF   = 1;
  flag_lightAUTO  = 0;
}

void trigger5()   //Light AUTO
{
  flag_lightON    = 0;
  flag_lightOFF   = 0;
  flag_lightAUTO  = 1;
}

Warum nutzt Du Serial(0) zum Nextion? Die brauchst Du zum Upload und für Debugausgaben. Der MEGA hat ja schließlich genügend HW-Serial.

Gruß Tommy

Warum benutzt Du keine Arrays für Deine numerierten Variablen?
Du könntest damit auch das switch/case-Gedöhns auflösen.
Warum fängst Du im case 17 wieder mit Volt14 an?
Wenn das so sein soll, geht auch:

case 14:
case 17:
// Machwas
break;
casé 15:
case 18:
// mach nochwas
break;

Warum machst Du für die drei flagVariablen, und initialisierst als int fürs Licht? Flag wäre für mich eher ein bool. Du verwendest die ja auch so.
Warum nimmst Du nicht ein Byte für alles?
Licht aus -> 0
Licht an -manuell -> 1
Licht auto -> 2
Braucht es die ganzen TriggerFunktionen nicht...

Und wenn Du an der Stelle, wo Du jetzt deine Kommentare zum Powermeter drin hast versuchst zu senden, dann floodest Du die serielle Schnittstelle.

Und wie @Tommy56 schrieb: Nicht die erste Serielle belegen, damit verlierst Du die Debugmöglichkeit.
Darum gebe ich da auch keinen weiteren Hinweis zum flooden....

Hey Tommy,

ich kann dir gar nicht genau sagen, warum ich Serial(0) fürs Nextion nutze. Also ich hatte keinen besonderen Grund dafür. Würdest du empfehlen, den Serial(0) für solche Anwendungen nicht zu verwenden?

Folgendes habe ich aber bereits getestet:

  • Dateneingang vom BMS auf Serial(1)
  • Datenausgang zum Nextion auf Serial(2)

Leider hat dies keine Besserung gebracht.

LG
Philipp

Er hat es empfohlen und ich tue es auch.
Grüße Uwe

Hey Uwe,

leider hat dies aber nichts am Problem geändert, das dann nur Müll aufm Nextion ankommt.

LG
Philipp

Dann hast Du Serial aber für Debugmeldungen auf den seriellen Monitor frei und die wirst Du zur Fehlersuche brauchen.
Die von Dir benutzte Lib kenne ich nicht, ich nutze wie viele, keine Lib, sondern kommuniziere direkt mit dem Nextion.

Baue Dir serielle Ausgaben ein und schau, wo Dein Programm falsch abbiegt.
Evtl. wäre es sinnvoll, erst mal die komplette Kommunikation mit dem Nextion einzeln auszutesten.

Gruß Tommy

Glaube ich Dir gerne weil das nicht das Problem war.
Weil Du zu schnell zu viele Daten versendest. Bei 9600 Baud braucht jedes Byte ca 1mS zur Übertragung. Wenn Du den Buffer vollschreibst verlierst Du Daten. Das was Durchkommt ergibt dann keinen Sinn.
Grüße Uwe

Da Du mich ignorierst, wird Dir jemand anders unter die Nase reiben müssen, was Dein Problem ist.

1 Like

Hey Uwe,

Ich soll also versuchen die Daten für z.B. Zellspannung, welche nicht extrem schnell am Display aktualisiert werden müssen, seltener zu senden um dadurch die Buslast zu minimieren?

Würde es was bringen, den Buffer zwischenzeitlich zu leeren?

LG
Philipp

Hey Tommy,

die Lib funktioniert mMn ziemlich gut und vor allem simpel für Einsteiger, weshalb wir diese gewählt haben.

Die Kommunikation mit dem Arduino funktioniert komischerweise ohne die besagte Nachricht im besagten Bereich einwandfrei, weshalb es für mich auch so schwierig ist, das Problem zu verstehen.

LG
Philipp

Hallo lieber my_xy_project,

es tut mir sehr leid, das ich noch nicht dazu gekommen bin allen auf einmal, vor allem dir vorne weg, zu antworten. Deine Antwort beinhaltet ziemlich viele Kommentare abseits meiner Problemstellung, weshalb ich diese bei der Beantwortung hinten angestellt habe und du mir sowieso keine weiteren Hinweise zum flooden geben wolltest, obwohl ich bereits versucht habe die Serial(0) auf Serial(2) zu ändern.
Die hat aber, wie bereits im anderen Kommentar erwähnt, keinen Erfolg mir sich gebracht.

LG
Philipp

Ich habe Dir geschrieben, wo Dein Problem ist.
Wenn Du im Nachhinein erst damit rauskommst, das Du das schon mal anders hattest, dafür kann ja wohl keiner ausser Du.
Also nochmal von vorne:
Den Display an einen anderen Seriellen Port.
Dann kannst Du ausprobieren, was ich meinte, indem Du einfach als letzte Zeile in Deinen Code schreibst:

Serial.println(millis());

Du wirst feststellen, das Ausgaben zwar kommen, aber zwischendurch etwas fehlt. Denn die Codegeschwindigkeit ist eindeutig schneller als die Ausgabe.

Und wenn Du gut gemeinte Ratschläge nicht brauchst, dann ist Deine Hoffnung auf dazulernen evtl. vergebens.
Aber das ist meine Meinung.

Du könntest z.B. nur dann senden wenn vorher auch eine BMS-Message durchging:
Das sähe dann am Ende vom loop() so aus:

  if (header_BMS)
  {
    //Powermeter
    //Fehlend: Gaspedal einlesen + auswerten und Wert an Display schicken.
    //Falls Schütze geschalten -> Wert + Powermeter
    //Falls Schütze offen -> Powermeter darf keinen Wert übermitteln
    myObject.writeNum("PM.val", powermeter);
    header_BMS = 0;
  }
}

Nein, den brauchst Du ja zum Senden der Daten.

Betreibe Datenminimalismus.
Alles was sich selten ändert kann auch nur selten geschrieben werden.
Alles was etwas unruhig ist Mittelwert bilden.
Alles was sich nicht verändert hat, muß nicht neu geschrieben werden.

Grüße Uwe

Hallo Uwe,

danke für den Allgemeinen Tipp! :slight_smile:
Ich versuche mit der Zeit mein Programm bzw. die Datenverarbeitung nach deinen Ratschlägen umzustrukturieren.

LG
Philipp

Hallo my_xy_project,

ich teste heute folgendes, aufgrund deiner Empfehlung:

  • Kommunikation vom Display vom Serial(0) auf Serial(2) umstellen
  • Serial.println(millis()); am Ende der loop einfügen und die Ausgabe beobachten.

Die Codegeschwindigkeit ist schnell als die Ausgabe, weil ich viele Daten sende und der Durchlauf pro loop zu schnell geht, aufgrund des verhältnismäßig geringen restlichen Code?

Das untenstehende werde ich auch testen und ich finde deinen Vorschlag mit der Lichtsteuerung (0,1,2) ziemlich genial. Da bin ich gar nicht drauf gekommen, wahrscheinlich weil es das erste größere Projekt und mir einfach die Erfahrung fehlt.
Um den Switch Case mit Arrays aufzulösen, muss ich mir das ganze erst nochmal zu Gemüte führen...:smiley: Fand die aktuelle Idee ziemlich gut realisiert, aber anscheinend noch nicht wirklich ausgereift.

  if (header_BMS)
  {
    //Powermeter
    //Fehlend: Gaspedal einlesen + auswerten und Wert an Display schicken.
    //Falls Schütze geschalten -> Wert + Powermeter
    //Falls Schütze offen -> Powermeter darf keinen Wert übermitteln
    myObject.writeNum("PM.val", powermeter);
    header_BMS = 0;
  }
}

LG
Philipp

Ach, das ist relativ.
Software entwickelt sich am laufendem Objekt :wink:

Genau das.
Damit Du mal eine Vorstellung bekommst, dein Code... Der gibt nach 100 loopdurchläufen immer aus, wie lange das gedauert hat...

/*
  Fehler: Sobald Botschaften innerhalb der Loop, aber außerhalt dem Switch Case auf die Serielle Schnittstelle zum Display gelegt werden, kommt es zu Problemen!
*/

uint32_t startTime;
uint32_t stopTime;
uint8_t Umlauf;


//*********************************************************************************************************
// Bibliothek einbinden
#include "EasyNextionLibrary.h"

//*********************************************************************************************************
// Serielle Kommunikation festlegen
EasyNex myObject(Serial);

//*********************************************************************************************************
// Globale Variable definieren
//Taster Display
int flag_motor          = 0;
int flag_sportansicht   = 0;
int flag_ecoansicht     = 0;
int flag_lightON        = 0;
int flag_lightOFF       = 1;
int flag_lightAUTO      = 0;

//Hilfsvariablen
int licht_relais        = 11;
int motor_relais        = 12;
int LED                 = 13;
int eingang_fotodiode   = A0;
int wert_fotodiode      = 0;
byte eingang_hallsensor = 21;
int anzahl_flanken      = 0;
//char zeilenumbruch    = '\n';

//Daten vom BMS
int cell_temp1       = 0;
int cell_temp2       = 0;
int cell_temp3       = 0;
int cell_temp4       = 0;

int cell_volt1       = 0;
int cell_volt2       = 0;
int cell_volt3       = 0;
int cell_volt4       = 0;
int cell_volt5       = 0;
int cell_volt6       = 0;
int cell_volt7       = 0;
int cell_volt8       = 0;
int cell_volt9       = 0;
int cell_volt10      = 0;
int cell_volt11      = 0;
int cell_volt12      = 0;
int cell_volt13      = 0;
int cell_volt14      = 0;
int cell_volt15      = 0;
int cell_volt16      = 0;
int cell_volt_min    = 0;
int cell_volt_max    = 0;
int cell_volt_ges    = 0;

int batterieschuetz  = 0; //0 = offen, 0 = geschlossen
int powermeter       = 69; //0 = Off; 69 = Ready

int ladezustand      = 0;
int ladenaktiv       = 0;

//Kommunikation mit BMS
int data = 0;
String eingang_BMS          = "";
String zwischenspeicher_BMS = "";
int header_BMS              = 0;
float botschaft_BMS         = 0.0;




//*********************************************************************************************************
//Funktionsdefinitionen

//Motor Ein/Aus
void motorsteuerung (int i)
{
  if (i % 2 == 1)
  {
    digitalWrite(motor_relais, LOW);
  }
  else
  {
    digitalWrite(motor_relais, HIGH);
  }
}

//Lichtsteuerung
void lichtsteuerung (int an, int aus, int automatik)
{
  if (aus == 1)
  {
    digitalWrite(licht_relais, HIGH);
  }
  else if (an == 1)
  {
    digitalWrite(licht_relais, LOW);
  }
  else
  {
    wert_fotodiode = analogRead(eingang_fotodiode);
    if (wert_fotodiode > 250)
    {
      digitalWrite(licht_relais, LOW);
    }
    else
    {
      digitalWrite(licht_relais, HIGH);
    }
  }
}

//Flankenzaehler Hallsensor
void flankenzaehler_hallsensor()
{
  anzahl_flanken++;
}

//Drehzahlberechnung
void drehzahlberechnung(int i)
{
  i = i / 3;
  //Serial.print("Drehzahl = ");
  //Serial.println(i);
}

//Laden aktiv oder inaktiv
void ladeansicht(int i)
{
  if (i == ladenaktiv)
  {
  }
  else if (i == 0 & ladenaktiv == 1)
  {
    myObject.writeStr("page 0");
    ladenaktiv = 0;
  }
  else
  {
    myObject.writeStr("page 5");
    ladenaktiv = 1;
  }
}

//Schütze offen oder geschlossen
/*void schuetzauswertung(int i)
  {
  if(i == batterieschuetz)
  {
  }
  else if(i == 1 & batterieschuetz == 0)
  {
    powermeter = 69;
    batterieschuetz = 1;
  }
  else if(i == 0 & batterieschuetz == 1)
  {
    powermeter = 0;
    batterieschuetz = 0;
  }
  }*/


//*********************************************************************************************************
void setup()
{
  //Baudrate festlegen für Serielle Schnittstellen
  myObject.begin(9600);
  Serial1.begin(2400);
  //Eingänge festlegen
  pinMode(eingang_hallsensor, INPUT_PULLUP);
  //Ausgänge festlegen
  pinMode(motor_relais, OUTPUT);
  pinMode(licht_relais, OUTPUT);
  pinMode(LED, OUTPUT);
  //Interrupts aufrufen
  attachInterrupt(digitalPinToInterrupt(eingang_hallsensor), flankenzaehler_hallsensor, FALLING);
  //  //Starte Interrupt Timer
  //  TCCR0A=(1<<WGM01);    //Set the CTC mode
  //  OCR0A=0xF9; //Value for ORC0A for 1ms
  //
  //  TIMSK0|=(1<<OCIE0A);   //Set the interrupt request
  //  sei(); //Enable interrupt
  //
  //  TCCR0B|=(1<<CS01);    //Set the prescale 1/64 clock
  //  TCCR0B|=(1<<CS00);
  startTime = millis();
}

//*********************************************************************************************************
void loop()
{
  //Zyklische Abfrage vom Display
  myObject.NextionListen();
  //Funktionsaufrufe
  motorsteuerung(flag_motor);
  lichtsteuerung(flag_lightON, flag_lightOFF, flag_lightAUTO);
  drehzahlberechnung(anzahl_flanken);
  //Datenempfang und Verarbeitung vom BMS
  if (Serial1.available() > 0)
  {
    data = Serial1.read();
    if (char(data) != '\n')
    {
      eingang_BMS += char(data);
    }
    else
    {
      zwischenspeicher_BMS = eingang_BMS;
      eingang_BMS = "";
      header_BMS = zwischenspeicher_BMS.substring(0, 2).toInt();
      botschaft_BMS = zwischenspeicher_BMS.substring(2).toFloat();
      switch (header_BMS)
      {
        //Spannung
        case  1:
          cell_volt1   = ((int)(botschaft_BMS * 100));
          myObject.writeNum("SZ1.val", cell_volt1);
          break;
        case  2:
          cell_volt2   = ((int)(botschaft_BMS * 100));
          myObject.writeNum("SZ2.val", cell_volt2);
          break;
        case  3:
          cell_volt3   = ((int)(botschaft_BMS * 100));
          myObject.writeNum("SZ3.val", cell_volt3);
          break;
        case  4:
          cell_volt4   = ((int)(botschaft_BMS * 100));
          myObject.writeNum("SZ4.val", cell_volt4);
          break;
        case  5:
          cell_volt5   = ((int)(botschaft_BMS * 100));
          myObject.writeNum("SZ5.val", cell_volt5);
          break;
        case  6:
          cell_volt6   = ((int)(botschaft_BMS * 100));
          myObject.writeNum("SZ6.val", cell_volt6);
          break;
        case  7:
          cell_volt7   = ((int)(botschaft_BMS * 100));
          myObject.writeNum("SZ7.val", cell_volt7);
          break;
        case  8:
          cell_volt8   = ((int)(botschaft_BMS * 100));
          myObject.writeNum("SZ8.val", cell_volt8);
          break;
        case  9:
          cell_volt9   = ((int)(botschaft_BMS * 100));
          myObject.writeNum("SZ9.val", cell_volt9);
          break;
        case 10:
          cell_volt10  = ((int)(botschaft_BMS * 100));
          myObject.writeNum("SZ10.val", cell_volt10);
          break;
        case 11:
          cell_volt11  = ((int)(botschaft_BMS * 100));
          myObject.writeNum("SZ11.val", cell_volt11);
          break;
        case 12:
          cell_volt12  = ((int)(botschaft_BMS * 100));
          myObject.writeNum("SZ12.val", cell_volt12);
          break;
        case 13:
          cell_volt13  = ((int)(botschaft_BMS * 100));
          myObject.writeNum("SZ13.val", cell_volt13);
          break;
        case 14:
          cell_volt14  = ((int)(botschaft_BMS * 100));
          myObject.writeNum("SZ14.val", cell_volt14);
          break;
        case 15:
          cell_volt15  = ((int)(botschaft_BMS * 100));
          myObject.writeNum("SZ15.val", cell_volt15);
          break;
        case 16:
          cell_volt16  = ((int)(botschaft_BMS * 100));
          myObject.writeNum("SZ16.val", cell_volt16);
          break;
        case 17:
          cell_volt14  = ((int)(botschaft_BMS * 100));
          myObject.writeNum("SZ14.val", cell_volt14);
          break;
        case 18:
          cell_volt15  = ((int)(botschaft_BMS * 100));
          myObject.writeNum("SZ15.val", cell_volt15);
          break;
        case 19:
          cell_volt16  = ((int)(botschaft_BMS * 100));
          myObject.writeNum("SZ16.val", cell_volt16);
          break;
        //Schütze 00=offen; 01=geschlossen
        //case 20: schuetzauswertung((int)botschaft_BMS); break;
        //Ladezustand
        case 21:
          ladezustand  = ((int)botschaft_BMS);
          myObject.writeNum("Ladelevel.val", ladezustand);
          myObject.writeNum("Ladezustand.val", ladezustand);
          break;
        //Ladesituation
        case 25:
          ladeansicht((int)botschaft_BMS);
          break;
        //Temperatur
        case 30:
          cell_temp1   = ((int)(botschaft_BMS * 100));
          myObject.writeNum("TZ1.val", cell_temp1);
          break;
        case 31:
          cell_temp2   = ((int)(botschaft_BMS * 100));
          myObject.writeNum("TZ2.val", cell_temp2);
          break;
        case 32:
          cell_temp3   = ((int)(botschaft_BMS * 100));
          myObject.writeNum("TZ3.val", cell_temp3);
          break;
        case 33:
          cell_temp4   = ((int)(botschaft_BMS * 100));
          myObject.writeNum("TZ4.val", cell_temp4);
          break;
        default:
          break;
      }
    }
  }
  //Powermeter
  //Fehlend: Gaspedal einlesen + auswerten und Wert an Display schicken.
  //Falls Schütze geschalten -> Wert + Powermeter
  //Falls Schütze offen -> Powermeter darf keinen Wert übermitteln
  //myObject.writeNum("PM.val", powermeter);
  umlauf++;
  if (umlauf == 100)
  {
    stopTime = millis();
    delay(100);
    Serial.print(F("Loopdurchläufe: "));
    Serial.println(umlauf);
    delay(10);
    Serial.print(F("Start bei: "));
    Serial.print(startTime);
    Serial.println(" ms");
    delay(10);
    Serial.print(F("Stop bei: "));
    Serial.print(stopTime);
    Serial.println(" ms");
    delay(10);
    Serial.print(F("Jeder Umlauf dauert etwa: "));
    Serial.println((stopTime - startTime) / umlauf);
    umlauf = 0;
    StartTime = millis();
  }
}


//*********************************************************************************************************
//Triggersignale vom Display
void trigger0()   //Motor
{
  flag_motor = flag_motor + 1;
}

void trigger1()   //Sportansicht
{
  //BMS Rückmelden das Sportmodus aktiv ist
}

void trigger2()   //Ecoansicht
{
  //BMS Rückmelden das Ecomodus aktiv ist
}

void trigger3()   //Light ON
{
  flag_lightON    = 1;
  flag_lightOFF   = 0;
  flag_lightAUTO  = 0;
}

void trigger4()   //Light OFF
{
  flag_lightON    = 0;
  flag_lightOFF   = 1;
  flag_lightAUTO  = 0;
}

void trigger5()   //Light AUTO
{
  flag_lightON    = 0;
  flag_lightOFF   = 0;
  flag_lightAUTO  = 1;
}

Hallo my_xy_projekt,

wie angekündigt habe ich die Kommunikation der Schnittstellen geändert:

  • Daten vom BMS Serial(2)
  • Daten ans Display (Serial(1)

Die Zeit pro Loop beträgt ca.7-10ms. Was für meinen Geschmack ziemlich flott ist :smiley:

Die Lichtsteuerung habe ich ebenfalls angepasst und nun kann ich nachvollziehen wie du mit den Arrays gearbeitet hättest. Verständlicher vom Code finde ich jedoch den Switch Case, weshalb ich auch dabei geblieben bin, aber die Idee mit den Arrays in dem Zusammenhang gefällt mir sehr gut und hilft evlt. bei Folgeprojekten.

Mit deiner genannten if(header_BMS) funktioniert es zu 80%.
Ich kann jetzt auch nachvollziehen, warum meine Serielle Schnittstelle im alten Code überflutet wurde. Teilweise werden aber immer noch Botschaften falsch übermittelt. Ich dachte mir, die if Bedingung einfach alle 50ms-100ms durchlaufen zu lassen.
Dann sollte die Zeit dazwischen lang genug sein, um alle Daten vernünftig anzuzeigen und trotzdem die Geschwindigkeit etc. schnell genug zu aktualisieren :slight_smile:

Und vielen Dank für die Hilfe! Da ware ich selbst nicht drauf gekommen und vorallem hab ich es jetzt kapiert, woran es lag.

//Version: 1.9
//Änderungshistorie
//- Licht on/off/auto fertig
//- Motor fertig
//- BMS Datenempfang und -senden fertig
//- Hallsensor einbinden - unvollständig!
//- Interrupt auskommentiert -> Ansonsten Fehler

//Debugvariablen
uint32_t startTime;
uint32_t stopTime;
uint8_t umlauf;

//*********************************************************************************************************
// Bibliothek einbinden
#include "EasyNextionLibrary.h"

//*********************************************************************************************************
// Serielle Kommunikation festlegen
EasyNex myObject(Serial1);

//*********************************************************************************************************
// Globale Variable definieren
  //Taster Display
  int flag_motor          = 0;
  int flag_sportansicht   = 0;
  int flag_ecoansicht     = 0;
  int light               = 0; //0=aus, 1=an, 2=auto

  //Hilfsvariablen
  int licht_relais        = 11;
  int motor_relais        = 12;
  int LED                 = 13;
  int eingang_fotodiode   = A0;
  int wert_fotodiode      = 0;
  byte eingang_hallsensor = 21;
  int anzahl_flanken      = 0;
  //char zeilenumbruch    = '\n';
  
  //Daten vom BMS
  int cell_volt1       = 0;
  int cell_volt2       = 0;
  int cell_volt3       = 0;
  int cell_volt4       = 0;
  int cell_volt5       = 0;
  int cell_volt6       = 0;
  int cell_volt7       = 0;
  int cell_volt8       = 0;
  int cell_volt9       = 0;
  int cell_volt10      = 0;
  int cell_volt11      = 0;
  int cell_volt12      = 0;
  int cell_volt13      = 0;
  int cell_volt14      = 0;
  int cell_volt15      = 0;
  int cell_volt16      = 0;
  int cell_volt_min    = 0;
  int cell_volt_max    = 0; 
  int cell_volt_ges    = 0;

  int temp_inverter    = 0;
  int temp_umgebung    = 0;
  int temp_motor       = 0;
  int temp_box         = 0;
  int temp_battery1    = 0;
  int temp_battery2    = 0;
  int temp_battery_max = 0;

  int batterieschuetz  = 0; //0 = offen, 1 = geschlossen
  int powermeter       = 0; //0 = Off; 69 = Ready

  int ladezustand      = 0; 
  int ladenaktiv       = 0;

  int notaus           = 0; //0 = i.O., 1 = Notaus gedrückt

  int luefter          = 0;

  //Kommunikation mit BMS
  int data = 0;
  String eingang_BMS          = "";
  String zwischenspeicher_BMS = "";
  int header_BMS              = 0;
  float botschaft_BMS         = 0.0;


  

//*********************************************************************************************************
//Funktionsdefinitionen

  //Motor Ein/Aus
  void motorsteuerung (int i)
  {
    if(i % 2 == 1)
    {
      digitalWrite(motor_relais, LOW);
    }
      
    else
    {
      digitalWrite(motor_relais, HIGH);
    }
  }

  //Lichtsteuerung
  void lichtsteuerung (int licht)
  {
     if(licht == 1)
     {
      digitalWrite(licht_relais, HIGH);
     }

     else if(licht == 0)
     {
      digitalWrite(licht_relais, LOW);
     }

     else
     {
      wert_fotodiode = analogRead(eingang_fotodiode);
      if(wert_fotodiode > 250)
      {
        digitalWrite(licht_relais, LOW);
      }
      else
      {
        digitalWrite(licht_relais, HIGH);
      }
     }
  }

  //Flankenzaehler Hallsensor
  void flankenzaehler_hallsensor()
  {
    anzahl_flanken++;
  }

  //Drehzahlberechnung
  void drehzahlberechnung(int i)
  {
    i = i / 3; 
    //Serial.print("Drehzahl = ");
    //Serial.println(i); 
  }

  //Laden aktiv oder inaktiv
  void ladeansicht(int i)
  {
    if(i == ladenaktiv)
    {
    }
    else if(i == 0 & ladenaktiv == 1)
    {
      myObject.writeStr("page 0");
      ladenaktiv = 0;
    }
    else
    {
      myObject.writeStr("page 5");
      ladenaktiv = 1;
    }
  }

    //Notaus aktiv
  void notausauswertung(int i)
  {
    if(i == notaus)
    {
    }
    else if(i == 1 & notaus == 0)
    {
      myObject.writeStr("page 9");
      notaus = 1;
    }
    else
    {
      myObject.writeStr("page 1");
      notaus = 0;
    }
  }
 
  //Schütze offen oder geschlossen
  void schuetzauswertung(int i)
  {
    if(i == batterieschuetz)
    {
    }
    else if(i == 1 & batterieschuetz == 0)
    {
      powermeter = 69;
      batterieschuetz = 1;
    }
    else 
    {
      powermeter = 0;
      batterieschuetz = 0;
    }
  }

    
//*********************************************************************************************************
void setup() 
{
  //Baudrate festlegen für Serielle Schnittstellen
  Serial.begin(9600);
  myObject.begin(9600);
  Serial2.begin(2400);

  //Eingänge festlegen
  pinMode(eingang_hallsensor,INPUT_PULLUP);
  
  //Ausgänge festlegen
  pinMode(motor_relais, OUTPUT);
  pinMode(licht_relais, OUTPUT);
  pinMode(LED, OUTPUT);

  //Interrupts aufrufen
  attachInterrupt(digitalPinToInterrupt(eingang_hallsensor), flankenzaehler_hallsensor, FALLING);

//  //Starte Interrupt Timer
//  TCCR0A=(1<<WGM01);    //Set the CTC mode   
//  OCR0A=0xF9; //Value for ORC0A for 1ms
// 
//  TIMSK0|=(1<<OCIE0A);   //Set the interrupt request
//  sei(); //Enable interrupt
// 
//  TCCR0B|=(1<<CS01);    //Set the prescale 1/64 clock
//  TCCR0B|=(1<<CS00);

}

//*********************************************************************************************************
void loop() 
{
  //Zyklische Abfrage vom Display
  myObject.NextionListen();

  //Funktionsaufrufe
  motorsteuerung(flag_motor);

  lichtsteuerung(light);

  drehzahlberechnung(anzahl_flanken);

  //Datenempfang und Verarbeitung vom BMS
  if(Serial2.available() > 0) 
  {
    data = Serial2.read(); 
    if (char(data) != '\n') 
    {
      eingang_BMS += char(data);
    }  
    else 
    {  
      zwischenspeicher_BMS = eingang_BMS;     
      eingang_BMS = "";

      header_BMS = zwischenspeicher_BMS.substring(0,2).toInt();
      botschaft_BMS = zwischenspeicher_BMS.substring(2).toFloat();
        
      switch(header_BMS)
      {
        //Spannung        
        case  1: cell_volt1     = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ1.val", cell_volt1); break; 
        case  2: cell_volt2     = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ2.val", cell_volt2); break;
        case  3: cell_volt3     = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ3.val", cell_volt3); break;
        case  4: cell_volt4     = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ4.val", cell_volt4); break;
        case  5: cell_volt5     = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ5.val", cell_volt5); break;
        case  6: cell_volt6     = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ6.val", cell_volt6); break;
        case  7: cell_volt7     = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ7.val", cell_volt7); break;
        case  8: cell_volt8     = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ8.val", cell_volt8); break; 
        case  9: cell_volt9     = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ9.val", cell_volt9); break;
        case 10: cell_volt10    = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ10.val", cell_volt10); break;
        case 11: cell_volt11    = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ11.val", cell_volt11); break;
        case 12: cell_volt12    = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ12.val", cell_volt12); break;
        case 13: cell_volt13    = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ13.val", cell_volt13); break;
        case 14: cell_volt14    = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ14.val", cell_volt14); break;
        case 15: cell_volt15    = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ15.val", cell_volt15); break;
        case 16: cell_volt16    = ((int)(botschaft_BMS*100)); myObject.writeNum("SZ16.val", cell_volt16); break;           
        case 17: cell_volt_min  = ((int)(botschaft_BMS*100)); myObject.writeNum("SZmin.val", cell_volt_min); break;
        case 18: cell_volt_max  = ((int)(botschaft_BMS*100)); myObject.writeNum("SZmax.val", cell_volt_max); break;
        case 19: cell_volt_ges  = ((int)(botschaft_BMS*100)); myObject.writeNum("SZges.val", cell_volt_ges); break;     

        //Schütze 00=offen; 01=geschlossen
        case 20: schuetzauswertung((int)botschaft_BMS); break;
       
        //SOC
        case 21: ladezustand  = ((int)botschaft_BMS); myObject.writeNum("Ladelevel.val", ladezustand); 
                                                      myObject.writeNum("Ladezustand.val", ladezustand); break;

        //Alive-Timer alle 200ms
        //case 23: Timer zählt von 0 - 15 -> eingehende Zahl von größer sein, als vorhergehende
  
        //Ladesituation
        case 25: ladeansicht((int)botschaft_BMS); break;

        //Notaus
        case 26: notausauswertung((int)botschaft_BMS); break;

        //Lüfter
        case 27: luefter          = ((int)(botschaft_BMS*100)); myObject.writeNum("fan.val", luefter);           break;

        //Temperatur
        case 31: temp_inverter    = ((int)(botschaft_BMS*100)); myObject.writeNum("Tinv.val", temp_inverter);    break;
        case 32: temp_umgebung    = ((int)(botschaft_BMS*100)); myObject.writeNum("Tumg.val", temp_umgebung);    break;
        case 33: temp_motor       = ((int)(botschaft_BMS*100)); myObject.writeNum("Tmot.val", temp_motor);       break;
        case 34: temp_box         = ((int)(botschaft_BMS*100)); myObject.writeNum("Tbox.val", temp_box);         break;
        case 35: temp_battery1    = ((int)(botschaft_BMS*100)); myObject.writeNum("Tba1.val", temp_battery1);    break;
        case 36: temp_battery2    = ((int)(botschaft_BMS*100)); myObject.writeNum("Tba2.val", temp_battery2);    break;
        case 37: temp_battery_max = ((int)(botschaft_BMS*100)); myObject.writeNum("Tbam.val", temp_battery_max); break;
    
        default: break; 
      }       
    }
  }

  //Debuggen
  /*
  umlauf++;
  if (umlauf == 100)
  {
    stopTime = millis();
    delay(100);
    Serial.print(F("Loopdurchläufe: "));
    Serial.println(umlauf);
    delay(10);
    Serial.print(F("Start bei: "));
    Serial.print(startTime);
    Serial.println(" ms");
    delay(10);
    Serial.print(F("Stop bei: "));
    Serial.print(stopTime);
    Serial.println(" ms");
    delay(10);
    Serial.print(F("Jeder Umlauf dauert etwa: "));
    Serial.println((stopTime - startTime) / umlauf);
    umlauf = 0;
    startTime = millis();
  }
  Serial.println(millis());
  */


}

//*********************************************************************************************************
//Triggersignale vom Display
//Triggersignale vom Display
void trigger0()   //Motor
{
  flag_motor = flag_motor + 1;
}

void trigger1()   //Sportansicht
{
  //BMS Rückmelden das Sportmodus aktiv ist 
}

void trigger2()   //Ecoansicht
{
  //BMS Rückmelden das Ecomodus aktiv ist 
}

void trigger3()   //Light ON
{
  light = 1;
}

void trigger4()   //Light OFF
{
  light = 0;
}

void trigger5()   //Light AUTO
{
  light = 2;
}

Das ist ab kurz nach Arduino-Start immer erfüllt.
millis()=0 macht nicht, was Du denkst. Das dürfte Dir der Compiler um die Ohren hauen.

Gruß Tommy

Hey Tommy,

danke für deine Nachricht.
Ich wollte damit lediglich schematisch aufzeigen, das ich die if nur alle 50ms durchlaufen lassen möchte. Anscheinend kam dies in meinem obigen Beitrag falsch rüber und daher habe ich es entsprechend geändert das es nicht mehr zu Missverständnissen kommt :slight_smile:
Wie du bereits erwähnt hast, will es der Compailer sowieso nicht.

VG
Philipp