ESP32, traiter le port Série avec le coeur1 ?

Bonjour,

J’essaie de faire un semoir qui sera monté sur une planteuse à patates. Il est entraîné par un moteur pas à pas.
Pour le pas à pas j’ai choisi la librairie (FastAccelStepper) qui tourne sur le coeur0 de l’ESP32, comme ça, le programme principal sur le coeur1 n’influence pas le Stepper.

Le problème vient quand j’envoie des informations sur le moniteur série, le pas à pas perd beaucoup de pas. Il fait des accoups et tourne anormalement lentement.

De ce que j’ai lu, l’ESP32 gère tous ce qui est communications sur le coeur0.

  • Donc est-ce-que je peux déplacer la gestion du port-série sur le coeur1 ?

  • Comment contrôler qu’elle cœur gère le port-série ?

Pour info: Avec le port-série au minimum, actuellement en fonctionnement, l'ESP fait ~60 x la loop() par milli-seconde.

Si ça peux aider, voilà le code actuel. Mais je vous préviens c’est en chantier et c’est un truc de novice.

//forum : https://forum.arduino.cc/c/international/francais
  //Pointeur vers RangMachine, voir: https://forum.arduino.cc/t/verifier-si-une-instance-de-bibliotheque-est-declaree/1117499/27
  //Fonction avec argument(s) optioneel voir: https://forum.arduino.cc/t/fonction-avec-argument-optionnel-qui-compile-pas/1117046
  //Connection du codeur voir: https://forum.arduino.cc/t/codeur-npn-5v-24v-sur-esps32-3-3v/1118626

#define version   V0_4_02
// Description:
    //
  //Archithecture:
    //Micro-contrôleur: ESP32_38pins
    //Codeur: 600points/tour  >> informe de la distance parcourue par la roue de la machine
    //Pas-à-pas Nena../200step/tour >> entraine la roue doseuse du semoire
    //Driver A4988  >> pilotage du moteur pas-à-pas.  (avec ESP32, voir: https://www.youtube.com/watch?v=6rjTFtLgqZU)
    //Boost-voltage 12-24V   (optionnel) >> sert à transformer le ~12v du véhicule en 24v pour le moteur, plus grand régime avec 24v qu'avec les ~13,5v du véhicule) 
    //Pour chaque rang de la planteuse
      //Un capteur de passage de plant >> sert à détecter si un plant à réellement été planté. (pour les pattates, j'utilise un switch sur la chaîne d'allimentation)
      //Led témions-manque LED5mm_Rouge  >> indicateur lumineux servent à avertire de chaque plant non détecté par le capteur de passage ou la mise en alarme du rang
      //>>Pas encors paramètré<< //Led rang-actif LED3mm_verte >> indique si le rang de la planteuse est activé
    //Les autres switchs (interrupteurs)
      //[swSemeOn]  >> active le semoire
      //[swPlanteOn]  >> active les rang de la planteuse
      //[swMoteurOn]  >> activation mannuel du moteur du semoire (pour purger le mécanisme, par exemple)
      //[swAlReset]  >> effacer les alarmes et réinitaliser les paramètres d'alarme après résolution du problème (les anciennes valeurs seront conservées pour les statistiques finals mais plus utilisées pour les alarmes)
      // swBuzzerOff >> pour éteindre l'alarme sonor. (Brancher directement sur le câble d'allimentation du buzzer ou sur son relais)
    //Les autres témoins
      //Lampe Alarme central  >> Relais activant un témions lumineux d'alarme centralisée
      //Buzzer Alarme central >> Relais activant un témoins sonor d'alarme centralisée
      //LedSemOn LED5mm_Vert  >> allumée lorce-que le semoire est actif
      //LedPlanteON LED5mm_vert >> allumée si tous les rang de la planteuse sont actif, clignotte si les rang sont partiellement actif.


//Modifications:
  //V0_3_0 et V0_3_01
    //-mise à jour de la position current du stepper à 2'146'000'111
      //-lors de la mise à jour avec [setCurrentPosition()] ou [addCurrentPosition()], [getCurrentPosition()] prend un certin temps à ce stabiliser.
        // ce temps de stabilisation fait perdre quelques pas au moteur. donc ma solution est de le faire le moins souvent possible
      // je le fait que quand le compteur dépasse 2 milliard de stepp (ou nStepperTour dépasse 60'000).
    //-correction de l'addition des stepps pour le calcul de la vitesse
    //-correction du calcul de vitesse (ajout de la ligne :TempVtI ++;)pour tenir compte du dernier enregistrement
      // [#define DEBUGcalculSpeed] pour vérifier le calcul de la vitesse
    //-déplacement des Pins du codeur (à 0 et 2 celà empèche le téléverssement; déplacer au 26 et 27)
    //-ajout variable nStepperTour: éviter que le moteur s'embale à cause d'une décélération trop lente
        //-avec l'ancienne version, le moteur s'embalait lors d'arrêt brusque, il décélairait pas asseé vite et recommancait une nouvelle boucle ect...ect...
        //-avec l'ajout de [nStepperTour] le retard/avance du moteur est calculé sur beaucoup-plus de tours.
    //-amélioration du calcul de retard (lissage) à l'aide du traceur série ([#define DEBUGstepperValTraceur])
  //V0_3_02
    // mise à jours des variables de vitesse
    // ajout des fonctios de vitesse
    // ajout des fonctions de distance
    // changement du calcul de vitesse du stepper (sans pris en charge de la vitesse d'avancement, "plus réactif")
    // ALARME SUR-VITESSE : ajout d'une alarme de vitesse limite du stepper (rpm trop rapide)
    // ajout lampe alarme centrale sur Pin 25
    // remplacer [vtSteppSec] Par [vtSteppMin]
    // ajout switch on-off plante et on-off seme  >>[swPlanteOn] et [swSemeOn]
    // Mise en place de la bibliothèque [rangMachine]
  //V0_3_03
    //  transformer les rangMachine en tableau de pointeurs autoévolutif celon le nombre de rangs
      //paramètrer le logitiel à la bibliothèque [rangMachine]
    // corriger la fonction [majAlarme()]
    // intégrer le buzzer à l'alarme central [majAlarme()]
    // paramètrer switch on-off plante et on-off seme  >>[swPlanteOn] et [swSemeOn]
    // ajouter un switch purger [swMoteurOn] pour purger manuellement le semoir avant l'étalonage. (aussi utile pour un contrôle visuel de fonctionnement du semoir)
  //V0_4_01
    // refaire le Debouns switch dans [rangMachine::addPoints()] est réécriture des déclancheurs, ajout moyenne majEspacePlants
  //>>> A FAIRE:
    // terminer la bibliothèque [rangMachine]
    // nettoyer la bibliothèque [rangMachine]
    // faire les fonctions de statistiques de la planteuse (partielement fais)
    // faire les fonctions de statistiques du semoire
    // ajout distance semée (différant de distance plantée)>> [cptPntDistSeme] / [cptPntDistPlante] /global [cptPntDist]
    // contrôler les calcules de vitesses, la vitesse du PàP me semble incoérante
    // Ajouter un capteur de hall sur le rouleau pour contrôler le blocage du semoir et faire les fonctions en découlant
    // A tester: Envoyer les changements de vitesse au stepper au minimum toutes les 2millis()
    // A tester: Déplacer le "Serial.beguine" sur le coeur1

//FIN modif

#include <Arduino.h>
#include <FastAccelStepper.h>
  FastAccelStepperEngine engine = FastAccelStepperEngine();
  FastAccelStepper *stepper;
#include "rangMachine.h"
    const uint8_t nbrlignePlanteuse = 2;  // nombre de lignes de la planteuse >> actuellement maximum 4 lignes

//LES PINS
  //codeur
  const uint8_t codeurAPin = 14;//27;
  const uint8_t codeurBPin = 27;//14;
 
  //stepper
  #define stepPinStepper 16
  #define enablePinStepper 17
  #define dirPinStepper 4
 
  //rang planteuse (switch et led manque un plant)
  const uint8_t rangPinSwitch[4]{23, 21, 18, 2};
  const uint8_t rangPinLedManque[4]{22, 19, 5, 15};
  //Old variante: rangMachine rang1(23,22);
    //rangMachine rang2(21,19);
    //rangMachine rang3(18,5);
    //rangMachine rang4(2,15);

  //switchs
  const uint8_t swSemeOn = 36;//35;
  const uint8_t swPlanteOn = 39;//32;
  const uint8_t swAlReset = 35;//25;
  const uint8_t swMoteurOn = 34;//33;
    // swBuzzerOff >> Brancher directement sur le câble d'allimentation du buzzer ou sur son relais

  //témoins
  //const uint8_t ledStepper = 18;  >> branchée sur enablePinStepper et VC
  const uint8_t ledAlCentral = 32;
  const uint8_t buzzAlCentral = 33;
  const uint8_t ledSemeOn = 26;
  const uint8_t ledPlanteOn = 25;

//FIN des pins

//#define DEBUG
  #ifdef DEBUG
    //#define DEBUGloopStepp_stepp
    #define DEBUGloopSpeed    //V0.3.4 Environ de 60'400 loop/s; V0.4.0(2rangs) ~59'000 loop/s
    //#define DEBUGAlarme
    //#define DEBUGswitch
    //#define DEBUGcodeur
    //#define DEBUGcodeurSpeed
    //#define DEBUGcalculSpeed
    //#define DEBUGstepper
    //#define DEBUGenableOutputs
    //#define DEBUGstepperValeurs
    //#define DEBUGstepperValTraceur   //comme [DEBUGstepperValeurs] mais sur le traceur série
    //#define DEBUGstepperSpeed
    //#define DEBUGmanques
  #endif  
      
  #ifdef DEBUGloopSpeed
    uint16_t DebugCptLoop = 1;
    uint16_t DebugCptLoopMultiple = 1;
    uint32_t DebugTimmerLoop = millis();
  #endif
  #ifdef DEBUGAlarme
    byte DebugAlarme1 = 99;
    uint8_t DebugAlOld_cptManqueRapide = 0;
    uint32_t DebugAlOld_cptManque = 0;
    uint64_t DebugAlOld_cptPlant = 0;
  #endif
//FIN debug
#define InfoSerialMoniteur            //Afficher les information importante du déroulement du programmme sur le moniteur série

//LES VARIABLES :
  //Variables Etalonnage
    const uint16_t steppTour = 2000;    //nombre de pas pour un tour machine (peut-hêtre varier pour modifier la precision de l'étalonnage. Ici = 10 tours du moteur pas-à-pas.)
    const uint16_t pntSteppTour = 12000; //nombre de points de codeur pour un tour machine (1[steppTour]).
    const uint32_t pnt100m = 100000;    //nombre de points du codeur pour une distance de 100 mètres.
    const int8_t valeurPnt = -1;        //valeur d'un point; 1 = horaire; -1 = anti-horaire
    const uint16_t timelapseVt = 16;   //temps entre deux mesure de vitesse (ne pas déssendre en dessous de 10 pour une vitesse stable)

  //Varible Planteuse
    rangMachine* lignePlanteuse[nbrlignePlanteuse];
    const uint16_t distancePlant = 570;   // distance en points entre chaque plants
    //const uint16_t debouncePlante = distancePlant/3;  // distance de passage d'un plant sous le switch (1pnt ~ 1mm d'avancement de la planteuse)
    byte valRangAlarme[nbrlignePlanteuse];
    byte oldValRangAlarme[nbrlignePlanteuse];

  //Variables points et stepps
    int16_t codeurPnt = 0 ;             //nombre de points enregistrés par le codeur pas encors traités dans la boucle
    int16_t newPnt = 0;                 //nombre de points traités par la boucle en cour d'exécution.
    int16_t newPntStepper = 0;          // nombre de points pour le semoir
    int32_t lastPntPos = 0;             //position du codeur (tour machine) lors de la boucle précédante.
    int32_t lastSteppPos = 0;          //position du stepper (tour machine) lors de la boucle précédante.
    uint16_t nStepperTour = 0;          //nombre de fois [steppTour] à enlever à [stepper->getCurrentPosition] pour avoir ça position "angulaire"
    int16_t newStepp = 0;               //nombre de pas à ajouter pour la boucle en cour d'exécution.
    uint16_t cptPntVt = 0;              //nombre absolut de points à ajouter pour le calcul de la vitesse { += abs(newPnt)}.
    int32_t cptPntDist = 0;               //nombre de points du compteur de distance parcourue. Compteur vidé tous les kilo-mètres dans [cptPntKm].
    int16_t cptPntKm = 0;               //nombre de kilomètres parcourus par la machine.
    int32_t cptPntDistSeme = 0;               //nombre de points du compteur de distance parcourue. Compteur vidé tous les kilo-mètres dans [cptPntKmSeme].
    int16_t cptPntKmSeme = 0;               //nombre de kilomètres parcourus par la machine.
    int32_t cptPntDistPlante = 0;               //nombre de points du compteur de distance parcourue. Compteur vidé tous les kilo-mètres dans [cptPntKmPlante].
    int16_t cptPntKmPlante = 0;               //nombre de kilomètres parcourus par la machine.

  //Variables temps et vitesses
    uint32_t lastTime = millis();       //milliseconde de référence lors de la boucle précédante.
    uint32_t newTime = lastTime;        //milliseconde de référence lors de la boucle en cour d'exécution.
    uint32_t newTimelapseVt = millis() + timelapseVt; //délais pour la prochaine mesure de vitesse   += [timelapseVt]
    uint16_t tblPntVt[21];              // tableau pour le stockage du nombre de points vitesse mesurés. (Utilisé pour lissage de la vitesse mesurée).
    int8_t iTblPntVt = -20;             //position de la case du tableau en cour d'écriture.
    bool jTblPntVt = true;              //première ou deusième mesure de vitesse pour moyenner la case en cour d'écriture. (chaque case du tableau contient les somme des deuxdirnière mesures, sauf au démarrage, il y a une mesure fois deux dans chaque case pour gagner en vitesse de mise à jour)
    uint32_t vtPntMin;                  //vitesse d'avancement en points/minutte.
    int32_t vtSteppMin;                 //vitesse moteur en stepp/minutte
    float vtMsec;                       //vitesse d'avancement en mètres/seconde

  //Avertissement et communications: ->lampes témoins; signal sonore; communication avec le boitier de commande; communication avec le GPS; ...
    //Variables alarmes
    uint32_t lastTimeAlBlink = millis();  //dernière fois que la lampe alarme centrale à été allumée
    uint32_t lastTimeAlBuzz = millis();
    int8_t etatAlLampe = LOW;           // état de la lampe alarme centrale >> 0 = éteinte; 1 = allumée
    int8_t etatAlBuzz = LOW;
    byte alarme1 = 0;   //bit0 = alarmeOn;
    byte oldAlarme1 = 0;//bit1 = alarme ligne 1;
                        //bit2 = alarme ligne 2;  
                        //bit3 = alarme ligne 3;
                        //bit4 = alarme ligne 4;  
                        //bit5 = PàP trop vite;
                        //bit6 = PàP bloqué;      
                        //bit7 = buzzerOn;       
      
      //bit à bit Voir: https://www.locoduino.org/spip.php?article70
        ////bitWrite(x, n, b) permet d’écrire un bit. Le premier argument, x est la donnée où on écrit le bit, le second argument, n est le numéro du bit et le 3e, b est la valeur à écrire, 0 ou 1.
        //bitRead(x, n) permet de lire un bit. Le premier argument, x est la donnée d’où on lit le bit, le second argument, n est le numéro du bit.
        //bitSet(x, n) permet de mettre à 1 un bit. Le premier argument, x est la donnée où on écrit le bit, le second argument, n est le numéro du bit
        //bitClear(x, n) permet de mettre à 0 un bit. Le premier argument, x est la donnée où on écrit le bit, le second argument, n est le numéro du bit

  //Autres variables
    //Switch pilotage
    bool swSeme = false;// = digitalRead(swSemeOn);
    bool swPlante = false;// = digitalRead(swPlanteOn);
    uint32_t swSemPlanDebounce = 0;
    //bool alReset = false;
    //bool saveSD = false;

    //Compteurs de manques: -> contrôle si un planton déclanche le switch tous les x centimètres sur chaque ligne de la planteuse
      //>>> Remplacer par la bibliothèque [rangMachine]
    

    //Variables Stepper
    int16_t miniSteppSpeed = 5;
    int16_t maxiSteppSpeed = 1333;  //1667 = 500RPM; 1500 = 450RPM; 1333 = 400RPM; ...
    int32_t newSpeedStepp = 0;
    int32_t retardStepp = 0;
    int32_t lastRetardStepp = 0;
    int32_t majSpeedStepp = 0;
    bool stepperOn = false;
    // //Ancienne version: int8_t iMajStepperCurrentPos = 0;   //compteur pour éviter la re-mise-à-jour du compteur de position du PàP avant son activation complette

//FIN des variables
void manuelMoteurOn(uint16_t ManuelOnSpeed = 100);  //Voir: https://forum.arduino.cc/t/fonction-avec-argument-optionnel-qui-compile-pas/1117046/5

void setup() {

  
  //#if (defined DEBUG || defined InfoSerialMoniteur)
    Serial.begin(115200);
    delay (5);
    #ifdef DEBUG
      Serial.println("\t\t  S T A R T  (setup)");
    #endif
  //#endif//DEBUG

  //Pins Mode
    pinMode(codeurAPin, INPUT_PULLUP);
    pinMode(codeurBPin, INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(codeurAPin), comptePnt, RISING); //RISING ; CHANGE);
    pinMode(swSemeOn, INPUT);  // pull-up externe  >>INPUT_PULLUP);
    pinMode(swPlanteOn, INPUT);  // pull-up externe  >>INPUT_PULLUP);
    pinMode(swAlReset, INPUT);  // pull-up externe  >>INPUT_PULLUP);
    pinMode(swMoteurOn, INPUT);  // pull-up externe  >>INPUT_PULLUP);
    pinMode(ledAlCentral, OUTPUT);
    pinMode(buzzAlCentral, OUTPUT);
    pinMode(ledSemeOn, OUTPUT);
    pinMode(ledPlanteOn, OUTPUT);

  //Initialiser les rang
    memset(lignePlanteuse, 0, sizeof lignePlanteuse); //=> Initialise les pointeurs créés ci-dessus à NULL
    memset(valRangAlarme, 0, sizeof valRangAlarme);
    memset(oldValRangAlarme, 0, sizeof oldValRangAlarme);

    for (uint8_t i = 0; i < nbrlignePlanteuse; i++) {
      lignePlanteuse[i] = new rangMachine (rangPinSwitch[i], rangPinLedManque[i]);
    }

  //Initialiser le Pas_à_pas
    engine.init();
    stepper = engine.stepperConnectToPin(stepPinStepper); // ### ESP32 * allows up to 200000 generated steps per second
    if (stepper) {
      stepper->setDirectionPin(dirPinStepper);
      stepper->setEnablePin(enablePinStepper);
      stepper->setSpeedInHz(10);
      stepper->setAcceleration(6000);    //steps/s²
      stepper->setCurrentPosition(0);
      stepper->setAutoEnable(true);   //void setAutoEnable(bool auto_enable);
      stepper->setDelayToEnable(60);  //int8_t setDelayToEnable(uint32_t delay_us);
      stepper->setDelayToDisable(1500);  //void setDelayToDisable(uint16_t delay_ms);
      if (stepper->getCurrentPosition() >= steppTour) {
        nStepperTour = int(stepper->getCurrentPosition() / steppTour);
      }
    }

  digitalWrite(ledAlCentral, etatAlLampe);

  #ifdef InfoSerialMoniteur
    Serial.println ("Informations sur le moniteur série activées");
  #endif
  #ifdef DEBUG
    Serial.println ("Mode DEBUG activé");
  #endif
  #if (defined DEBUG || defined InfoSerialMoniteur)
    Serial.println("*********************************************************END SETUP***");
  #endif//DEBUG
  delay(5);
}

void loop() {
  //Initialise les varibles traitées pou cette boucle
            #ifdef DEBUGloopStepp_stepp
              Serial.print("DEBUGloopStepp_stepp: A01, ");
            #endif//DEBUG
    newPnt = codeurPnt;
    newTime = millis();

    //Contrôle les switchs
            #ifdef DEBUGloopStepp_stepp
              Serial.print("02, "); //A_02
            #endif//DEBUG

      if(swSemPlanDebounce < millis()){
        if(!swSeme != digitalRead(swSemeOn)){
          swSeme = digitalRead(swSemeOn);   swSeme = !swSeme;
          swSemPlanDebounce = millis()+20;
Serial.println("\nSeme switch changé");
                #ifdef DEBUGswitch
                if(swSeme) Serial.println("Seme ON"); else Serial.println("Seme OFF");
                #endif
        }
        if(!swPlante != digitalRead(swPlanteOn)){
          swPlante = digitalRead(swPlanteOn); swPlante = !swPlante;
          swSemPlanDebounce = millis()+20;

          #ifdef DEBUGswitch
          if(swPlante) Serial.println("Plante ON"); else Serial.println("Plante OFF");
          #endif
        }
      }
            #ifdef DEBUGloopStepp_stepp
              Serial.print("03, ");
            #endif//DEBUG
      if (!digitalRead(swAlReset)) alarmeReset();
            #ifdef DEBUGloopStepp_stepp
              Serial.print("04, ");
            #endif//DEBUG
      if (!digitalRead(swMoteurOn)) manuelMoteurOn();

  //Calcul de la distance et vitesse d'avancement
          #ifdef DEBUGloopStepp_stepp
            Serial.print("| C01, ");
          #endif//DEBUG
    if (newPnt != 0) {
      addDistance();
    }
    else newPntStepper = 0;
    
    cptPntVt += abs(newPnt);
    if (newTimelapseVt <= newTime) {
      addVt();
      newTimelapseVt += timelapseVt; 

        #ifdef DEBUGstepperValTraceur
          Serial.print("");      Serial.print(retardStepp);
          Serial.print(" , ");      Serial.print(majSpeedStepp);
          Serial.print(" , ");      Serial.print(newSpeedStepp);
          Serial.print(" , ");      Serial.println(vtSteppMin/60);
        #endif
    }

  //Convetie les points en stepp    >> newStepp = nombre de points à ajouter au moteur
          #ifdef DEBUGloopStepp_stepp
            Serial.print("| B01, ");
          #endif//DEBUG
    newStepp = ((lastPntPos + newPntStepper) * steppTour / pntSteppTour) - lastSteppPos;
    if(newStepp < 1) {    //éviter au moteur de tourner en arrière
      newStepp = 0;
    }

  //Evoye les points aux rangs et contrôle les alarmes manques
    #ifdef DEBUGloopStepp_stepp
      Serial.print("| D01, ");
    #endif//DEBUG

    for(int i = 0; i < nbrlignePlanteuse; i ++){
      valRangAlarme[i] = lignePlanteuse[i]->addPoints(newPnt, true);  //.addPoints(nombre_points_a_ajouter, rang_activé) retourne: byte rang_Alarmes (voir bibliothèque pour détails)
      if(valRangAlarme[i] > 1) {bitSet(alarme1, i+1);}
      else if(valRangAlarme[i] == 1) { }
      else {bitClear(alarme1, i+1);}
    }

  //Controle le retard et adapte la vitesse du moteur
    #ifdef DEBUGloopStepp_stepp
      Serial.print("| E01, ");
    #endif//DEBUG
    int32_t TempStepperAngle = stepper->getCurrentPosition() - nStepperTour * steppTour;
    retardStepp = (lastSteppPos + newStepp) - TempStepperAngle;
    int32_t reelSpeedMoteur = 0;
    if(swSeme) {
      reelSpeedMoteur = stepper->getCurrentSpeedInMilliHz()/1000;
    }
    majSpeedStepp = (retardStepp + (abs(reelSpeedMoteur) +1)/10) * 5; // [x10] pour compensser dans le 10èmme de seconde // [-vtSteppMin/60 / Y] pour avoir un temp de décélération    
    newSpeedStepp = (majSpeedStepp);
    if (newSpeedStepp < miniSteppSpeed) {newSpeedStepp = 0;}
    else if (newSpeedStepp > maxiSteppSpeed) {newSpeedStepp = maxiSteppSpeed;}
    else if (reelSpeedMoteur > 1500) {stepper->setAcceleration(2000);}
    else if (reelSpeedMoteur < 1400 && reelSpeedMoteur > 1100) {stepper->setAcceleration(5000);}
    else {stepper->setAcceleration(10000);}

      // //Test vélossité : vitesse envoyé - vitesse réelle >>> voir version 0_3_02
    #ifdef DEBUGstepperSpeed
      //Serial.print("points de retard ");      Serial.print(retardStepp);
      //Serial.print("\tpoints logitiel "); Serial.print(lastSteppPos);
      //Serial.print("\tpoints moteur ");      Serial.print(stepper->getCurrentPosition());
      //Serial.print("\tmise à jour vitesse "); Serial.print(majSpeedStepp);
      Serial.print("\tvitesse calculcodeur "); 
      Serial.print(vtSteppMin/60);
      Serial.print("\tvitesse points/s ");             
      Serial.print(vtPntMin/60); 
    #endif
    
  //envoye la nouvelle vitesse au moteur  //>> newSpeedStepp = vitesse à envoyer au moteur
    #ifdef DEBUGloopStepp_stepp
      Serial.print("| F01, ");
    #endif//DEBUG
    stepperOn = stepper->isRunning(); //Renvoye vrai pendant l'arrêt du moteur (décélération jusqu'au stop)
    if (newSpeedStepp != 0) {
      stepper->setSpeedInHz(newSpeedStepp);
      if (!stepperOn) {
        stepper->runForward();
      }
      else {
        stepper->applySpeedAcceleration();
      }
      //stepper->move(newStepp);  //le PaP est régulé uniquement par la vitesse. (le nombre de pas influence la vitesse par l'intermédiaire du [retardStepp])
      #ifdef DEBUGstepperSpeed
        Serial.print(" | newSpeedStepp\t");             
        Serial.print(newSpeedStepp);
      #endif
    }
    else {
      if (stepperOn) {
        stepper->applySpeedAcceleration();  //Pour appliquer la valeur de décélération pendant l'arrêt du moteur
        stepper->stopMove();
        #ifdef DEBUGstepperSpeed
          Serial.print("\tArrêt du moteur envoyé");
        #endif
      }
      else {
      //else if (stepper->isEnableStepper()) { //Trouver la fonction qui renvoie l'état de la pin enable du moteur !! getEnablePinHighActive()ne fonctionne pas
        #ifdef DEBUGstepperSpeed
          Serial.print("\tMoteur est à l'arrêt et il est désactivé");
        #endif
        if (stepper->getCurrentPosition() > 2000111222){  // ~ 147'000'000 de stepp avant le bouclage automatique du comteur [int32_t]
          majStepperCurrentPos();  //profiter de l'arrêt du PàP pour remettre "à zéro" son compteur de position
        }
        else if (nStepperTour > 55000) {
          majStepperCurrentPos();  //profiter de l'arrêt du PàP pour remettre "à zéro" son compteur de position
        }
      }
      #ifdef DEBUGstepperSpeed
        Serial.print("\tnewSpeedStepp :\t");             
        Serial.print(newSpeedStepp);
      #endif
    }
    #ifdef DEBUGstepperSpeed
      Serial.println();  
    #endif

    #ifdef DEBUGenableOutputs
      //Serial.println(stepper->enableOutputs());
      //Serial.println(stepper->disableOutputs());
    #endif
    
    #ifdef DEBUGstepperValeurs
      Serial.print("> isRunning ");       Serial.print(stepper->isRunning());
      Serial.print("\tisStopping ");      Serial.print(stepper->isStopping());
      //Serial.print("\t||\tretard ");      Serial.print(stepper->disableOutputs());//>>Modifie la valeur Enable à false    //bool disableOutputs();returns true, if disabled
      //Serial.print("\tenableOutputs ");       Serial.print(stepper->enableOutputs());//>>Modifie la valeur Enable à true    //bool enableOutputs();returns true, if enabled
      Serial.print("\t||\tretard ");      Serial.print(retardStepp);
      Serial.print("\tmajSpeedStepp ");      Serial.print(majSpeedStepp);
      Serial.print("\tnewSpeedStepp ");      Serial.print(newSpeedStepp);
      Serial.print("\tvtSteppSec ");      Serial.print(vtSteppMin/60);
      Serial.print("\tvtPntMin ");      Serial.print(vtPntMin);
      Serial.print("\tgetSpeedInHz ");        Serial.print(stepper->getSpeedInMilliHz()/1000);//uint32_t getSpeedInMilliHz()
      //Serial.print("\txxx ");                 Serial.print(xxx);
    #endif

  //Contrôle du steppermotor
    #ifdef DEBUGloopStepp_stepp
      Serial.print("| G01, ");
    #endif//DEBUG
    if (stepperOn){
      if (newSpeedStepp >= maxiSteppSpeed || vtSteppMin/60 >  maxiSteppSpeed *18/20){
        bitSet(alarme1, 5);    //Alarme On
      }
      else if (bitRead(alarme1, 5)){
        if (newSpeedStepp < maxiSteppSpeed *19/20 && vtSteppMin/60 <  maxiSteppSpeed *26/30){
          bitClear(alarme1, 5); //AlarmeOff
        }
      }
    }
  
  //Réinitialisation des variables
    #ifdef DEBUGloopStepp_stepp
      Serial.print("| H01, ");
    #endif//DEBUG
    lastTime = newTime;
    codeurPnt -= newPnt;
    lastPntPos += newPntStepper;
    lastSteppPos += newStepp;
    if (lastPntPos >= pntSteppTour) {
      lastPntPos -= pntSteppTour;
      lastSteppPos -= steppTour;
      nStepperTour ++;
      //Si le compteur arrive à ça limite, vidange des compteurs. (normalement se fait avant d'arriver à ce stade de remplissage, quand le moteur est à l'arrêt)
      if (stepper->getCurrentPosition() > 2146000123 || nStepperTour > 64000) {
        majStepperCurrentPos();
        }
    }
    lastRetardStepp = retardStepp;

    if (alarme1 != 0) majAlarme();  //ATTEENTION, c'est majAlarme qui doit metre le 1er bit à zéro pour permettre l'extinction de l'alarme
  
  //#ifdef DEBUG...
    #ifdef DEBUGloopStepp_stepp
      Serial.println("| I01, ");
    #endif//DEBUG
    #ifdef DEBUGloopSpeed
      DebugCptLoop ++;
      if(DebugCptLoop>10000){
      Serial.print("*");
        DebugCptLoop = 1;
        DebugCptLoopMultiple ++;
        if(DebugCptLoopMultiple>100){
          DebugCptLoopMultiple = 1;
          Serial.println( "1'000'000 de loop");
          Serial.print(" (millis pour 1*10^6 loop = ");
          Serial.print(millis()- DebugTimmerLoop);
          Serial.print(" | loop/s = ");
          Serial.print(1000000000 / (millis()- DebugTimmerLoop));
          Serial.println(" )");
          DebugTimmerLoop = millis();
        }
      }
    #endif
    #ifdef DEBUGAlarme
      //Rang à analyser:
      #define _TempRang  1
              #ifdef _TempRang
                if(lignePlanteuse[_TempRang] != NULL) {
                  if(lignePlanteuse[_TempRang]->getNbrPlanter() != DebugAlOld_cptPlant){
                    Serial.print("O");
                    DebugAlOld_cptPlant = lignePlanteuse[_TempRang]->getNbrPlanter();
                  }
                  //else if(lignePlanteuse[_TempRang]->getNbrManquer() != DebugAlOld_cptManque){
                  if(lignePlanteuse[_TempRang]->getNbrManquer() != DebugAlOld_cptManque){
                    Serial.print("X");
      //testDEBUG: Serial.println(lignePlanteuse[_TempRang]->getNbrManquer()); delay(300);
                    DebugAlOld_cptManque = lignePlanteuse[_TempRang]->getNbrManquer();
                  }
                  //else {Serial.print(".");}
                }
              #endif

      if (alarme1 != DebugAlarme1){
        Serial.print ("byte alarme1 = "); Serial.print(alarme1);
        if(bitRead(alarme1, 1)) Serial.print ("\t>> alarme ligne1");
        if(bitRead(alarme1, 2)) Serial.print ("\t>> alarme ligne2");
        if(bitRead(alarme1, 3)) Serial.print ("\t>> alarme ligne3");
        if(bitRead(alarme1, 4)) Serial.print ("\t>> alarme ligne4");
        if(bitRead(alarme1, 5)) Serial.print ("\t>> alarme trop vite");
        if(bitRead(alarme1, 6)) Serial.print ("\t>> alarme semoir bloqué");
        for(int i = 0; i < nbrlignePlanteuse; i ++){
          if(bitRead(alarme1, i+1)){
            byte _TempAlarmeRangByte = lignePlanteuse[i]->getAlarme();
            Serial.print ("\n >>> byte alarme ligne "); Serial.print(i+1); Serial.print(" = "); Serial.print(_TempAlarmeRangByte);
            if(bitRead(_TempAlarmeRangByte, 0)) Serial.print ("\t>> Manque un plant");
            if(bitRead(_TempAlarmeRangByte, 1)) Serial.print ("\t>> alarme manques répétés");
            if(bitRead(_TempAlarmeRangByte, 2)) Serial.print ("\t>> alarme % manque dépassé");
            if(bitRead(_TempAlarmeRangByte, 3)) Serial.print ("\t>> alarme capteur bloqué à ON");
            if(bitRead(_TempAlarmeRangByte, 4)) Serial.print ("\t>> alarme plants trop proche");  //Alarme pas encors programmée
            if(bitRead(_TempAlarmeRangByte, 5)) Serial.print ("\t>> alarme bit5");                //Alarme pas utilisée
            if(bitRead(_TempAlarmeRangByte, 6)) Serial.print ("\t>> alarme bit6");                //Alarme pas utilisée
            if(bitRead(_TempAlarmeRangByte, 7)) Serial.print ("\t>> alarme bit7");                //Alarme pas utilisée
          }
        }
        DebugAlarme1 = alarme1;
        Serial.println();
      }
    #endif
    #ifdef DEBUGstepperValeurs
      Serial.println(" >> next loop >>");
    #endif

  #ifdef InfoSerialMoniteur
    printInfoSerialMoniteur();
  #endif
}

void majStepperCurrentPos(){
      
  if (nStepperTour > 2){    //Contrôle si la mise à jour à u le temp de s'activer;
    int32_t TempStepperPos = stepper->getCurrentPosition();
    stepper->setCurrentPosition(TempStepperPos - nStepperTour * steppTour);
    nStepperTour = 0;

      #ifdef DEBUG
        Serial.println("\n\n*****************************************************");
        Serial.print("stepper->getCurrentPosition() :\t");
        Serial.println(TempStepperPos);
        Serial.println("\n\tMise à jour de la position de moteur pas à pas\n");
        delay(5);
        Serial.print("stepper->getCurrentPosition() :\t");
        Serial.println(stepper->getCurrentPosition());
        Serial.println("\n*****************************************************\n");
      #endif
  } else {
      #ifdef DEBUG
        Serial.println("\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
        Serial.println("\tmaj ANNULEE de la position de moteur pas à pas\n");
        Serial.print("stepper->getCurrentPosition() :\t");
        Serial.println(stepper->getCurrentPosition());
        Serial.println("\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
      #endif
  }
}

void addDistance(){
  if (swSeme) newPntStepper = newPnt; else newPntStepper = 0;
  if (newPnt < 0){
    if (cptPntDist > newPnt * -1) {
      cptPntDist += newPnt;
    }
    else if (cptPntKm > 0){
      cptPntDist += pnt100m * 10;
      cptPntKm --;
      cptPntDist += newPnt;
    }
    else {cptPntDist = 0;}
    if(swSeme){
      if (cptPntDistSeme > newPnt * -1) {
        cptPntDistSeme += newPnt;
      }
      else if (cptPntKmSeme > 0){
        cptPntDistSeme += pnt100m * 10;
        cptPntKmSeme --;
        cptPntDistSeme += newPnt;
      }
      else {cptPntDistSeme = 0;}
    }
    else {cptPntDistSeme = 0;}
    if(swPlante){
      if (cptPntDistPlante > newPnt * -1) {
      cptPntDistPlante += newPnt;
      }
      else if (cptPntKmPlante > 0){
        cptPntDistPlante += pnt100m * 10;
        cptPntKmPlante --;
        cptPntDistPlante += newPnt;
      }
      else {cptPntDistPlante = 0;}
    }
    else {cptPntDistPlante = 0;}
  }
  else {
    cptPntDist += newPnt;               //nombre de points du compteur de distance parcourue. Compteur vidé tous les kilo-mètres dans [cptPntKm].
    if(swSeme) cptPntDistSeme += newPnt;
    if(swPlante) cptPntDistPlante += newPnt;
  }
  if (cptPntDist >= pnt100m * 10) {
    cptPntKm ++;               //nombre de kilomètres parcourus par la machine.
    cptPntDist -= pnt100m * 10;
  }
  if (cptPntDistSeme >= pnt100m * 10) {
    cptPntKmSeme ++;               //nombre de kilomètres parcourus par la machine.
    cptPntDistSeme -= pnt100m * 10;
  }
  if (cptPntDistPlante >= pnt100m * 10) {
    cptPntKmPlante ++;               //nombre de kilomètres parcourus par la machine.
    cptPntDistPlante -= pnt100m * 10;
  }
}
void addVt(){
  int8_t TempVtI = 20;
  int32_t TempVtSommePnt = 0;

  if (iTblPntVt < 0){   //enregistrement simple au demarrage
    TempVtI += iTblPntVt;
    tblPntVt[TempVtI] = cptPntVt * 2;
    iTblPntVt ++;
    TempVtI ++;
    jTblPntVt = true;
  }
  else {    //Enregistrement double si différent de 0 points / seconde  (pour faire désendre plus rapidement lors d'arrêt brusque)
            //>> implique qu'il y est aumoins 1 point pendant timelapseVt[millis] pour la vitesse minimum
    if (jTblPntVt) {
      tblPntVt[iTblPntVt] = cptPntVt * 2;
      if (cptPntVt == 0) {
        iTblPntVt ++;
      }
      else {
        jTblPntVt = false;
      }
    }
    else {
      // uint16_t TempTblVal  = tblPntVt[iTblPntVt] / 2;
      // tblPntVt[iTblPntVt] = TempTblVal + cptPntVt;
      tblPntVt[iTblPntVt] = tblPntVt[iTblPntVt] / 2 + cptPntVt;
      iTblPntVt ++;
      jTblPntVt = true;
    }
  }

  if (iTblPntVt > 19) {
    iTblPntVt = 0;
  }
  //Calculs
  for (int i=0; i<TempVtI; i++) {
    TempVtSommePnt += tblPntVt[i];
  }

  vtPntMin = TempVtSommePnt * 60000 / timelapseVt / 40;  //en [pnt/min] >> pnt = TempVtSommePnt >> temps[min] = 40[enregistrements] *timelapseVt[millis] /60'000 [millis/minutte]
  vtSteppMin = vtPntMin * steppTour / pntSteppTour;
  //vtMsec = int((TempVtSommePnt*10000*1000/timelapseVt/40)/pnt100m)/100;
  //Test print Vitesse: printVtKmH(); Serial.print(" km/h\t");printVtMs(); Serial.print(" m/s\t");Serial.print(vtPntMin/60);Serial.print(" pnt/s\t|\t"); Serial.print(vtSteppMin/200); Serial.print(" RPM moteur\t"); printDistMpalnter(); Serial.println(" mètres plantés");
  
  #ifdef DEBUGcalculSpeed
  Serial.print("\niTblPntVt "); 
  Serial.print(iTblPntVt ); 
  Serial.print("\tcptPntVt "); 
  Serial.print(cptPntVt); 
  Serial.print("\tvtSteppMin "); 
  Serial.print(vtSteppMin);
  Serial.print("\tvtPntMin "); 
  Serial.print(vtPntMin); 
  Serial.print("\tvtkm/h "); printVtKmH(); 
  Serial.print("\tTempVtSommePnt "); 
  Serial.println(TempVtSommePnt);
  #endif

  if (TempVtSommePnt == 0) {iTblPntVt = -20;}
  cptPntVt = 0;
}

void printVtKmH() {       //vitesse d'avancement en kilomètres / heure
  uint32_t TempVtMH = vtPntMin*60*100/pnt100m;
  uint32_t TempVtMHDecimal = int(TempVtMH/10 - int(TempVtMH/1000)*100);
  Serial.print(int(TempVtMH/1000));
  Serial.print(".");
  // pour 2 décimales: if (TempVtMHDecimal < 10) {Serial.print("0");}
  // pour 2 décimales: Serial.print(TempVtMHDecimal);
  // pour 1 décimale: 
  Serial.print(TempVtMHDecimal/10);
  //serial.print(" km/h");
}
void printVtMs() {        //vitesse d'avancement en mètres / seconde
  uint32_t TempVtCmS = vtPntMin *10000 / pnt100m /60;
  uint32_t TempVtCmSDecimal = TempVtCmS - int(TempVtCmS/100)*100;
  Serial.print(int(TempVtCmS/100));
  Serial.print(".");
  if (TempVtCmSDecimal < 10) Serial.print("0");
  Serial.print(TempVtCmSDecimal);
  //serial.print(" m/s");
}
void printDistMpalnter() {  //>>> A adapter à la bibliothèque <<< 
  uint16_t TempMPlanter = nbrlignePlanteuse * cptPntDist * 100 / pnt100m;
  uint16_t TempiKm = 0;
  while (TempMPlanter > 999){
    TempiKm ++;
    TempMPlanter -= 1000;
  }
  TempiKm += nbrlignePlanteuse * cptPntKm;
  if (TempiKm > 0){
    if(TempiKm >= 1000) {
      Serial.print(int(TempiKm/1000));
      Serial.print("'");
      Serial.print(TempiKm - int(TempiKm /1000)*1000);
    }
    else {
    Serial.print(TempiKm);
    }
    Serial.print(".");
    if (TempMPlanter < 100) Serial.print(0);
    if (TempMPlanter < 10) Serial.print(0);
  }
  Serial.print(TempMPlanter);
  //serial.print(" m plantés")
}
void printNbrPlants() {} //A FAIRE !
void printNbrPlantsManque() {} //A FAIRE !


bool majAlarme(){  //>>> A adapter à la bibliothèque <<< 
  int8_t TempCptAlarme = 0;
  bool TempReponce;
  if (bitRead(alarme1, 5)) TempCptAlarme +=1;  //PàP trop vite
  if (bitRead(alarme1, 6)) TempCptAlarme +=10;  //PàP bloqué
  if (bitRead(alarme1, 1)) TempCptAlarme +=5;  //alarme ligne 1
  if (bitRead(alarme1, 2)) TempCptAlarme +=5;  //alarme ligne 2
  if (bitRead(alarme1, 3)) TempCptAlarme +=5;  //alarme ligne 3
  if (bitRead(alarme1, 4)) TempCptAlarme +=5;  //alarme ligne 4

  if (TempCptAlarme == 0){            //AlarmeSTOP
    bitWrite(alarme1, 0, 0);
    bitClear(alarme1, 7);             //BuzzerOFF
    //alarmecentralBlink(false);
    TempReponce = false;
  }
  else if (!bitRead(alarme1, 0)) {    //AlarmeSTART
    bitWrite(alarme1, 0, 1);
    //alarmecentralBlink(true);
    TempReponce = true;
  }
  else {                              //AlarmeON
    //alarmecentralBlink(true);
    if(TempCptAlarme > 1){
      bitWrite(alarme1, 7, 1);        //BuzzerON
    }
    TempReponce = true;
  }

  alarmecentral(alarme1);
  
  return TempReponce;
}
void alarmecentral(byte AlarmeEtat) {
  if (bitRead(AlarmeEtat, 0)){
    if(etatAlLampe){
      if (lastTimeAlBlink + 120 <= millis()){
        etatAlLampe = LOW;
      }
    }
    else {
      if (lastTimeAlBlink + 200 <= millis()){
        lastTimeAlBlink = millis();
        etatAlLampe = HIGH;
      }
    }
  }
  else {
    etatAlLampe = LOW;
    //etatAlBuzzer = LOW;
  }
  
  digitalWrite(ledAlCentral, etatAlLampe);

  if (bitRead(AlarmeEtat, 7)){
    if(etatAlBuzz){
      if (lastTimeAlBuzz + 100 <= millis()){
        etatAlBuzz = LOW;
      }
    }
    else {
      if (lastTimeAlBuzz + 300 <= millis()){
        lastTimeAlBuzz = millis();
        etatAlBuzz = HIGH;
      }
    }
  }
  else {
    etatAlBuzz = LOW;
  }
  
  digitalWrite(buzzAlCentral, etatAlBuzz);
}
void alarmeReset(){
  delay(20); //Anti-rebond bloquant mais suffisant, l'action ne s'execute qu'exceptionnellement, la loop arrive à rattrapper le retard...
    if (digitalRead(swAlReset)) return;

          #ifdef DEBUGAlarme
            Serial.print ("START_reset_alarme byte alarme1 = "); Serial.println(alarme1);
          #endif
          #ifdef DEBUGswitch
            Serial.print("Reset alarme Start");
          #endif

  while (!digitalRead(swAlReset)) {    } //Attend que le bouton soit relâcher pour éviter de faire le reset en boucle
          // #ifdef DEBUGloopStepp_stepp  >>>SAns bouton c'est normal que ça bloque !!!
          //   Serial.print("b");  //A_03_b
          // #endif//DEBUG

  for (int i = 0; i< nbrlignePlanteuse; i++){
    //Old variante: alarmeResetRang(i+1);
    lignePlanteuse[i]->resetAlarme();
  }
  alarme1 = 0;
  majAlarme();
  
          #ifdef DEBUGswitch
            Serial.println("\t Reset alarme END");
          #endif
          #ifdef DEBUGAlarme
            Serial.print ("END_reset_alarme byte alarme1 = "); Serial.println(alarme1);
          #endif

  delay(5);
}
void alarmeResetRang(const uint8_t nrRang){
    lignePlanteuse[nrRang]->resetAlarme();
}

void manuelMoteurOn(uint16_t ManuelOnSpeed){    //active le moteur du semoir lentement (vitesse = 100step/s, accélération = 30step/s²)
  delay(20);    //Anti-rebond bloquant mais suffisant, la fonction s'execute à l'arrêt de la machine
  if (digitalRead(swMoteurOn)) return;
  
  #ifdef DEBUGswitch
    Serial.print("manuel moteur ON");
  #endif
  stepper->stopMove();
  while (stepper->isRunning()) {  } 
  delay(2);
  int32_t _tempStepperCurrentPos = stepper->getCurrentPosition();
  uint32_t _tempStepperCurrentAccel = stepper->getAcceleration();
  uint32_t _tempStepperSpeed = stepper->getSpeedInMilliHz();

  stepper->setSpeedInHz(ManuelOnSpeed);
  stepper->setAcceleration(30);    //steps/s²
  stepper->applySpeedAcceleration();
  stepper->runForward();
  while (!digitalRead(swMoteurOn)) {  }
  stepper->setAcceleration(200);    //steps/s²
  stepper->applySpeedAcceleration();
  stepper->stopMove();
  while (stepper->isRunning()) {  }
  delay(2);
  stepper->setSpeedInMilliHz(_tempStepperSpeed);  
  stepper->setAcceleration(_tempStepperCurrentAccel);    //steps/s²
  stepper->setCurrentPosition(_tempStepperCurrentPos);
  stepper->applySpeedAcceleration();

  #ifdef DEBUGswitch
    Serial.println("\t manuel moteur OFF");
  #endif

}

void comptePnt() {
  if (digitalRead(codeurAPin) == digitalRead(codeurBPin)) {
    codeurPnt += valeurPnt;
  } 
  else {
    codeurPnt -= valeurPnt;
  }
}
#ifdef InfoSerialMoniteur
  uint32_t infoSerialMoniteurTimmer = 0;
  bool infoSerialMoniteurActualiser = true;

  void printInfoSerialMoniteur(){   //Affiche les information importantes sur le moniteur serie
  
    //Afficher les valeurs actuelles de la machine
    if(infoSerialMoniteurActualiser){
      if(infoSerialMoniteurTimmer < millis()){  //Actualise les données toutes les 10 secondes
        infoSerialMoniteurTimmer = millis() + 5000;
        uint16_t _TempManqueMilleTotal = 0;
        uint16_t _TempSpacePlantTotal = 0;
        uint64_t _TempNbrPlanteTotal = 0;
        uint64_t _TempNbrManqueTotal = 0;

        for(int i = 0; i < nbrlignePlanteuse; i++){
          _TempManqueMilleTotal += lignePlanteuse[i]->getManquePourMille();
          _TempSpacePlantTotal += lignePlanteuse[i]->getMoyenSpacePlant();
          _TempNbrPlanteTotal += lignePlanteuse[i]->getNbrPlanter();
          _TempNbrManqueTotal += lignePlanteuse[i]->getNbrManquer();
        }
        if(_TempManqueMilleTotal > 0) _TempManqueMilleTotal = _TempManqueMilleTotal / nbrlignePlanteuse;
        if(_TempSpacePlantTotal > 0) _TempSpacePlantTotal = _TempSpacePlantTotal * 100 / nbrlignePlanteuse * 100 / pnt100m;   //*100 pour passer en mètre, *100 pour passer en cm / pnt100m
        //1ère ligne
        Serial.println("\n*** Actualisations des valeurs **********************");
        Serial.print("** Vitesse: "); printVtKmH(); Serial.print("km/h");
        Serial.print("\tdistance parcourue: "); printDistMpalnter(); Serial.print("km");
        Serial.print("\tdistance entre plans: "); Serial.print(_TempSpacePlantTotal); Serial.print("cm");
        Serial.print("\tPlanteuse active: "); if(swPlante){Serial.print("OUI");} else{Serial.print("NON");}
        Serial.print("\tSemoir actif: "); if(swSeme){Serial.print("OUI");} else{Serial.print("NON");}
        Serial.println();
        //Ligne 2
        Serial.print("** Plants manqués: "); Serial.print(int(_TempManqueMilleTotal / 10)); 
          Serial.print("."); Serial.print(_TempManqueMilleTotal - (10 * int(_TempManqueMilleTotal / 10))); Serial.print("%");
        Serial.print("\tPlants plantés: "); Serial.print(_TempNbrPlanteTotal); Serial.print("pce");
        Serial.print("\tPlants manqués: "); Serial.print(_TempNbrManqueTotal); Serial.print("pce");
        Serial.println("\n*********************");
        
        // Effacer les oldALARME pour réafficher les alarme en court
        oldAlarme1 = 0;
        memset(oldValRangAlarme, 0, sizeof oldValRangAlarme);
      } 
    } 

    //Contrôler et afficher les ALARMES
      //Alarmes Rang
        for(int i = 0; i < nbrlignePlanteuse; i++){
          if(valRangAlarme[i] != oldValRangAlarme[i]){
            if(valRangAlarme[i] <= 1){
              if(oldValRangAlarme[i] > 1){                      //Aficher l'extinction (la fin) d'une alarme majeure
                //if(bitRead(oldValRangAlarme[i],1))  Serial.print("\n<<< Fin de l'alarme ... sur le rang "); Serial.print(i+1);
                Serial.print("\n... Le rang "); Serial.print(i+1); Serial.println(" >> n'a plus d'alarme");
              }
              if(valRangAlarme[i] == 1){                        // il y a juste un plant de manqué, c'est pas une grosse alarme
              Serial.print(" , "); Serial.print(i+1);               //j'affiche juste le n° du rang ou il manque un planté
              }                                                     //j'affiche rien à l'extinction de cette alarme
            }
            else {                                            //Une alarme importante et signalée
              if(abs(valRangAlarme[i] - oldValRangAlarme[i]) > 1){    //Contrôle que pas seulement le bit1 à changé
              Serial.print("\n!!! ALARME Rang "); Serial.print(i+1); 
              if(bitRead(valRangAlarme[i],1) << bitRead(oldValRangAlarme[i],1))  Serial.print("  ||\tmanques répétés");
              if(bitRead(valRangAlarme[i],2) << bitRead(oldValRangAlarme[i],2))  Serial.print("  ||\t% manque dépassé");
              if(bitRead(valRangAlarme[i],3) << bitRead(oldValRangAlarme[i],3))  Serial.print("  ||\tcapteur bloqué à ON");
              if(bitRead(valRangAlarme[i],4) << bitRead(oldValRangAlarme[i],4))  Serial.print("  ||\tplants trop proche");
              if(bitRead(valRangAlarme[i],5) << bitRead(oldValRangAlarme[i],5))  Serial.print("  ||\tbit5");
              if(bitRead(valRangAlarme[i],6) << bitRead(oldValRangAlarme[i],6))  Serial.print("  ||\tbit6");
              if(bitRead(valRangAlarme[i],7) << bitRead(oldValRangAlarme[i],7))  Serial.print("  ||\tbit7");
              
              if(bitRead(valRangAlarme[i],1) >> bitRead(oldValRangAlarme[i],1))  Serial.print("  ..\tRésolue manques répétés");
              if(bitRead(valRangAlarme[i],2) >> bitRead(oldValRangAlarme[i],2))  Serial.print("  ..\tRésolue % manque dépassé");
              if(bitRead(valRangAlarme[i],3) >> bitRead(oldValRangAlarme[i],3))  Serial.print("  ..\tRésolue capteur bloqué à ON");
              if(bitRead(valRangAlarme[i],4) >> bitRead(oldValRangAlarme[i],4))  Serial.print("  ..\tRésolue plants trop proche");
              if(bitRead(valRangAlarme[i],5) >> bitRead(oldValRangAlarme[i],5))  Serial.print("  ..\tRésolue bit5");
              if(bitRead(valRangAlarme[i],6) >> bitRead(oldValRangAlarme[i],6))  Serial.print("  ..\tRésolue tbit6");
              if(bitRead(valRangAlarme[i],7) >> bitRead(oldValRangAlarme[i],7))  Serial.print("  ..\tRésolue tbit7");

              Serial.println();
              if(bitRead(valRangAlarme[i],0))  Serial.print(" , "); Serial.print(i+1);
              }
              else if(bitRead(valRangAlarme[i],0))  Serial.print(" , "); Serial.print(i+1);
            }
            oldValRangAlarme[i] = valRangAlarme[i];
          }
        }
      //Alarmes semoir
      
        if(bitRead(alarme1, 5) || bitRead(alarme1, 6)){         //Contrôler si il y a une alarme pour le semoir
          if(bitRead(alarme1, 5) != bitRead(oldAlarme1, 5) || bitRead(alarme1, 6) != bitRead(oldAlarme1, 6)){   //Contrôler si elle n'a pas déjà été annoncée
            Serial.print("\n>>> ALARME Semoir");
            if(bitRead(alarme1, 5)) Serial.print("\t>> Vous roulez trop vite");
            if(bitRead(alarme1, 6)) Serial.print("\t>> STOP le semoir est bolqué");
            Serial.println();
          }
        }
        else if(bitRead(oldAlarme1, 5) || bitRead(oldAlarme1, 6)){
          Serial.print("\n... Le semoir "); Serial.println(" >> n'a plus d'alarme");
        }
        // bitWrite(oldAlarme1, 5, bitRead(alarme1, 5));
        // bitWrite(oldAlarme1, 6, bitRead(alarme1, 6));
        oldAlarme1 = alarme1;
      
      if(alarme1 == 0){infoSerialMoniteurActualiser = true;}
      else {infoSerialMoniteurActualiser = false;}
  }
#endif  //defined (InfoSerialMoniteur)

Salut, je suis un grand débutant en arduino donc je ne pourrais pas t'aider moi même à résoudre ton problème mais j'ai posé ta question tel quel à CHAT GPT et voici ce qu'il m'a répondu :

Il est effectivement possible que la communication série sur le cœur 0 de l'ESP32 perturbe le fonctionnement du moteur pas à pas, car elle peut monopoliser une partie des ressources du microcontrôleur.

Pour déplacer la gestion du port-série sur le cœur 1, vous pouvez utiliser la librairie "HardwareSerial" qui permet de choisir le cœur sur lequel la communication série sera effectuée. Par défaut, la communication série est gérée sur le cœur 0, mais vous pouvez spécifier le cœur 1 en utilisant la méthode "Serial1.begin()".

Par exemple, pour initialiser la communication série sur le cœur 1 avec une vitesse de transmission de 9600 bauds, vous pouvez utiliser la ligne de code suivante :

Serial1.begin(9600, SERIAL_8N1, 16, 17);

Notez que les broches 16 et 17 sont les broches RX et TX du cœur 1 de l'ESP32.

Pour contrôler sur quel cœur est gérée la communication série, vous pouvez utiliser la méthode "xPortGetCoreID()" de la librairie "FreeRTOS". Cette méthode renvoie l'identifiant du cœur sur lequel elle est exécutée (0 pour le cœur 0 et 1 pour le cœur 1).

Par exemple, pour afficher sur le moniteur série l'identifiant du cœur sur lequel est gérée la communication série, vous pouvez utiliser le code suivant :

Serial.println(xPortGetCoreID());

Aussi je n'ai pas lu tout ton code et j'ai vu qu'il était très long mais je te conseil vraiment de le séparer en plusieurs sous fichiers que tu appelleras dans un fichier main.ino. Cela te permettra d'avoir une meilleur lisibilité dans ton code ainsi qu'une meilleur modularité quand tu voudras effectué des changement.
J'espère avoir pu t'aider avec mes connaissance de grands débutant :slight_smile:

J'ai l'impression que ChatGPT confond cœur 1 et UART 1.

Ici encore, cette ligne permet d'afficher l'ID du cœur en cours d'exécution, certainement pas du cœur responsable de la gestion de la communication série.

Tout ce que je peux affirmer, c'est que l'ESP32 possède 32 vecteurs d’interruption par cœur, et donc qu'il est possible d'affecter les vecteurs d'interruption à un cœur, ou l'autre, mais il faudrait étudier de près le code de la gestion série pour en dire plus.

Ce n'est certainement pas le genre de question que poserais à ChatGPT, le code est certainement la source la plus fiable.

Je suis d'accord avec hbachetti , pour FreeRTOS j'ai ce lien qui est pas mal pour un novice comme moi.

Je pences que vais prendre le problème dans l'autre sens; Je vais déplacer le programme principal sur le coeur0 et FastAccelStepper sur le coeur1.
En espérand que le gestion du port-série ne bouge pas.

Pour "FastAccelstepper" ça ce fait avec la commande "Init(coeur);"

  void init();

#if defined(SUPPORT_CPU_AFFINITY)  //Defini dans common.h inclut à fatsAccelStepper)
  // In a multitasking and multicore system like ESP32, the steppers are
  // controlled by a continuously running task. This task can be fixed to one
  // CPU core with this modified init()-call. ESP32 implementation detail: For
  // values 0 and 1, xTaskCreatePinnedToCore() is used, or else xTaskCreate()
void init(uint8_t cpu_core);   //<<<<<<<<<<<< cette ligne pour choisir le coeur
#endif

Pour le programme principal, dans l'IDE ça doit être :
ArduinoRuns On "Core 0" (voir image ci-dessous)
Par contre, la ligne "Events Run On: "Core" je n'ai pas compris à quoi elle sert!

Y faut que je remonte ma machine de simulation pour tester ...

Apparemment, il s'agirait des événements FreeRTOS.

Merci,
Si je lis le #post10 de ton lien, c'est uniquement lié au Wifi:

Même ci au départ, j'ai pris un ESP32 pour son Wifi et ça vitesse, pour le moment le Wifi, je pences que je peux oublier, avec ce que la carte doit déjà gérer.

Mais par acquis de consience, je vais le mettre à la même place que le programme principal, comme ça je suis sur de laisser l'autre coeur uniquement pour le stepper.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.