Nextion zu Serial viel zu langsam

nach eine stelle mehr und dann passt es, jetzt 37.3
er zeigt auch nur c10-c11, die davor stehen noch auf 0

Nein.
Wenn ein Wert 1234 automatisch auf 1.234 abgebildet wird, dann muss da nix multipliziert werden.
Ausgangspunkt ist ein 16Bit-(unsigned)Integer.
Wir haben also Werte von 0 bis etwas über 65000, wobei ein Wert von 37000 die Zelle nspannung mit 3.7000 darstellt. -> Ich habe eine Kommastelle mehr im Wert, als Du in der Darstellung. -> Siehe oben in der Definition Scaler: 0.0001
Also muss ich das anders machen.
Ich baue eine Funktion mit einem Scaler, teile aber durch 10, wenn Du nicht im Nextion die Teilung und die Darstellung getrennt einstellen kannst.

Edit: Ging schneller als gedacht: - Las das HMI-File, wie es ist.

/*
  BMS_AKKU_letzter Stand
  Wird noch weiterentwickelt!
*/

#include <FlexCAN_T4.h>
FlexCAN_T4 <CAN1, RX_SIZE_256, TX_SIZE_16> can1;

static CAN_message_t rxmsg, txmsg;

constexpr byte cellNums {96};
struct CELLDATA                         // CAN-ID: 0x36
{
  uint16_t voltage;                     // #1#2 Scaler 0.0001
  uint16_t resistance;                  // #3#4 Scaler 0.01
  uint16_t openVoltage;                 // #5#6 Scaler 0.0001
  // uint8_t checkSum                   // #7 || Berechnung: CAN-ID + jedes Byte exclusive CRC-Byte + Länge inclusive CRC-Byte
};
//
constexpr byte thermoNums {12};
struct COOLER                           // CAN-ID: 0x1838F380
{
  int8_t temperature[thermoNums];       // #2
  uint8_t enable;                       // #3 || & 0x80 FAULTSTATUS!!!
  int8_t lowTemperature;                // #4
  int8_t highTemperature;               // #5
  // uint8_t highestId                  // #6    || ID dieses Moduls
  // uint8_t lowestId                   // #7    || ID dieses Moduls
};

struct PACK
{
  uint8_t stateOfCharge;                // CAN-ID 0x0640 #0
  uint16_t resistance;                  // CAN-ID 0x0640 #1#2 Scaler 0.001
  uint8_t healty;                       // CAN-ID 0x0640 #3
  uint16_t highestCellVoltage;          // CAN-ID 0x0640 #4#5 Scaler 0.0001
  uint16_t lowestCellVoltage;           // CAN-ID 0x0640 #6#7 Scaler 0.0001
  uint16_t maxDCLoad;                   // CAN-ID 0x0643 #0#1
  uint16_t maxCCLoad;                   // CAN-ID 0x0643 #2#3
  uint16_t absolutAmpere;               // CAN-ID 0x0643 #4#5 Scaler 0.1
  uint16_t absolutVoltage;              // CAN-ID 0x0643 #6#7 Scaler 0.1
  // flag => CAN-ID 0x200 -> Byte #0-> 4 Bit benutzt!!!
  uint8_t flag;                         //mil, balancing, charging, powerReady || 4x NAN
  // dtcFlag => CAN-ID 0x200 -> Byte #1-> 6 Bit benutzt!!!
  uint8_t dtcFlag;                      //CellOverHIGHVoltage, cellUnderLowVoltage, currentFailure, ThermistorFault, wiringOpen, ChargeSafeRelaisFailure
};
/*
  const char *flagObj[8] = {"p61.aph=", "p60.aph=", "t61.pco=", "t60.pco=", "NA", "NA", "NA", "NA"}; // NextionString je Wert
  const uint16_t flagVal[8][2] = {{0, 0}, {0, 0}, {33808, 33808}, {33808, 2016}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}; // Value je BIT
*/
//
struct BATT
{
  CELLDATA cell[cellNums];              // cellnum => #0 from CAN-ID: 0x36
  CELLDATA oldcell[cellNums];           // Merker
  COOLER cooler;                        // #0#1  || ID over all from CAN-ID: 0x1838F380
  COOLER oldcool;                       // Merker
  PACK pack;
  PACK oldpack;
} batt;
//
struct DRIVE
{
  uint16_t rotations;                   // CAN-ID: 0x500 #0#1
  uint16_t direction;                   // CAN-ID: 0x500 #2
  uint8_t mode;                         // CAN-ID: 0x501 #0
  uint8_t state;                        // CAN-ID: 0x501 #1
  int8_t heatsinkTemp;                  // CAN-ID: 0x501 #2
  int8_t engineTemp;                    // CAN-ID: 0x501 #3
  uint16_t voltage;                     // CAN-ID: 0x502 #0#1
  uint16_t ampere;                      // CAN-ID: 0x502 #2#3
};
DRIVE drive;
DRIVE oldDrive;

struct BMS
{
  uint16_t highTemperature;    // CAN-ID 0x0641 #0#1
  uint16_t lowTemperature;     // CAN-ID 0x0641 #2#3
  uint16_t internTemperature;  // CAN-ID 0x0641 #4#5
  uint16_t inputSupplyVoltage; // CAN-ID 0x0641 #6#7 Scaler 0.1
  uint16_t adcIsolation;       // CAN-ID 0x0642 #0#1
  uint16_t shortestWave;       // CAN-ID 0x0642 #2#3 Scaler 0.1
  uint16_t avgTemperature;     // CAN-ID 0x0642 #4#5
};

BMS bms;
BMS oldBms;

char nextionBuf[50] = {'\0'};
//
void setup()
{
  Serial.begin(115200);     // Serieller Monitor
  Serial2.begin(115200);    // Nextion
  can1.begin();
  can1.setBaudRate(500000);
  defaultModeMessage();     // füllt txmsg
  can1.write(txmsg);
}
//
void loop(void)
{
  canReadIn();
  nextReadIn();
  sendCellVoltage();
  /*
    sendCoolerData();
    sendPackData();
    sendDriveData();
    sendBmsData();
    Serial.flush();
  */
}
//
void sendCoolerData()
{
  static byte idx = 0;                                              // Merker
  const char *title = "d";
  sendData(title, idx, batt.cooler.temperature[idx], batt.oldcool.temperature[idx]);
  if (++idx >= thermoNums)                                          // nächster index und Prüfung auf Überlauf
  {
    idx = 0;
    sendData("x135", idx, batt.cooler.lowTemperature, batt.oldcool.lowTemperature);
    sendData("x136", idx, batt.cooler.highTemperature, batt.oldcool.highTemperature);
  }                                                      // dann fang an von vorne
}
//
void sendCellVoltage()
{
  static byte idx = 0;                                              // Merker welche Batteriezelle
  const char *title = "c";
  //const float scaler = 0.0001;
  sendData(title, idx, batt.cell[idx].voltage, batt.oldcell[idx].voltage, 10);
  // resistance & openvoltage ungenutzt!
  if (++idx >= cellNums)
  { idx = 0; }
}
//
void sendPackData()
{
  sendData("ChargeState", batt.pack.stateOfCharge, batt.oldpack.stateOfCharge);
  sendData("Resistance", batt.pack.resistance, batt.oldpack.resistance, 0.001);
  sendData("Healt", batt.pack.healty, batt.oldpack.healty);
  sendData("MaxCellVolt", batt.pack.highestCellVoltage, batt.oldpack.highestCellVoltage, 0.0001);
  sendData("MinCellVolt", batt.pack.lowestCellVoltage, batt.oldpack.lowestCellVoltage, 0.0001);
  sendData("MaxDCLoad", batt.pack.maxDCLoad, batt.oldpack.maxDCLoad);
  sendData("MaxCCLoad", batt.pack.maxCCLoad, batt.oldpack.maxCCLoad);
  sendData("PackAmpere", batt.pack.absolutAmpere, batt.oldpack.absolutAmpere, 0.1);
  sendData("PackVolage", batt.pack.absolutVoltage, batt.oldpack.absolutVoltage, 0.1);
}
//
void sendDriveData()
{
  sendData("UPM", drive.rotations, oldDrive.rotations);
  sendData("dir", drive.direction, oldDrive.direction);
  sendData("mode", drive.mode, oldDrive.mode);
  sendData("State", drive.state, oldDrive.state);
  sendData("Kuehler", drive.heatsinkTemp, oldDrive.heatsinkTemp);
  sendData("Engine", drive.engineTemp, oldDrive.engineTemp);
  sendData("Drivevolt", drive.voltage, oldDrive.voltage);
  sendData("Driveamp", oldDrive.ampere, oldDrive.ampere);
}
//
void sendBmsData()
{
  sendData("BMS01", bms.highTemperature, oldBms.highTemperature);
  sendData("BMS02", bms.lowTemperature, oldBms.lowTemperature);
  sendData("BMS03", bms.internTemperature, oldBms.internTemperature);
  sendData("BMS04", bms.inputSupplyVoltage, oldBms.inputSupplyVoltage, 0.1);
  sendData("BMS05", bms.adcIsolation, oldBms.adcIsolation);
  sendData("BMS06", bms.shortestWave, oldBms.shortestWave, 0.1);
  sendData("BMS07", bms.avgTemperature, oldBms.avgTemperature);
}
//

void canReadIn()
{
  // /*INDENT-OFF*
  if (can1.read(rxmsg))
  {
    switch (rxmsg.id)
    {
      case 0x36:
        if (rxmsg.buf[0] < cellNums)     // cellID passt noch als Element
        {
          batt.cell[rxmsg.buf[0]].voltage     = rxmsg.buf[1]<<8|rxmsg.buf[2];
          batt.cell[rxmsg.buf[0]].resistance  = rxmsg.buf[3]<<8|rxmsg.buf[4];
          batt.cell[rxmsg.buf[0]].openVoltage = rxmsg.buf[5]<<8|rxmsg.buf[6];
          /*
          uint8_t crc = rxmsg.id;
          for (byte b=0; b<7; b++)
          crc+=rxmsg.buf[b];
          crc+=8;
          Serial.print(F("cell CRC "));
          if(rxmsg.buf[7]!=crc)
          Serial.print(F("nicht "));
          Serial.println("OK");
          */
        }
        break;
      case 0x200:
        batt.pack.flag         = rxmsg.buf[0];
        batt.pack.dtcFlag      = rxmsg.buf[1];
        break;
      case 0x500:
        drive.rotations        = rxmsg.buf[0]<<8|rxmsg.buf[1];
        drive.direction        = rxmsg.buf[2]<<8|rxmsg.buf[3];
        break;
      case 0x501:
        drive.mode             = rxmsg.buf[0];
        drive.state            = rxmsg.buf[1];
        drive.heatsinkTemp     = rxmsg.buf[2];
        drive.engineTemp       = rxmsg.buf[3];
        break;
      case 0x502:
        drive.voltage          = rxmsg.buf[0]<<8|rxmsg.buf[1];
        drive.ampere           = rxmsg.buf[2]<<8|rxmsg.buf[3];
        break;
      /*
        case 0x581:
        bms.power = word(rxmsg.buf[5], rxmsg.buf[6]);
        break;
      */
      case 0x640:
        batt.pack.stateOfCharge      = rxmsg.buf[0];
        batt.pack.resistance         = rxmsg.buf[1]<<8|rxmsg.buf[2];
        batt.pack.healty             = rxmsg.buf[3];
        batt.pack.highestCellVoltage = rxmsg.buf[4]<<8|rxmsg.buf[5];
        batt.pack.lowestCellVoltage  = rxmsg.buf[6]<<8|rxmsg.buf[7];
        break;
      case 0x641:
        bms.highTemperature          = rxmsg.buf[0]<<8|rxmsg.buf[1];
        bms.lowTemperature           = rxmsg.buf[2]<<8|rxmsg.buf[3];
        bms.internTemperature        = rxmsg.buf[4]<<8|rxmsg.buf[5];
        bms.inputSupplyVoltage       = rxmsg.buf[6]<<8|rxmsg.buf[7];
        break;
      case 0x642:
        bms.adcIsolation             = rxmsg.buf[0]<<8|rxmsg.buf[1];
        bms.shortestWave             = rxmsg.buf[2]<<8|rxmsg.buf[3];
        bms.avgTemperature           = rxmsg.buf[4]<<8|rxmsg.buf[5];
        break;
      case 0x643:
        batt.pack.maxDCLoad          = rxmsg.buf[0]<<8|rxmsg.buf[1];
        batt.pack.maxCCLoad          = rxmsg.buf[2]<<8|rxmsg.buf[3];
        batt.pack.absolutAmpere      = rxmsg.buf[4]<<8|rxmsg.buf[5];
        batt.pack.absolutVoltage     = rxmsg.buf[6]<<8|rxmsg.buf[7];
        break;
      case 0x1838F380:
        uint16_t myId          = rxmsg.buf[0]<<8|rxmsg.buf[1];
        if (myId < thermoNums) // ID passt noch als Element
        {
          batt.cooler.temperature[myId]     = rxmsg.buf[2];
          batt.cooler.lowTemperature  = rxmsg.buf[4];
          batt.cooler.highTemperature = rxmsg.buf[5];
        }
        break;
    }
  }
// *INDENT-ON*
}
//
void checkNextionError(const byte myByte)
{
  const char check[] = {0x1A, 0xFF, 0xFF, 0xFF};  // Vergleichspuffer
  constexpr byte len {sizeof(check) / sizeof(check[0])};
  static char buf[len] = {'\0'};                  // Puffer
  buf[len - 1] = myByte;                          // Zeichen aufnehmen
  // Prüfung ob vom Nextion eine Ablehnung kam
  if (strncmp(buf, check, len))                   // Vergleich != 0?
  { Serial.println(F("NextionError!")); }
  for (byte b = 0; b < len - 1; b++)              // Zeichen im buffer verschieben
  { buf[b] = buf[b + 1];}
}
//
void nextReadIn()
{
  uint8_t x = Serial2.available();     // Es kommt was vom Nextion
  while (x--)
  {
    byte myByte = Serial2.read();      // Übernehme 1 zeichen
    hexPrint(myByte);                  // Kontrolle auf dem SerMon was ankommt
    defaultModeMessage();              // Füllt txmsg mit defaultwerten
    switch (myByte)                    //
    {
      case '1':                        // entspricht default
        can1.write(txmsg);
        break;
      case '2':
        txmsg.buf[5] = 0x4A;
        can1.write(txmsg);
        break;
      case '3':
        txmsg.buf[5] = 0x7D;
        can1.write(txmsg);
        break;
      default:
        // checkNextionError(myByte);
        break;
    }
  }
}
//
void sendData(const char *title, const uint16_t value, uint16_t &oldValue)
{
  if (value != oldValue)
  {
    sprintf(nextionBuf, "%s%s", title, ".val=");
    sendData2Nextion(nextionBuf, value);
    oldValue = value;
  }
}
//
void sendData(const char *title, const uint8_t value, uint8_t &oldValue)
{
  if (value != oldValue)
  {
    sprintf(nextionBuf, "%s%s", title, ".val=");
    sendData2Nextion(nextionBuf, value);
    oldValue = value;
  }
}
//
void sendData(const char *title, const uint16_t idx, const uint16_t value, uint16_t &oldValue, const uint8_t &scaler) // Nextion -> unsigned int16
{
  if (value != oldValue)
  {
    sprintf(nextionBuf, "%s%i%s", title, idx, ".val=");
    sendData2Nextion(nextionBuf, value/scaler);
    oldValue = value;
  }
}
//
void sendData(const char *title, const uint16_t idx, const uint16_t value, uint16_t &oldValue) // Nextion -> unsigned int16
{
  if (value != oldValue)
  {
    sprintf(nextionBuf, "%s%i%s", title, idx, ".val=");
    sendData2Nextion(nextionBuf, value);
    oldValue = value;
  }
}
//
void sendData(const char *title, const int8_t value, int8_t &oldValue)      // Nextion -> signed int8
{
  if (value != oldValue)
  {
    sprintf(nextionBuf, "%s%s", title, ".val=");
    sendData2Nextion(nextionBuf, value);
    oldValue = value;
  }
}
//
void sendData(const char *title, const uint16_t idx, const int8_t value, int8_t &oldValue)      // Nextion -> signed int8
{
  if (value != oldValue)
  {
    sprintf(nextionBuf, "%s%i%s", title, idx, ".val=");
    sendData2Nextion(nextionBuf, value);
    oldValue = value;
  }
}
//
void sendData(const char *title, const uint16_t idx, const int16_t value, int16_t &oldValue)    // Nextion -> signed int16
{
  if (value != oldValue)
  {
    sprintf(nextionBuf, "%s%i%s", title, idx, ".val=");
    sendData2Nextion(nextionBuf, value);
    oldValue = value;
  }
}
//
void sendData(const char *title, const uint16_t value, uint16_t &oldValue, const float scaler) // Nextion -> float
{
  if (value != oldValue)
  {
    sprintf(nextionBuf, "%s%s", title, ".val=");
    sendData2Nextion(nextionBuf, value * scaler);
    oldValue = value;
  }
}
// Nextion Ende ist 3* 0xFF
void nextionSendEnd()
{
  for (byte b = 0; b < 3; b++)
  { Serial2.write(0xFF); }
  Serial.println();
}
//
void sendData2Nextion(const char *sendBuf, const uint16_t value)
{
  Serial2.print(sendBuf);
  Serial2.print(value);
  Serial.print(sendBuf);
  Serial.print(value, 5);
  nextionSendEnd();
}
//
void sendData2Nextion(const char *sendBuf)
{
  Serial2.print(sendBuf);
  Serial.print(sendBuf);
  nextionSendEnd();
}
//
void defaultModeMessage()              // Vorbelegung
{
  txmsg.id = 0x601;
  txmsg.len = 8;
  txmsg.buf[0] = 0x23;
  txmsg.buf[1] = 0x00;
  txmsg.buf[2] = 0x20;
  txmsg.buf[3] = 0x31;
  txmsg.buf[4] = 0x00;
  txmsg.buf[5] = 0x26;
  txmsg.buf[6] = 0x00;
  txmsg.buf[7] = 0x00;
}

//
void hexPrint(const byte myByte)       // gibt das übergebene Byte im Format "0xBB, " aus
{
  static byte idx = 0;                 // Merker für Zeilenumbruch
  Serial.print(" 0x");                 // Einleitung der Darstellung
  if (myByte < 0x10)                   // Byte <= 9?
  { Serial.print(0); }                 // auffüllen
  Serial.print(myByte, HEX);           // Wert ausgeben
  Serial.print(", ");                  // für Formatierung
  if (++idx > 10)                      // Werte je Zeile erfüllt
  { Serial.println(); }                // Zeilenumbruch
}

also ich kann im nextion nur die kommastelle verschieben
das beste wäre ohne kommas an den nextion senden, und da die position des kommas setzten

Nimm den Code #262 - mit Scaler jetzt mit 10 auf uint16_t mit 4 virtuellen Nackommastellen reduziert

hab ich wohl übersehen, der von #262 funktioniert einwandtfrei, alle daten werden perfekt übergeben
und Superschnell :slight_smile:

Las mir nen Moment, ich bau noch das coolerpack.

1 Like

Das Display braucht insgesamt nur vier Ziffern.
321 wird wohl als 0.321 angezeigt, bei 54321 weiß ich nicht. Das kann @kozmonautic aber ausprobieren.

1 Like

sobald es 5stellig wird, verschiebt er automatisch das kommazeichen, um es innerhalb von 5 zeichen zu halten, bei 54321 zeigt e 54.32 an. man kann natürlich die Zeichen erhöhen, auf 7 z.b., dann zeigt er 5.4321 an

Das war Absicht meiner Aktion.
Ok, ich muss mich durch Deine Zuordnung wühlen und stosse dabei auf SOC auf der Hautseite und Page 5 - Können wir uns auf 1x n1 verständigen?

Der cooler sollte auch laufen.
Wenn der hier jetzt den cooler noch mitgibt und es keine Fehlerrückmeldung vom Nextion gibt, dann kannst Du die sendPackData() Zeile im loop() noch mit rein nehmen und bekommst den SOC -> Da muessen wir sehen, wie die Darstellung ist. Theoretisch ist die ganzzalig und 3 stellig :wink:

/*
  BMS_AKKU_letzter Stand
  Wird noch weiterentwickelt!
*/

#include <FlexCAN_T4.h>
FlexCAN_T4 <CAN1, RX_SIZE_256, TX_SIZE_16> can1;

static CAN_message_t rxmsg, txmsg;

constexpr byte cellNums {96};
struct CELLDATA                         // CAN-ID: 0x36
{
  uint16_t voltage;                     // #1#2 Scaler 0.0001
  uint16_t resistance;                  // #3#4 Scaler 0.01
  uint16_t openVoltage;                 // #5#6 Scaler 0.0001
  // uint8_t checkSum                   // #7 || Berechnung: CAN-ID + jedes Byte exclusive CRC-Byte + Länge inclusive CRC-Byte
};
//
constexpr byte thermoNums {12};
struct COOLER                           // CAN-ID: 0x1838F380
{
  int8_t temperature[thermoNums];       // #2
  uint8_t enable;                       // #3 || & 0x80 FAULTSTATUS!!!
  int8_t lowTemperature;                // #4
  int8_t highTemperature;               // #5
  // uint8_t highestId                  // #6    || ID dieses Moduls
  // uint8_t lowestId                   // #7    || ID dieses Moduls
};

struct PACK
{
  uint8_t stateOfCharge;                // CAN-ID 0x0640 #0
  uint16_t resistance;                  // CAN-ID 0x0640 #1#2 Scaler 0.001
  uint8_t healty;                       // CAN-ID 0x0640 #3
  uint16_t highestCellVoltage;          // CAN-ID 0x0640 #4#5 Scaler 0.0001
  uint16_t lowestCellVoltage;           // CAN-ID 0x0640 #6#7 Scaler 0.0001
  uint16_t maxDCLoad;                   // CAN-ID 0x0643 #0#1
  uint16_t maxCCLoad;                   // CAN-ID 0x0643 #2#3
  uint16_t absolutAmpere;               // CAN-ID 0x0643 #4#5 Scaler 0.1
  uint16_t absolutVoltage;              // CAN-ID 0x0643 #6#7 Scaler 0.1
  // flag => CAN-ID 0x200 -> Byte #0-> 4 Bit benutzt!!!
  uint8_t flag;                         //mil, balancing, charging, powerReady || 4x NAN
  // dtcFlag => CAN-ID 0x200 -> Byte #1-> 6 Bit benutzt!!!
  uint8_t dtcFlag;                      //CellOverHIGHVoltage, cellUnderLowVoltage, currentFailure, ThermistorFault, wiringOpen, ChargeSafeRelaisFailure
};
/*
  const char *flagObj[8] = {"p61.aph=", "p60.aph=", "t61.pco=", "t60.pco=", "NA", "NA", "NA", "NA"}; // NextionString je Wert
  const uint16_t flagVal[8][2] = {{0, 0}, {0, 0}, {33808, 33808}, {33808, 2016}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}; // Value je BIT
*/
//
struct BATT
{
  CELLDATA cell[cellNums];              // cellnum => #0 from CAN-ID: 0x36
  CELLDATA oldcell[cellNums];           // Merker
  COOLER cooler;                        // #0#1  || ID over all from CAN-ID: 0x1838F380
  COOLER oldcool;                       // Merker
  PACK pack;
  PACK oldpack;
} batt;
//
struct DRIVE
{
  uint16_t rotations;                   // CAN-ID: 0x500 #0#1
  uint16_t direction;                   // CAN-ID: 0x500 #2
  uint8_t mode;                         // CAN-ID: 0x501 #0
  uint8_t state;                        // CAN-ID: 0x501 #1
  int8_t heatsinkTemp;                  // CAN-ID: 0x501 #2
  int8_t engineTemp;                    // CAN-ID: 0x501 #3
  uint16_t voltage;                     // CAN-ID: 0x502 #0#1
  uint16_t ampere;                      // CAN-ID: 0x502 #2#3
};
DRIVE drive;
DRIVE oldDrive;

struct BMS
{
  uint16_t highTemperature;    // CAN-ID 0x0641 #0#1
  uint16_t lowTemperature;     // CAN-ID 0x0641 #2#3
  uint16_t internTemperature;  // CAN-ID 0x0641 #4#5
  uint16_t inputSupplyVoltage; // CAN-ID 0x0641 #6#7 Scaler 0.1
  uint16_t adcIsolation;       // CAN-ID 0x0642 #0#1
  uint16_t shortestWave;       // CAN-ID 0x0642 #2#3 Scaler 0.1
  uint16_t avgTemperature;     // CAN-ID 0x0642 #4#5
};

BMS bms;
BMS oldBms;

char nextionBuf[50] = {'\0'};
//
void setup()
{
  Serial.begin(115200);     // Serieller Monitor
  Serial2.begin(115200);    // Nextion
  can1.begin();
  can1.setBaudRate(500000);
  defaultModeMessage();     // füllt txmsg
  can1.write(txmsg);
}
//
void loop(void)
{
  canReadIn();
  nextReadIn();
  sendCellVoltage();
  sendCoolerData();
  //sendPackData();
  /*
    sendDriveData();
    sendBmsData();
    Serial.flush();
  */
}
//
void sendCoolerData()
{
  static byte idx = 0;                                              // Merker
  const char *title = "d";
  sendData(title, idx, batt.cooler.temperature[idx], batt.oldcool.temperature[idx]);
  if (++idx >= thermoNums)                                          // nächster index und Prüfung auf Überlauf
  {
    idx = 0;
    sendData("x135", idx, batt.cooler.lowTemperature, batt.oldcool.lowTemperature);
    sendData("x136", idx, batt.cooler.highTemperature, batt.oldcool.highTemperature);
  }
}
//
void sendCellVoltage()
{
  static byte idx = 0;                                              // Merker welche Batteriezelle
  const char *title = "c";
  constexpr byte scaler {10};
  sendData(title, idx, batt.cell[idx].voltage, batt.oldcell[idx].voltage, scaler);
  // resistance & openvoltage ungenutzt!
  if (++idx >= cellNums)
  { idx = 0; }
}
//
void sendPackData()
{
  sendData("n1", batt.pack.stateOfCharge, batt.oldpack.stateOfCharge);
  /*
    sendData("Resistance", batt.pack.resistance, batt.oldpack.resistance, 10);
    sendData("Healt", batt.pack.healty, batt.oldpack.healty);
    sendData("MaxCellVolt", batt.pack.highestCellVoltage, batt.oldpack.highestCellVoltage, 10);
    sendData("MinCellVolt", batt.pack.lowestCellVoltage, batt.oldpack.lowestCellVoltage, 10);
    sendData("MaxDCLoad", batt.pack.maxDCLoad, batt.oldpack.maxDCLoad);
    sendData("MaxCCLoad", batt.pack.maxCCLoad, batt.oldpack.maxCCLoad);
    sendData("PackAmpere", batt.pack.absolutAmpere, batt.oldpack.absolutAmpere, 100);
    sendData("PackVolage", batt.pack.absolutVoltage, batt.oldpack.absolutVoltage, 100);
  */
}
//
void sendDriveData()
{
  sendData("UPM", drive.rotations, oldDrive.rotations);
  sendData("dir", drive.direction, oldDrive.direction);
  sendData("mode", drive.mode, oldDrive.mode);
  sendData("State", drive.state, oldDrive.state);
  sendData("Kuehler", drive.heatsinkTemp, oldDrive.heatsinkTemp);
  sendData("Engine", drive.engineTemp, oldDrive.engineTemp);
  sendData("Drivevolt", drive.voltage, oldDrive.voltage);
  sendData("Driveamp", oldDrive.ampere, oldDrive.ampere);
}
//
void sendBmsData()
{
  sendData("BMS01", bms.highTemperature, oldBms.highTemperature);
  sendData("BMS02", bms.lowTemperature, oldBms.lowTemperature);
  sendData("BMS03", bms.internTemperature, oldBms.internTemperature);
  sendData("BMS04", bms.inputSupplyVoltage, oldBms.inputSupplyVoltage, 100);
  sendData("BMS05", bms.adcIsolation, oldBms.adcIsolation);
  sendData("BMS06", bms.shortestWave, oldBms.shortestWave, 100);
  sendData("BMS07", bms.avgTemperature, oldBms.avgTemperature);
}
//

void canReadIn()
{
  // /*INDENT-OFF*
  if (can1.read(rxmsg))
  {
    switch (rxmsg.id)
    {
      case 0x36:
        if (rxmsg.buf[0] < cellNums)     // cellID passt noch als Element
        {
          batt.cell[rxmsg.buf[0]].voltage     = rxmsg.buf[1]<<8|rxmsg.buf[2];
          batt.cell[rxmsg.buf[0]].resistance  = rxmsg.buf[3]<<8|rxmsg.buf[4];
          batt.cell[rxmsg.buf[0]].openVoltage = rxmsg.buf[5]<<8|rxmsg.buf[6];
          /*
          uint8_t crc = rxmsg.id;
          for (byte b=0; b<7; b++)
          crc+=rxmsg.buf[b];
          crc+=8;
          Serial.print(F("cell CRC "));
          if(rxmsg.buf[7]!=crc)
          Serial.print(F("nicht "));
          Serial.println("OK");
          */
        }
        break;
      case 0x200:
        batt.pack.flag         = rxmsg.buf[0];
        batt.pack.dtcFlag      = rxmsg.buf[1];
        break;
      case 0x500:
        drive.rotations        = rxmsg.buf[0]<<8|rxmsg.buf[1];
        drive.direction        = rxmsg.buf[2]<<8|rxmsg.buf[3];
        break;
      case 0x501:
        drive.mode             = rxmsg.buf[0];
        drive.state            = rxmsg.buf[1];
        drive.heatsinkTemp     = rxmsg.buf[2];
        drive.engineTemp       = rxmsg.buf[3];
        break;
      case 0x502:
        drive.voltage          = rxmsg.buf[0]<<8|rxmsg.buf[1];
        drive.ampere           = rxmsg.buf[2]<<8|rxmsg.buf[3];
        break;
      /*
        case 0x581:
        bms.power = word(rxmsg.buf[5], rxmsg.buf[6]);
        break;
      */
      case 0x640:
        batt.pack.stateOfCharge      = rxmsg.buf[0];
        batt.pack.resistance         = rxmsg.buf[1]<<8|rxmsg.buf[2];
        batt.pack.healty             = rxmsg.buf[3];
        batt.pack.highestCellVoltage = rxmsg.buf[4]<<8|rxmsg.buf[5];
        batt.pack.lowestCellVoltage  = rxmsg.buf[6]<<8|rxmsg.buf[7];
        break;
      case 0x641:
        bms.highTemperature          = rxmsg.buf[0]<<8|rxmsg.buf[1];
        bms.lowTemperature           = rxmsg.buf[2]<<8|rxmsg.buf[3];
        bms.internTemperature        = rxmsg.buf[4]<<8|rxmsg.buf[5];
        bms.inputSupplyVoltage       = rxmsg.buf[6]<<8|rxmsg.buf[7];
        break;
      case 0x642:
        bms.adcIsolation             = rxmsg.buf[0]<<8|rxmsg.buf[1];
        bms.shortestWave             = rxmsg.buf[2]<<8|rxmsg.buf[3];
        bms.avgTemperature           = rxmsg.buf[4]<<8|rxmsg.buf[5];
        break;
      case 0x643:
        batt.pack.maxDCLoad          = rxmsg.buf[0]<<8|rxmsg.buf[1];
        batt.pack.maxCCLoad          = rxmsg.buf[2]<<8|rxmsg.buf[3];
        batt.pack.absolutAmpere      = rxmsg.buf[4]<<8|rxmsg.buf[5];
        batt.pack.absolutVoltage     = rxmsg.buf[6]<<8|rxmsg.buf[7];
        break;
      case 0x1838F380:
        uint16_t myId          = rxmsg.buf[0]<<8|rxmsg.buf[1];
        if (myId < thermoNums) // ID passt noch als Element
        {
          batt.cooler.temperature[myId]     = rxmsg.buf[2];
          batt.cooler.lowTemperature  = rxmsg.buf[4];
          batt.cooler.highTemperature = rxmsg.buf[5];
        }
        break;
    }
  }
// *INDENT-ON*
}
//
void checkNextionError(const byte myByte)
{
  const char check[] = {0x1A, 0xFF, 0xFF, 0xFF};  // Vergleichspuffer
  constexpr byte len {sizeof(check) / sizeof(check[0])};
  static char buf[len] = {'\0'};                  // Puffer
  buf[len - 1] = myByte;                          // Zeichen aufnehmen
  // Prüfung ob vom Nextion eine Ablehnung kam
  if (strncmp(buf, check, len))                   // Vergleich != 0?
  { Serial.println(F("NextionError!")); }
  for (byte b = 0; b < len - 1; b++)              // Zeichen im buffer verschieben
  { buf[b] = buf[b + 1];}
}
//
void nextReadIn()
{
  uint8_t x = Serial2.available();     // Es kommt was vom Nextion
  while (x--)
  {
    byte myByte = Serial2.read();      // Übernehme 1 zeichen
    hexPrint(myByte);                  // Kontrolle auf dem SerMon was ankommt
    defaultModeMessage();              // Füllt txmsg mit defaultwerten
    switch (myByte)                    //
    {
      case '1':                        // entspricht default
        can1.write(txmsg);
        break;
      case '2':
        txmsg.buf[5] = 0x4A;
        can1.write(txmsg);
        break;
      case '3':
        txmsg.buf[5] = 0x7D;
        can1.write(txmsg);
        break;
      default:
        // checkNextionError(myByte);
        break;
    }
  }
}
//
void sendData(const char *title, const uint16_t value, uint16_t &oldValue)
{
  if (value != oldValue)
  {
    sprintf(nextionBuf, "%s%s", title, ".val=");
    sendData2Nextion(nextionBuf, value);
    oldValue = value;
  }
}
//
void sendData(const char *title, const uint8_t value, uint8_t &oldValue)
{
  if (value != oldValue)
  {
    sprintf(nextionBuf, "%s%s", title, ".val=");
    sendData2Nextion(nextionBuf, value);
    oldValue = value;
  }
}
//
void sendData(const char *title, const uint16_t idx, const uint16_t value, uint16_t &oldValue, const uint8_t &scaler) // Nextion -> unsigned int16
{
  if (value != oldValue)
  {
    sprintf(nextionBuf, "%s%i%s", title, idx, ".val=");
    sendData2Nextion(nextionBuf, value / scaler);
    oldValue = value;
  }
}
//
void sendData(const char *title, const uint16_t idx, const uint16_t value, uint16_t &oldValue) // Nextion -> unsigned int16
{
  if (value != oldValue)
  {
    sprintf(nextionBuf, "%s%i%s", title, idx, ".val=");
    sendData2Nextion(nextionBuf, value);
    oldValue = value;
  }
}
//
void sendData(const char *title, const int8_t value, int8_t &oldValue)      // Nextion -> signed int8
{
  if (value != oldValue)
  {
    sprintf(nextionBuf, "%s%s", title, ".val=");
    sendData2Nextion(nextionBuf, value);
    oldValue = value;
  }
}
//
void sendData(const char *title, const uint16_t idx, const int8_t value, int8_t &oldValue)      // Nextion -> signed int8
{
  if (value != oldValue)
  {
    sprintf(nextionBuf, "%s%i%s", title, idx, ".val=");
    sendData2Nextion(nextionBuf, value);
    oldValue = value;
  }
}
//
void sendData(const char *title, const uint16_t idx, const int16_t value, int16_t &oldValue)    // Nextion -> signed int16
{
  if (value != oldValue)
  {
    sprintf(nextionBuf, "%s%i%s", title, idx, ".val=");
    sendData2Nextion(nextionBuf, value);
    oldValue = value;
  }
}
//
void sendData(const char *title, const uint16_t value, uint16_t &oldValue, const float scaler) // Nextion -> float
{
  if (value != oldValue)
  {
    sprintf(nextionBuf, "%s%s", title, ".val=");
    sendData2Nextion(nextionBuf, value * scaler);
    oldValue = value;
  }
}
// Nextion Ende ist 3* 0xFF
void nextionSendEnd()
{
  for (byte b = 0; b < 3; b++)
  { Serial2.write(0xFF); }
  Serial.println();
}
//
void sendData2Nextion(const char *sendBuf, const uint16_t value)
{
  Serial2.print(sendBuf);
  Serial2.print(value);
  Serial.print(sendBuf);
  Serial.print(value, 5);
  nextionSendEnd();
}
//
void sendData2Nextion(const char *sendBuf)
{
  Serial2.print(sendBuf);
  Serial.print(sendBuf);
  nextionSendEnd();
}
//
void defaultModeMessage()              // Vorbelegung
{
  txmsg.id = 0x601;
  txmsg.len = 8;
  txmsg.buf[0] = 0x23;
  txmsg.buf[1] = 0x00;
  txmsg.buf[2] = 0x20;
  txmsg.buf[3] = 0x31;
  txmsg.buf[4] = 0x00;
  txmsg.buf[5] = 0x26;
  txmsg.buf[6] = 0x00;
  txmsg.buf[7] = 0x00;
}

//
void hexPrint(const byte myByte)       // gibt das übergebene Byte im Format "0xBB, " aus
{
  static byte idx = 0;                 // Merker für Zeilenumbruch
  Serial.print(" 0x");                 // Einleitung der Darstellung
  if (myByte < 0x10)                   // Byte <= 9?
  { Serial.print(0); }                 // auffüllen
  Serial.print(myByte, HEX);           // Wert ausgeben
  Serial.print(", ");                  // für Formatierung
  if (++idx > 10)                      // Werte je Zeile erfüllt
  { Serial.println(); }                // Zeilenumbruch
}

Deine Entscheidung, was Du angezeigt bekommen möchtest.
Das eine Mal dividieren macht den Kohl jetzt auch nicht fett. )

Temperaturen kommen noch nicht am nextion an
Also SOC kann man ja mehrfach vergeben also n1 und n6 gleichzeitig, das geht

page 0 ist ja der hauptschirm wärend man fährt, die wichtigsten daten, und page 5 wäre aktive wärend dem ladevorgang, wo alle daten angezeigt werden

achne ich glaub das geht garnicht
na dann ist es wohl besser den ladezustand wärend man fährt zu sehen, also auf page 0
dann würd ich sagen auch die spannung weg aus paqe 0, dafür aber auf page 5.

man muß sich halt gedanken machen, welche daten sind wichtig wärend der fahrt, und ich denke SOC ist eines der wichtigsten, gefolgt von Temperaturen

Ja, dann muss der aber auch 2x übertragen werden.
Also 2 komplette Datensätze mit Endekennung...
Wenn Du n1 mit auf Page 5 nimmst, spart das eine Übertragung und Du hast auf beiden Bildschirmen immer den selben Wert und keine Inkonsistenzen.

Die Temperaturwerte vom Kühler müssen aberr kommen. Was wird da für ein Format erwartet?
x135 und x136 sind auch fest vergeben.

nee völlig unwichtig soviele stellen hinterm komma, bis 3 stellig für die zellüberwachung ist ausreichend

ohje, weis ich leider nicht
vielleicht steht was im #122

NImm doch mal den HMI-Editor und gib für den x135 eine Zahl ein.
1, 12, 123, 1234, 12345
Was wird ausgegeben -> wann gibt es keine Errormeldung mehr?

es gibt nie eine errormeldung, bei 1 =0.1, bei 12=1.2, bei 123=12.3, bei 1234=123.4
solange zahlen ohne komma kommen, kann man im nextion das komme an individueller stelle setzten
selbst bei 100000000 kommt kein fehler

Hm.
Da ich nur Ganzzahlen habe, muss das funktionieren.
Ich habe mal für x135 und x136 einen Zwang gesetzt, dass die immer gesendet werden müssen.
Es muss also auf dem SerMon x135.val= erscheinen...
Und so wie es da steht, wird es auch an den Nextion gegegebn.

/*
  BMS_AKKU_letzter Stand
  Wird noch weiterentwickelt!
*/

#include <FlexCAN_T4.h>
FlexCAN_T4 <CAN1, RX_SIZE_256, TX_SIZE_16> can1;

static CAN_message_t rxmsg, txmsg;

constexpr byte cellNums {96};
struct CELLDATA                         // CAN-ID: 0x36
{
  uint16_t voltage;                     // #1#2 Scaler 0.0001
  uint16_t resistance;                  // #3#4 Scaler 0.01
  uint16_t openVoltage;                 // #5#6 Scaler 0.0001
  // uint8_t checkSum                   // #7 || Berechnung: CAN-ID + jedes Byte exclusive CRC-Byte + Länge inclusive CRC-Byte
};
//
constexpr byte thermoNums {12};
struct COOLER                           // CAN-ID: 0x1838F380
{
  int8_t temperature[thermoNums];       // #2
  uint8_t enable;                       // #3 || & 0x80 FAULTSTATUS!!!
  int8_t lowTemperature;                // #4
  int8_t highTemperature;               // #5
  // uint8_t highestId                  // #6    || ID dieses Moduls
  // uint8_t lowestId                   // #7    || ID dieses Moduls
};

struct PACK
{
  uint8_t stateOfCharge;                // CAN-ID 0x0640 #0
  uint16_t resistance;                  // CAN-ID 0x0640 #1#2 Scaler 0.001
  uint8_t healty;                       // CAN-ID 0x0640 #3
  uint16_t highestCellVoltage;          // CAN-ID 0x0640 #4#5 Scaler 0.0001
  uint16_t lowestCellVoltage;           // CAN-ID 0x0640 #6#7 Scaler 0.0001
  uint16_t maxDCLoad;                   // CAN-ID 0x0643 #0#1
  uint16_t maxCCLoad;                   // CAN-ID 0x0643 #2#3
  uint16_t absolutAmpere;               // CAN-ID 0x0643 #4#5 Scaler 0.1
  uint16_t absolutVoltage;              // CAN-ID 0x0643 #6#7 Scaler 0.1
  // flag => CAN-ID 0x200 -> Byte #0-> 4 Bit benutzt!!!
  uint8_t flag;                         //mil, balancing, charging, powerReady || 4x NAN
  // dtcFlag => CAN-ID 0x200 -> Byte #1-> 6 Bit benutzt!!!
  uint8_t dtcFlag;                      //CellOverHIGHVoltage, cellUnderLowVoltage, currentFailure, ThermistorFault, wiringOpen, ChargeSafeRelaisFailure
};
/*
  const char *flagObj[8] = {"p61.aph=", "p60.aph=", "t61.pco=", "t60.pco=", "NA", "NA", "NA", "NA"}; // NextionString je Wert
  const uint16_t flagVal[8][2] = {{0, 0}, {0, 0}, {33808, 33808}, {33808, 2016}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}; // Value je BIT
*/
//
struct BATT
{
  CELLDATA cell[cellNums];              // cellnum => #0 from CAN-ID: 0x36
  CELLDATA oldcell[cellNums];           // Merker
  COOLER cooler;                        // #0#1  || ID over all from CAN-ID: 0x1838F380
  COOLER oldcool;                       // Merker
  PACK pack;
  PACK oldpack;
} batt;
//
struct DRIVE
{
  uint16_t rotations;                   // CAN-ID: 0x500 #0#1
  uint16_t direction;                   // CAN-ID: 0x500 #2
  uint8_t mode;                         // CAN-ID: 0x501 #0
  uint8_t state;                        // CAN-ID: 0x501 #1
  int8_t heatsinkTemp;                  // CAN-ID: 0x501 #2
  int8_t engineTemp;                    // CAN-ID: 0x501 #3
  uint16_t voltage;                     // CAN-ID: 0x502 #0#1
  uint16_t ampere;                      // CAN-ID: 0x502 #2#3
};
DRIVE drive;
DRIVE oldDrive;

struct BMS
{
  uint16_t highTemperature;    // CAN-ID 0x0641 #0#1
  uint16_t lowTemperature;     // CAN-ID 0x0641 #2#3
  uint16_t internTemperature;  // CAN-ID 0x0641 #4#5
  uint16_t inputSupplyVoltage; // CAN-ID 0x0641 #6#7 Scaler 0.1
  uint16_t adcIsolation;       // CAN-ID 0x0642 #0#1
  uint16_t shortestWave;       // CAN-ID 0x0642 #2#3 Scaler 0.1
  uint16_t avgTemperature;     // CAN-ID 0x0642 #4#5
};

BMS bms;
BMS oldBms;

char nextionBuf[50] = {'\0'};
//
void setup()
{
  Serial.begin(115200);     // Serieller Monitor
  Serial2.begin(115200);    // Nextion
  can1.begin();
  can1.setBaudRate(500000);
  defaultModeMessage();     // füllt txmsg
  can1.write(txmsg);
}
//
void loop(void)
{
  canReadIn();
  nextReadIn();
  sendCellVoltage();
  sendCoolerData();
  //sendPackData();
  /*
    sendDriveData();
    sendBmsData();
    Serial.flush();
  */
}
//
void sendCoolerData()
{
  static byte idx = 0;                     // Merker
  const char *title = "d";
  sendData(title, idx, batt.cooler.temperature[idx], batt.oldcool.temperature[idx]);
  if (++idx >= thermoNums)                 // nächster index und Prüfung auf Überlauf
  {
    idx = 0;
    sendData("x135", idx, batt.cooler.lowTemperature, batt.oldcool.lowTemperature);
    sendData("x136", idx, batt.cooler.highTemperature, batt.oldcool.highTemperature);
    batt.oldcool.lowTemperature = 100;
    batt.oldcool.highTemperature = 100;
  }
}
//
void sendCellVoltage()
{
  static byte idx = 0;                                              // Merker welche Batteriezelle
  const char *title = "c";
  constexpr byte scaler {10};
  sendData(title, idx, batt.cell[idx].voltage, batt.oldcell[idx].voltage, scaler);
  // resistance & openvoltage ungenutzt!
  if (++idx >= cellNums)
  { idx = 0; }
}
//
void sendPackData()
{
  static byte state = 0;
  switch (state)
  {
    case 0:
      sendData("n1", batt.pack.stateOfCharge, batt.oldpack.stateOfCharge);
      batt.oldpack.stateOfCharge = batt.pack.stateOfCharge + 1;  // Hack für 2 Sendungen
      sendData("n6", batt.pack.stateOfCharge, batt.oldpack.stateOfCharge);
      break;
    /*
      sendData("Resistance", batt.pack.resistance, batt.oldpack.resistance, 10);
      sendData("Healt", batt.pack.healty, batt.oldpack.healty);
      sendData("MaxCellVolt", batt.pack.highestCellVoltage, batt.oldpack.highestCellVoltage, 10);
      sendData("MinCellVolt", batt.pack.lowestCellVoltage, batt.oldpack.lowestCellVoltage, 10);
      sendData("MaxDCLoad", batt.pack.maxDCLoad, batt.oldpack.maxDCLoad);
      sendData("MaxCCLoad", batt.pack.maxCCLoad, batt.oldpack.maxCCLoad);
      sendData("PackAmpere", batt.pack.absolutAmpere, batt.oldpack.absolutAmpere, 100);
      sendData("PackVolage", batt.pack.absolutVoltage, batt.oldpack.absolutVoltage, 100);
    */
    default:
      state = 0;
      break;
  }
  state++;
}
//
void sendDriveData()
{
  sendData("UPM", drive.rotations, oldDrive.rotations);
  sendData("dir", drive.direction, oldDrive.direction);
  sendData("mode", drive.mode, oldDrive.mode);
  sendData("State", drive.state, oldDrive.state);
  sendData("Kuehler", drive.heatsinkTemp, oldDrive.heatsinkTemp);
  sendData("Engine", drive.engineTemp, oldDrive.engineTemp);
  sendData("Drivevolt", drive.voltage, oldDrive.voltage);
  sendData("Driveamp", oldDrive.ampere, oldDrive.ampere);
}
//
void sendBmsData()
{
  sendData("BMS01", bms.highTemperature, oldBms.highTemperature);
  sendData("BMS02", bms.lowTemperature, oldBms.lowTemperature);
  sendData("BMS03", bms.internTemperature, oldBms.internTemperature);
  sendData("BMS04", bms.inputSupplyVoltage, oldBms.inputSupplyVoltage, 100);
  sendData("BMS05", bms.adcIsolation, oldBms.adcIsolation);
  sendData("BMS06", bms.shortestWave, oldBms.shortestWave, 100);
  sendData("BMS07", bms.avgTemperature, oldBms.avgTemperature);
}
//
void canReadIn()
{
  // /*INDENT-OFF*
  if (can1.read(rxmsg))
  {
    switch (rxmsg.id)
    {
      case 0x36:
        if (rxmsg.buf[0] < cellNums)     // cellID passt noch als Element
        {
          batt.cell[rxmsg.buf[0]].voltage     = rxmsg.buf[1]<<8|rxmsg.buf[2];
          batt.cell[rxmsg.buf[0]].resistance  = rxmsg.buf[3]<<8|rxmsg.buf[4];
          batt.cell[rxmsg.buf[0]].openVoltage = rxmsg.buf[5]<<8|rxmsg.buf[6];
          /*
          uint8_t crc = rxmsg.id;
          for (byte b=0; b<7; b++)
          crc+=rxmsg.buf[b];
          crc+=8;
          Serial.print(F("cell CRC "));
          if(rxmsg.buf[7]!=crc)
          Serial.print(F("nicht "));
          Serial.println("OK");
          */
        }
        break;
      case 0x200:
        batt.pack.flag         = rxmsg.buf[0];
        batt.pack.dtcFlag      = rxmsg.buf[1];
        break;
      case 0x500:
        drive.rotations        = rxmsg.buf[0]<<8|rxmsg.buf[1];
        drive.direction        = rxmsg.buf[2]<<8|rxmsg.buf[3];
        break;
      case 0x501:
        drive.mode             = rxmsg.buf[0];
        drive.state            = rxmsg.buf[1];
        drive.heatsinkTemp     = rxmsg.buf[2];
        drive.engineTemp       = rxmsg.buf[3];
        break;
      case 0x502:
        drive.voltage          = rxmsg.buf[0]<<8|rxmsg.buf[1];
        drive.ampere           = rxmsg.buf[2]<<8|rxmsg.buf[3];
        break;
      /*
        case 0x581:
        bms.power = word(rxmsg.buf[5], rxmsg.buf[6]);
        break;
      */
      case 0x640:
        batt.pack.stateOfCharge      = rxmsg.buf[0];
        batt.pack.resistance         = rxmsg.buf[1]<<8|rxmsg.buf[2];
        batt.pack.healty             = rxmsg.buf[3];
        batt.pack.highestCellVoltage = rxmsg.buf[4]<<8|rxmsg.buf[5];
        batt.pack.lowestCellVoltage  = rxmsg.buf[6]<<8|rxmsg.buf[7];
        break;
      case 0x641:
        bms.highTemperature          = rxmsg.buf[0]<<8|rxmsg.buf[1];
        bms.lowTemperature           = rxmsg.buf[2]<<8|rxmsg.buf[3];
        bms.internTemperature        = rxmsg.buf[4]<<8|rxmsg.buf[5];
        bms.inputSupplyVoltage       = rxmsg.buf[6]<<8|rxmsg.buf[7];
        break;
      case 0x642:
        bms.adcIsolation             = rxmsg.buf[0]<<8|rxmsg.buf[1];
        bms.shortestWave             = rxmsg.buf[2]<<8|rxmsg.buf[3];
        bms.avgTemperature           = rxmsg.buf[4]<<8|rxmsg.buf[5];
        break;
      case 0x643:
        batt.pack.maxDCLoad          = rxmsg.buf[0]<<8|rxmsg.buf[1];
        batt.pack.maxCCLoad          = rxmsg.buf[2]<<8|rxmsg.buf[3];
        batt.pack.absolutAmpere      = rxmsg.buf[4]<<8|rxmsg.buf[5];
        batt.pack.absolutVoltage     = rxmsg.buf[6]<<8|rxmsg.buf[7];
        break;
      case 0x1838F380:
        uint16_t myId          = rxmsg.buf[0]<<8|rxmsg.buf[1];
        if (myId < thermoNums) // ID passt noch als Element
        {
          batt.cooler.temperature[myId]     = rxmsg.buf[2];
          batt.cooler.lowTemperature  = rxmsg.buf[4];
          batt.cooler.highTemperature = rxmsg.buf[5];
        }
        break;
    }
  }
// *INDENT-ON*
}
//
void checkNextionError(const byte myByte)
{
  const char check[] = {0x1A, 0xFF, 0xFF, 0xFF};  // Vergleichspuffer
  constexpr byte len {sizeof(check) / sizeof(check[0])};
  static char buf[len] = {'\0'};                  // Puffer
  buf[len - 1] = myByte;                          // Zeichen aufnehmen
  // Prüfung ob vom Nextion eine Ablehnung kam
  if (strncmp(buf, check, len))                   // Vergleich != 0?
  { Serial.println(F("NextionError!")); }
  for (byte b = 0; b < len - 1; b++)              // Zeichen im buffer verschieben
  { buf[b] = buf[b + 1];}
}
//
void nextReadIn()
{
  uint8_t x = Serial2.available();     // Es kommt was vom Nextion
  while (x--)
  {
    byte myByte = Serial2.read();      // Übernehme 1 zeichen
    hexPrint(myByte);                  // Kontrolle auf dem SerMon was ankommt
    defaultModeMessage();              // Füllt txmsg mit defaultwerten
    switch (myByte)                    //
    {
      case '1':                        // entspricht default
        can1.write(txmsg);
        break;
      case '2':
        txmsg.buf[5] = 0x4A;
        can1.write(txmsg);
        break;
      case '3':
        txmsg.buf[5] = 0x7D;
        can1.write(txmsg);
        break;
      default:
        // checkNextionError(myByte);
        break;
    }
  }
}
//
void sendData(const char *title, const uint16_t value, uint16_t &oldValue)
{
  if (value != oldValue)
  {
    sprintf(nextionBuf, "%s%s", title, ".val=");
    sendData2Nextion(nextionBuf, value);
    oldValue = value;
  }
}
//
void sendData(const char *title, const uint8_t value, uint8_t &oldValue)
{
  if (value != oldValue)
  {
    sprintf(nextionBuf, "%s%s", title, ".val=");
    sendData2Nextion(nextionBuf, value);
    oldValue = value;
  }
}
//
void sendData(const char *title, const uint16_t idx, const uint16_t value, uint16_t &oldValue, const uint8_t &scaler) // Nextion -> unsigned int16
{
  if (value != oldValue)
  {
    sprintf(nextionBuf, "%s%i%s", title, idx, ".val=");
    sendData2Nextion(nextionBuf, value / scaler);
    oldValue = value;
  }
}
//
void sendData(const char *title, const uint16_t idx, const uint16_t value, uint16_t &oldValue) // Nextion -> unsigned int16
{
  if (value != oldValue)
  {
    sprintf(nextionBuf, "%s%i%s", title, idx, ".val=");
    sendData2Nextion(nextionBuf, value);
    oldValue = value;
  }
}
//
void sendData(const char *title, const int8_t value, int8_t &oldValue)      // Nextion -> signed int8
{
  if (value != oldValue)
  {
    sprintf(nextionBuf, "%s%s", title, ".val=");
    sendData2Nextion(nextionBuf, value);
    oldValue = value;
  }
}
//
void sendData(const char *title, const uint16_t idx, const int8_t value, int8_t &oldValue)      // Nextion -> signed int8
{
  if (value != oldValue)
  {
    sprintf(nextionBuf, "%s%i%s", title, idx, ".val=");
    sendData2Nextion(nextionBuf, value);
    oldValue = value;
  }
}
//
void sendData(const char *title, const uint16_t idx, const int16_t value, int16_t &oldValue)    // Nextion -> signed int16
{
  if (value != oldValue)
  {
    sprintf(nextionBuf, "%s%i%s", title, idx, ".val=");
    sendData2Nextion(nextionBuf, value);
    oldValue = value;
  }
}
//
void sendData(const char *title, const uint16_t value, uint16_t &oldValue, const float scaler) // Nextion -> float
{
  if (value != oldValue)
  {
    sprintf(nextionBuf, "%s%s", title, ".val=");
    sendData2Nextion(nextionBuf, value * scaler);
    oldValue = value;
  }
}
// Nextion Ende ist 3* 0xFF
void nextionSendEnd()
{
  for (byte b = 0; b < 3; b++)
  { Serial2.write(0xFF); }
  Serial.println();
}
//
void sendData2Nextion(const char *sendBuf, const uint16_t value)
{
  Serial2.print(sendBuf);
  Serial2.print(value);
  Serial.print(sendBuf);
  Serial.print(value, 5);
  nextionSendEnd();
}
//
void sendData2Nextion(const char *sendBuf)
{
  Serial2.print(sendBuf);
  Serial.print(sendBuf);
  nextionSendEnd();
}
//
void defaultModeMessage()              // Vorbelegung
{
  txmsg.id = 0x601;
  txmsg.len = 8;
  txmsg.buf[0] = 0x23;
  txmsg.buf[1] = 0x00;
  txmsg.buf[2] = 0x20;
  txmsg.buf[3] = 0x31;
  txmsg.buf[4] = 0x00;
  txmsg.buf[5] = 0x26;
  txmsg.buf[6] = 0x00;
  txmsg.buf[7] = 0x00;
}
//
void hexPrint(const byte myByte)       // gibt das übergebene Byte im Format "0xBB, " aus
{
  static byte idx = 0;                 // Merker für Zeilenumbruch
  Serial.print(" 0x");                 // Einleitung der Darstellung
  if (myByte < 0x10)                   // Byte <= 9?
  { Serial.print(0); }                 // auffüllen
  Serial.print(myByte, HEX);           // Wert ausgeben
  Serial.print(", ");                  // für Formatierung
  if (++idx > 10)                      // Werte je Zeile erfüllt
  { Serial.println(); }                // Zeilenumbruch
}

Und es darf kein Fehler vom Nextion gemeldet werden....

also auf dem nextion kommen 2 werte, 2.2 und nochmal 2.2, sollte 22 sein normal
auf dem Serialmonitor

20:02:20.206 ->  0xFF,  0x1A,  0xFF, x1350.val=42
20:02:20.206 -> x1360.val=42
20:02:20.206 ->  0xFF,  0xFF,  0x1A,  0xFF,  0xFF,  0xFF,  0x1A,  0xFF, x1350.val=42
20:02:20.206 -> x1360.val=42
20:02:20.206 ->  0xFF, 
20:02:20.206 ->  0xFF, 
20:02:20.206 ->  0x1A, 
20:02:20.206 ->  0xFF, 
20:02:20.206 ->  0xFF, 
20:02:20.206 ->  0xFF, 
20:02:20.206 ->  0x1A, 
20:02:20.206 ->  0xFF, 
20:02:20.206 -> x1350.val=42
20:02:20.206 -> x1360.val=42
20:02:20.206 ->  0xFF, 
20:02:20.206 ->  0xFF, 
20:02:20.206 ->  0x1A, 
20:02:20.206 ->  0xFF, 
20:02:20.206 ->  0xFF, 
20:02:20.206 ->  0xFF, 
20:02:20.206 ->  0x1A, 
20:02:20.206 ->  0xFF, 
20:02:20.206 -> x1350.val=42
20:02:20.206 -> x1360.val=42
20:02:20.238 ->  0xFF, 
20:02:20.238 ->  0xFF, 
20:02:20.238 ->  0x1A, 
20:02:20.238 ->  0xFF, 
20:02:20.238 ->  0xFF, 
20:02:20.238 ->  0xFF, 
20:02:20.238 ->  0x1A, 
20:02:20.238 -> c0.val=104400
20:02:20.238 ->  0xFF, 
20:02:20.238 ->  0xFF, 
20:02:20.238 ->  0xFF, 
20:02:20.238 ->  0x1A, 
20:02:20.238 -> c10.val=104311
20:02:20.238 ->  0xFF, 
20:02:20.238 ->  0xFF, 
20:02:20.238 ->  0xFF, 
20:02:20.238 -> x1350.val=42
20:02:20.238 -> x1360.val=42

bei den spannungen seh ich noch bei c11, ist auch eine kommastelle verrutscht, antelle 3.7 haben wir 0.37

Huch, da ist eine 0 drin.
Moment....
Ok, die 0 ist noch aus dem idx geschuldet.
In `sendCoolerData()
die Zeilen ändern in:

    sendData("x135", batt.cooler.lowTemperature, batt.oldcool.lowTemperature);
    sendData("x136", batt.cooler.highTemperature, batt.oldcool.highTemperature);

Zum verschieben der Kommastelle kannst Du in sendCellVoltage den scaler von derzeit 10 auch auf 100 stellen. oder auf 1. :wink:

`

komisch, es ändert sich zwar die kommastelle, aber komplett, die c11 ist jetzt noch weiter nach hinten, c0-10 0.37, und c11 0.037
und wenn ich scaler auf 1 tu, haben wir bei den ersten 11 cellen 37v und bei der 12. 3.7

und hier sind wir auch eine stelle zu weit vor, also anstatt 22 haben wir 2.2