Rare phénomène avec adresse 0 de l'EEPROM - Arduino Mega

Bonjour,

Je viens de constater un phénomène étrange en utilisant l'adresse 0 de l'EEPROM. J'y écris un byte "niveau" pour mémoriser une valeur comprise entre 0 et 3 que je relis au démarrage pour allumer une des 4 LEDs représentant ce niveau. Mon programme (simulation d'une commande de micro-station d'épuration) connaît deux modes:

  • mode "run": les données "cycle" et "durée" sont utilisées pour allumer le "moteur" (simulé par une 5ème LED) pour la donnée "durée" et avec un cycle tous deux correspondant au niveau
  • mode "config": le niveau peut être changé par un bouton-poussoir qui boucle entre 0 et 3, retour à 0 etc. Le nouveau niveau est mémorisé dans l'EEPROM à l'adresse 0

Le changement entre modes est commandé par un "switch" ("toggle").
Voici ce que je constate: le niveau valant 3 (LED "3" allumée) je débranche le câble USB et je le rebranche et le niveau passe à 2 (LED "2" allumée); la même chose se produit lorsque je ferme la fenêtre "Serial monitor" sur mon PC; si j'utilise l'adresse 1 de l'EEPROM, le comportement est normal (le niveau 3 reste 3 dans les 2 cas.
Que se passe-t-il avec l'adresse 0 au démarrage ou à la fermeture de la fenêtre "serial monitor"? Est-ce une adresse réservée?
Merci de m'aiguiller vers la doc ad-hoc.
Papynouche
Voici le code

/*
 * Micro-Station
 *
 * Ce programme contrôle le moteur d'une micro-station d'épuration
 * selon le niveau (programmable en mode "arrêt")
 * Fonctionnement:
 *     a) mode arrêt: choisir le niveau en appuyant sur le bouton "niveau" jusqu'à l'allumage de la lampe correspondante (veille jusqu'à maxi)
 *     b) mettre en mode marche  
 *     c) en mode marche: le programme enclenche le moteur cycliquement et pour une durée dépendant du niveau
 *            Niveau 0 (veille): cycle x0 minutes, durée y0 minutes
 *            Niveau 1 (<=3 personnes): cycle x1 minutes, durée y1 minutes
 *            Niveau 2 (4-6 personnes): cycle x2 minutes, durée y2 minutes
 *            Niveau 3 (>6 personnes): cycle x3 minutes, durée y3 minutes
 *
 * Attention: lors de la première mise en route, démarrer toujours le module en mode "arrêt" et choisissez le niveau; celui-ci
 *            sera mémorisé dans le module
 */  
 
// Include EEPROM lib
#include <EEPROM.h>

//  Inputs
int  modeButtonPin = 2;               // Mode button pin
int  levelButtonPin = 3;              // Level selection button pin
//  Outputs
int  level0LedPin = 6;                // Level 0 LED
int  level1LedPin = 7;                // Level 1 LED
int  level2LedPin = 8;                // Level 2 LED
int  level3LedPin = 9;                // Level 3 LED
// int  level4LedPin = 10;

int simulPot = 0;

int  motorPin = 10;                    // Motor control output
int  modeLedPin = 13;                  // Mode led output


// Variables
int  modeVal = LOW;
int  modeButtonState = HIGH;
int  levelButtonState = HIGH;
byte currentLevel = 0;
byte previousCurrLevel;
int  motorStatus = LOW;
unsigned long interval;                         // The current cycle (wait period) or duration (run period) interval
unsigned long previousMillis = 0;               // will store the last time that the motor status was changed
int addr = 0;                                   // EEPROM address to/from which currentLevel will be written/read
int simulRate = 1000;


// Arrays

int cycle[4] = {600,300,200,150};
int duration[4] = {30,60,90,120};

/*
*  SET-UP
*/
void setup()                    // run once, when the sketch starts
{
  pinMode(level0LedPin, OUTPUT);    // Level 0 Led output (Green)
  pinMode(level1LedPin, OUTPUT);    // Level 1 Led output (Red)
  pinMode(level2LedPin, OUTPUT);    // Level 2 Led output (Red)
  pinMode(level3LedPin, OUTPUT);    // Level 3 Led output (Red)
//  pinMode(level4LedPin, OUTPUT);    // Level 3 Led output (Red)
  pinMode(modeLedPin, OUTPUT);      // Mode Led output (Yellow)
  pinMode(motorPin, OUTPUT);        // Motor control output (Yellow)

  pinMode(modeButtonPin, INPUT);    // Mode selection button input
  pinMode(levelButtonPin, INPUT);   // Level selection button input
  
  digitalWrite (motorPin,LOW);      // Initially stop the motor
  digitalWrite (modeLedPin, modeVal);   // Initially set mode to "Run" (LOW)
  currentLevel = EEPROM.read(addr);
  previousCurrLevel = currentLevel;
  litLevelLed (currentLevel);
  previousMillis = millis();
  simulRate = analogRead(simulPot);
  simulRate /= 200;
  Serial.begin(115200);
  Serial.println("Initialisation ");
  Serial.println(int(currentLevel));
}
/*
*  LOOP
*/
void loop() {                    // run over and over again

  // Check Mode button
  modeButtonState = digitalRead(modeButtonPin);
  if (modeButtonState == LOW) {
    modeVal = HIGH;  // Configuration mode, motor stopped
    digitalWrite (motorPin,LOW);  // Stop the motor when starting configuration
  }
  else {
    if (modeVal == HIGH) {
      simulRate = analogRead(simulPot);
      simulRate /= 200;
      motorStatus = LOW;  // Start motor immediately after configuration
      interval = duration[currentLevel] *simulRate; //the motor runs
      if (millis() > interval){previousMillis = millis() - interval;}
      else {previousMillis = 0;}
    }
    modeVal = LOW;  // Motor running
  }
  digitalWrite (modeLedPin,modeVal);
  
  // If mode = "Stop" then allow level selection
  if (modeVal == HIGH) { // HIGH = STOP = configuration
    levelButtonState = digitalRead (levelButtonPin);
    if (levelButtonState == LOW) {
      currentLevel += 1;
      if (currentLevel > 3){
        currentLevel = 0;
      }
      litLevelLed(currentLevel);
      delay(500);
    }
    EEPROM.write(addr, currentLevel);
    if (previousCurrLevel != currentLevel) {
      Serial.print(int(currentLevel));
      Serial.print(" ");
      Serial.println(int(previousCurrLevel));
    }
    previousCurrLevel = currentLevel;
  }
  else { // modeVal LOW = RUN = Motor Control
    simulRate = analogRead(simulPot);
    simulRate /= 100;
    if (millis() < previousMillis) {previousMillis = millis();}
    if (millis() - previousMillis >= interval) {
      // save the last time the motor was switched on 
      previousMillis = millis();
      // if the motor is off turn it on and vice-versa
      if (motorStatus == LOW){
        motorStatus = HIGH;
        interval = duration[currentLevel] *simulRate ;
      }
      else  {
        motorStatus = LOW;
        interval = cycle[currentLevel] *simulRate*10 ;
      }
    // switch the motor to the current motor status
    digitalWrite(motorPin, motorStatus);
    litLevelLed(currentLevel);
    }
  }  
}

void litLevelLed(int ledNumber) {      // Led number from 0 to 3
 digitalWrite (level0LedPin, LOW);
 digitalWrite (level1LedPin, LOW);
 digitalWrite (level2LedPin, LOW);
 digitalWrite (level3LedPin, LOW);

 if (ledNumber == 0) {
   digitalWrite (level0LedPin, HIGH);
 }
 else
 if (ledNumber == 1) {
   digitalWrite (level1LedPin, HIGH);
 }
 else
 if (ledNumber == 2) {
   digitalWrite (level2LedPin, HIGH);
 }
 else
 if (ledNumber == 3) {
   digitalWrite (level3LedPin, HIGH);
 }
}

Bonjour
Sur les premiers microcontrolleurs AVR (90S2313 pour moi) l'EEPROM souffrait d'un bug qui se manifestait principalement par une corruption à l'adresse 0 (liée si mes souvenirs sont bons à la manière dont Vcc monte de 0 à 5V à la mise sous tension). Depuis j'ai toujours, à tort ou à raison et sans chercher à faire de nouvelles vérifications, continué d'éviter d'utilser cette adresse !!!
J'ai retrouvé un échange sur AvrFreaks http://www.avrfreaks.net/index.php?name=PNphpBB2&file=printview&t=75638&start=0
Il serait intéressant de savoir si les AVR actuels présententent la même 'caractéristique'.

Grand merci..Je pensais bien qu'il devait s'agir de ce genre de raison, en tout cas pour la mise sous tension. Apparemment, la fermeture de la fenêtre "Serial monitor" (voire l'ouverture) provoque également une mise hors tension de la carte si celle-ci est alimentée via l'USB (qui doit probablement repasser hors tension lorsqu'on active ou déactive le serial monitor). Dorénavant j'éviterai d'utiliser l'adresse 0.