🛠 Persister une calibration dans l'EEPROM de l'ATmega (512 octets ou 1 Ko)
Objectifs
L'un des vrais bonheurs de l'AVR face à la Due (qui a 0 octet d'EEPROM) : la Duemilanove embarque 512 octets d'EEPROM (ATmega168) ou 1 Ko (ATmega328), conservés sans alimentation. Vous allez stocker une valeur de calibration dans une structure, l'écrire seulement quand elle change (l'EEPROM est limitée en cycles d'écriture), et vérifier qu'elle survit à la coupure totale de l'alimentation.
Matériel
- 1 Arduino Duemilanove (ATmega328 conseillée : 1 Ko d'EEPROM)
- 1 bouton poussoir (broche 2 vers GND) pour demander la sauvegarde
- 1 potentiomètre sur A0 pour simuler la mesure à calibrer
- Câble mini-USB ou alimentation secteur autonome
Code complet
// Calibration persistee en EEPROM (bibliothque EEPROM fournie avec le core)
#include <EEPROM.h>
struct Calibration { // 4 octets
uint16_t zéro; // offset de calibration
uint16_t magic; // marqueur de validité
};
const uint16_t MAGIC = 0xABCD;
const byte BOUTON = 2;
Calibration cal;
void setup {
pinMode(BOUTON, INPUT_PULLUP);
Serial.begin(9600);
EEPROM.get(0, cal); // lecture adresse 0
if (cal.magic != MAGIC) { // première vie de la carte ?
cal.zéro = analogRead(A0);
cal.magic = MAGIC;
EEPROM.put(0, cal); // écriture initiale
Serial.println("Calibration initialisee");
} else {
Serial.print("Calibration rechargee : zéro=");
Serial.println(cal.zéro);
}
}
void loop {
if (digitalRead(BOUTON) == LOW) { // bouton enfonce
delay(50); // anti-rebond grossier
if (digitalRead(BOUTON) == LOW) {
cal.zéro = analogRead(A0);
EEPROM.put(0, cal); // écrit seulement sur demande
Serial.print("zéro enregistre : ");
Serial.println(cal.zéro);
while (digitalRead(BOUTON) == LOW) { } // attend le relachement
}
}
}
Vérification attendue
Première exécution : « Calibration initialisee ». Éteindre complètement (débrancher USB ET alimentation), rebrancher : la carte affiche « Calibration rechargee : zéro=… » avec la valeur précédente, pas une réinitialisation. Appuyer sur le bouton avec le potentiomètre en position différente change la valeur persistée. Sur une 168, la même structure occupe 4 des 512 octets disponibles.
Erreurs fréquentes
- Écrire l'EEPROM à chaque loop : la spec AVR annonce ~100 000 cycles par octet ; un
EEPROM.update(qui n'écrit que si la valeur change) ou une écriture sur événement est obligatoire en continu. - Écrire au-delà de la taille réelle : 512 octets sur ATmega168, 1024 sur ATmega328 — un
EEPROM.putà l'adresse 1020 d'une structure de 4 octets passe, à 1024 ça déborde silencieusement selon les cas. - Croire que
EEPROM.getsur une puce neuve renvoie 0 : une EEPROM vierge vaut 0xFF ; d'où le marqueurmagicpour détecter la première vie. - Changer la structure de la struct sans changer l'adresse ou le magic : l'ancien contenu est réinterprété n'importe comment — versionner ses structures.
- Mélanger les cartes : un croquis compilé pour 328 téléversé sur 168 plante avant même de parler à l'EEPROM (voir le tuto Blink et le choix du processeur).
- Comparer des flottants lus d'EEPROM avec
==: préférer les entiers (ici uint16_t) ou une tolérance.
Autres tutoriels pour cette carte
- Faire clignoter la LED 13 d'une Duemilanove (et choisir le bon ATmega)
- Bouton poussoir et moniteur série sur la Duemilanove (avec ses 0,5 s de silence)
- Potentiomètre et variation LED : l'ADC 10 bits et le PWM 8 bits version AVR
- Ajouter un deuxième port série avec SoftwareSerial (GPS sur broches 10/11)
- Régler la référence de mesure avec AREF et analogReference
- Convertir la Duemilanove en programmateur AVR (ArduinoISP) pour graver des puces nues
Exemples de code pour cette carte
clignotante.inoArduinobouton-led.inoArduinopwm-respiration.inoArduinopotentiometre-plotter.inoArduinoservo-balayage.inoArduinobuzzer-melodie.inoArduino