Lecture/ecriture d'une variable décimale en RAM sur le RTC DS1307

Bonjour,

j'ai réalisé un montage simple sur arduino uno avec 2 boutons poussoirs et 1 Lcd 2x16, l'un des BP incrémente un compteur décimal entre 0 et 999 et l'autre BP remet le compteur à 0, j'affiche la valeur du compteur sur le LCD. Tout ça fonctionne trés bien mais lorsque je coupe l'alimentation du Uno évidemment je perds la valeur de mon compteur.
J'ai donc opté pour le rajout d'un module RTC DS1307 (horloge temps réel) qui possède 56 octets de RAM sauvegardés par pile bouton, l'avantage c'est qu'avec la Ram on est pas limité en cycles d'écriture/lecture.

Et c'est là que ça se corse pour moi, j'ai trouvé un exemple d'utilisation de la RAM du 1307 ici :

et ça donne ceci avec l'exemple qui permet de stocker un message dans la ram et de le relire :

#include <Wire.h>
#include <RTClib.h>
 
RTC_DS1307 RTC;
 
void setup () {
    Serial.begin(57600);
    Wire.begin();
    RTC.begin();
     
    // Write bytes in RAM.
    uint8_t data[13] = {
        'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\n',
    };
    RTC.writeBytesInRam(0x08, 13, data);
}
 
void loop () {
    // Read bytes in RAM.
    uint8_t data[13] = { 0 };
    RTC.readBytesInRam(0x08, 13, data);
     
    // Print bytes on Serial.
    Serial.write(data, 13);
    delay(5000);
}

je souhaiterai utiliser cet exemple en remplaçant le message texte par ma variable compteur d'une valeur comprise entre 0 et 999, d'après les docs il faut travailler en BCD donc convertir ma variable puis lors de la lecture la convertir à nouveau en décimal, ma variable se codera donc entre 4 bits (0) et 12 bits (999), donc j'en déduis que 2 octets de la ram sont suffisants pour stocker ma valeur.
Comment mettre en forme ceci dans l'exemple donné?
merci pour votre aide.

999 tient sur un entier donc tu définis une variable qui contiendra la valeur du compteur à sauver.

unsigned int valCompt;

Ensuite il faut couper cet entier en 2 octets. On va ré-utiliser le tableau de l'exemple

data[0] = valCompt & OxFF; // isole les 8 poids faibles de l'entier
data[1] = (valCompt >> 8) & OxFF; // isole les 8 poids forts de l'entier

il ne reste plus qu'à faire l'écriture dans la zone mémoire du DS1307.

Pour récupérer la valeur. Tu fais l'inverse

Tu fais lire la mémoire du DS1307 dans un tableau et ensuite tu reconstruis valCompt

valCompt= data[1]<<8 + data[0];

Il est évident que le tableau data est trop grand pour ton besoin. Tu peux modifier sa déclaration pour l'adapter à ton programme.

Et si l'entier est beaucoup plus gros ?

Genre : 1 000 000 000 ?

Merci

gunsman76:
Et si l'entier est beaucoup plus gros ?

Genre : 1 000 000 000 ?

Merci

On utilise un unsigned long et on le fait 4 fois pour sauver les 4 octets qui le composent.

En y réflechissant un peu, on peut aussi coder un appel à la fonction plus générique.

    RTC.writeBytesInRam(adresse, sizeof(ma_variable), (uint8_t *)&ma_variable);

Cette manière de faire adresse directement la zone contenant la variable. Et on a pas besoin de savoir comment elle est stockée en mémoire.

Pour la restauration il suffit de faire l'inverse. Il faut évidemment que la variable soit créée avant l'appel

    RTC.readBytesInRam(adresse, sizeof(ma_variable), (uint8_t *)&ma_variable);

ATTENTION: sizeof détermine à la compilation la taille de la variable donc ce système ne fonctionnera qu'avec des variables de type connue au moment de la compilation. Ne fonctionne pas avec des pointeurs sur des variables.

edit: typage du pointeur passé en argument

Donc en gros je divise 1 000 000 000

Le 1er : 1
le 2e : 000
le 3e: 000
et le 4e : 000

J'avais déjà étudié ce problème mais jamais vraiment réussi à trouver une solution. En fait quand je démarre la première sauvegarde, ça fonctionne parfaitement. Mais à la 2e écriture, le chiffre est complétement à l'ouest.

void setup() {
 
  lcd.begin(16, 2);
  lcd.clear();
  delay(10);
  
  EEPROM_readAnything (0,compteur);
  
  //Serial.begin(115200);

}  

void loop() {

// code pour incrémenter le compteur en fonction d'une action, je vous épargne le code

    EEPROM_writeAnything (0,compteur);  
  
}

Je vous ai mis juste une petite partie du code histoire d'etayer mes propos.

En fait le compteur est du type : compteur++ il s'incrémente lors de chaque action. Le but est ensuite de stocké la valeur du compteur afin qu'elle soit enregistré lors d'une coupure de courant.

Peut-être que je devrais plutôt stocker la valeur du compteur dans la ram de l'horloge du DS1307...

fdufnews:
En y réflechissant un peu, on peut aussi coder un appel à la fonction plus générique.

    RTC.writeBytesInRam(adresse, sizeof(ma_variable), (uint8_t *)&ma_variable);

Cette manière de faire adresse directement la zone contenant la variable. Et on a pas besoin de savoir comment elle est stockée en mémoire.

Pour la restauration il suffit de faire l'inverse. Il faut évidemment que la variable soit créée avant l'apel

    RTC.readBytesInRam(adresse, sizeof(ma_variable), (uint8_t *)&ma_variable);

ATTENTION: sizeof détermine à la compilation la taille de la variable donc ce système ne fonctionnera qu'avec des variables de type connue au moment de la compilation. Ne fonctionne pas avec des pointeurs sur des variables.

C'est exactement ce qu'il faut que je fasse !!!!

Je teste début de semaine et je reviens avec le résultat.

EDIT :

A propos de l'adresse, la dessus j'ai vraiment une grosse lacune. J'ai une adresse de départ : 0x08, je ne m'occupe que de celle là ou il faut que je fasse autre chose ?

:slight_smile:

Je remonte un peu ce post...

Quel valeur je dois mettre pour l'adresse :

RTC.writeBytesInRam(adresse, sizeof(ma_variable), (uint8_t *)&ma_variable);

Merci

Bonsoir,
As-tu regardé la datasheet du composant ?
Regarde page 8 : http://datasheets.maximintegrated.com/en/ds/DS1307.pdf

Je viens de regarder, merci. :slight_smile:

Donc le datasheet indique 08h-3Fh.

J'utilise o8h, en fait là, j'ai beau lire et relire mes livres arduino, les adresses mémoires sont pour moi vraiment une étape complexe.

Bonsoir,
Allez une piste : Utilisation de la RAM du DS1307 - iDreamMicro

He hé, j'étais justement en teain de regarder !

Je vais faire des tests et essayer de trouver la solution.

Merci