[Resolu] Tableau dynamique

Bonjour.

Une nouvelle fois je me tourne vers vous. Ma question est la suivante : Est il possible de completer dynamiquement un tableau de taille inconnue ?

float temperature = 0;
float delta = 0;
int nombre_alarmes = 0;
String message_alarme[] = "";

void setup {
}

void loop {
   ...
  // initier les alarmes

  if (temperature > 25){
    nouvelle_alarme = true;
    message_alarme[nombre_alarmes] = "alarme temperature >>";
    nombre_alarmes++;     
  }

  if (delta > 0.2){
    nouvelle_alarme = true;
    message_alarme[nombre_alarmes] = "alarme delta t°";
    nombre_alarmes++;     
  }
   
etc ...

}

Il n'y a pas d'erreur de compilation mais ça ne fonctionne pas. L'arduino UNO n'aime pas du tout et tout se bloque. Je dois rater qque chose :~.

Je vous remercie par avance

bonjour,
je ferais un truc de ce genre

float temperature = 0;
float delta = 0;
int nombre_alarmes = 0;
int ancienne_alarme = 0;
String message_alarme = “”;

void setup {
}

void loop {

// initier les alarmes

if (temperature > 25 || delta > 0.2){
nombre_alarmes = ancienne_alarme + 1;

if (temperature > 25){
nouvelle_alarme = true;
message_alarme[nombre_alarmes] += “alarme temperature >>”;
}

if (delta > 0.2){
nouvelle_alarme = true;
message_alarme[nombre_alarmes] += “alarme delta t°”;
}
ancienne_alarme = nombre_alarmes;
}
etc …

}

Bonjour, essaie comme ça :

void loop {
  if (temperature > 25){
    nouvelle_alarme = true;
    message_alarme += "alarme temperature >>";
  }
  if (delta > 0.2){
    nouvelle_alarme = true;
    message_alarme += "alarme delta t°";     
  }
}

merci mais ça ne fonctionne pas. la carte plante à chaque fois …
un simple prog comme suit :

String message_alarme[]="";

void setup() {
  Serial.begin(9600);  
}

void loop() {
  for (int i; 0 <10; i++) {
    message_alarme[i] = "alarme ";
    Serial.println(message_alarme[i]);
  }
  delay(10000000);
}

me donne n’importe quoi dans le moniteur serie et apres qques secondes, l’arduino cesse de fonctionner.
C’est un grand mystere …

Cette déclaration n'est pas bonne

String message_alarme[]="";

Un tableau de String est une collection de pointeurs vers des objets String tu ne peux donc pas y affecter une chaîne. D'autre part la définition d'un tableau sans dimension ne réserve de la place que pour le pointeur lui même puisqu'à la compilation on ignore le nombre d'éléments dudit tableau. Donc à chaque fois que l'on crée un nouvel élément pour le tableau il faut redimensionner le tableau. C'est le noyau du C qui le fait, mais cela veut dire recréer le tableau sur le tas et supprimer l'ancien c'est gourmand en mémoire car cela la fragmente. Sur une cible comme l'Arduino avec relativement peu de mémoire l'utilisation de tableau dynamique n'est pas vraiment recommandée. Si tu as une idée du nombre d'éléments dont tu auras besoin il serait largement préférable de déclarer un tableau avec cette dimension. D'autant que ce n'est pas le tableau qui tient de la place en mémoire c'est les objets qu'il indexe.

déjà il faudrait savoir ce que tu veux faire exactement. sinon, une solution serait d'écrire dans un fichier sur une sd les alarmes.

Bonjour,

Ce que tu essaye de faire c'est de l'allocation dynamique de mémoire. Sauf que tu ne déclares qu'un pointeur sur String et non un tableau de String ! (type[] variable; c'est un tableau dynamique ... en C#, pas en C/C++).

Autre chose, String est une vrai saloperie avec déjà de l'allocation dynamique en interne. Faire un tableau dynamique de String c'est vraiment pas une bonne idée, sauf si tu veut avoir des bugs aléatoires impossible à résoudre (fragmentation de la mémoire RAM).

Explique nous un peu plus ce que tu veut faire au final, ta méthode actuelle n'est vraisemblablement pas la plus adapté ;)

merci beaucoup pour vos éclaircissements.

... Faire un tableau dynamique de String c'est vraiment pas une bonne idée, sauf si tu veut avoir des bugs aléatoires impossible à résoudre (fragmentation de la mémoire RAM).

Effectivement, dans le petit programme que je vous ai indiqué, le moniteur serie affiche même parfois des lignes du code !

Explique nous un peu plus ce que tu veut faire au final, ta méthode actuelle n'est vraisemblablement pas la plus adapté

Dans la boucle loop, différents capteurs analogiques sont lus. Pour chacun de ces capteurs une alarme est générée si une ou plusieurs conditions sont réunies. Je souhaitais créer un array[] contenant un message correspondant à chaque alarme et ainsi pouvoir accéder à l'ensemble des messages grace à a quelque chose du genre :

for (int i = 0; i= sizeof(myarray); i++) {
   Serial.println(myarray[i]);
}

Les erreurs sont stockées dans un tableau affichés grace à l'action d'un interrupteur sur une broche d'interruption. Je ne connais pas le nombre d'erreurs qui ont ête générées dans la boucle loop je ne peux donc pas le dimensionner d'une façon fixe...

les array[] de chaine ont vraiment mauvais caractere... :grin:

je vois 2 solutions dans ce cas si tu ne connais pas le nb d'alarmes : 1- comme au dessus, écrire sur une carte sd les alarmes dans un fichier 2- connecter sur un pc via ethernet et envoyer les erreurs dans une bdd

ludobabs:
Effectivement, dans le petit programme que je vous ai indiqué, le moniteur serie affiche même parfois des lignes du code !

Les langages C et C++ sont dit “compilé”, tu ne peut donc pas voir du code du programme dans le serial monitor :wink:
Au mieux tu doit pouvoir voir des morceaux de chaine de caractères statique mais pas plus.

ludobabs:
Dans la boucle loop, différents capteurs analogiques sont lus. Pour chacun de ces capteurs une alarme est générée si une ou plusieurs conditions sont réunies. Je souhaitais créer un array contenant un message correspondant à chaque alarme et ainsi pouvoir accéder à l’ensemble des messages grace à a quelque chose du genre :

En gros tu veut faire un système d’historique des alarmes ?

ludobabs:
Les erreurs sont stockées dans un tableau affichés grace à l’action d’un interrupteur sur une broche d’interruption. Je ne connais pas le nombre d’erreurs qui ont ête générées dans la boucle loop je ne peux donc pas le dimensionner d’une façon fixe…

Tu as toujours une limite : la mémoire RAM disponible.
Elle n’est pas infini, il faut que tu te fixe un maximum pour ton tableau.

Les messages d’alarmes sont toujours de type prédéterminé ?
Si oui tu peut faire autre chose, plus propre, un tableau de structure !

/** Enumération des types d'alarmes possible */
typedef enum {
    ALARME_AUCUNE,  /*!< Pas d'alarme */
    ALARME_TEMPERATURE, /*!< Alarme de température */
    ALARME_DELTA, /*!< Alarme de ... */
// ... etc
} TypeAlarme_t;

/** Structure d'une alarme */
typedef struct {
    unsigned long temps; /*!< Temps du déclenchement de l'alarme */
    byte capteur; /*!< Capteur ayant déclenché l'alarme */
    TypeAlarme_t type; /*!< Type d'alarme */
} Alarme_t;

/** Historique des alarmes */
const byte NB_ALARMES_MAX = 50;
Alarme_t historique[NB_ALARMES_MAX] = {0, 0, ALARME_AUCUNE};

/** Gestion de l'historique comme un buffer circulaire */
byte historique_head = 0;

/** Ajout d'une alarme dans l'historique */
void ajoutAlarme(byte capteur, TypeAlarme_t type) {
    Alarme_t alarme;
    alarme.temps = millis();
    alarme.capteur = capteur;
    alarme.type = type;
    historique[historique_head] = alarme;
    if(++historique_head == NB_ALARMES_MAX)
        historique_head = 0; // Écrase les historiques plus ancien si on manque de place
}

/** Affichage des alarmes de la plus ancienne à la plus récente */
void afficheAlarmes() {
    for(byte j = 0, i = historique_head; j < NB_ALARMES_MAX; ++j, i = (i + 1) % NB_ALARMES_MAX) {
        if(historique[i].type == ALARME_AUCUNE) continue;
        Serial.print(historique[i].temps);
        Serial.print(F(" - "));
        Serial.print(historique[i].capteur);
        Serial.print(F(" : "));
        switch(historique[i].type) {
            case ALARME_TEMPERATURE:
                Serial.println(F("Alarme temperature"));
                break;

            case ALARME_DELTA:
                Serial.println(F("Alarme temperature"));
                break;
        }
    }
}

Edit: correction d’une erreur au niveau des sizeof(), remplacé par un const (plus simple à comprendre).

Sinon tu peut faire un système déporté comme le propose infobarquee :

Re à tous. Sur les conseils de skywodd :

Place tout tes typedef dans un fichier .h (alarmes.h par exemple) et ajoute un include en haut de ton code :
#include “alarmes.h” par exemple.
Cela devrait régler le problème de compilation

Je souhaite générer une erreur par boucle et l’afficher, le code principal est :

#include "alarmes.h" 

/** Historique des alarmes */
Alarme_t historique[50] = {0, 0, ALARME_AUCUNE};

/** Gestion de l'historique comme un buffer circulaire */
byte historique_head = 0;

void setup()
{
    Serial.begin(9600);  
}

void loop()
{

    ajoutAlarme(1,ALARME_TEMPERATURE);
    afficheAlarmes();

   delay(5000);
}

/** Ajout d'une alarme dans l'historique */
void ajoutAlarme(byte capteur, TypeAlarme_t type) {
    Alarme_t alarme;
    alarme.temps = millis();
    alarme.capteur = capteur;
    alarme.type = type;
    historique[historique_head] = alarme;
    if(++historique_head == sizeof(historique))
        historique_head = 0; // Écrase les historiques plus ancien si on manque de place
}

/** Affichage des alarmes de la plus ancienne à la plus récente */
void afficheAlarmes() {
    for(byte j = 0, i = historique_head; j < sizeof(historique); ++j, i = (i + 1) % sizeof(historique)) {
        if(historique[i].type == ALARME_AUCUNE) continue;
        Serial.print(historique[i].temps);
        Serial.print(F(" - "));
        Serial.print(historique[i].capteur);
        Serial.print(F(" : "));
        switch(historique[i].type) {
            case ALARME_TEMPERATURE:
                Serial.println(F("Alarme temperature"));
                break;

            case ALARME_DELTA:
                Serial.println(F("Alarme delta"));
                break;
        }
    }
}

le code de alarmes.h :

/** Enumération des types d'alarmes possible */
typedef enum {
    ALARME_AUCUNE,  /*!< Pas d'alarme */
    ALARME_TEMPERATURE, /*!< Alarme de température */
    ALARME_DELTA, /*!< Alarme de ... */
// ... etc
} TypeAlarme_t;

/** Structure d'une alarme */
typedef struct {
    unsigned long temps; /*!< Temps du déclenchement de l'alarme */
    int capteur; /*!< Capteur ayant déclenché l'alarme */
    TypeAlarme_t type; /*!< Type d'alarme */
} Alarme_t;

Il y a de nouveaux probleme au niveau de l’affichage de l’historique dans le moniteur série. je vous tiens informés.

Un grand merci à tous pour votre aide

Et bien voila. Ca fonctionne. Un grand merci à toute la communauté et à skywodd en particulier. Me voici donc à la tête d’un magnifique système d’historique des alarmes. C’est génial.

Voici le code

Alarmes.h

/** Enumération des types d'alarmes possible */
typedef enum {
  ALARME_AUCUNE,  /*!< Pas d'alarme */
  ALARME_TEMPERATURE, /*!< Alarme de température */
  ALARME_DELTA, /*!< Alarme de ... */
  // ... etc
} 
TypeAlarme_t;

/** Structure d'une alarme */
typedef struct {
  unsigned long temps; /*!< Temps du déclenchement de l'alarme */
  unsigned char capteur; /*!< Capteur ayant déclenché l'alarme */
  TypeAlarme_t type; /*!< Type d'alarme */
} 
Alarme_t;

le prog. principal.

/*

// fichier alarmes.h

//Enumération des types d'alarmes possible
typedef enum {
  ALARME_AUCUNE,  //!< Pas d'alarme
  ALARME_TEMPERATURE, //*!< Alarme de température
  ALARME_DELTA, //!< Alarme de ...
  // ... etc
} 
TypeAlarme_t;

// Structure d'une alarme
typedef struct {
  unsigned long temps; //!< Temps du déclenchement de l'alarme
  unsigned char capteur; //!< Capteur ayant déclenché l'alarme
  TypeAlarme_t type; //!< Type d'alarme
} 
Alarme_t;

*/

#include "alarmes.h" 

/** Historique des alarmes */
Alarme_t historique[50] = {0, 0, ALARME_AUCUNE};

/** Gestion de l'historique comme un buffer circulaire */
byte historique_head = 0;

void setup()
{
    Serial.begin(9600);  
}

void loop()
{

    ajoutAlarme(1,ALARME_DELTA);
    ajoutAlarme(1,ALARME_TEMPERATURE);    
    
    afficheAlarmes();

   delay(10000);
}



/** Ajout d'une alarme dans l'historique */
void ajoutAlarme(byte capteur, TypeAlarme_t type) {
    Alarme_t alarme;
    alarme.temps = millis();
    alarme.capteur = capteur;
    alarme.type = type;
    historique[historique_head] = alarme;
    if(++historique_head == sizeof(historique))
        historique_head = 0; // Écrase les historiques plus ancien si on manque de place
}

/** Affichage des alarmes de la plus ancienne à la plus récente */
void afficheAlarmes() {
    for(byte j = 0, i = historique_head; j < sizeof(historique) / sizeof(Alarme_t); ++j, i = (i + 1) % (sizeof(historique) / sizeof(Alarme_t))) {
        if(historique[i].type == ALARME_AUCUNE) continue;
        Serial.print(historique[i].temps);
        Serial.print(F(" - "));
        Serial.print(historique[i].capteur);
        Serial.print(F(" : "));
        switch(historique[i].type) {
            case ALARME_TEMPERATURE:
                Serial.println(F("Alarme temperature"));
                break;

            case ALARME_DELTA:
                Serial.println(F("Alarme delta"));
                break;
        }
    }
}

Dans le moniteur serie nous obtenons :

0 - 1 : Alarme delta
0 - 1 : Alarme temperature
0 - 1 : Alarme delta
0 - 1 : Alarme temperature
10001 - 1 : Alarme delta
10001 - 1 : Alarme temperature
etc …

merci

Pour ceux qui veulent le détails : j'utilisai sizeof(historique) qui retourne la taille en octet du tableau, comme un idiot j'avais oublié de diviser cette taille par la taille d'un élément du tableau. Du coup, buffer overflow, et comme toujours dans ce genre de cas on se retrouve avec à peu prés n'importe quoi sur la sortie sortie.

En modifiant :

sizeof(historique)

par :

sizeof(historique) / sizeof(Alarme_t)

le problème est réglé.

J'ai édité mon post précédant pour y intégrer une constante au lieu d'utiliser des sizeof(). C'est plus simple à comprendre quand on débute :grin: