Communicatie tussen ESP32 en Nextion 7" Enh. te traag

Projecten die niet passen in bovenstaande onderwerpen
Berichten: 4
Geregistreerd: 22 Okt 2013, 22:25

Communicatie tussen ESP32 en Nextion 7" Enh. te traag

Berichtdoor YvesD » 19 Dec 2018, 14:09

Hallo allemaal,

In een projectje van me zit een esp32 (Lolin 32S) en een Nextion 7" (Enhanced).
Alles werkt naar behoren qua lay-out, uitsturen van een 3.3v signaal naar de ESP32, soit leuk projectje op zich.

Mijn project is eigenlijk een uiterst tijdskritische chronometer (gebruikt in hondensport Flyball)

Dus op welbepaalde momenten dient er ook data naar de Nextion te gaan (a rato van 9600bps), voor een volledige uitvoer en weergave op de Nextion heb ik (door een tijd vooraf en achteraf te nemen in microseconden) kunnen uitmaken dat de volledige cyclus van weergeven ongeveer 88.000 µsec nodig heeft ofte 0.088sec.

Op een drietal momenten is dit geen enkel probleem, want dan heeft het systeempje zo'n 1,5 sec "vrije tijd en dus niets te registreren", kritisch wordt het op een bepaald moment wanneer de uitvoer zou moeten plaatsnemen maar er ook interrupts getriggerd kunnen worden (op een niet voorspelbaar moment)…

Mijn vraag is tweedelig:
Als ik de baudrate verhoog, dan zou in theorie de communicatie sneller verlopen, maar soms krijg ik dan een ongewenste herstart van de ESP32, dus heb ik de waarde terug op 9600bps geplaatst om dit op te vangen.
Is het normaal dat er dingen fout gaan (reboot ESP32) bij een baudrate van 115200?

Ik had geprobeerd om een routine uit te werken waarbij ik via de sensors en positie van de honden een "idle" status doorgeef, zodat het systeem weet "ik kan nu gerust iets versturen", maar ik loop tegen mijn eigen beperkingen aan qua skills in het programeren… (ik dacht aan iets als Blink without delay)

Alle gegevens worden opgeslagen in een tweedimensionele array, en kunnen uitgelezen worden.
Zijn er ergens ideeën om mij gewoon dat duwtje in de rug te geven zodat ik terug wat voort kan prielen aan de code... (ik hoef absoluut geen afgewerkte code hoor, anders is de fun er voor mij ook af :) , eerder iets van probeer eens dit of dat...

ik zet hieronder even de functie die ervoor zorgt dat de data opgeslagen wordt in de array en de functie die de uitvoer verzorgt

Code: Alles selecteren
void CheckPassing() {
  if ( ( InterruptSensor1Counter > 0) && (esp_timer_get_time() > DebounceSensor1) && Transition == NO ) { /* ISR1 Handling for false start */
    Transition = B;
    DogNumber = 1;
    bFault = ON;
    InterruptSensor1Counter = 0;
    DogTimes[DogNumber].inTimeIn = InterruptSensor1Time;
    MSG = "FALSE START !";
    return;
  }
  if ( ( InterruptSensor1Counter > 0) && (esp_timer_get_time() > DebounceSensor1) && Transition == A ) { /* ISR1 Handling for normal crossing*/
    Transition = B;
    InterruptSensor1Counter = 0;
    DogTimes[DogNumber].inTimeIn = InterruptSensor1Time;
    MSG = "DOG DETECTED";
    return;
  }
  if ( (InterruptSensor2Counter > 0) && (esp_timer_get_time() > DebounceSensor2) && Transition == B ) { /* ISR2 Handling "DOG IN" */
    Transition = C;
    InterruptSensor2Counter = 0;
    triggerState = PASS;
    MSG = "DOG IN";
    return;
  }
  if ( (InterruptSensor3Counter > 0) && (esp_timer_get_time() > (DebounceSensor3) ) && Transition == C ) { /* ISR3 Handling "TO BOX" */
    Transition = D;
    InterruptSensor3Counter = 0;
    DogTimes[DogNumber].inTimeOut = InterruptSensor3Time;
    DogTimes[DogNumber].boxTimeIn = InterruptSensor3Time;
    triggerState = IN;
    MSG = "TO BOX";
    return;
  }
  if ( (InterruptSensor3Counter > 0) && (esp_timer_get_time() > (DebounceSensor3) ) && Transition == D ) { /* ISR3 Handling "FROM BOX" */
    Transition = E;
    InterruptSensor3Counter = 0;
    DogTimes[DogNumber].boxTimeOut = InterruptSensor3Time;
    DogTimes[DogNumber].outTimeIn = InterruptSensor3Time;
    triggerState = BOX;
    MSG = "FROM BOX";
    return;
  }
  if ( (InterruptSensor2Counter > 0) && (esp_timer_get_time() > DebounceSensor2) && Transition == E) { /* ISR2 Handling "DOG OUT" */
    Transition = F;
    InterruptSensor2Counter = 0;
    MSG = "DOG OUT";
    return;
  }
  if ( (InterruptSensor1Counter > 0) && (esp_timer_get_time() > (DebounceSensor1) )  && Transition == F) { /* ISR2 Handling :: CODE E*/
    long proccesTime1 = 0;
    long proccesTime2 = 0;
    Transition = A;
    InterruptSensor1Counter = 0;
    DogTimes[DogNumber].outTimeOut = InterruptSensor1Time;
    triggerState = OUT;
    proccesTime1 = esp_timer_get_time(); /* check how long this action to the Nextion will take */
    upDateNextion(triggerState, DogNumber);
    proccesTime2 = esp_timer_get_time(); /* end of the monitoring of the above function */
    DogNumber++;
    HeatsToRun--;
    MSG = "WAITING FOR NEXT DOG IN";
    Serial.println(proccesTime1);
    Serial.println(proccesTime2);
    return;
  }
} /* end of CheckPassing() */

void upDateNextion(uint8_t itriggerState, uint8_t iDogNumber ){
  if(itriggerState != _OFF){
    switch (itriggerState) /*triggerState options : _OFF=0,PASS=1,IN=2,BOX=3,OUT=4 */
    {
    case 1:
    {
        /* triggerState = PASS */
        DogTimes[iDogNumber].passTime = DogTimes[iDogNumber].inTimeIn - DogTimes[iDogNumber - 1].outTimeOut;
        String nexPassTime = String((float)DogTimes[iDogNumber].passTime / 1000000.0, 3);
        switch (iDogNumber)
        {
        case 1:{passTime1.setText(nexPassTime.c_str());break;}
        case 2:{passTime2.setText(nexPassTime.c_str());break;}
        case 3:{passTime3.setText(nexPassTime.c_str());break;}
        case 4:{passTime4.setText(nexPassTime.c_str());break;}
        case 5:{passTime5.setText(nexPassTime.c_str());break;}
        case 6:{passTime6.setText(nexPassTime.c_str());break;}
        }
        break;
    }
    case 2:
    {
        /* triggerState = IN */
        DogTimes[iDogNumber].inTime = DogTimes[iDogNumber].inTimeOut - DogTimes[iDogNumber].inTimeIn;
        if( DogTimes[iDogNumber].inTime < 0)
        {
            File file = SD.open("/DogTimes.txt", FILE_APPEND);
            file.print("\nError in InTime detected :: logging data ::\n");
            file.print("startTime :: " +String(DogTimes[iDogNumber].startTime)+"\n");
            file.print("raceTime :: " +String(DogTimes[iDogNumber].raceTime)+"\n");
            file.print("StartTime :: ");
            file.print(StartTime);
            file.print("\n");
            file.print("RaceTimeRed :: "+String(RaceTimeRed)+"\n");
            file.print("inTimeIn :: "+String(DogTimes[iDogNumber].inTimeIn)+"\n");
            file.print("inTimeOut :: "+String(DogTimes[iDogNumber].inTimeOut)+"\n");
            file.print("inTime :: "+String(DogTimes[iDogNumber].inTime)+"\n");
            file.print(":: End of error datalogging::\n");
            file.close();
            MSG = "errors logged to SD Card";
        }
        String nexInTime   = String((float)DogTimes[iDogNumber].inTime / 1000000.0, 3);
        switch (iDogNumber)
        {
        case 1:{inTime1.setText(nexInTime.c_str());break;}
        case 2:{inTime2.setText(nexInTime.c_str());break;}
        case 3:{inTime3.setText(nexInTime.c_str());break;}
        case 4:{inTime4.setText(nexInTime.c_str());break;}
        case 5:{inTime5.setText(nexInTime.c_str());break;}
        case 6:{inTime6.setText(nexInTime.c_str());break;}
        }
        Convert(DogTimes[iDogNumber].inTime, 0, iDogNumber);
        break;
    }
    case 3:
    {
          /* triggerState = BOX */
        DogTimes[iDogNumber].boxTime = DogTimes[iDogNumber].boxTimeOut - DogTimes[iDogNumber].boxTimeIn;
        String nexBoxTime  = String((float)DogTimes[iDogNumber].boxTime / 1000000.0, 3);
        switch (iDogNumber)
        {
        case 1:{boxTime1.setText(nexBoxTime.c_str());break;}
        case 2:{boxTime2.setText(nexBoxTime.c_str());break;}
        case 3:{boxTime3.setText(nexBoxTime.c_str());break;}
        case 4:{boxTime4.setText(nexBoxTime.c_str());break;}
        case 5:{boxTime5.setText(nexBoxTime.c_str());break;}
        case 6:{boxTime6.setText(nexBoxTime.c_str());break;}
        }
        break;
    }
    case 4:
    {
        /* triggerState = OUT */
        /* outTime *//* Transition = F */
        DogTimes[iDogNumber].outTime = DogTimes[iDogNumber].outTimeOut - DogTimes[iDogNumber].outTimeIn;
        String nexOutTime  = String((float)DogTimes[iDogNumber].outTime/1000000.0,3);
        switch (iDogNumber)
        {
        case 1:{outTime1.setText(nexOutTime.c_str());break;}
        case 2:{outTime2.setText(nexOutTime.c_str());break;}
        case 3:{outTime3.setText(nexOutTime.c_str());break;}
        case 4:{outTime4.setText(nexOutTime.c_str());break;}
        case 5:{outTime5.setText(nexOutTime.c_str());break;}
        case 6:{outTime6.setText(nexOutTime.c_str());break;}
        }
        Convert(DogTimes[iDogNumber].outTime,1,iDogNumber);
        /* heatTime *//* Transition = F */
        DogTimes[iDogNumber].heatTime = DogTimes[iDogNumber].outTimeOut - DogTimes[iDogNumber].inTimeIn;
        String nexHeatTime=String((float)DogTimes[iDogNumber].heatTime/1000000.0,3);
        switch (iDogNumber)
        {
        case 1:{heatTime1.setText(nexHeatTime.c_str());break;}
        case 2:{heatTime2.setText(nexHeatTime.c_str());break;}
        case 3:{heatTime3.setText(nexHeatTime.c_str());break;}
        case 4:{heatTime4.setText(nexHeatTime.c_str());break;}
        case 5:{heatTime5.setText(nexHeatTime.c_str());break;}
        case 6:{heatTime6.setText(nexHeatTime.c_str());break;}
        }
        /* teamTime *//* Transition = F */
        DogTimes[iDogNumber].teamTime = DogTimes[iDogNumber].outTimeOut - DogTimes[iDogNumber].raceTime;
        String nexTeamTime=String((float)DogTimes[iDogNumber].teamTime/1000000.0,3);
        teamTime.setText(nexTeamTime.c_str());
        /* nettoTime *//* Transition = F */
        DogTimes[iDogNumber].teamNetto = DogTimes[1].heatTime + DogTimes[2].heatTime + DogTimes[3].heatTime + DogTimes[4].heatTime + DogTimes[5].heatTime + DogTimes[6].heatTime;
        String nexTeamNetto=String((float)DogTimes[iDogNumber].teamNetto/1000000.0,3);
        teamNetto.setText(nexTeamNetto.c_str());
        /* teamPass *//* Transition = F */
        DogTimes[iDogNumber].teamPass = DogTimes[1].passTime + DogTimes[2].passTime + DogTimes[3].passTime + DogTimes[4].passTime + DogTimes[5].passTime + DogTimes[6].passTime;
        String nexTeamPass=String((float)DogTimes[iDogNumber].teamPass/1000000.0,3);
        teamPass.setText(nexTeamPass.c_str());
        break;
      }
    }
    runningStatus.setText(MSG.c_str());
    triggerState = _OFF;
  }
}



Bedankt bij voorbaat,

Yves

Advertisement

Gebruikers-avatar
Berichten: 2655
Geregistreerd: 06 Aug 2016, 01:03

Re: Communicatie tussen ESP32 en Nextion 7" Enh. te traag

Berichtdoor Koepel » 19 Dec 2018, 18:44

Heb je met een commando de baudrate van het display veranderd ? Daardoor ben ik meerdere keren de communicatie met het display kwijt geraakt. Ik heb zelfs een sketch geschreven die het display naar een normale baudrate terug probeert te zetten.
Natuurlijk scheelt het als de baudrate hoger is. Meteen naar 115200 is misschien een stap te ver.

Met zo'n stukje code kan ik weinig beginnen.

Normal wordt in een interrupt de millis() of micros() waarde opgeslagen, en bij een volgend interrupt weer. Vervolgens wordt het verschil berekend.

Als je schrijft over 88.000 µsec, dan is die punt een Nederlandse punt en geen Engelse punt ? Dus het zijn 88 milliseconden ? Dat is heel veel. In 88 milliseconden kan ik de kattenbak leegmaken, mijn hond uitlaten, en mijn aquarium schoonmaken.

Gebruik je SoftwareSerial voor het display ? Dan kun je het meten van tijd vergeten. SoftwareSerial neemt vrijwel alles over en dan werkt er bijna niets meer. Dan kun je misschien nog een ledje laten knipperen.

Berichten: 1
Geregistreerd: 18 Okt 2018, 21:10

Re: Communicatie tussen ESP32 en Nextion 7" Enh. te traag

Berichtdoor YvesDS » 19 Dec 2018, 21:12

Hi Koepel,
de baudrate heb ik direct in de Nextion gecodeerd met bauds=115200 (nu dus terug bauds=9600) in de préinitialisatie van pagina 0.
in de software setup() staat hij ook op eenzelfde waarde, als het datgene is wat je bedoelde en vroeg.

het gaat inderdaad over 88000 µseconden, dus 88 milliseconden !
dit leek mij idd zeer lang...
de communicatie gebeurd via HardwareSerial (2), zoals voorgeschreven door o.a. Andreas Spiess

eigenlijk komt het erop neer dat ik op drie momenten de kans heb om gegevens door te sturen, omdat er dan gegarandeerd niets te gebeuren staat...
ik kan makkelijk een flag switchen en in de main loop() die afvangen om de uitvoer te laten doorgaan, maar het systeem moet natuurlijk steeds zo snel mogelijk een weergave kunnen doorlopen, en op één kritisch punt kan het zijn dat ik 0.001sec "vrije tijd" heb, maar even goed 0.789sec ...
dus op dit punt willen de mensen ook uitvoer zien, maar die zal er pas komen wanneer er terug anderhalve seconde "vrije tijd" is...
doordat de volledige uitvoer zo rond de 0.088sec op zich neemt kom ik daar in de problemen...

ik kan hier gemakkelijk de volledige code meegeven, maar die is om en bij de 1000 regels, ik denk (vrees) dat daar niemand zit op te wachten (maar het kan hé, die code is zeker geen geheim!)

ik weet nu niet als er een ISR uitgevoerd wordt, als de code dan ook voortgezet word waar hij voor de interrupt mee bezig was (ser. comm. naar de Nextion dus) - want indien dit zo is, dan dien ik mij eigenlijk geen zorgen te maken....


Grtz,
Yves

Gebruikers-avatar
Berichten: 2655
Geregistreerd: 06 Aug 2016, 01:03

Re: Communicatie tussen ESP32 en Nextion 7" Enh. te traag

Berichtdoor Koepel » 19 Dec 2018, 21:39

Gelukkig, een hardware serial poort gebruikt interrupts en een buffer.
Dan zou 115200 geen probleem hoeven te zijn. Ik begrijp niet waarom de ESP32 een herstart maakt. Misschien is het een combinatie van verschillende problemen.

Bij nexSerial.begin() stel ik een hogere baudrate in. Dus niet bij de initialisatie van pagina 0.

De "normale" ITEAD_Nextion_Arduino library zit nogal slecht in elkaar. Als je iets verstuurd, dan wordt er gewacht op een reactie.
Ik gebruik die library niet meer en ik gebruik een commando ("bkcmd=0") om die reactie weg te laten. Vervolgens heb ik zelf (beperkte) code geschreven om gegevens te lezen die van het Nextion scherm af komen. Samen met een hogere baudrate werkt het dan al een stuk beter.

Wanneer je het meten van de tijd in de Arduino loop() doet, dan loop je sowieso tegen allerlei problemen op. De Nextion library is dan maar één van de dingen die voor problemen zorgt. Je hebt echt interrupts nodig.

Berichten: 4
Geregistreerd: 22 Okt 2013, 22:25

Re: Communicatie tussen ESP32 en Nextion 7" Enh. te traag

Berichtdoor YvesD » 19 Dec 2018, 22:44

Hey koepel,
maar interrupts worden wel degelijk gebruikt hoor. (zie de 3 IRAM_ATTR HandleSensor_x__Interrupt() functies)
ik heb daarnet nog even zitten proberen met de hogere baudrates, maar enkel de 9600 werkt stabiel genoeg :?

ik wou de code toevoegen als een attachment, maar er word geen .ino of .txt aanvaard
dus ik heb effe de code hieronder geplaatst


Code: Alles selecteren
#include "esp_timer.h"
#include <NeoPixelBus.h>
/* SD Card stuff */
#include <SPI.h>
#include <SD.h>
#include "FS.h"
#include "sd_defines.h"
/* Nextion stuff*/
#include "Nextion.h"

NexRtc  rtc;
HardwareSerial nexSerial(2);

#define ENHANCED
/* the buttons on the teampage */
void startRacePopCallback(void *ptr);
void saveTeamPopCallback(void *ptr);
void resetTeamPopCallback(void *ptr);
void saveDataPopCallback(void *ptr);
void clearTeamPopCallback(void *ptr);
void dataToSerialPopCallback(void *ptr);
void clearDataPopCallback(void *ptr);
void setDebouncePopCallback(void *ptr);
void calSensorsPopCallback(void *ptr);
/*Declare a button objects*/
NexButton startRace = NexButton(1, 47, "startRace");
NexButton saveTeam = NexButton(1, 61, "saveTeam");
NexButton resetTeam = NexButton(1, 50, "resetTeam");
NexButton saveData = NexButton(1, 51, "saveData");
NexButton clearTeam = NexButton(1, 62, "clearTeam");
NexButton dataToSerial = NexButton(3, 1, "dataToSerial");
NexButton clearData = NexButton(3, 4, "clearData");
NexButton setDebounce = NexButton(3, 9, "setDebounce");
NexButton calSensors = NexButton(3, 10, "calSensors");
/*Declare a text objects*/
NexText dog1 = NexText(1, 1, "dog1"); NexText dog2 = NexText(1, 2, "dog2"); NexText dog3 = NexText(1, 3, "dog3");
NexText dog4 = NexText(1, 4, "dog4"); NexText dog5 = NexText(1, 5, "dog5"); NexText dog6 = NexText(1, 6, "dog6");
NexText inTime1 = NexText(1, 9, "inTime1"); NexText inTime2 = NexText(1, 14, "inTime2"); NexText inTime3 = NexText(1, 19, "inTime3");
NexText inTime4 = NexText(1, 24, "inTime4"); NexText inTime5 = NexText(1, 29, "inTime5"); NexText inTime6 = NexText(1, 34, "inTime6");
NexText boxTime1 = NexText(1, 10, "boxTime1"); NexText boxTime2 = NexText(1, 15, "boxTime2"); NexText boxTime3 = NexText(1, 20, "boxTime3");
NexText boxTime4 = NexText(1, 25, "boxTime4"); NexText boxTime5 = NexText(1, 30, "boxTime5"); NexText boxTime6 = NexText(1, 35, "boxTime6");
NexText outTime1 = NexText(1, 11, "outTime1"); NexText outTime2 = NexText(1, 16, "outTime2"); NexText outTime3 = NexText(1, 21, "outTime3");
NexText outTime4 = NexText(1, 26, "outTime4"); NexText outTime5 = NexText(1, 31, "outTime5"); NexText outTime6 = NexText(1, 36, "outTime6");
NexText heatTime1 = NexText(1, 12, "heatTime1"); NexText heatTime2 = NexText(1, 17, "heatTime2"); NexText heatTime3 = NexText(1, 22, "heatTime3");
NexText heatTime4 = NexText(1, 27, "heatTime4"); NexText heatTime5 = NexText(1, 32, "heatTime5"); NexText heatTime6 = NexText(1, 37, "heatTime6");
NexText passTime1 = NexText(1, 13, "passTime1"); NexText passTime2 = NexText(1, 18, "passTime2"); NexText passTime3 = NexText(1, 23, "passTime3");
NexText passTime4 = NexText(1, 28, "passTime4"); NexText passTime5 = NexText(1, 33, "passTime5"); NexText passTime6 = NexText(1, 38, "passTime6");
NexText teamTime = NexText(1, 43, "teamTime"); NexText teamPass = NexText(1, 44, "teamPass"); NexText teamNetto = NexText(1, 46, "teamNetto");
NexText runningStatus = NexText(1, 68, "runningStatus");
NexNumber heatsToRun = NexNumber(1, 8, "heatsToRun");
NexNumber debounce = NexNumber(3, 8, "debounce");
NexText kmphIn = NexText(1, 66, "kmphIn");
NexText kmphOut = NexText(1, 67, "kmphOut");
NexText jumpHeight = NexText(1, 71, "t3");
/*Register objects to the touch event list*/
NexTouch *nex_listen_list[] = {
  &startRace,
  &saveTeam,
  &resetTeam,
  &saveData,
  &clearTeam,
  &dataToSerial,
  &clearData,
  &setDebounce,
  &calSensors,
  NULL
};

/* global settings */
#define ON 1
#define OFF 0
#define Sensor1 32
#define Sensor2 34
#define Sensor3 33
#define InputStart 15
#define INPUT_PULLDOWN 0x09
#define MAX_BUFFER 17 /* zero based array for data of the dog, heats and races */
#define RedFaultPin 27
#define BlueFaultPin 14
#define OrangeFaultPin 12
#define GreenFaultPin 13
#define nexBaudRate 9600
const int PixelCount = 72;
const byte PixelPin = 25;
char buffer[200] = {0};
uint32_t GENERAL_DEBOUNCE = 120000; /* to be set as value of debounce time  = normal time of a crossing !*/
/* end of global settings */

/* settings for manual fault buttons */
bool Red = OFF; /* flag */
bool Blue = OFF; /* flag */
bool Orange = OFF; /* flag */
bool Green = OFF; /* flag */
long RedPrevTime = 0; /* debouncereference */
long BluePrevTime = 0; /* debouncereference */
long OrangePrevTime = 0; /* debouncereference */
long GreenPrevTime = 0; /* debouncereference */
/* end of manual fault buttons settings */


typedef struct DebugTimes { /* everything needed to debug the dognumbers and data */
  uint8_t  ISRNumber;
  uint32_t ISRTime;
}; volatile DebugTimes DebugTime[100]; volatile uint8_t DebugIterator = 0; static bool DebugOutPutData = OFF; /* END */
typedef struct DogFaults { /*DogFaults*/
  bool D1 = OFF;
  bool D2 = OFF;
  bool D3 = OFF;
  bool D4 = OFF;
  bool D5 = OFF;
  bool D6 = OFF;
}; static DogFaults DogFault;/*end of dogfaults*/
struct DogTimeSTRUCT { /* time capturing */
  bool Fault = OFF;
  String jumpHeight = "";
  String TeamName = "Blank";
  String DogName = "Blank";
  byte Position = 0;
  long startTime;
  long raceTime;
  long inTimeIn = 0; /*to store the clock value from the ingoing sensorbreak S1*/
  long inTimeOut = 0; /*to store the clock value from the ingoing sensorbreak S1*/
  long inTime = 0; /*to store the clock value from the ingoing sensorbreak S1*/
  long outTimeIn = 0; /*to store the clock value from the outgoing sensorbreak S1*/
  long outTimeOut = 0; /*to store the clock value from the outgoing sensorbreak S1*/
  long outTime = 0; /*to store the clock value from the outgoing sensorbreak S1*/
  long boxTimeIn = 0; /*to store the clock value between two dogs passing the sensor S1*/
  long boxTimeOut = 0; /*to store the clock value between two dogs passing the sensor S1*/
  long boxTime = 0; /*to store the clock value between two dogs passing the sensor S1*/
  long heatTime = 0; /* to store the trainins value on sensor S3 */
  long passTime = 0;
  long teamNetto = 0;
  long teamPass = 0;
  long teamTime = 0;
  double Pass = 0; /*to store the float value of the passing*/
  double Heat = 0; /*to store the float value of the heat per dog*/
  double Team = 0; /* add each dog's time up since start */
  double TIn = 0; /*to store the float value */
  double SBS = 0; /*to store the float value*/
  double Tout = 0; /*to store the float value*/
  double speedIn = 0;
  double speedOut = 0;
}; DogTimeSTRUCT DogTimes[MAX_BUFFER];
/*NeoPixel Stuff */
NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
/*set color value for lights*/
RgbColor red(255, 0, 0);
RgbColor green(0, 255, 0);
RgbColor blue(0, 0, 255);
RgbColor orange(255, 128, 0);
RgbColor white(255, 255, 255);
RgbColor black(0, 0, 0);
RgbColor purple(177, 35, 207);
RgbColor sky(47, 196, 196);
/* end of NeoPixel stuff */
static String setupDone = "(Re-)Setup by MCU!";
static String MSG = "";

static bool OutputDone = OFF;
static bool OutputCrossingCode = ON;
static bool DebugTextOutput = ON;
volatile bool bFault = OFF;
static bool PassFault = OFF;
static bool StartSequenceHandled = OFF;
static bool FaultLightStatus = OFF;
static bool bStarted = OFF;
static bool bTeamSaved = OFF;
static bool canDisplay = OFF;

static uint8_t DogNumber = 0; /*systeem van de enum herbekijken en over schakelen naar uint8_t*/
static uint8_t NumberOfDogFaults = 0;
static uint8_t HeatsToRun = 0;
static uint32_t canDisplayTime = 0;
static uint32_t StartTime = 0;

static byte HeatsCompleted = 0;
volatile byte InterruptSensor1Counter = 0;

static uint32_t RaceTimeRed = 0;
static uint32_t FaultLightStartTime = 0;
static uint32_t OutPutDataTime = 0;
volatile uint32_t InterruptSensor1Time = 0;
volatile uint32_t PrevSensor1Time = 0;
volatile byte InterruptSensor2Counter = 0;
volatile uint32_t InterruptSensor2Time = 0;
volatile uint32_t PrevSensor2Time = 0;
volatile byte InterruptSensor3Counter = 0;
volatile uint32_t InterruptSensor3Time = 0;
volatile uint32_t PrevSensor3Time = 0;
volatile uint32_t DebounceSensor1 = 0;
volatile uint32_t DebounceSensor2 = 0;
volatile uint32_t DebounceSensor3 = 0;

enum TransitionState {NO, A, B, C, D, E, F}; TransitionState Transition(NO);
enum RaceSTATE {STATE_IDLE, STARTED, STARTING, RUNNING, STOPPING, STOPPED}; RaceSTATE Status(STATE_IDLE);
enum LightSTATE {ALL_OFF, RED_ON, ORANGE1_ON, ORANGE2_ON, GREEN_ON, BLUE_ON}; LightSTATE LightStatus(ALL_OFF);
enum triggerNextionOutPut {_OFF, PASS, IN, BOX, OUT}; triggerNextionOutPut triggerState(_OFF);

portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;

void IRAM_ATTR HandleSensor1Interrupt() {/* ISR1 */
  portENTER_CRITICAL_ISR(&mux);
  if (esp_timer_get_time() > DebounceSensor1)
  {
    InterruptSensor1Counter++;
    InterruptSensor1Time = esp_timer_get_time();
    DebounceSensor1 = InterruptSensor1Time + GENERAL_DEBOUNCE;/* debounce for 0.12seconds on this sensor*/
  }
  portEXIT_CRITICAL_ISR(&mux);
}
void IRAM_ATTR HandleSensor2Interrupt() { /* ISR2 */
  portENTER_CRITICAL_ISR(&mux);
  if (esp_timer_get_time() > DebounceSensor2)
  {
    InterruptSensor2Counter++;
    InterruptSensor2Time = esp_timer_get_time();
    DebounceSensor2 = InterruptSensor2Time + GENERAL_DEBOUNCE;/* debounce for 0.12seconds on this sensor*/
  }
  portEXIT_CRITICAL_ISR(&mux);
}
void IRAM_ATTR HandleSensor3Interrupt() {/* ISR3 */
  portENTER_CRITICAL_ISR(&mux);
  if (esp_timer_get_time() > DebounceSensor3)
  {
    InterruptSensor3Counter++;
    InterruptSensor3Time = esp_timer_get_time();
    DebounceSensor3 = InterruptSensor3Time + GENERAL_DEBOUNCE;/* debounce for 0.12seconds on this sensor*/
  }
  portEXIT_CRITICAL_ISR(&mux);
}
void raceEndStatus() { /* next part is to handle the end of a race */
  if (digitalRead(InputStart) && Status == STOPPING && esp_timer_get_time() > StartTime + 3000000)
  {
    LightStatus = ALL_OFF;
    Status == STATE_IDLE;
    for (int i = 0; i < MAX_BUFFER; i++)
    {
      DogTimes[i].startTime = 0; DogTimes[i].raceTime = 0;
      DogTimes[i].inTimeIn = 0; DogTimes[i].inTimeOut = 0; DogTimes[i].inTime = 0;
      DogTimes[i].outTimeIn = 0; DogTimes[i].outTimeOut = 0; DogTimes[i].outTime = 0;
      DogTimes[i].boxTimeIn = 0; DogTimes[i].boxTimeOut = 0; DogTimes[i].boxTime = 0;
      DogTimes[i].heatTime = 0; DogTimes[i].passTime = 0; DogTimes[i].teamNetto = 0; DogTimes[i].teamPass = 0; DogTimes[i].teamTime = 0;
      DogTimes[i].Pass = 0; DogTimes[i].Heat = 0; DogTimes[i].Team = 0; DogTimes[i].TIn = 0;
      DogTimes[i].SBS = 0; DogTimes[i].Tout = 0; DogTimes[i].Fault = OFF;
      DogTimes[i].TeamName = "Blank"; DogTimes[i].DogName = "Blank"; DogTimes[i].Position = 0;
    }
    return;
  }
}
void RaceLightStatus() { /* DONE !! */
  if (!StartSequenceHandled)
  {
    if (digitalRead(InputStart) && Status == STATE_IDLE)/*when startbutton is pressed !*/
    {
      StartTime = esp_timer_get_time();/*capture the time the buttons was activated*/
      RaceTimeRed = StartTime + 3000000;/* add 3seconds to have the racing time already */
      for (int i = 0; i < MAX_BUFFER; i++)
      {
        DogTimes[i].startTime = StartTime;
        DogTimes[i].raceTime = RaceTimeRed;
      }
      DogTimes[0].outTimeOut = RaceTimeRed;
      Transition = NO;
      Status = STARTED; /* change the satus to started */
//      return;
    }
    if (Status == STARTED && LightStatus == ALL_OFF && esp_timer_get_time() > StartTime) /*activate the startlights*/
    {
      RedLight(ON);
      LightStatus = RED_ON;
      Status = STARTING;
      return;
    }
    if (Status == STARTING && LightStatus == RED_ON && esp_timer_get_time() > StartTime + 1000000)/* switch from red to orange1 light*/
    {
      RedLight(OFF);
      Orange1Light(ON);
      LightStatus = ORANGE1_ON;
      return;
    }
    if (Status == STARTING && LightStatus == ORANGE1_ON && esp_timer_get_time() > StartTime + 2000000)/* switch from orange1 to orange2 light*/
    {
      Orange1Light(OFF);
      Orange2Light(ON);
      LightStatus = ORANGE2_ON;
      return;
    }
    if (Status == STARTING && LightStatus == ORANGE2_ON && esp_timer_get_time() > StartTime + 3000000)/* switch from orange2 to green light & start the race*/
    {
      Orange2Light(OFF);
      if (DogNumber == 0)/* nothing passed sensors so far */
      {
        RaceTimeRed = esp_timer_get_time();
        Transition = A;
        DogNumber = 1;
      }
      GreenLight(ON);
      LightStatus = GREEN_ON;
      Status = RUNNING;
      return;
    }
    if (Status == RUNNING && LightStatus == GREEN_ON && esp_timer_get_time() > StartTime + 4000000)/*make sure the startsequence is stopped correctly*/
    {
      GreenLight(OFF);
      LightStatus = ALL_OFF;
      StartSequenceHandled = ON;
      return;
    }
  }
}
void CheckFault() {
  if (bFault){/*if bFault is true*/
    FaultLightStartTime = esp_timer_get_time();/* take referencetime*/
    WhiteLight(ON);/* put on white fault lamp for 2.0seconds*/
    sendCommand("pio7=1");/*set buzzer ON on the Nextion*/
    FaultLightStatus = ON;/* set the white-is-on flag*/
    bFault = OFF;/* wait for a next fault to happen, so reset bFault to false*/
    switch (DogNumber)
    {
      case 1:
        RedLight(ON);
        DogFault.D1 = ON;
        break;
      case 2:
        BlueLight(ON);
        DogFault.D2 = ON;
        break;
      case 3:
        Orange2Light(ON);
        DogFault.D3 = ON;
        break;
      case 4:
        GreenLight(ON);
        DogFault.D4 = ON;
        break;
      case 5:
        PurpleLight(ON);
        DogFault.D5 = ON;
        break;
      case 6:
        SkyLight(ON);
        DogFault.D6 = ON;
        break;
    }
    return;
  }
  if (FaultLightStatus == ON && esp_timer_get_time() > FaultLightStartTime + 2000000){/* if the white fault lamp is on since 2.0seconds*/
    FaultLightStartTime = 0;/* reset the captured time to zero*/
    WhiteLight(OFF);/*put white fault lamp to "off"*/
    sendCommand("pio7=0");/*set buzzer OFF on the Nextion*/
    FaultLightStatus = OFF;/* reset status of the white lamp*/
    return;
  }
}
void CheckPassing() {
  if ( ( InterruptSensor1Counter > 0) && (esp_timer_get_time() > DebounceSensor1) && Transition == NO ) { /* ISR1 Handling for false start */
    Transition = B;
    DogNumber = 1;
    bFault = ON;
    InterruptSensor1Counter = 0;
//    PrevSensor1Time = InterruptSensor1Time;
    DogTimes[DogNumber].inTimeIn = InterruptSensor1Time;
    MSG = "FALSE START !";
    return;
  }
  if ( ( InterruptSensor1Counter > 0) && (esp_timer_get_time() > DebounceSensor1) && Transition == A ) { /* ISR1 Handling for normal crossing*/
    Transition = B;
    InterruptSensor1Counter = 0;
//    PrevSensor1Time = InterruptSensor1Time;
    DogTimes[DogNumber].inTimeIn = InterruptSensor1Time;
    MSG = "DOG DETECTED";
    return;
  }
  if ( (InterruptSensor2Counter > 0) && (esp_timer_get_time() > DebounceSensor2) && Transition == B ) { /* ISR2 Handling "DOG IN" */
    Transition = C;
    InterruptSensor2Counter = 0;
//    PrevSensor2Time = InterruptSensor2Time;
    triggerState = PASS;
    MSG = "DOG IN";
    return;
  }
  if ( (InterruptSensor3Counter > 0) && (esp_timer_get_time() > (DebounceSensor3) ) && Transition == C ) { /* ISR3 Handling "TO BOX" */
    Transition = D;
    InterruptSensor3Counter = 0;
//    PrevSensor3Time = InterruptSensor3Time;
    DogTimes[DogNumber].inTimeOut = InterruptSensor3Time;
    DogTimes[DogNumber].boxTimeIn = InterruptSensor3Time;
    triggerState = IN;
    MSG = "TO BOX";
    return;
  }
  if ( (InterruptSensor3Counter > 0) && (esp_timer_get_time() > (DebounceSensor3) ) && Transition == D ) { /* ISR3 Handling "FROM BOX" */
    Transition = E;
    InterruptSensor3Counter = 0;
//    PrevSensor3Time = InterruptSensor3Time;
    DogTimes[DogNumber].boxTimeOut = InterruptSensor3Time;
    DogTimes[DogNumber].outTimeIn = InterruptSensor3Time;
    triggerState = BOX;
    MSG = "FROM BOX";
    return;
  }
  if ( (InterruptSensor2Counter > 0) && (esp_timer_get_time() > DebounceSensor2) && Transition == E) { /* ISR2 Handling "DOG OUT" */
    Transition = F;
    InterruptSensor2Counter = 0;
//    PrevSensor2Time = InterruptSensor2Time;
    MSG = "DOG OUT";
    return;
  }
  if ( (InterruptSensor1Counter > 0) && (esp_timer_get_time() > (DebounceSensor1) )  && Transition == F) { /* ISR2 Handling :: CODE E*/
    long proccesTime1 = 0;
    long proccesTime2 = 0;
    Transition = A;
    InterruptSensor1Counter = 0;
//    PrevSensor1Time = InterruptSensor1Time;
    DogTimes[DogNumber].outTimeOut = InterruptSensor1Time;
    triggerState = OUT;
//    proccesTime1 = esp_timer_get_time();
    upDateNextion(triggerState, DogNumber);
//    proccesTime2 = esp_timer_get_time();
    DogNumber++;
    HeatsToRun--;
    MSG = "WAITING FOR NEXT DOG IN";
//Serial.println(proccesTime1);
//Serial.println(proccesTime2);
    return;
  }
} /* end of CheckPassing() */
void upDateNextion(uint8_t itriggerState, uint8_t iDogNumber ){
  if(itriggerState != _OFF){
//    long proccesTime1 = 0;
//    long proccesTime2 = 0;
//    proccesTime1 = esp_timer_get_time();
    switch (itriggerState) /*triggerState options : _OFF=0,PASS=1,IN=2,BOX=3,OUT=4 */
    {
    case 1:
    {
        /* triggerState = PASS */
        DogTimes[iDogNumber].passTime = DogTimes[iDogNumber].inTimeIn - DogTimes[iDogNumber - 1].outTimeOut;
        String nexPassTime = String((float)DogTimes[iDogNumber].passTime / 1000000.0, 3);
        switch (iDogNumber)
        {
        case 1:{passTime1.setText(nexPassTime.c_str());break;}
        case 2:{passTime2.setText(nexPassTime.c_str());break;}
        case 3:{passTime3.setText(nexPassTime.c_str());break;}
        case 4:{passTime4.setText(nexPassTime.c_str());break;}
        case 5:{passTime5.setText(nexPassTime.c_str());break;}
        case 6:{passTime6.setText(nexPassTime.c_str());break;}
        }
        break;
    }
    case 2:
    {
        /* triggerState = IN */
        DogTimes[iDogNumber].inTime = DogTimes[iDogNumber].inTimeOut - DogTimes[iDogNumber].inTimeIn;
        if( DogTimes[iDogNumber].inTime < 0)
        {
            File file = SD.open("/DogTimes.txt", FILE_APPEND);
            file.print("\nError in InTime detected :: logging data ::\n");
            file.print("startTime\t\t::\t\t" +String((float)DogTimes[iDogNumber].startTime/1000000.0,3)+"\n");
            file.print("raceTime\t\t::\t\t" +String((float)DogTimes[iDogNumber].raceTime/1000000.0,3)+"\n");
            file.print("RaceTimeRed\t\t::\t\t"+String((float)RaceTimeRed/1000000.0,3)+"\n");
            file.print("inTimeIn\t\t::\t\t"+String((float)DogTimes[iDogNumber].inTimeIn/1000000.0,3)+"\n");
            file.print("inTimeOut\t\t::\t\t"+String((float)DogTimes[iDogNumber].inTimeOut/1000000.0,3)+"\n");
            file.print("inTime\t\t::\t\t"+String((float)DogTimes[iDogNumber].inTime/1000000.0,3)+"\n");
            file.print(":: End of error datalogging::\n");
            file.close();
            MSG = "errors logged to SD Card";
        }
        String nexInTime   = String((float)DogTimes[iDogNumber].inTime / 1000000.0, 3);
        switch (iDogNumber)
        {
        case 1:{inTime1.setText(nexInTime.c_str());break;}
        case 2:{inTime2.setText(nexInTime.c_str());break;}
        case 3:{inTime3.setText(nexInTime.c_str());break;}
        case 4:{inTime4.setText(nexInTime.c_str());break;}
        case 5:{inTime5.setText(nexInTime.c_str());break;}
        case 6:{inTime6.setText(nexInTime.c_str());break;}
        }
        Convert(DogTimes[iDogNumber].inTime, 0, iDogNumber);
        break;
    }
    case 3:
    {
          /* triggerState = BOX */
        DogTimes[iDogNumber].boxTime = DogTimes[iDogNumber].boxTimeOut - DogTimes[iDogNumber].boxTimeIn;
        String nexBoxTime  = String((float)DogTimes[iDogNumber].boxTime / 1000000.0, 3);
        switch (iDogNumber)
        {
        case 1:{boxTime1.setText(nexBoxTime.c_str());break;}
        case 2:{boxTime2.setText(nexBoxTime.c_str());break;}
        case 3:{boxTime3.setText(nexBoxTime.c_str());break;}
        case 4:{boxTime4.setText(nexBoxTime.c_str());break;}
        case 5:{boxTime5.setText(nexBoxTime.c_str());break;}
        case 6:{boxTime6.setText(nexBoxTime.c_str());break;}
        }
        break;
    }
    case 4:
    {
        /* triggerState = OUT */
        /* outTime *//* Transition = F */
        DogTimes[iDogNumber].outTime = DogTimes[iDogNumber].outTimeOut - DogTimes[iDogNumber].outTimeIn;
        String nexOutTime  = String((float)DogTimes[iDogNumber].outTime/1000000.0,3);
        switch (iDogNumber)
        {
        case 1:{outTime1.setText(nexOutTime.c_str());break;}
        case 2:{outTime2.setText(nexOutTime.c_str());break;}
        case 3:{outTime3.setText(nexOutTime.c_str());break;}
        case 4:{outTime4.setText(nexOutTime.c_str());break;}
        case 5:{outTime5.setText(nexOutTime.c_str());break;}
        case 6:{outTime6.setText(nexOutTime.c_str());break;}
        }
        Convert(DogTimes[iDogNumber].outTime,1,iDogNumber);
        /* heatTime *//* Transition = F */
        DogTimes[iDogNumber].heatTime = DogTimes[iDogNumber].outTimeOut - DogTimes[iDogNumber].inTimeIn;
        String nexHeatTime=String((float)DogTimes[iDogNumber].heatTime/1000000.0,3);
        switch (iDogNumber)
        {
        case 1:{heatTime1.setText(nexHeatTime.c_str());break;}
        case 2:{heatTime2.setText(nexHeatTime.c_str());break;}
        case 3:{heatTime3.setText(nexHeatTime.c_str());break;}
        case 4:{heatTime4.setText(nexHeatTime.c_str());break;}
        case 5:{heatTime5.setText(nexHeatTime.c_str());break;}
        case 6:{heatTime6.setText(nexHeatTime.c_str());break;}
        }
        /* teamTime *//* Transition = F */
        DogTimes[iDogNumber].teamTime = DogTimes[iDogNumber].outTimeOut - DogTimes[iDogNumber].raceTime;
        String nexTeamTime=String((float)DogTimes[iDogNumber].teamTime/1000000.0,3);
        teamTime.setText(nexTeamTime.c_str());
        /* nettoTime *//* Transition = F */
        DogTimes[iDogNumber].teamNetto = DogTimes[1].heatTime + DogTimes[2].heatTime + DogTimes[3].heatTime + DogTimes[4].heatTime + DogTimes[5].heatTime + DogTimes[6].heatTime;
        String nexTeamNetto=String((float)DogTimes[iDogNumber].teamNetto/1000000.0,3);
        teamNetto.setText(nexTeamNetto.c_str());
        /* teamPass *//* Transition = F */
        DogTimes[iDogNumber].teamPass = DogTimes[1].passTime + DogTimes[2].passTime + DogTimes[3].passTime + DogTimes[4].passTime + DogTimes[5].passTime + DogTimes[6].passTime;
        String nexTeamPass=String((float)DogTimes[iDogNumber].teamPass/1000000.0,3);
        teamPass.setText(nexTeamPass.c_str());
        break;
      }
    }
    runningStatus.setText(MSG.c_str());
    triggerState = _OFF;
//    proccesTime2 = esp_timer_get_time();
//    Serial.println(proccesTime1);
//    Serial.println(proccesTime2);
   
  }
}

void checkSensor1() {
  if (digitalRead(Sensor1))
  {
    sendCommand("cirs 330,330,8,RED");
  } else {
    sendCommand("cirs 330,330,8,GREEN");
  }
  return;
}
void checkSensor2() {
  if (digitalRead(Sensor2))
  {
    sendCommand("cirs 300,330,8,RED");
  } else {
    sendCommand("cirs 300,330,8,GREEN");
  }
  return;
}
void checkSensor3() {
  if (digitalRead(Sensor3))
  {
    sendCommand("cirs 40,330,8,RED");
  } else {
    sendCommand("cirs 40,330,8,GREEN");
  }
  return;
}

void setup() {
  MSG = "MCU Setup executed !";
  Serial.begin(115200);
  Serial.print("Initializing SD card...");
  if (!SD.begin(5)){Serial.println("Card Mount Failed");return;}
//    uint8_t cardType = SD.cardType();
//  if (cardType == CARD_NONE){Serial.println("No SD card attached");}
//  Serial.print("SD Card Type: ");
//  if (cardType == CARD_MMC){Serial.println("MMC");}
//  else if (cardType == CARD_SD){Serial.println("SDSC");}
//  else if (cardType == CARD_SDHC){Serial.println("SDHC");}
//  else {Serial.println("UNKNOWN");}
  uint64_t cardSize = SD.cardSize() / (1024 * 1024);
  Serial.printf("SD Card Size: %lluMB\n", cardSize);
//  listDir(SD, "/", 0);
  readFile(SD, "/DogTimes.txt");
  nexSerial.begin(nexBaudRate, SERIAL_8N1, 16, 17);
  nexInit();
  File file = SD.open("/DogTimes.txt", FILE_APPEND);
  if (!file)
  {
    String appendMsg = "Failed to open SD-file";
    runningStatus.setText(appendMsg.c_str());
    return;
  }
  file.print("\n");
  file.print(setupDone.c_str());
  file.print("\n");
  file.close();
  startRace.attachPop(startRacePopCallback);  /* Register the pop event callback function of the current text component. */
  saveTeam.attachPop(saveTeamPopCallback);    /* Register the pop event callback function of the current button0 component. */
  resetTeam.attachPop(resetTeamPopCallback);  /* Register the pop event callback function of the current button0 component. */
  saveData.attachPop(saveDataPopCallback);
  clearTeam.attachPop(clearTeamPopCallback);
  dataToSerial.attachPop(dataToSerialPopCallback);
  clearData.attachPop(clearDataPopCallback);
  setDebounce.attachPop(setDebouncePopCallback);
  calSensors.attachPop(calSensorsPopCallback);
  pinMode(InputStart, INPUT_PULLDOWN);
  pinMode(Sensor1, INPUT_PULLDOWN); /* Handler side sensors*/
  pinMode(Sensor2, INPUT_PULLDOWN); /* Box side sensors*/
  pinMode(Sensor3, INPUT_PULLDOWN); /* training sensors near box*/
  attachInterrupt(digitalPinToInterrupt(Sensor1), HandleSensor1Interrupt, RISING);
  attachInterrupt(digitalPinToInterrupt(Sensor2), HandleSensor2Interrupt, RISING);
  attachInterrupt(digitalPinToInterrupt(Sensor3), HandleSensor3Interrupt, RISING);
  strip.Begin();
  strip.Show();
  runningStatus.setText(MSG.c_str());
  MSG = "";

}

void loop() {
  nexLoop(nex_listen_list);
  if (triggerState != _OFF && triggerState != OUT){
    upDateNextion(triggerState, DogNumber );
  }
  CheckFault();
  if (HeatsToRun > 0) {
    CheckPassing();
    RaceLightStatus();  /* the start/stop buttons was activated */
  } else {
    Status == STOPPING;
    HeatsToRun = 100;
    raceEndStatus();       /* handle the different states of one race */
  }
}

/* Specific Nextion functions */
/* SYSTEM PAGE */
void calSensorsPopCallback(void *ptr) { /*Button to calibrate sensors on setup of ring*/
  checkSensor1();
  checkSensor2();
  checkSensor3();
  return;
}
void setDebouncePopCallback(void *ptr) { /*Button to set the debounce scale*/
  uint32_t value;
  String sStatusMsg = "";
  debounce.getValue(&value);
  GENERAL_DEBOUNCE = value * 1000;
  sStatusMsg = "Debouncing @ : " + String(GENERAL_DEBOUNCE) + " microseconds";
  runningStatus.setText(sStatusMsg.c_str());
}
void dataToSerialPopCallback(void *ptr) { /*button to send ALL THE DATA on the SD CARD to the serial monitor*/
  String statusMSG = "Data send to serial";
  listDir(SD, "/", 0);
  readFile(SD, "/DogTimes.txt");
  runningStatus.setText(statusMSG.c_str());
}
void clearDataPopCallback(void *ptr) { /*button to EMPTY the logfile on the SD CARD*/
  File file = SD.open("/DogTimes.txt", FILE_WRITE);
  String statusMSG = "Data cleared on SD !";
  String appendMsg = "";
  if (!file)
  {
    appendMsg = "Failed to open file";
    runningStatus.setText(appendMsg.c_str());
    return;
  }
  file.print("\nResultaten van de trainingen :\n\n\n");
  file.close();
  runningStatus.setText(statusMSG.c_str());
}
/* TRAINING PAGE */
void saveTeamPopCallback(void *ptr) { /*button to save the DOGS and JUMPHEIGHT to the MCU before starting a NEW SESSION*/
  uint32_t number;
  String statusMSG = "Teamdata saved !";
  memset(buffer, 0, sizeof(buffer));
  dog1.getText(buffer, sizeof(buffer));
  DogTimes[1].DogName = buffer;
  memset(buffer, 0, sizeof(buffer));
  dog2.getText(buffer, sizeof(buffer));
  DogTimes[2].DogName = buffer;
  memset(buffer, 0, sizeof(buffer));
  dog3.getText(buffer, sizeof(buffer));
  DogTimes[3].DogName = buffer;
  memset(buffer, 0, sizeof(buffer));
  dog4.getText(buffer, sizeof(buffer));
  DogTimes[4].DogName = buffer;
  memset(buffer, 0, sizeof(buffer));
  dog5.getText(buffer, sizeof(buffer));
  DogTimes[5].DogName = buffer;
  memset(buffer, 0, sizeof(buffer));
  dog6.getText(buffer, sizeof(buffer));
  DogTimes[6].DogName = buffer;
  /* determine number of heats to run */
  heatsToRun.getValue(&number);
  HeatsToRun =  number;
  runningStatus.setText(statusMSG.c_str());
}
void saveDataPopCallback(void *ptr) { /*button to save the data from last session to SD CARD*/
  memset(buffer, 0, sizeof(buffer));
  jumpHeight.getText(buffer, sizeof(buffer));
  DogTimes[0].jumpHeight = buffer;
  File file = SD.open("/DogTimes.txt", FILE_APPEND);
  String appendMsg = "";
  String statusMSG = "Data saved to SD !";
  String infoMSG = "";
  if (!file) {
    appendMsg = "Failed to open file";
    runningStatus.setText(appendMsg.c_str());
    return;
  }
  file.print("\nDogs jumping over " + DogTimes[0].jumpHeight + "\n");
  file.print("\nDogname\t:\t\tinTime\t:\tboxTime\t:\toutTime\t:\theatTime:\tpassTime:\tspeedIn\t:\tspeedOut\n\n");
  for (int i = 1; i < 7; i++) {
    infoMSG =  DogTimes[i].DogName;
    file.print(infoMSG.c_str());
    file.print("\t\t:\t");
    infoMSG =  String((float)DogTimes[i].inTime / 1000000.0, 3);
    file.print(infoMSG.c_str());
    file.print("\t:\t");
    infoMSG =  String((float)DogTimes[i].boxTime / 1000000.0, 3);
    file.print(infoMSG.c_str());
    file.print("\t:\t");
    infoMSG =  String((float)DogTimes[i].outTime / 1000000.0, 3);
    file.print(infoMSG.c_str());
    file.print("\t:\t");
    infoMSG =  String((float)DogTimes[i].heatTime / 1000000.0, 3);
    file.print(infoMSG.c_str());
    file.print("\t:\t");
    infoMSG =  String((float)DogTimes[i].passTime / 1000000.0, 3);
    file.print(infoMSG.c_str());
    file.print("\t:\t");
    infoMSG =  String((float)DogTimes[i].speedIn, 2);
    file.print(infoMSG.c_str());
    file.print("\t:\t");
    infoMSG =  String((float)DogTimes[i].speedOut, 2);
    file.print(infoMSG.c_str());
    file.print("\n");
  }
  file.print("\n\n");
  file.close();
  runningStatus.setText(statusMSG.c_str());
}
void clearTeamPopCallback(void *ptr){ /*button to start a NEW SESSION wit the SAME DOGS*/
  String resetTimes = "0.000";
  MSG = "Time's cleared, dogs saved";
  for (int i = 0; i < MAX_BUFFER; i++)
  {
    DogTimes[i].startTime = 0;
    DogTimes[i].raceTime = 0;
    DogTimes[i].jumpHeight = "";
    DogTimes[i].inTimeIn = 0;      DogTimes[i].inTimeOut = 0;      DogTimes[i].inTime = 0;
    DogTimes[i].outTimeIn = 0;     DogTimes[i].outTimeOut = 0;     DogTimes[i].outTime = 0;
    DogTimes[i].boxTimeIn = 0;     DogTimes[i].boxTimeOut = 0;     DogTimes[i].boxTime = 0;
    DogTimes[i].heatTime = 0;      DogTimes[i].passTime = 0;       DogTimes[i].teamTime = 0;
    DogTimes[i].teamNetto = 0;     DogTimes[i].teamPass = 0;
    DogTimes[i].Pass = 0;          DogTimes[i].Heat = 0;           DogTimes[i].Team = 0;
    DogTimes[i].TIn = 0;           DogTimes[i].SBS = 0;            DogTimes[i].Tout = 0;
    DogTimes[i].speedIn = 0;       DogTimes[i].speedOut = 0;       DogTimes[i].Fault = OFF;
    DogTimes[i].TeamName = "Blank"; DogTimes[i].DogName = "Blank";  DogTimes[i].Position = 0;
  }
  OutputDone = OFF;
  OutputCrossingCode = ON;
  DogNumber = 0;
  HeatsCompleted = 0;
  DebugTextOutput = ON;
  InterruptSensor1Counter = 0; InterruptSensor1Time = 0;DebounceSensor1 = 0;
  InterruptSensor2Counter = 0; InterruptSensor2Time = 0;DebounceSensor2 = 0;
  InterruptSensor3Counter = 0; InterruptSensor3Time = 0;DebounceSensor3 = 0;
  StartTime = 0; RaceTimeRed=0; FaultLightStartTime=0; OutPutDataTime =0;
  bFault=OFF; PassFault=OFF;
  StartSequenceHandled = OFF; NumberOfDogFaults=0;
  Status = STATE_IDLE; Transition = NO; triggerState = _OFF; LightStatus = ALL_OFF;
  FaultLightStatus =OFF; bStarted = OFF; bTeamSaved = OFF; canDisplay = OFF;
  canDisplayTime = 0;
  passTime1.Set_background_color_bco(65535);
  passTime2.Set_background_color_bco(65535);
  passTime3.Set_background_color_bco(65535);
  passTime4.Set_background_color_bco(65535);
  passTime5.Set_background_color_bco(65535);
  passTime6.Set_background_color_bco(65535);
  AllLights(OFF);
  runningStatus.setText(MSG.c_str());
  MSG = "";

}
void startRacePopCallback(void *ptr){ /*button to START or STOP ongoing SESSION*/
  uint32_t number;
  String sStatusMsg = "";
  heatsToRun.getValue(&number);
  HeatsToRun =  number;
  if (!bStarted)
  {
    bStarted = !bStarted;
    sStatusMsg = "Debouncing @ : " + String(GENERAL_DEBOUNCE) + " microseconds, over " + String(HeatsToRun) + " heats";
  }
  else
  {
    bStarted = !bStarted;
    sStatusMsg = "RACE COMPLETED, heats left over : " + String(HeatsToRun) + " heats !";
  }
  runningStatus.setText(sStatusMsg.c_str());
}
void resetTeamPopCallback(void *ptr){ /*button to RESET ALL DOGS AND TIMES for a new set of dogs to be entered*/
  String resetTimes = "0.000";
  String buttonMSG = "Start Race";
  startRace.setText(buttonMSG.c_str());
  startRace.Set_font_color_pco(65535);
  String dogMsg = "";
  MSG = "RESET :: Time's cleared, dogs cleared";
  for (int i = 0; i < MAX_BUFFER; i++)
  {
    DogTimes[i].startTime = 0;
    DogTimes[i].raceTime = 0;
    DogTimes[i].jumpHeight = "";
    DogTimes[i].inTimeIn = 0;      DogTimes[i].inTimeOut = 0;      DogTimes[i].inTime = 0;
    DogTimes[i].outTimeIn = 0;     DogTimes[i].outTimeOut = 0;     DogTimes[i].outTime = 0;
    DogTimes[i].boxTimeIn = 0;     DogTimes[i].boxTimeOut = 0;     DogTimes[i].boxTime = 0;
    DogTimes[i].heatTime = 0;      DogTimes[i].passTime = 0;       DogTimes[i].teamTime = 0;
    DogTimes[i].teamNetto = 0;     DogTimes[i].teamPass = 0;
    DogTimes[i].Pass = 0;          DogTimes[i].Heat = 0;           DogTimes[i].Team = 0;
    DogTimes[i].TIn = 0;           DogTimes[i].SBS = 0;            DogTimes[i].Tout = 0;
    DogTimes[i].speedIn = 0;       DogTimes[i].speedOut = 0;       DogTimes[i].Fault = OFF;
    DogTimes[i].TeamName = "Blank"; DogTimes[i].DogName = "Blank";  DogTimes[i].Position = 0;
  }
  OutputDone = OFF;
  OutputCrossingCode = ON;
  DogNumber = 0;
  HeatsCompleted = 0;
  DebugTextOutput = ON;
  InterruptSensor1Counter = 0;
  InterruptSensor2Counter = 0; 
  InterruptSensor3Counter = 0; 
  InterruptSensor1Time = 0;
  InterruptSensor2Time = 0;
  InterruptSensor3Time = 0;
  DebounceSensor1 = 0;
  DebounceSensor2 = 0;
  DebounceSensor3 = 0;
  StartTime = 0;
  RaceTimeRed = 0;
  FaultLightStartTime = 0;
  OutPutDataTime = 0;
  bFault = OFF;
  PassFault = OFF;
  StartSequenceHandled = OFF;
  NumberOfDogFaults=0;
  Status = STATE_IDLE;
  Transition = NO;
  triggerState = _OFF;
  LightStatus = ALL_OFF;
  FaultLightStatus = OFF;
  bStarted = OFF;
  bTeamSaved = OFF;
  canDisplay = OFF;
  canDisplayTime = 0;
  passTime1.Set_background_color_bco(65535);
  passTime2.Set_background_color_bco(65535);
  passTime3.Set_background_color_bco(65535);
  passTime4.Set_background_color_bco(65535);
  passTime5.Set_background_color_bco(65535);
  passTime6.Set_background_color_bco(65535);
  AllLights(OFF);
  runningStatus.setText(MSG.c_str());
  MSG ="";
}
void Convert(long Speed, bool field, byte dognumber) { /* 0 for inSpeed - 1 for outSpeed - bvb 1105437*/
  double CalcSpeed = 0;
  double mathSpeed = Speed / 1000000.0;
  String realSpeed = "";
  CalcSpeed = ( 11.05 / mathSpeed ) * 3.6;
  realSpeed = String(CalcSpeed, 2);
  if (!field)
  {
    kmphIn.setText(realSpeed.c_str());
    DogTimes[dognumber].speedIn = CalcSpeed;
  } else {
    kmphOut.setText(realSpeed.c_str());
    DogTimes[dognumber].speedOut = CalcSpeed;
  }
}
/* end of Nextion specific functions */

/* Light specific functions */
void WhiteLight(bool bOnOff) {
  switch (bOnOff)
  {
    case true:
      for (int i = 0; i < 8; i++)
      {
        strip.SetPixelColor(i, white);
        strip.Show();
      }
      sendCommand("cirs 600,55,15,WHITE");
      break;
    case false:
      for (int i = 0; i < 8; i++)
      {
        strip.SetPixelColor(i, black);
        strip.Show();
      }
      sendCommand("cirs 600,55,15,BLACK");
      break;
  }
}
void RedLight(bool bOnOff) {
  switch (bOnOff)
  {
    case true:
      for (int i = 8; i < 16; i++)
      {
        strip.SetPixelColor(i, red);
        strip.Show();
      }
      sendCommand("cirs 600,90,15,RED");
      break;
    case false:
      for (int i = 8; i < 16; i++)
      {
        strip.SetPixelColor(i, black);
        strip.Show();
      }
      sendCommand("cirs 600,90,15,BLACK");
      break;
  }
  return;
}
void Orange1Light(bool bOnOff) {
  switch (bOnOff)
  {
    case 1:
      for (int i = 16; i < 24; i++)
      {
        strip.SetPixelColor(i, orange);
        strip.Show();
      }
      sendCommand("cirs 600,125,15,YELLOW");
      break;
    case 0:
      for (int i = 16; i < 24; i++)
      {
        strip.SetPixelColor(i, black);
        strip.Show();
      }
      sendCommand("cirs 600,125,15,BLACK");
      break;
  }
}
void BlueLight(bool bOnOff) {
  switch (bOnOff)
  {
    case 1:
      for (int i = 16; i < 24; i++)
      {
        strip.SetPixelColor(i, blue);
        strip.Show();
      }
      sendCommand("cirs 600,125,15,BLUE");
      break;
    case 0:
      for (int i = 16; i < 24; i++)
      {
        strip.SetPixelColor(i, black);
        strip.Show();
      }
      sendCommand("cirs 600,125,15,BLACK");
      break;
  }
}
void Orange2Light(bool bOnOff) {
  switch (bOnOff)
  {
    case 1:
      for (int i = 24; i < 32; i++)
      {
        strip.SetPixelColor(i, orange);
        strip.Show();
      }
      sendCommand("cirs 600,160,15,YELLOW");
      break;
    case 0:
      for (int i = 24; i < 32; i++)
      {
        strip.SetPixelColor(i, black);
        strip.Show();
      }
      sendCommand("cirs 600,160,15,BLACK");
      break;
  }
}
void GreenLight(bool bOnOff) {
  switch (bOnOff)
  {
    case 1:
      for (int i = 32; i < 40; i++)
      {
        strip.SetPixelColor(i, green);
        strip.Show();
      }
      sendCommand("cirs 600,195,15,GREEN");
      break;
    case 0:
      for (int i = 32; i < 40; i++)
      {
        strip.SetPixelColor(i, black);
        strip.Show();
      }
      sendCommand("cirs 600,195,15,BLACK");
      break;
  }
}
void SkyLight(bool bOnOff) {
  switch (bOnOff)
  {
    case 1:
      for (int i = 48; i < 56; i++)
      {
        strip.SetPixelColor(i, sky);
        strip.Show();
      }
      //      sendCommand("cirs 600,195,15,45337");
      break;
    case 0:
      for (int i = 48; i < 56; i++)
      {
        strip.SetPixelColor(i, black);
        strip.Show();
      }
      //      sendCommand("cirs 600,195,15,BLACK");
      break;
  }
}
void PurpleLight(bool bOnOff) {
  switch (bOnOff)
  {
    case 1:
      for (int i = 40; i < 48; i++)
      {
        strip.SetPixelColor(i, purple);
        strip.Show();
      }
      //      sendCommand("cirs 600,195,15,45337");
      break;
    case 0:
      for (int i = 40; i < 48; i++)
      {
        strip.SetPixelColor(i, black);
        strip.Show();
      }
      //      sendCommand("cirs 600,195,15,BLACK");
      break;
  }
}
void AllLights(bool bOnOff) {
  switch (bOnOff)
  {
    case 1:
      for (int i = 0; i < 72; i++)
      {
        strip.SetPixelColor(i, white);
        strip.Show();
      }
      sendCommand("fill 581,32,40,187,WHITE");
      break;
    case 0:
      for (int i = 0; i < 72; i++)
      {
        strip.SetPixelColor(i, black);
        strip.Show();
      }
      sendCommand("fill 581,32,40,187,BLACK");
      break;
  }
}

/* FILE SYSTEM and SD Card */
void listDir(fs::FS &fs, const char * dirname, uint8_t levels) {
  Serial.printf("Listing directory: %s\n", dirname);

  File root = fs.open(dirname);
  if (!root) {
    Serial.println("Failed to open directory");
    return;
  }
  if (!root.isDirectory()) {
    Serial.println("Not a directory");
    return;
  }

  File file = root.openNextFile();
  while (file) {
    if (file.isDirectory()) {
      Serial.print("  DIR : ");
      Serial.println(file.name());
      if (levels) {
        listDir(fs, file.name(), levels - 1);
      }
    } else {
      Serial.print("  FILE: ");
      Serial.print(file.name());
      Serial.print("  SIZE: ");
      Serial.println(file.size());
    }
    file = root.openNextFile();
  }
}
void createDir(fs::FS &fs, const char * path) {
  Serial.printf("Creating Directory: %s\n", path);
  if (fs.mkdir(path)) {
    Serial.println("Directory created");
  } else {
    Serial.println("mkdir failed");
  }
}
void removeDir(fs::FS &fs, const char * path) {
  Serial.printf("Removing Directory: %s\n", path);
  if (fs.rmdir(path)) {
    Serial.println("Directory removed");
  } else {
    Serial.println("rmdir failed");
  }
}
void readFile(fs::FS &fs, const char * path) {
  Serial.printf("Reading file: %s\n", path);

  File file = fs.open(path);
  if (!file) {
    Serial.println("Failed to open file for reading");
    return;
  }

  Serial.print("Read from file: ");
  while (file.available()) {
    Serial.write(file.read());
  }
  file.close();
}
void writeFile(fs::FS &fs, const char * path, const char * message) {
  Serial.printf("Writing file: %s\n", path);

  File file = fs.open(path, FILE_WRITE);
  if (!file) {
    Serial.println("Failed to open file for writing");
    return;
  }
  if (file.print(message)) {
    Serial.println("File written");
  } else {
    Serial.println("Write failed");
  }
  file.close();
}
void appendFile(fs::FS &fs, const char * path, const char * message) {
  Serial.printf("Appending to file: %s\n", path);

  File file = fs.open(path, FILE_APPEND);
  if (!file) {
    Serial.println("Failed to open file for appending");
    return;
  }
  if (file.print(message)) {
    Serial.println("Message appended");
  } else {
    Serial.println("Append failed");
  }
  file.close();
}
void renameFile(fs::FS &fs, const char * path1, const char * path2) {
  Serial.printf("Renaming file %s to %s\n", path1, path2);
  if (fs.rename(path1, path2)) {
    Serial.println("File renamed");
  } else {
    Serial.println("Rename failed");
  }
}
void deleteFile(fs::FS &fs, const char * path) {
  Serial.printf("Deleting file: %s\n", path);
  File file = fs.open(path);
  if (!file)
  {
    Serial.println("No file named like this in directory");
  }
  if (fs.remove(path)) {
    Serial.println("File deleted");
  } else {
    Serial.println("Delete failed");
  }
}

Gebruikers-avatar
Berichten: 2655
Geregistreerd: 06 Aug 2016, 01:03

Re: Communicatie tussen ESP32 en Nextion 7" Enh. te traag

Berichtdoor Koepel » 19 Dec 2018, 23:20

Dat van die baudrate begrijp ik niet. Heb je korte draden en een goede GND verbinding ?

Ik heb niet met een ESP32 gewerkt, zelfs nog steeds niet met een EPS8266 :( er zijn wel een paar dingen die opvallen.

De NeoPixel library gebruikt een timing protocol. Om dat voor elkaar te krijgen worden de interrupts uitgezet !
Om snel te reageren kun je de NeoPixels vervangen door SPI clock/data gebaseerde RGB leds.

De "esp_timer_get_time()" is dat een high resolution 64-bit teller in microseconden ?
Toch gebruik je die waarde op een manier die na 50 dagen verkeerd gaat. Weet je hoe millis() en micros() te gebruiken ? Je mag bijvoorbeeld geen tijd in de toekomst berekenen. Met micros() kan dat na 70 minuten verkeerd gaan, en volgens mij gebruik je soms 32-bit variabelen. Je berekent onder andere dingen in de toekomst met 2, 3 en 4 seconden.

Het is teveel voor me om een probleem met buffers te zien. De gewone "buffer[200]" lijkt in orde. De DogTimes[MAX_BUFFER] is nog best groot en er zitten String objecten in. Die tekst binnen zo'n object zit daarom niet binnen de "DogTimes", maar "DogTimes" heeft dat String object, terwijl de tekst ergens anders in de heap zit. Je kopieert nergens een "DogTimes" object naar iets anders volgens mij, dus dat lijkt ook in orde.

Het belangrijkste onderdeel is niet duidelijk voor me. Ik zou graag een duidelijk onderscheid willen zien tussen de interrupt en de rest van de code.
Zijn de sensors mechanisch ? Is de debounce echt nodig ?
Ik weet niet of een interrupt twee maal wordt gedaan, en welke tijd berekend wordt.
Je interrupt code doet iets met debounce, en de loop() roept CheckPassing() aan, die ook weer iets met debounce doet. Dat kan ik niet overzien of dat allemaal goed gaat.

Je zou een kleine test sketch kunnen maken, die alleen één ding test (met die interrupts) en dat naar de seriele monitor stuurt.

Berichten: 4
Geregistreerd: 22 Okt 2013, 22:25

Re: Communicatie tussen ESP32 en Nextion 7" Enh. te traag

Berichtdoor YvesD » 20 Dec 2018, 21:49

Koepel schreef:De "esp_timer_get_time()" is dat een high resolution 64-bit teller in microseconden ?

ik dacht van wel : https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/esp_timer.html


Toch gebruik je die waarde op een manier die na 50 dagen verkeerd gaat. Weet je hoe millis() en micros() te gebruiken ? Je mag bijvoorbeeld geen tijd in de toekomst berekenen. Met micros() kan dat na 70 minuten verkeerd gaan, en volgens mij gebruik je soms 32-bit variabelen. Je berekent onder andere dingen in de toekomst met 2, 3 en 4 seconden.

De chrono loopt zelden langer dan 35sec. op een training, en meestal slechts 16 à 18 sec op een wedstrijd


Zijn de sensors mechanisch ? Is de debounce echt nodig ?

De sensors zijn 12v fotocellen NPN NO, die via een BC557 naar 3.3v gebracht worden en dan in de ESP32S.
De debounce is wel nodig om foutieve lezingen uit te sluiten, honden hebben staarten en poten en kunnen 2* kort na elkaar triggeren, vandaar

Gebruikers-avatar
Berichten: 2655
Geregistreerd: 06 Aug 2016, 01:03

Re: Communicatie tussen ESP32 en Nextion 7" Enh. te traag

Berichtdoor Koepel » 20 Dec 2018, 22:45

Volgens mij is er een mogelijkheid dat het na 70 minuten verkeerd gaat. Dat is 70 minuten na aanzetten, ongeacht hoe kort de tijd is die je meet.

Het blijft voor mij onduidelijk hoe een tijd gestart en gestopt wordt. De debounce is me ook niet duidelijk.

Je hebt gemeten hoelang de communicatie met het display duurt. Maar die 88 ms heeft nergens mee te maken. Als de communicatie met het display via hardware-serial gaat, dan is er een interrupt voor elk byte dat verstuurd of ontvangen wordt. Dat is heel kort. De interrupts van je sensoren hebben daar nauwelijks last van.

Ik heb de indruk dat je niet een probleem gemeten hebt, maar een probleem hebt verzonnen dat niet bestaat :o
Je kunt een tweede arduino gebruiken om een puls te geven. En dan een dag laten draaien om te kijken of het soms verkeerd gemeten wordt.

Terug naar Overige projecten

Wie is er online?

Gebruikers in dit forum: Bing [Bot], Google [Bot] en 8 gasten