[arduino] PWM, harmonique et afficheur LCD. une histoire de compatibilité

Bonjour,
je suis actuellement dans l'impasse.

Lorsque je pilote un variateur avec une sortie PWM de mon arduino, mon afficheur LCD s’éteint ou se met afficher des caractères mandarin!

J'ai donc installé des condensateur de découplage (100µF) au niveau de chaque alimentation, utilisé des fils blindés et relié chaque masse et terre de l'alimentation du variateur et de la carte. :stuck_out_tongue_closed_eyes: Et mit un filtre basse bas sur ma sortie PWM (27µF et 1Kohm)

Le problème persiste. :cold_sweat:

J'ai donc deux questions:
Quelqu’un aurait il une idée afin de régler le problème en hardware?
Quelqu'un pourrait-il m'expliquer comment réinitialiser mon afficheur après chaque pilotage du variateur?

Merci d'avance

Un schéma pour comprendre comment est câblé l’ensemble

il y a un logiciel sympa pour en creer un?

Il semble que le problème vienne pas seulement du variateur. Maintenant, même lorsque qu’il est hors tension le programme bug.
j’identifie le bug dans ma fonction “mode_manu()”. L’afficheur s’éteint.

#include "encoder.h"
#include <MsTimer2.h> 
#include <LiquidCrystal.h> // Inclusion de la librairie pour afficheur LCD 


//définition des caractéristique moteur et variateur
#define vit_max_mot 9.1 //vitesse maxi tu moteur en tr/s
 
//definition des E/S Codeur  
#define encoder0PinA  3 // pin A de l'encodeur
#define encoder0PinB  5 //pin b de l'encodeur
#define encoder0Pos  2 //pin 0 de l'encodeur
#define encoder0sens 44
#define NbP_Cod 3600 //Nombre de pts du codeur

//definition des leds 
#define L1 52  
#define L2 50
#define L3 48
#define L4 46

//definition des E/S LCD
#define RS 12  
#define E 11 

#define D4 6 
#define D5 7 
#define D6 8 
#define D7 9 

//definition des boutons
#define pin_init 53
#define pin_manu 47
#define pin_auto 49
#define pin_rec 51

//Potentiometre
#define pot A0
#define Var 10

//Commande var
#define En 42

//definition des variables globales
  int Tab_Mes[1000][1];  //tableau de mesure des positions
  boolean Tab_Sens[1000][1];  //tableau de mesure de sens
  unsigned int i=0; 
  int j=0;
  unsigned int t=0;

//definitions des drapeaux
  boolean Flag_rec=false; 
  boolean Flag_auto=false;
  boolean Flag_manu=false;
  boolean Flag_init=false;

//Initialisation des class
  Codeur Codeur(encoder0PinA,encoder0PinB,encoder0Pos,encoder0sens);
  LiquidCrystal lcd(RS, E, D4, D5, D6, D7);// initialisation LCD en mode 4 bits 

//initialisation du programme
   void setup() 
     { 
         //attachInterrupt(encoder0Pos, blink, RISING); //drapeau de detection de tours
         //attachInterrupt(5, blink_0, RISING);
  
   //Configuration du port serie 
         Serial.begin (57600);
         Serial.println ("start");
   
   //-------definition des E/S----------
         pinMode(pin_rec, INPUT); //bouton mode enregistrement
         pinMode(pin_init, INPUT); //bouton init
         pinMode(pin_auto, INPUT); //bp mode auto
         pinMode(pin_manu, INPUT); //bp Mode manu
         pinMode(En, OUTPUT); //bit de commande moteur
   
         digitalWrite (pin_rec, HIGH); //activation des resistance de pull up
         digitalWrite(pin_init, HIGH); 
         digitalWrite(pin_auto, HIGH); 
         digitalWrite(pin_manu, HIGH); 
   
         pinMode(L1, OUTPUT);   //L1 est une broche de sortie
         pinMode(L2, OUTPUT);   //L2 est une broche de sortie
         pinMode(L3, OUTPUT);   // ...
         pinMode(L4, OUTPUT);
         pinMode(Var, OUTPUT);
         pinMode(encoder0sens, OUTPUT);
   
         Codeur.flag_0=false;
   
   //--------definition des timer--------------
         //MsTimer2::set(100, InterruptTimer2); // période 100ms 
         //MsTimer2::start(); // active Timer2 
   
   //--------initialisation sortie anal---------
         analogWrite(Var,0);
   
   //------------initialisation LCD--------------
         lcd.begin(16,2); // Initialise le LCD avec 20 colonnes x 4 lignes 
         delay(10); // pause rapide pour laisser temps initialisation

   // Test du LCD

         lcd.print("Jouanel ") ; // affiche la chaîne texte - message de test
         delay(200);
         lcd.setCursor(7, 1) ; // 10ème col - 2ème ligne - positionne le curseur à l'endroit voulu (colonne, ligne) (1ère=0 !) 
         lcd.print("industrie") ; // affiche la chaîne texte - message de test
         delay(2000); // pause de 2 secondes
   
         lcd.clear();
         delay(300);
         lcd.print("Bordeuse ") ; // affiche la chaîne texte - message de test
         delay(300);
         lcd.setCursor(7, 1) ; // 10ème col - 2ème ligne - positionne le curseur à l'endroit voulu (colonne, ligne) (1ère=0 !) 
         lcd.print("a memoire") ; // affiche la chaîne texte - message de test
        
 } 


 void loop() 
 { 
         
         
         //aff_pos(); //affiche la position du codeur sur le port serie
   
 //-----verification appui bouton----------
         Bp_rec(); //bouton d'enregistrement
         Bp_lec();  //bouton init
         Bp_auto(); // bouton passage auto 
         bp_manu();
  

  
   
//-------mode automatique---------
     for (i=i;i<101&&Flag_auto==true;i++)
       {
         digitalWrite(encoder0sens, Tab_Sens[i][1]);
         digitalWrite(En, LOW);//TEST
         Bp_auto();
         Bp_lec();  
         t=calc_vit(i);
         
         analogWrite(Var,t);
         delay(200);
         Serial.println(t);
         //Chenillard();
         Serial.println(i);
         if(i>=100)
          { 
            digitalWrite(En, HIGH);//TEST
             Flag_auto=false;
             aff_lcd(); 
             i=0;
           }  
        }
        
//---------mode manuel---------    
    if(Flag_manu==true)
      {
          //aff_pos();
          digitalWrite(En, LOW);
          bp_manu(); 
          Bp_lec();
          //mode_manu();
          Rec_pos(); //enregistre la position du codeur toute les 1/5 de seconde
      }  
    else
      {
          digitalWrite(En, HIGH);
       }  
         
//-----------------------------------------------           
//------REinitialisation de l'afficheur LCD------
//------------------------------------------------
  if(Flag_init==true)
    {
      //init_lcd();
    }
  else
    {
      Flag_init=false;
    }        
       
 } 
 
//---------------------------------------------------------
//----------------definition des fonctions-----------------
//---------------------------------------------------------

La suite

//remise à zero par interruption de la position du compteur

  void blink()
    {
      Codeur.flag_0=true;
      //Codeur.CodPos=0;
      Serial.println("flag");
    }

//-------detection de l'appui bouton mode auto--------

  void Bp_auto()
    {
      static unsigned long t_auto;
      if((millis()-t_auto>3000)&&(digitalRead(pin_auto)==LOW))
        {
           Serial.println("prout_auto");
           Flag_auto=!Flag_auto; 
           Flag_rec = false;
           Flag_manu =false;
           t_auto=millis();
           aff_lcd();
        } 
    }

//-------detection del'appui bouton pour la remise a false des drapeaux
  void Bp_lec()
    {
        static unsigned long t_lec;
        if((millis()-t_lec>3000)&&(digitalRead(pin_init)==LOW))
          {
            Serial.println("prout");
            Flag_auto=false;
            Flag_rec = false;
            Flag_manu =false;
            Flag_init=true;
            i=0;
            t_lec=millis();
            aff_lcd();
          } 
    }

//--------detection de l'appui du bouton mode manuel----

  void bp_manu()
  {
    static unsigned long t_manu;
    if((millis()-t_manu>3000)&&(digitalRead(pin_manu)==LOW))
      {
         Flag_manu=!Flag_manu;
         Flag_auto=false;
         Serial.println("manu");
         t_manu=millis();
         //aff_lcd();
         j=0;
       } 
  
  }

//----mode manuel-----

  void mode_manu()
    {
      static unsigned long t_mmanu;
    if(millis()-t_mmanu>200)
      {
      static int val;
      val = analogRead(pot);
      delay(10);
      analogWrite(Var,val/4);
      delay(10);
       t_mmanu=millis();
      }
    }
//-------detection de l'appui bouton pour l'enregistrement--------
   void Bp_rec()
    {
      static unsigned long t_rec;
      if((millis()-t_rec>3000)&&(digitalRead(pin_rec)==LOW))
          {
             Flag_rec = !Flag_rec;
             Flag_auto=false;
             Serial.println("Flag_rec");
             t_rec=millis();
             aff_lcd();
             j=0;
           } 
           
    }

//affiche la position du codeur sur le port serie

  void aff_pos ()
    {
      static int ref;
      int val= Codeur.pos(); 
      if ((val<=ref-100)||(val>=ref+100))
         { 
          ref=val;
          Serial.println (val);        
         }
    }

//----enregistrement de la position du codeur toutes les 200 millisecondes

  void Rec_pos()
    {
      static unsigned long t_ref;
      int val= Codeur.pos(); 
      if ((millis()-t_ref>200)&&(j<100)&&(Flag_rec==true))
        {
         Tab_Mes[j][1]=abs(val);
         Tab_Sens[j][1]=Codeur.CodSens;
         j++;
         Serial.println(j);
         
         //Serial.println(Codeur.CodSens);
         t_ref=millis();
         Codeur.CodPos=0;
         if (j>=99)
           {
             Flag_rec=false; 
            // aff_lcd();
           }
        } 
    }

//calcule de la vitesse du moteur en fonction des mesures faites sur le codeur    

  unsigned int calc_vit(int j)
    {
      Serial.println(Tab_Mes[j][1]);
      unsigned int somme=(Tab_Mes[j][1]*0.354);
      //Serial.println(somme);
      return somme; 
    }

//--fonction test du temps calculé

  void Chenillard()
    {
      digitalWrite(L1, LOW);   //allumer L1
      delay(t);
  
      digitalWrite(L1, HIGH);  //on éteint L1
      digitalWrite(L2, LOW);   //on allume L2 en même temps que l'on éteint L1
      
      delay(t);
   
      digitalWrite(L2, HIGH);  //on éteint L2 et 
      digitalWrite(L3, LOW);   //on allume immédiatement L3
      delay(t); 
    
      digitalWrite(L3, HIGH);
      digitalWrite(L4, LOW);
      delay(t);
   
      digitalWrite(L4, HIGH);
      delay(t);
   }


/*
void InterruptTimer2() 
{ 
  // debut de la fonction d'interruption Timer2
  
t=abs(calc_vit(i)/50);
}*/

//-----------Gestion de l'afficheur LCD------

void aff_lcd()
{
  if(Flag_auto==true)
  {
    lcd.clear();
    delay(10);
    lcd.setCursor(1, 0) ;
    lcd.print("Mode auto") ;
    delay(10);
  }
  else if(Flag_rec==true)
  {
    lcd.clear();
    delay(10);
    lcd.setCursor(0, 0) ;
    lcd.print("Mode manuel") ;
    delay(10);
    lcd.setCursor(0, 1) ;
    lcd.print("Enregistrement") ;
    delay(10);
  }
  else if(Flag_manu==true)
  {
    lcd.clear();
    delay(10);
    lcd.setCursor(0, 0) ;
    lcd.print("Mode manuel") ;
    delay(10);
  }
  else
   {
    lcd.clear();
    delay(10);
    lcd.setCursor(0, 0) ;
    lcd.print("attente") ;
    delay(10);                                                                                                      
  }
  
  
}

//initialisation de l'afficheur lcd

  void init_lcd()
  {
    lcd.begin(16,2); // Initialise le LCD avec 20 colonnes x 4 lignes 
    delay(10); // pause rapide pour laisser temps initialisation
    lcd.clear();
    delay(10);
    lcd.setCursor(0, 0) ;
    lcd.print("attente") ;
    delay(10);  
  }

Geocramtou:
il y a un logiciel sympa pour en creer un?

Papier + crayon + main + photo/scanner rapide pas cher
Fritzing
Eagle
Kicad

dans mode_manu() :

analogWrite(Var,val/4);

est-ce que justement tu n'écris pas sur une pin du LCD?

sinon, tu n'optimises pas trop tes variables. Tu n'es pas sur un PC, tu m'as pas 2Go de RAM + 10Go d'échange... à mon avis, il y a peut-être un pb de ce côté-là, à voir...

L'autre cause de ton souci : comment alimentes-tu ton montage? (papier crayon photo!)

//definition des variables globales
  int Tab_Mes[1000][1];  //tableau de mesure des positions
  boolean Tab_Sens[1000][1];  //tableau de mesure de sens

Dis donc tu utilises quoi comme arduino? Avec ces 2 tableaux tu bouffes un sacré paquet de mémoire.

J’alimente mon montage et ma carte via une alimentation de PC que j’ai démonté.
Comment Pourrais je optimiser mes variable? Est ce vraiment nécessaire?

J'utilise un arduino 2560 et ces tableaux me sont nécessaire.
je dois stocker beaucoup de données, d'ou le choix de cette carte.

Pour ton tableau de boolean, tu peux regrouper 8 bool dans un octet, il deviendra donc

byte Tab_Sens[125]; //tableau de mesure de sens --> première optimisation... 125 octets au lieu de 1000.

Ensuite, pour Tab_Mes qui prend déjà 2000 octets, as-tu vraiment besoin d'int? est-ce que des valeurs sur 8 bits ne te suffiraient pas?

Je ne saisis pas trop pourquoi tu fais des tableaux à deux dimensions, car la seconde dimension est inutile (n'a qu'une valeur possible...)

Sinon, j'ai trouvé ce qui cloche.

Tu as mis une capa directement sur la pin 10, et tu utilises le régulateur de la carte pour alimenter ton système, donc quand tu mets la pin 10 à 1, ça fait un balaise d'appel de courant, le régulateur s'écrase, et tu fais tomber ton alim suffisamment pour faire des choses zarbis.

Pareil pour ton potar entre les pins 3 et 5 et la masse, c'est pas du tout une bonne idée si ces pins sont des sorties...

Je pense que tu as fais une erreur de schéma, car ton LCD ne peut pas marcher branché comme ça (et je ne vois pas de 5V arriver dessus...)

Moi ce que je ne voie pas arriver sur le LCD c'est la masse...

Par contre pour éviter des interférences entre la carte et le variateur j'aurais transistorise la sortie en 5 ou 12V en fonction du variateur.
Ou carrément avec çà propre l'alimentation.

A mon avis ça vient surtout de la masse : un fil qui passe d'un système à l'autre, ce n'est pas bon (les contrôleurs de LCD sont assez tatillons avec ça)

Une masse se tire en étoile depuis l'alimentation (ou le régulateur), un fil pour chaque "consommateur".

Merci pour vos réponses! =)

Pour ton tableau de boolean, tu peux regrouper 8 bool dans un octet, il deviendra donc

byte Tab_Sens[125]; //tableau de mesure de sens --> première optimisation... 125 octets au lieu de 1000.

Je ne savait pas qu'une variable de type Bool prend un octet, du coup tu n'aurais pas un lien pour m'expliquer comment utiliser les différent bits d'un type bool?

Ensuite, pour Tab_Mes qui prend déjà 2000 octets, as-tu vraiment besoin d'int? est-ce que des valeurs sur 8 bits ne te suffiraient pas?
Je ne saisis pas trop pourquoi tu fais des tableaux à deux dimensions, car la seconde dimension est inutile (n'a qu'une valeur possible...)

Le but final et de mémoriser les position de deux codeurs, d'ou le tableau à deux dimension.
J'ai besoin de int, la valeur des codeur pouvant prendre jusqu’à 20 000.

Tu as mis une capa directement sur la pin 10, et tu utilises le régulateur de la carte pour alimenter ton système, donc quand tu mets la pin 10 à 1, ça fait un balaise d'appel de courant, le régulateur s'écrase, et tu fais tomber ton alim suffisamment pour faire des choses zarbis.

J'ai testé avec et sans, le système répond exactement pareil. Et comment filtré ma sortie sinon?

Pareil pour ton potar entre les pins 3 et 5 et la masse, c'est pas du tout une bonne idée si ces pins sont des sorties...

Mon potar est en faite un codeur ! =)

Je pense que tu as fais une erreur de schéma, car ton LCD ne peut pas marcher branché comme ça (et je ne vois pas de 5V arriver dessus...)

J'ai oublié de précisé qu'il était directement alimenté par mon alimentation 5V

Par contre pour éviter des interférences entre la carte et le variateur j'aurais transistorise la sortie en 5 ou 12V en fonction du variateur.
Ou carrément avec çà propre l'alimentation.

J'ai essayé et toujours exactement le même problème! même avec un darlington

A mon avis ça vient surtout de la masse : un fil qui passe d'un système à l'autre, ce n'est pas bon (les contrôleurs de LCD sont assez tatillons avec ça)

Une masse se tire en étoile depuis l'alimentation (ou le régulateur), un fil pour chaque "consommateur".

Normalement avec un condensateur de découplage on devrait être tranquille non?

Finalement, je pense que le système plantait pour plusieurs raisons, masse, harmonique, compatibilité électromagnétique, surement programme (une boucle sur aff_lcd(); ).... Merci pour vos précieux conseils.

D'ailleurs si vous en avez d'autre, je suis preneur!

le nouveau schéma

Pour utiliser un tableau 8 fois plus petit :

byte tableau[125];

boolean lit_tableau(word index){
  return (tableau[index >> 3] & (1 << (index % 8)));
}

void ecrit_tableau(word index, boolean valeur){
  if (valeur) { 
    tableau[index>>3] |= (1 << (index % 8)) ;
  } else {  
    tableau[index>>3] &= ~(1 << (index % 8)) ;
  }
}

Il doit y avoir plus rapide, mais c’est une idée.