Go Down

Topic: [Resolu] Tableau dynamique (Read 6842 times) previous topic - next topic

ludobabs

Jan 13, 2013, 10:10 am Last Edit: Jan 15, 2013, 08:28 pm by ludobabs Reason: 1
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 ?

Code: [Select]

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

infobarquee

bonjour,
je ferais un truc de ce genre
Quote
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 ...

}
AUCUNE AIDE PAR MP

numero_744

Bonjour, essaie comme ça :
Code: [Select]

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

ludobabs


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

Code: [Select]
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 ...


fdufnews

Cette déclaration n'est pas bonne
Code: [Select]
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.

infobarquee

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.
AUCUNE AIDE PAR MP

skywodd

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é ;)
Des news, des tutos et plein de bonnes choses sur http://skyduino.wordpress.com !

ludobabs

#7
Jan 13, 2013, 01:57 pm Last Edit: Jan 13, 2013, 02:04 pm by ludobabs Reason: 1
merci beaucoup pour vos éclaircissements.

Quote

...
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 !

Quote
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 :

Code: [Select]

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...  :smiley-mr-green:

infobarquee

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
AUCUNE AIDE PAR MP

skywodd

#9
Jan 13, 2013, 02:38 pm Last Edit: Jan 16, 2013, 02:16 pm by skywodd Reason: 1

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 ;)
Au mieux tu doit pouvoir voir des morceaux de chaine de caractères statique mais pas plus.


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 ?


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 !

Code: [Select]
/** 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 :
http://skyduino.wordpress.com/2013/01/02/arduino-systeme-de-traitement-online-offline/
Des news, des tutos et plein de bonnes choses sur http://skyduino.wordpress.com !

ludobabs

Re à tous. Sur les conseils de skywodd :

Quote
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 :
Code: [Select]
#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 :
Code: [Select]
/** 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

ludobabs

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
Code: [Select]
/** 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.
Code: [Select]
/*

// 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 :
Quote
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

skywodd

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 :
Code: [Select]
sizeof(historique)
par :
Code: [Select]
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 :smiley-mr-green:
Des news, des tutos et plein de bonnes choses sur http://skyduino.wordpress.com !

Go Up