Je souhaiterais stocké un tableau de float dans la mémoire.
Quelle mémoire me direz-vous ?
Je ne sais pas encore justement.
Au vu de la taille du tableau : 500 valeurs (==> 4*500 = 2000 octets).
Je voulais le stocker dans la Flash mais je suis tombé sur cette phrase dans le site officiel qui m'a refroidie :
" Note: Flash (PROGMEM) memory can only be populated at program burn time. You can’t change the values in the flash after the program has started running. " (Ce qui est logic après tout !)
Concernant la EEPROM, quand je vois tout ce qu'il faut mettre en oeuvre pour stocker un int, ça ne me motive pas de faire une fonction pour stocker et lire un tableau de float de cette taille.
Il y aurait-il une solution plus simple à mettre en place ?
Est-ce que tes 500 float sont des valeurs constantes pré-déterminées ?
Si oui, aucun souci pour le stocker en flash ou en EEPROM (ce qui n'a vraiment rien de très compliqué).
Si non, par exemple si tes float sont le résultat d'une acquisition :
=> le plus simple est de passer sur une arduino MEGA qui dispose de 8 ko de RAM
L'EEPROM est envisageable si le nombre de réécritures est restreint, par exemple si tu réalises 10 mesures par jour et que tu veux conserver l'historique des mesures sur 50 jours glissants.
Autre possibilité : fichier log sur carte SD
Si tes floats sont corrélés entre eux, par exemple si la variation de l'un à l'autre est minime, il est peut-être possible de les compresser en modifiant la logique stockage, et de passer dans la ram d'une uno.
Ils correspondent à quoi ces float ?
Si jamais c'est un résultat de calcul effectué à partir de données binaires de moins de 32 bits (par ex lecture d'une température sur 12 bits via une sonde DS18b20, ou encore calcul à partir d'un analogRead à 10 bits), il serait bien plus futé de stocker les données source.
Pour répondre à vos remarques et pour être plus précis, il s'agit en fait de stocker les valeurs d'un capteur de courant.
Je lis le courant d'un moteur DC et j'aimerais stocker l'évolution de ce courant afin de pouvoir l'afficher et l'analyser après extinction de ma carte.
J'utilise une Méga2560 et concernant l'EEPROM je sais que j'ai un peu de marge mais quand même, c'est beaucoup plus simple d'écrire et de lire dans la Flash (dommage ).
Je vais voir ce qu'est EEPROMex.h (jamais entendu parler ^^ ).
J'insiste sur un point : si ton capteur de courant te délivre une tension analogique, que tu lis via un analogRead(), pas la peine de stocker un float. 10 bits suffisent et tu peux stocker trois fois plus de mesures.
bricoleau:
J'insiste sur un point : si ton capteur de courant te délivre une tension analogique, que tu lis via un analogRead(), pas la peine de stocker un float. 10 bits suffisent et tu peux stocker trois fois plus de mesures.
Oui, effectivement je peux stocker que les valeurs entières [0;500] puis faire la conversion après.
C'est une autre approche que je n'avais pas envisagé dans la mesure où je voulais stocker le "lissage" du courant lu mais je peux toujours appliquer l'algorithme de lissage après.
pepe:
Dans l'exemple, on réalise la moyenne sur les dix dernières mesures. On doit donc retirer la onzième plus ancienne valeur mesurée à chaque ajout d'une nouvelle.
Dans le cas contraire, on calculerait une moyenne sur toutes les mesures effectuées depuis l'allumage de la carte, et au fil du temps la valeur des nouvelles mesures aurait une importance de plus en plus négligeable dans le résultat obtenu.
Je voyais ça comme ça mais pour ma part j'aurais mis cette ligne dans une condition sinon comment être sûr
que c'est tout le temps la 11e valeur qui sera soustraite ?
J'ai essayé de raisonner par coup d'horloge du microcontrôleur en partant des conditions initiales et c'est là que je bloque.
Voici le code :
const int numReadings = 10;
int readings[numReadings]; // the readings from the analog input
int readIndex = 0; // the index of the current reading
int total = 0; // the running total
int average = 0; // the average
int inputPin = A0;
void setup() {
// initialize serial communication with computer:
Serial.begin(9600);
// initialize all the readings to 0:
for (int thisReading = 0; thisReading < numReadings; thisReading++) {
readings[thisReading] = 0;
}
}
void loop() {
// subtract the last reading:
total = total - readings[readIndex];
// read from the sensor:
readings[readIndex] = analogRead(inputPin);
// add the reading to the total:
total = total + readings[readIndex];
// advance to the next position in the array:
readIndex = readIndex + 1;
// if we're at the end of the array...
if (readIndex >= numReadings) {
// ...wrap around to the beginning:
readIndex = 0;
}
// calculate the average:
average = total / numReadings;
// send it to the computer as ASCII digits
Serial.println(average);
delay(1); // delay in between reads for stability
}
Voici mon raisonnement :
Au premier coup d'horloge on part des conditions initiales :
total = total - readings[readIndex]; // total = 0 - readings[0] => total = 0
readings[readIndex] = analogRead(inputPin); // readings[0]= 25 (par exemple)
total = total + readings[readIndex]; // total = 0 + readings[0] <==> total=0+25 ==> total=25
readIndex = readIndex + 1; //readIndex = 0+1 ==> readIndex = 1;
if (readIndex >= numReadings) { // condition fausse on passe à la ligne suivante
// ...wrap around to the beginning:
readIndex = 0;
}
average = total / numReadings; // average = 25/10 ==> average = 2 (car c'est un int)
// A ce stade on a :
// readIndex = 1; et readings[1] est inconnu = x
//total=25
// Au coup d'horloge suivant :
total = total - readings[readIndex]; // total = 25 - readings[1] => total = 25 - x (c'est ça qui ne me va pas !)
readings[readIndex] = analogRead(inputPin); // readings[1]= 18 (par exemple)
total = total + readings[readIndex]; // total = (25 - x) + readings[1] <==> total=25-x+18 ==> total=43-x
readIndex = readIndex + 1; //readIndex = 1+1 ==> readIndex = 2;
if (readIndex >= numReadings) { // condition fausse on passe à la ligne suivante
// ...wrap around to the beginning:
readIndex = 0;
}
average = total / numReadings; // average = (43-x)/10 ==> average = ?
// A ce stade on a :
// readIndex = 2; et readings[2] est inconnu
//total = 43-x !!!!!!!
pepe:
On utilise un tampon circulaire (readings[]) initialisé à 0.
Durant les dix premières boucles loop(), on "retire" donc juste une valeur 0 du tampon, et la moyenne passe progressivement de 0 à une valeur correspondant à la valeur moyenne réelle des mesures.
À partir de la onzième boucle loop(), on "retire" une valeur correspondant effectivement à une ancienne mesure, effectuée dix boucles plus tôt (puisqu'il y a exactement 10 valeurs stockées dans le tampon circulaire), et la moyenne est calculée sur 10 véritables mesures.
C'est plus compréhensible en raisonnant par boucle et non par coup d'horloge.
Je vais bidouiller un peu ce code pour mieux le comprendre.
Pour optimiser cette portion de code, utiliser une puissance de 2 pour le nombre d'échantillons (16 au lieu de 10 par exemple) ainsi la division peut-être réalisée avec des décalages (beaucoup plus rapide) Le compteur/index dans le tableau d'échantillons peut être borné par un & au lieu d'un test.
fdufnews:
Pour optimiser cette portion de code, utiliser une puissance de 2 pour le nombre d'échantillons (16 au lieu de 10 par exemple) ainsi la division peut-être réalisée avec des décalages (beaucoup plus rapide) Le compteur/index dans le tableau d'échantillons peut être borné par un & au lieu d'un test.
Ce que tu suggères c'est décaler juste l'index tous les 16 valeurs ? Au lieu de revenir à 0 et supprimer à jamais les valeurs du tableau (en remettant l'index à 0).
Mais du coup avec une puissance de 2, on ne perd pas en précision ?
Je comptais faire l'inverse, prendre 5 au lieu de 10 pour être 2 fois plus précis mais cela implique une certaine lenteur.