Relais arduino à l'aide d'un Pro Mini et ENC28j60

Salut à tous,

Je vous écris un message aujourd'hui car je n'y comprend plus rien avec mon module enc28j60 qui n'est autre qu'un shield petit et très peu cher (2 euros sur ebay).

En fait, tout fonctionne très bien jusqu’à un certain point. Je m'explique! Mon projet est celui-ci: contrôler 4 prises via ethernet avec une interface HTML. j'ai la base en HTML mais c'est tout. J'ai commencé par chercher parmis les différentes librairies disponibles sur le net pour le shield. J'ai retenu "EtherShield" qui est un bon compromis entre taille et fonctions implémentées. Certaines librairies allant jusqu'a prendre 20kb (très limite sur un Pro mini car 30kb max) avec le "Hello World!".

Soit, tout allait très bien, jusqu'a ce que je constate que lorsque j'accède à l'adresse IP locale, il y a un long chargement puis plus rien. Je fais des recherches et il en ressort que la RAM du ATMEGA328 est saturée (2kb au total). J'ai utilisé "avr-size" afin de calculer l'estimation RAM en invite de commande. Très utile d'ailleurs!

Je tombe sur des explications avec PROGMEM, ce que je réalise aussitôt. A nouveau, je me retrouve dans le même problème: pour une page HTML légère cela fonctionne mais lorsque je charge les 4 boutons des relais, la page ne veut plus s'ouvrir. Avr-size me dit que j'utilise +- 1kb. Donc, est-ce un problème de RAM de l'arduino ou du buffer du module ethernet?

D'ailleurs mon code peut être optimisé mais je n'y arrive pas
°mettre une boucle for pour charger les chaines de strings.
°utiliser une concaténation pour choisir la couleur du bouton (vert si allumé et rouge si éteint, donc lorsque l'on clique, ça change)

Je vous remercie de votre aide :slight_smile:
Gilles
Passionné d'électronique et d'arduino

Sans code comment veux-tu qu'on t'aide ...

Voila mon code :smiley:

// pins

#include "etherShield.h"
#include "ETHER_28J60.h"
#include <avr/pgmspace.h>    //bibliothèque nécessaire au stockage d'informations dans la mémoire du circuit

int relay1 = 2;
int relay2 = 3;
int relay3 = 4;
int relay4 = 5;
boolean r1 = true;
boolean r2 = true;
boolean r3 = true;
boolean r4 = true;

// On définit ici nos chaines de caractères afin de pouvoir les enregistrer dans la mémoire
prog_char string_0[] PROGMEM = "<!DOCTYPE HTML> \r \n";
prog_char string_1[] PROGMEM = "<html>\r \n";
prog_char string_2[] PROGMEM = "<title>Relays over internet</title>\r \n";
prog_char string_3[] PROGMEM = "<body bgcolor=black>\r \n";
prog_char string_4[] PROGMEM = "<font color=white>\r \n";
prog_char string_5[] PROGMEM = "<center>\r \n";
prog_char string_6[] PROGMEM = "<b>You can make your choice among the different plugs available!</b>


\r \n";
prog_char string_7[] PROGMEM = "<FORM><INPUT type=button style=\"background-color:#3cb371\" value=Switch1 onClick=window.location='/?cmd1\'></FORM>\r \n";
prog_char string_8[] PROGMEM = "<FORM><INPUT type=button style=\"background-color:#E30000\" value=Switch1 onClick=window.location='/?cmd1\'></FORM>\r \n";
prog_char string_9[] PROGMEM = "<FORM><INPUT type=button style=\"background-color:#3cb371\" value=Switch2 onClick=window.location='/?cmd2\'></FORM>\r \n";
prog_char string_10[] PROGMEM = "<FORM><INPUT type=button style=\"background-color:#E30000\" value=Switch2 onClick=window.location='/?cmd2\'></FORM>\r \n";
prog_char string_11[] PROGMEM = "<FORM><INPUT type=button style=\"background-color:#3cb371\" value=Switch3 onClick=window.location='/?cmd3\'></FORM>\r \n";
prog_char string_12[] PROGMEM = "<FORM><INPUT type=button style=\"background-color:#E30000\" value=Switch3 onClick=window.location='/?cmd3\'></FORM>\r \n";
prog_char string_13[] PROGMEM = "<FORM><INPUT type=button style=\"background-color:#3cb371\" value=Switch4 onClick=window.location='/?cmd4\'></FORM>\r \n";
prog_char string_14[] PROGMEM = "<FORM><INPUT type=button style=\"background-color:#E30000\" value=Switch4 onClick=window.location='/?cmd4\'></FORM>\r \n";
prog_char string_15[] PROGMEM = "</html>";

// A présent, définir un tableau pour accéder aux chaînes
PROGMEM const char *string_table[] ={ 	   //création d'un tableau appelé string_table

    string_0, string_1, string_2, string_3, string_4, string_5, string_6, string_7, string_8, string_9, string_10, string_11};

char buffer[130]; // On définit un buffer qui fait la taille de la plus grande chaine de caractères arrondie à la dixaine supérieure afin de ne pas déborder

//TCP/IP SETTINGS ---------------------------------------------------------------------------------------------------------

static uint8_t mac[6] = {0x54, 0x55, 0x58, 0x10, 0x00, 0x3A};   // this just needs to be unique for your network, 
                                                                // so unless you have more than one of these boards
                                                                // connected, you should be fine with this value.
                                                           
static uint8_t ip[4] = {192, 168, 1, 15};                       // the IP address for your board. Check your home hub
                                                                // to find an IP address not in use and pick that
                                                                // this or 10.0.0.15 are likely formats for an address
                                                                // that will work.

static uint16_t port = 80;                                      // Use port 80 - the standard for HTTP

//-------------------------------------------------------------------------------------------------------------------------

ETHER_28J60 e;

void setup()
{ 
  e.setup(mac, ip, port);
  pinMode(relay1, OUTPUT);
  pinMode(relay2, OUTPUT);
  pinMode(relay3, OUTPUT);
  pinMode(relay4, OUTPUT);
  digitalWrite(relay1, r1);
  digitalWrite(relay2, r2);
  digitalWrite(relay3, r3);
  digitalWrite(relay4, r4);
  Serial.begin(9600);
  Serial.println("Communication etablie arduinoRelay v1");
}

void loop()
{
  char* params;
  if (params = e.serviceRequest())
  {
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[0])));
    e.print(buffer);
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[1])));
    e.print(buffer);
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[2])));
    e.print(buffer);
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[3])));
    e.print(buffer);
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[4])));
    e.print(buffer);
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[5])));
    e.print(buffer);
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[6])));
    e.print(buffer);
    if ( r1 == true){
      strcpy_P(buffer, (char*)pgm_read_word(&(string_table[7])));
      e.print(buffer);
    }else{
      strcpy_P(buffer, (char*)pgm_read_word(&(string_table[8])));
      e.print(buffer);
    }
    if ( r2 == true){
      strcpy_P(buffer, (char*)pgm_read_word(&(string_table[9])));
      e.print(buffer);
    }else{
      strcpy_P(buffer, (char*)pgm_read_word(&(string_table[10])));
      e.print(buffer);
    }
    if ( r3 == true){
      strcpy_P(buffer, (char*)pgm_read_word(&(string_table[11])));
      e.print(buffer);
    }else{
      strcpy_P(buffer, (char*)pgm_read_word(&(string_table[12])));
      e.print(buffer);
    }
    if ( r1 == true){
      strcpy_P(buffer, (char*)pgm_read_word(&(string_table[13])));
      e.print(buffer);
    }else{
      strcpy_P(buffer, (char*)pgm_read_word(&(string_table[14])));
      e.print(buffer);
    }
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[15])));
    e.print(buffer);
    Serial.print("END");
    if (strcmp(params, "?cmd1") == 0)
    {
      r1 = !r1;
      digitalWrite(relay1, r1);
    }
    else if (strcmp(params, "?cmd2") == 0)
    {
      r2 = !r2;
      digitalWrite(relay2, r2);
    }
    else if (strcmp(params, "?cmd3") == 0)
    {
      r3 = !r3;
      digitalWrite(relay3, r3);
    }
    else if (strcmp(params, "?cmd4") == 0)
    {
      r4 = !r4;
      digitalWrite(relay4, r4);
    }
    else if (strcmp(params, "?invert") == 0){
      r1 = !r1; r2 = !r2; r3 = !r3; r4 = !r4;
      digitalWrite(relay1, r1);
      digitalWrite(relay2, r2);
      digitalWrite(relay3, r3);
      digitalWrite(relay4, r4);
    }
    if (strcmp(params, "?allOff") == 0){
      if ( r1 == false){ r1 = !r1;}
      if ( r2 == false){ r2 = !r2;}
      if ( r3 == false){ r3 = !r3;}
      if ( r4 == false){ r4 = !r4;}
      digitalWrite(relay1, r1);
      digitalWrite(relay2, r2);
      digitalWrite(relay3, r3);
      digitalWrite(relay4, r4);
    }
    e.respond();
  }
}

Déjà il y a plus simple que PROGMEM et source de beaucoup moins d'erreur : F().

Par exemple :

strcpy_P(buffer, (char*)pgm_read_word(&(string_table[0])));
    e.print(buffer);

remplaçable par :

e.print(F("<!DOCTYPE HTML> \r \n"));

Si à mon avis la source de ton bug est ici :

PROGMEM const char *string_table[] ={ 
 string_0, string_1, string_2, string_3, string_4, string_5, string_6, string_7, string_8, string_9, string_10, string_11};

T'as pas l'impression qu'il en manque ? :wink:

Effectivement petite erreur de ma part :smiley: Oups mais ça ne change en rien le problème :slight_smile: ma page ne veut toujours pas se charger...

Je vais simplifier le code avec F() ! Mais est-il possible de transformer ceci:

PROGMEM const char *string_table[] ={ string_0, string_1, string_2, string_3, string_4, string_5, string_6, string_7, string_8, string_9, string_10, string_11, string_12, string_13, string_14};

Par une boucle for? J'ai essayé mais sans résultat :cry: Ou alors avec F() plus besoin?

Avec F() plus besoin :wink:

En fait dès que tu a en argument dans une fonction une chaine de caractère fixe, tu peux utiliser F() pour placer cette chaine dans la flash au lieu de la RAM. Si je prend un simple "Hello World", on peux aussi simplement que ça remplacer :

Serial.print("Hello World");
ethernet.print("Hello World");

Par :

Serial.print(F("Hello World"));
ethernet.print(F("Hello World"));

A noter que le revers de la médaille est une perte de vitesse lié au fait la mémoire flash est bien plus lente que la RAM

Merci pour ton conseil et donc tu penses que ça va résoudre mon problème de page qui charge indéfiniment? Car j'avais mis des Serial.println() après chaque écriture de buffer et en ouvrant la console, j'ai obtenu des caractères étranges :S

Preuve que c'est peut-être bien les PROGMEM qui posent problème :wink:

J'espère vraiment que c'est ça! Je mets au point le nouveau code ce soir! et je le publie :slight_smile:

Malheureusement, je ne sais pas si il faut que la fonction soit implémentée car c'est une librairie pour mon module ethernet...

décidément, personne ne sait m'aider? :cry:

J'ai regardé la lib n'utilisa pas la classe print.h, il a juste créer des méthodes print(). Et utiliser F() en argument impose une prise en charge spécifique, donc en l'état pas possible de directement utiliser F() en fait ...

Après ta page est pas bien grande, elle te bouffe pas énormément de RAM la