State Machine et Matrice LED 8x8

Bonjour, je suis en train de concevoir un dispositif avec un Arduino Uno, un bouton et une matrice led 8x8.
J'aimerais pouvoir charger différentes boucles animées sur l'arduino et passer de l'un à l'autre en pressant le bouton.
Je vous montre le schematics ainsi que le code que j'ai développé en m'appuyant sur un cours traitant des State Machine et ce que j'ai trouvé sur un générateur de sprites pour LedMatrix

#include <LedControl.h>
#include <MD_MAX72xx.h>


//There will be 3 states, ONE, TWO, THREE, (+ one default called ZERO), each state is a sprite animation on the 8x8 LedMatrix,
//with the push of a button the states will go from one to an other
//Using a MAX7219
// pin 12 is connected to the DataIn
//pin 11 is connected to the CLK
//pin 10 is connected to LOAD
//pin 2 is connected to switch
#define button 2


LedControl display = LedControl(12, 11, 10, 1);

int state = 0;              //integrer to hold current state
int old = 0;                //integrer to hold last state
int buttonPoll = 0;         //integrer to hold button state




const uint64_t ZERO[] PROGMEM = {
  0x3c4281818181423c,
  0x003c424242423c00,
  0x0000182424180000,
  0x0000001818000000,
  0x0000182424180000,
  0x0018244242241800,
  0x003c424242423c00,
  0x3c4281818181423c,
  0x6681810000818166,
  0x8100000000000081,
  0x4281000000008142
};
const int ZERO_LEN = sizeof(ZERO) / 8;


const uint64_t ONE[] PROGMEM = {
  0x3c4201010101023c,
  0x3c0201010101423c,
  0x1c0201010181423c,
  0x0c0201018181423c,
  0x040201818181423c,
  0x000281818181423c,
  0x004081818181423c,
  0x204080818181423c,
  0x304080808181423c,
  0x384080808081423c,
  0x3c4080808080423c,
  0x3c4280808080403c,
  0x3c42818080804038,
  0x3c42818180804030,
  0x3c42818181804020,
  0x3c42818181814000,
  0x3c42818181810200,
  0x3c42818181010204,
  0x3c4281810101020c,
  0x3c4281010101021c
};
const int ONE_LEN = sizeof(ZERO) / 8;

const uint64_t TWO[] PROGMEM = {
  0x0c0e0c0800000000,
  0x0002070f00000000,
  0x000000000f070200,
  0x00000000080c0e0c,
  0x0000000010307030,
  0x00000000f0e04000,
  0x0040e0f000000000,
  0x3070301000000000
};
const int TWO_LEN = sizeof(ZERO) / 8;

const uint64_t THREE[] PROGMEM = {
  0x3c4e8d9999b1723c,
  0x3c46879db9e1623c,
  0x3c4287bffde1423c,
  0x3c4281ffff81423c,
  0x3c42e1f99f87423c,
  0x3c62f1b99d8f463c,
  0x3c72b199998d4e3c,
  0x3c5a999999995a3c
};
const int THREE_LEN = sizeof(ZERO) / 8;

void setup() {
  pinMode (button, INPUT);        //button set as input
  display.shutdown(0, false);
  /* Set the brightness to a medium values */
  display.setIntensity(0, 7);
  /* and clear the display */
  display.clearDisplay(0);
}



void displayImage(uint64_t image) {
  for (int i = 0; i < 8; i++) {
    byte row = (image >> i * 8) & 0xFF;
    for (int j = 0; j < 8; j++) {
      display.setLed(0, i, j, bitRead(row, j));
    }
  }
}

int i = 0;
void loop() {
  //debouncing routine to read button
  buttonPoll = digitalRead(button);    //poll the state of button
  if (buttonPoll == 1) {               //check if it has been pressed
    delay(10);                            //wait 50ms
    buttonPoll = digitalRead(button);     //poll button again
    if (buttonPoll == 0) {                //if it is 0 considered one press
      state = old + 1;                    //increase state by 1
    }
  }
  else {                                 //if button has not been pressed
    delay(10);                            //wait 50ms
  }
  switch (state) {                      //react to button press & state
    case 1:                                 // if state is 1
      //insert ONE
      /*wheel pattern */
      uint64_t one;
      memcpy_P(&one, &ONE[i], 8);

      displayImage(one);
      if (++i >= ONE_LEN ) {
        i = 0;
      }


      delay(100);


      old = state;
      break;
    case 2:
      uint64_t two;
      memcpy_P(&two, &TWO[i], 8);

      displayImage(two);
      if (++i >= TWO_LEN ) {
        i = 0;
      }
      delay(100);


      old = state;
      break;
    case 3:
      //insert THREE
      uint64_t three;
      memcpy_P(&three, &THREE[i], 8);

      displayImage(three);
      if (++i >= THREE_LEN ) {
        i = 0;
      }
      delay(100);

      old = state;
      break;


    default:
      //insert ZERO
      //if state is not 1,2,3
      uint64_t zero;
      memcpy_P(&zero, &ZERO[i], 8);

      displayImage(zero);
      if (++i >= ZERO_LEN ) {
        i = 0;
      }
      delay(100);


      old = 0;
      break;




  }
}

Le code fonctionne à quelques erreurs près... :
J'ai un State default qui fonctionne très bien au démarage,
puis quand j'appuie pour passer au state ONE ma boucle animé se coupe au milieu (elle fait plus de 8 sprites contrairement aux autres.. le problème vient peut être de là), ensuite quand je presse pour passer au state TWO ma boucle fonctionne sauf qu'elle vient remplacer des sprites par ceux du state ONE (ceux qui manquent dans le précédant j'ai l'impression) et pour le state THREE il se passe quelquechose de similaire (un sprite appartenant au state TWO remplace un du state THREE). Sachant qu'en plus je dois appuyer plusieurs fois sur le bouton et trouver le bon timing pour passer à la boucle suivante... pour ce probleme j'ai compris que je devais utiliser un attachInterrupt mais je n'ai fait qu'empirer les choses après mes tentatives...

Vous avez des idées sur ce qui bloque? Je précise que je suis novice en Arduino mais que j'arrive à démêler pas mal de chose en regardant des sketchs et que j’espérais trouver plus de tutoriels ou de documentation concernant les Led à Matrice mais après plusieurs semaines à tourner en rond je bloque.. Je vois des projets bien plus compliquer fonctionner et des librairies qui regorgent de super effets (comme Parola) mais rien permettant d'incorporer proprement ses propres sprites/animations.

Bonjour,
Il faudrait penser à mettre i à 0 lorsque state change.

Penses à faire un ctrl+t dans l'IDE pour mettre le code en forme parce qu'il est difficile à lire à cause d'une mauvaise indentation.

Merci pour l'astuce du ctrl +t j'ai édité,

pour le i = 0 ce n'est pas ce que je fais déjà dans mes "case"?

il faut que j'en rajoute un en fin comme cela?

 case 1:                                // if state is 1
      //insert ONE
      /*wheel pattern */
      uint64_t one;
      memcpy_P(&one, &ONE[i], 8);

      displayImage(one);
      if (++i >= ONE_LEN ) {
        i = 0;
      }
      delay(100);
      old = state;

      i = 0;

      break;

Quand je fais ça mes sprites sont immobiles et c'est toujours aussi compliqué de passer d'un état à l'autre en appuyant sur le bouton

Oui c'est normal puisqu'en faisant ça tu as i toujours égal à 0.
Ce que je dis c'est de mettre i à 0 lorsque tu détectes un appui et que tu incrémentes la valeur de state.
En effet si tu affiches le 12ème sprite de ONE (donc i = 12) et que tu détectes un appui sur le bouton state va passer à 2 et tu vas entrer dans le case 2 avec i = 12 alors que TWO n'a que 8 sprites le programme va donc tapper en mémoire un peu n'importe où.

Ton problème de lecture du bouton est causé par la manière dont tu gères la détection d'une transition.

  buttonPoll = digitalRead(button);    //poll the state of button
  if (buttonPoll == 1) {               //check if it has been pressed
    delay(10);                            //wait 50ms
    buttonPoll = digitalRead(button);     //poll button again
    if (buttonPoll == 0) {                //if it is 0 considered one press
      state = old + 1;                    //increase state by 1
    }
  }
  else {                                 //if button has not been pressed
    delay(10);                            //wait 50ms
  }

Tu lis l'état du bouton et tu testes 10ms plus tard s'il a changé d'état. Si la transition se produit 20ms plus tard elle est perdu puisqu'elle a eu lieu pendant l'affichage du sprite.
Il vaudrait mieux

  • lire l'état du bouton.
  • mémoriser son état dans une variable (ETAT_BOUTON)
  • comparer avec l'état de la variable au coup précédent (ETAT_PREC)
    if (ETAT_BOUTON == LOW && ETAT_PREC == HIGH)
  • s'il y a eu une transition HIGH --> LOW,
    • incrémenter state,
    • mettre i = 0
  • faire ETAT_PREC = ETAT_BOUTON

Autrement, il y a des librairies qui font ça très bien.
Par exemple

Merci pour ta réponse et tes indications... bon déjà je viens d'apprendre qu'il était possible de coder en français... je reviens de loin.. du coup j'ai passé un peu de temps à essayer de retranscrire ça en anglais histoire de rester cohérent.
ça donne quelquechose comme ça?

void loop() {
                                                      
  buttonPoll = digitalRead(button);                   
  ButtonState;
  LastButtonState;
  
  if (ButtonState == LOW && LastButtonState == HIGH) 
  {                                                   
    ControlState = old + 1;                                                                              
    i = 0;
    LastButtonState = ButtonState;         
  
  }

Là j'ai beau appuyer sur le bouton rien ne se passe, je reste bloqué sur mon animation default/zero.
Désolé je fais surement des bourdes, je ne maîtrise pas du tout du coup je cherche des exemples de state machine qui pourrait correspondre à ce que je cherche à la base. Pour la librairie je préfère voir d'abord comment le faire sans pour le moment..

Ce serait bien de mettre un code complet et qui compile.
Parce que là on ne voit pas la définition des variables.
Tu affectes l'état du bouton à buttonPoll mais tu ne l'utilises pas.

Le code compile, il a pas tellement changé hormis ce que tu as soulevé comme erreurs.
Y a surement des doublons dans la définition par contre...

#include <LedControl.h>
#include <MD_MAX72xx.h>


//There will be 3 states, ONE, TWO, THREE, (+ one default called ZERO), each state is a sprite animation on the 8x8 LedMatrix,
//with the push of a button the states will go from one to an other
//Using a MAX7219
// pin 12 is connected to the DataIn
//pin 11 is connected to the CLK
//pin 10 is connected to LOAD
//pin 2 is connected to switch
#define button 2


LedControl display = LedControl(12, 11, 10, 1);

int state = 0;              //integrer to hold current state
int ButtonState = 0;        //take current button state
int LastButtonState = 0;    //take last button state
int ControlState = 0;       //take control unit status

int old = 0;                //integrer to hold last state
int buttonPoll = 0;         //integrer to hold button state




const uint64_t ZERO[] PROGMEM = {
  0x3c4281818181423c,
  0x003c424242423c00,
  0x0000182424180000,
  0x0000001818000000,
  0x0000182424180000,
  0x0018244242241800,
  0x003c424242423c00,
  0x3c4281818181423c,
  0x6681810000818166,
  0x8100000000000081,
  0x4281000000008142
};
const int ZERO_LEN = sizeof(ZERO) / 8;


const uint64_t ONE[] PROGMEM = {
  0x3c4201010101023c,
  0x3c0201010101423c,
  0x1c0201010181423c,
  0x0c0201018181423c,
  0x040201818181423c,
  0x000281818181423c,
  0x004081818181423c,
  0x204080818181423c,
  0x304080808181423c,
  0x384080808081423c,
  0x3c4080808080423c,
  0x3c4280808080403c,
  0x3c42818080804038,
  0x3c42818180804030,
  0x3c42818181804020,
  0x3c42818181814000,
  0x3c42818181810200,
  0x3c42818181010204,
  0x3c4281810101020c,
  0x3c4281010101021c
};
const int ONE_LEN = sizeof(ZERO) / 8;

const uint64_t TWO[] PROGMEM = {
  0x0c0e0c0800000000,
  0x0002070f00000000,
  0x000000000f070200,
  0x00000000080c0e0c,
  0x0000000010307030,
  0x00000000f0e04000,
  0x0040e0f000000000,
  0x3070301000000000
};
const int TWO_LEN = sizeof(ZERO) / 8;

const uint64_t THREE[] PROGMEM = {
  0x3c4299a5a599423c,
  0x0018244242241800,
  0x003c665a5a663c00
};
const int THREE_LEN = sizeof(ZERO) / 8;

void setup() {

  pinMode (button, INPUT);        //button set as input
  display.shutdown(0, false);
  /* Set the brightness to a medium values */
  display.setIntensity(0, 7);
  /* and clear the display */
  display.clearDisplay(0);
}



void displayImage(uint64_t image) {
  for (int i = 0; i < 8; i++) {
    byte row = (image >> i * 8) & 0xFF;
    for (int j = 0; j < 8; j++) {
      display.setLed(0, i, j, bitRead(row, j));
    }
  }
}

int i = 0;
void loop() {
  //debouncing routine to read button
  buttonPoll = digitalRead(button);                   //poll the state of button
  ButtonState;
  LastButtonState;

  if (ButtonState == LOW && LastButtonState == HIGH)
  { //check if it has been pressed
    ControlState = old + 1;                                   //increase state by 1
    i = 0;
    LastButtonState = ButtonState;

  }

  switch (state) {                         //react to button press & state
    case 1:                                // if state is 1
      //insert ONE
      /*wheel pattern */
      uint64_t one;
      memcpy_P(&one, &ONE[i], 8);

      displayImage(one);
      if (++i >= ONE_LEN ) {
        i = 0;
      }


      delay(100);


      old = state;



      break;
    case 2:
      uint64_t two;
      memcpy_P(&two, &TWO[i], 8);

      displayImage(two);
      if (++i >= TWO_LEN ) {
        i = 0;
      }
      delay(100);


      old = state;



      break;
    case 3:
      //insert THREE
      uint64_t three;
      memcpy_P(&three, &THREE[i], 8);

      displayImage(three);
      if (++i >= THREE_LEN ) {
        i = 0;
      }
      delay(100);

      old = state;



      break;


    default:
      //insert ZERO
      //if state is not 1,2,3
      uint64_t zero;
      memcpy_P(&zero, &ZERO[i], 8);

      displayImage(zero);
      if (++i >= ZERO_LEN ) {
        i = 0;
      }
      delay(100);


      old = 0;



      break;




  }
}

Les 2 lignes au-dessus ne font rien et les variables ne reçoivent aucune valeur.
buttonPoll n'est pas utilisé
ControlState n'est pas utilisé
Tu ne changes jamais le contenu de state.
Tu as fait un gros mélange entre state et ControlState d'un coté et buttonPoll et ButtonState de l'autre.

Okay je pensais que c'était juste des doublons sur le coup vis à vis des nouvelles que j'avais rajoutées...

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