[RESOLU] Optimisation code _ Mon arduino Uno plante.....plus!

Bonsoir,
J'aimerais optimiser mon code pour qu'il prenne moins de place dans ma UNO car il ne fonctionne pas complètement.
Quand j'active le NTP la partie Ethernet ne fonctionne pas.
Si je désactive le NTP update, tout le reste fonctionne normalement.
Je pense que c'est un problème de taille de mon code qui doit être trop important.

Quelqu'un aurait une idée?

CODE:

control4.ino (23.6 KB)

Qu'entends tu par NTP ?
J'ai déjà eu un problème similaire, j'allumais une led après avoir initialisé le serveur, mais la led ne marchait pas... et si je désactivais Ethernet.begin(), elle fonctionnait. Je crois que cela venait du fait que mon serveur était mal configuré, et que mon réseau lui non plus n'était pas correctement configuré.

Mais montre ton code (apparemment il y a eu un bug), sinon on ne pourra pas t'aider :s

Apparment il faut être "Online" pour voir la pièce jointe et télécharger mon code.

Sinon je peux le mettre en clair avec les quotes mais il y en a pour long :grin:

Darwoon:
Qu'entends tu par NTP ?
J'ai déjà eu un problème similaire, j'allumais une led après avoir initialisé le serveur, mais la led ne marchait pas... et si je désactivais Ethernet.begin(), elle fonctionnait. Je crois que cela venait du fait que mon serveur était mal configuré, et que mon réseau lui non plus n'était pas correctement configuré.

Mais montre ton code (apparemment il y a eu un bug), sinon on ne pourra pas t'aider :s

Alors si je mets la partie configuration jusqu'au Setup compris ça donne ça:

/*
Relais Box Control
http://johnlenfr.1s.fr
 */
 
#include <SPI.h>	
#include <Ethernet.h>	
#include <Wire.h>
#include <QuadEncoder.h>
#include <Deuligne.h>
#include <Keybord.h>
#include "RTClib.h"
#include <EthernetUdp.h>
// Valeur de la période de la boucle de base.
#define periode 20 // en millisecondes.
// Configuration ethernet - internet
// Configuration des adresses Ethernet (MAC) et Internet (IP) du serveur TCP/IP de la carte Arduino.
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0xB5, 0x42 };//Valeur en hexadécimale de l'adresse MAC de la carte Arduino. Valeur unique sur le réseau.
IPAddress ip(192,168,1,12);

// Configuration pour connection à un serveur NTP pour mise à jour de l'heure
unsigned int localPort = 8888;             // local port to listen for UDP packets
IPAddress timeServer(95, 130, 9, 77);      // http://Ntp.crashdump.fr se synchronise sur les serveur de strate 1
//IPAddress timeServer(193, 79, 237, 14);
//IPAddress timeServer(193, 52, 137, 193);   //http://www.pool.ntp.org/fr/
const int NTP_PACKET_SIZE= 48;             // NTP time stamp is in the first 48 bytes of the message
byte pb[NTP_PACKET_SIZE];                  // buffer to hold incoming and outgoing packets

//Déclaration Internet
EthernetServer server(80);//déclaration du serveur internet de la carte Arduino.
// A UDP instance to let us send and receive packets over UDP
EthernetUDP Udp;


//Libellés des boutons.
#define texte_relais_1_on "R1_ON" 	//
#define texte_relais_1_off "R1_OFF" //
#define texte_relais_2_on "R2_ON" 	//
#define texte_relais_2_off "R2_OFF" //
#define texte_relais_3_on "R3_ON" 	//
#define texte_relais_3_off "R3_OFF" //
#define texte_relais_4_on "R4_ON" 	//
#define texte_relais_4_off "R4_OFF" //

//texte en constante pour les Boutons de commandes digitales.
const String libelleBoutonAOn=texte_relais_1_on; //
const String libelleBoutonAOff=texte_relais_1_off; //
const String libelleBoutonBOn=texte_relais_2_on; //
const String libelleBoutonBOff=texte_relais_2_off; //
const String libelleBoutonCOn=texte_relais_3_on; //
const String libelleBoutonCOff=texte_relais_3_off; //
const String libelleBoutonDOn=texte_relais_4_on; //
const String libelleBoutonDOff=texte_relais_4_off; //

int nb_pins=22;//nombre de pin de la carte suivant le type de carte (par défaut le maximum).
String ChaineHTML; // chaine html de stockage.

int boutonA = 0; // 0 = off, 1 = on 
int boutonB = 0; // 0 = off, 1 = on 
int boutonC = 0; // 0 = off, 1 = on 
int boutonD = 0; // 0 = off, 1 = on 

// reserved port for communication with Ethernet+SD shield
//#define SD_SS     4
#define ETH_SS   10
#define SPI_MOSI 11
#define SPI_MISO 12
#define SPI_CLK  13

// encoder variables
#define SWI 2 // Intr 0 = Pin 2
#define CHA 6
#define CHB 7
#define MENULED 5
// initialize the encoder
QuadEncoder encoder(CHA,CHB); // initialize the encoder
// has the encoder moved on this loop?
boolean moved = false;

typedef enum clock__members
{   clock__MemberDay,
    clock__MemberMonth,
    clock__MemberYear,
    clock__MemberHour,
    clock__MemberMinute,
    clock__MemberSecond
} clock__member_t;

static void clock__printDatetime();
static RTC_DS1307  clock__rtc;
static DateTime clock__currentTime;
static clock__member_t clock__currentMember = clock__MemberDay;

// initialize the library with the numbers of the interface pins
Deuligne lcd;

// other vars
boolean ledIsOn = false;

// SD card vars
boolean sdcard = false;

// counter
int count = 0;

// for refresh time
const unsigned long DISPLAY_INTERVAL = 20000; // in ms
static unsigned long lastTime=0;  // in ms
unsigned long time=millis();      // in ms
unsigned long starting_time=millis();      // in ms

// for refresh time day
const unsigned long DISPLAY_INTERVAL_day = 86400000; // wait for 1 day
static unsigned long lastTime_day=0;  // in ms
unsigned long time_day=0;      // in ms

// relais status of the slave device (Arduino NANO)
boolean relayON[4];
char buf[2];

// make some custom characters:
byte relaisON [8] = {
  0b11111,
  0b11111,
  0b11111,
  0b11111,
  0b11111,
  0b11111,
  0b11111,
  0b11111
};

byte relaisOFF [8] = {
  0b11111,
  0b10001,
  0b10001,
  0b10001,
  0b10001,
  0b10001,
  0b10001,
  0b11111
};


///// SETUP /////
void setup() {

       Ethernet.begin(mac, ip);
       server.begin();
       Wire.begin(); 
       
       pinMode(CHA, INPUT);
       pinMode(CHB, INPUT);
       pinMode(SWI, INPUT);
       pinMode(MENULED,OUTPUT); //debug to led 5

       // Initialize RTC.
       clock__rtc.begin();
       delay(100);

       lcd.init(); // LCD
       // create a new character
       lcd.createChar(0, relaisOFF);
       lcd.createChar(1, relaisON);
       lcd.clear();
       // turn on backlight
       lcd.backLight(true);

       starting_time = millis(); // get local time
       //freeRAM();
       ntpUpdate(); // update RTC time with NTP protocol if connected to network
       //freeRAM ();
       relayON[1]=false;
       relayON[2]=false;
       relayON[3]=false;
       relayON[4]=false; 
}

Tu détectes déjà des erreurs?

Bonjour,

Ton problème actuellement c'est que tu utilises mal ta mémoire RAM.
Tu gaspilles inutilement le peu de ressource dont tu disposes ...

  • N'utilise pas de const String mais des char[] en mémoire flash (macro F("..."))
    --> Toutes tes chaines de char constantes doivent être en flash !
  • N'utilise jamais String, c'est une saloperie sans nom
  • remplace tes if(c=='x') else if (c=='y') ... par un switch/case
  • ne stock pas en mémoire RAM le html, envoi le html directement morceaux par morceaux
  • Wire.print(int) existe, pas besoin d'utiliser itoa() et d'avoir un buffer en mémoire
  • choisi au mieux tes types, pas besoin d'un int pour une variable >=255, un byte suffit
    ...

Bonjour skywodd

Ton problème actuellement c'est que tu utilises mal ta mémoire RAM.
Tu gaspilles inutilement le peu de ressource dont tu disposes ...

Oui je sais pas programmer, j'essaye de m'inspirer de ce qui traine sur la toile mais je n'ai pas vraiment de bases solides :grin:

J'avais testé d'afficher la RAM dispo avec freeRAm et je suis aux alentours de 127-147. Ce n'est pas suffisant?

  • N'utilise pas de const String mais des char[] en mémoire flash (macro F("..."))

Tu as un exemple de déclaration?
Je dois faire : char[]= F("TEST"); ?

--> Toutes tes chaines de char constantes doivent être en flash !

Comment je les mets en flash? toujours avec le F("...") ?

  • N'utilise jamais String, c'est une saloperie sans nom

A la place de string je mets quoi?

  • remplace tes if(c=='x') else if (c=='y') ... par un switch/case

ça ok je vais essayer

  • ne stock pas en mémoire RAM le html, envoi le html directement morceaux par morceaux

Comment je procède pour faire ça?

  • Wire.print(int) existe, pas besoin d'utiliser itoa() et d'avoir un buffer en mémoire

Peut-être que le Wire.print ça fonctionne mais moi j'ai fait un Wire.write, pour lequel cela ne fonctionne pas.
J'ai essayé hier soir un Wire.write(i) le problème c'est que je reçois un caractère bizarre de l'autre coté (sur la Nano en réception)

  • choisi au mieux tes types, pas besoin d'un int pour une variable >=255, un byte suffit

Tu veux dire si l'int est <=255? je déclare byte i=0; ?

Ce qui est bizzare c'est que quand je zappe une partie du code, le reste fonctionne, donc je pensais que c'était plutot du à un manque de mémoire morte (là ou on stoke le programme compilé) plutot que vive non?

J'ai remarqué également que je ne peux pas faire de débug, car je n'arrive pas à utiliser Serial.begin et Serial.print ...
Est-ce que c'est à cause de l'ethernet qui utilise déjà le TX-RX?

john_lenfr:
J'avais testé d'afficher la RAM dispo avec freeRAm et je suis aux alentours de 127-147. Ce n'est pas suffisant?

Vu le code je dirai que non, c'est un cas typique de manque de RAM.
(et comme par hasard le code utilise des String, coïncidence ? Je pense pas ...)

john_lenfr:
Tu as un exemple de déclaration?
Je dois faire : char[]= F("TEST"); ?

const char[] toto PROGMEM = "toto" ;

Mais en y regardant bien tu utilises ces constantes qu'une seule fois ... c'est donc inutile de les rendre globales ...
Fait directement un F("le texte du bouton") dans le client.print() qui va bien.

john_lenfr:
Comment je les mets en flash? toujours avec le F("...") ?

Avant :

Serial.println("toto");

Aprés :

Serial.println(F("toto"));

john_lenfr:
A la place de string je mets quoi?

Des tableaux de char classique, comme devrais le faire tout bon développeur sur microcontrôleurs.
Au moins ça t'oblige à faire un code structuré, pas des trucs du genre HTMLmachin += "


....", avec des String de partout ...

john_lenfr:
Comment je procède pour faire ça?

Tu fait tes client.print() au moment où tu veut envoyer les info au lieu de les stocker en RAM puis de tout envoyer d'un coup.

Avant :

ChaineHTML = "<TD><FORM METHOD='GET' ACTION='/a'><INPUT TYPE='submit' VALUE='";
ChaineHTML += libelleBoutonAOn;
ChaineHTML += "' ></FORM></TD>";

Aprés :

client.print(F("<TD><FORM METHOD='GET' ACTION='/a'><INPUT TYPE='submit' VALUE='"));
client.print(F("le texte du bouton"));
client.print(F("' ></FORM></TD>"));

john_lenfr:
Peut-être que le Wire.print ça fonctionne mais moi j'ai fait un Wire.write, pour lequel cela ne fonctionne pas.
J'ai essayé hier soir un Wire.write(i) le problème c'est que je reçois un caractère bizarre de l'autre coté (sur la Nano en réception)

Faire un Wire.write(tableau, taille) d'un tableau de char revient à faire un Wire.print(), en moins bien.
Faire un Wire.write(pointeur) revient à envoyer l'adresse du pointeur ... c'est pas du tout ce que tu veut :wink:

Tu ne sembles pas encore faire la différence entre envois binaire et envois textuel.
Regarde "ASCII CODE" sur google tu comprendras pourquoi tu reçois des trucs bizarre :wink:

john_lenfr:
Tu veux dire si l'int est <=255? je déclare byte i=0; ?

Ben oui ...
Si tu as besoin de garder 100ml d'eau tu prend pas une bassine ?
Pareil en programmation si tu veut stocker une valeur <=255 tu prends un byte, ça suffit.

john_lenfr:
Ce qui est bizzare c'est que quand je zappe une partie du code, le reste fonctionne, donc je pensais que c'était plutot du à un manque de mémoire morte (là ou on stoke le programme compilé) plutot que vive non?

Si tu manquais de ROM le compilateur t'enverrais chier en te disant que la section ".text" de ton programme ne passe pas en mémoire.
Même en forçant le compilateur (enfin le linker pour être précis) l'upload ne fonctionnerai pas, lors de la vérification il y aurait forcément une erreur.
C'est donc forcément un problème de RAM :wink:

Ok, je sens que je suis pas couché ce soir en rentrant du boulo :grin:

En tout cas ça me rassure que c'est du à la RAM, ça veut dire que je vais pouvoir réussir l'ensemble du code en optimisant!

Bonsoir skywodd,

j'ai fait tout ce que tu m'as dit et le programme ne plante plus.

C'est impressionant! je suis à 1070 de freeRAM maintenant!!
Comparé aux 127-147 ya pas photo!

Merci pour les conseils, du coup je vais pouvoir rajouter des choses :grin:

Une ptite vidéo pour voir à quoi ça ressemble ici: Relais Box Control with Arduino Ethernet LCD Quadencoder Serial - YouTube

Il n'y avait pas encore l'implémentation du NTP et DST mais le principal y est.

john_lenfr:
j'ai fait tout ce que tu m'as dit et le programme ne plante plus.

C'était donc bien un problème de mémoire RAM insuffisante.

john_lenfr:
C'est impressionant! je suis à 1070 de freeRAM maintenant!!
Comparé aux 127-147 ya pas photo!

C'est la magie de l'optimisation :grin:
Tu as du aussi gagner un peu de place en mémoire flash (mais pas autant qu'en RAM).

Ps: publie ton code "âpres optimisation" que cela puisse servir d'exemple aux prochains lecteurs de ce topic :wink: