IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Arduino Discussion :

Est-il possible que la pile (le stack) joue des tours sans prévenir?


Sujet :

Arduino

  1. #1
    Membre du Club
    Homme Profil pro
    retraité
    Inscrit en
    Décembre 2019
    Messages
    122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : retraité

    Informations forums :
    Inscription : Décembre 2019
    Messages : 122
    Points : 60
    Points
    60
    Par défaut Est-il possible que la pile (le stack) joue des tours sans prévenir?
    Bonjour à tous les spécialistes

    Grâce aux excellents conseils reçus ici même, principalement par Jay M que je remercie encore, j'ai bien progressé et fini par aboutir dans l'utilisation des eeprom.

    Pourtant, ce ne fut pas sans mal, même en utilisant des procédures qu'il avait conçues spécialement à mes besoins, et que j'ai bien adoptées. Déjà là, j'ai été confronté à des comportements inexplicables, qui m'avaient fortement déstabilisé.

    Un comportement très similaire me semble se reproduire à présent, dans d'autres procédures, où, malgré les témoins de passages et l'allumage de LED colorées pour prouver certains passages, j'arrive à une conclusion pour laquelle j'ai des preuves, mais que je ne sais pas expliquer.

    Devant cet aspect totalement illogique, et parce que j'ai des boucles qui appellent des boucles ... une procédure qui fonctionne bien une première fois, se perd en route lors du second passage.

    En un point particulier, un test doit reboucler, le test est bien fait mais le saut n'a pas lieu.

    Pourtant, rien dans la compilation ne permet de déceler cette limitation. Voilà son libellé:

    Le croquis utilise 14036 octets (43%) de l'espace de stockage de programmes. Le maximum est de 32256 octets.
    Les variables globales utilisent 1395 octets (68%) de mémoire dynamique, ce qui laisse 653 octets pour les variables locales. Le maximum est de 2048 octets.
    Mon hypothèse actuelle serait que la pile pourrait être corrompue (débordée).

    Est-ce possible? Plausible?

    Si oui, y a-t-il un moyen de le savoir.

    S'il s'avère que c'est vrai, y a-t-l des solutions pour passer outre?

    Merci d'avance pour toute aide que vous pourrez m'apporter pour me faire avancer.

  2. #2
    Membre éclairé
    Homme Profil pro
    Enseignant
    Inscrit en
    Juin 2004
    Messages
    516
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Juin 2004
    Messages : 516
    Points : 706
    Points
    706
    Par défaut
    Salut gienas (on ne connait bien sur un forum où j'ai un 'k' en moins ,

    tu ne parles que de boucle, donc à priori la pile n'est pas à mettre en cause. La pile évolue au rythme des appels de fonctions et de la création de variables locales.
    Des variables locales peuvent être créées dans des boucles, mais si les boucles exécutées restent les même, la pile ne devrait pas évoluer tant que ça.

    Ce qui fait bien planter les programmes, ce sont les débordement de tableau. Il y a aussi la gestion dynamique de la mémoire, mais dans ce cas c'est le tas qui est utilisé et tu n'as pas fait référence à cette gestion dynamique.

    En un point particulier, un test doit reboucler, le test est bien fait mais le saut n'a pas lieu.
    On peut voir e code en question?

    A+

  3. #3
    Membre du Club
    Homme Profil pro
    retraité
    Inscrit en
    Décembre 2019
    Messages
    122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : retraité

    Informations forums :
    Inscription : Décembre 2019
    Messages : 122
    Points : 60
    Points
    60
    Par défaut
    Citation Envoyé par jackk Voir le message
    Salut gienas (on ne connait bien sur un forum où j'ai un 'k' en moins ...
    Le monde est petit. Ça fait du bien de se retrouver entre amis. ;-)

    Citation Envoyé par jackk Voir le message
    ... tu ne parles que de boucle, donc à priori la pile n'est pas à mettre en cause. La pile évolue au rythme des appels de fonctions et de la création de variables locales ...
    Justement, j'avais eu l'impression, dans mon précédent problème, que c’était "l'accumulation" des fonctions qui appelaient des fonctions qui créaient le problème.

    Je l'avais résolu en me "rapprochant" du loop en créant une liste de fonctions qui s'appellent successivement que j'ai résolu mon problème.

    Citation Envoyé par jackk Voir le message
    ... Des variables locales peuvent être créées dans des boucles, mais si les boucles exécutées restent les même, la pile ne devrait pas évoluer tant que ça ...

    Je n'ai pratiquement pas de variables locales. Elles sont presque exclusivement toutes globales pour être accessibles par toutes les fonctions.

    Citation Envoyé par jackk Voir le message
    ... Ce qui fait bien planter les programmes, ce sont les débordement de tableau ...
    Je n'ai pratiquement pas de tableau. Donc, peu de chance que ce soit ça.

    Citation Envoyé par jackk Voir le message
    ... Il y a aussi la gestion dynamique de la mémoire, mais dans ce cas c'est le tas qui est utilisé et tu n'as pas fait référence à cette gestion dynamique ...
    Comme je ne maîtrise pas, je pense ne pas utiliser. J'imagine que ça ne peut pas se faire à l'insu de son plein gré. ;-)

    Citation Envoyé par jackk Voir le message
    ... On peut voir le code en question? ...
    C'est souvent compliqué d'être exhaustif, mais on peut essayer.

    Si tu as jeté un œil sur mes besoins précédents, c'est lié à l'utilisation d'une EEPROM qui contient 10080 octets successifs dont les quatre bits de poids faible sont les états de quatre relais qui doivent monter si leur bit correspondant est à 1. Les 10080 cases ce sont les 10080 minutes d'une semaine entre dimanche 0H00 et samedi 23H59.

    Ma procédure comporte actuellement fonctions appelées par le main si un bouton est dans la bonne position.

    Une première lecture de l'eeprom se passe bien et me détecte bien la première série dite zone de programmation d'un destinataire. ce destinataire fixe le masque qui permet de savoir que le bit eeprom concerne bien le bon relais. Une zone, c'est une série de 1 qui se suivent. Le début d'une zone c'est l'adresse du premier 1 (minuteDebutAllumage) et le dernier 1 c'est l'adresse de l'extinction de cette zone (minuteFinAllumage).

    L'ensemble des procédures de ce problème concerne le contrôle de la programmation d'un destinataire et lui seul. Une fois la première zone trouvée, mon afficheur LCD le bloque et montre le nom du destinataire et les limites de la zone sous la forme
    CONTROLE PROGRAMME
    CUISINE
    DIM 12H00 DIM 13H45
    A ce stade, la pression d'une touche clavier dite 3 va chercher la prochaine zone du même destinataire et m'en annonce les limites. Ça s’arrête quand j'arrive à la limite des 10080 que j'ai grossi un peu pour détecter, le temps du débogage la fin de l'eeprom qui contient encore ses FF.

    Mon programme actuel a été truqué pour afficher sur le moniteur lors de la première passe, les états lus, qui fonctionnent bien, puis des messages témoins de passage indiquant les numéros de lignes.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    ///   =============================================
    void detectionDeProchaineZoneProgramme () // trouve les deux limites de prochaine zone
    {
      while ( memoryAddress < 10200 ) // recherche de relais
      {
    relance:
        if ( memoryAddress % 50 == 0 ) Serial.print ( "\n" ) ;  // sauts de lignes
        // Serial.print ( "-" ) ; // temoin passages suivant
        octetLu = memoire.readByte ( memoryAddress + 6L ) ;
        octetLu &= 0x0F ;  // ne conserve que les relais mais peut être supprimé
        Serial.print ( octetLu , DEC ) ; Serial.print ( " " ) ;
        memoryAddress ++ ;
        if ( temoinDeBoucle != 0 ) // hors du premier passage
        {
          Serial.print ( "\nboucle numéro = " ) ; Serial.print ( temoinDeBoucle + 1 , DEC ) ;
          Serial.print ( "\nmemoryAddress = " ) ; Serial.print ( memoryAddress , DEC ) ;
          Serial.print ( "\t" ) ;
          Serial.print ( "octetLu masqué = " ) ; Serial.println ( octetLu , DEC ) ;
        }
        if ( octetLu & bitRelais == 0 ) allumeRouge () ; /// même niveau de pile
        if ( octetLu & bitRelais == 0 ) Serial.print ( "\nJe relance pour boucler au second passage(ligne 1052)\n" ) ;
        if ( octetLu & bitRelais == 0 ) goto relance ;  // ajout incertain
        if ( octetLu & bitRelais != 0 )    // je suis en commande donc en zone programmée
        {
          // J'ai un relais, le bon
          minuteDebutAllumage = memoryAddress ;  // mise en mémoire pour affichage
          memoryAddress ++ ; // il faut incrémenter adresse
          Serial.print ( "\nZone de chauffe voie " ) ;
          Serial.println ( destinataireProgrammation + 1 , DEC ) ;
          Serial.print ( "Début en " ) ;
          Serial.println ( minuteDebutAllumage , DEC ) ;
          // allumeJaune () ; // rouge on est dans la fonction, jaune on est en while
          // continuer jusqu'à trouver zéro: fin de zone
          while ( memoryAddress < 10200 )
          {
            allumeBleu () ;
            octetLu = memoire.readByte ( memoryAddress + 6L ) ;
            cpt = octetLu & bitRelais ;  // temoin provisoire
            if ( cpt == 0 ) return ; // fin de zone
            memoryAddress ++ ;
            Serial.print ( cpt , DEC ) ; Serial.print ( " " ) ;
            if ( memoryAddress % 100 == 0 ) Serial.print ( "\n" ) ;  // sauts de lignes
            // exit ;
          }
     
        }
     
      }
    }
    //  =======================
    De guerre lasse, j'ai fini par boucler sur un goto relance, et, ne voyant pas le résultat de ce bouclage, j'ai introduit des tests préalables dont les résultats ne sont plus lus, lorsqu'arrive le premier 0 après la première zone bien trouvée.

    Le voyant rouge ne s'allume pas, et bien sûr, le message moniteur correspondant non plus, preuve que l'instruction

    if ( octetLu & bitRelais == 0 ) allumeRouge () ; /// même niveau de pile

    n'allume pas, alors que la lecture précédente était bien la bonne, un 0.

    voilà le moniteur dont j'ai appris l'usage grâce à Jay M qu'à présent j'aime bien.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
     
      Temoin passage ligne 999
      Temoin passage ligne 1002  Détection zone: memoryAddress = 3
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 
    Zone de chauffe voie 1
    Début en 720
    1   Temoin passage ligne 1005  Détection zone: memoryAddress = 722
    Trouvé adresse deb: 720  trouvé adresse fin: 722
    Jour 0  Heure 12  Minute 0
      Temoin passage ligne 1009  attente du clavier 3
    ...............  Temoin passage ligne 1018 Touche 3 lue memoryAddress =722
      Temoin passage ligne 1002  Détection zone: memoryAddress = 722
    0 
    boucle numéro = 2
    memoryAddress = 723	octetLu masqué = 0
    Si tu as la patience de te pencher dessus, je ne doute pas que tu vas trouver un truc.

  4. #4
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 711
    Points : 5 390
    Points
    5 390
    Par défaut
    Salut gienas

    pour être sûr qu'on parle bien de la même chose, la représentation mémoire dans l'EEPROM c'est quelque chose comme cela

    Nom : relais.png
Affichages : 166
Taille : 62,6 Ko

    ici par exemple avec des 1 (j'ai pas représenté les 0 dans les octets), on dit que le relai 6 est activé entre Lundi 0h01 et Lundi 0h08, le relais 4 du Lundi 0h05 au lundi 0h07 et le relais 2 du Lundi 0h02 au lundi 0h04

    c'est bien cela ?

    et vous souhaitez étant donné une moment de la semaine savoir quel sont les prochains relais qui vont s'activer et quand ? c'est bien cela ?

  5. #5
    Membre du Club
    Homme Profil pro
    retraité
    Inscrit en
    Décembre 2019
    Messages
    122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : retraité

    Informations forums :
    Inscription : Décembre 2019
    Messages : 122
    Points : 60
    Points
    60
    Par défaut
    Citation Envoyé par Jay M Voir le message
    ... pour être sûr qu'on parle bien de la même chose, la représentation mémoire dans l'EEPROM c'est quelque chose comme cela ...
    C'est exactement cela.

    Citation Envoyé par Jay M Voir le message
    ... ici par exemple avec des 1 (j'ai pas représenté les 0 dans les octets), on dit que le relai 6 est activé entre Lundi 0h01 et Lundi 0h08, le relais 4 du Lundi 0h05 au lundi 0h07 et le relais 2 du Lundi 0h02 au lundi 0h04

    c'est bien cela? ...
    En effet. La seule différence c'est que les quatre pistes sont "jointives" (en mémoire. Elles sont les quatre bits de poids faible, d'où un masque à 0x0F pour les laisser subsister.

    Citation Envoyé par Jay M Voir le message
    ... et vous souhaitez étant donné une moment de la semaine savoir quel sont les prochains relais qui vont s'activer et quand? c'est bien cela?
    C'est également ça.

    L'eeprom a été nettoyée avec tes routines et je décale la lecture de quelques points, quatre je crois, pour tenir compte de ton "motMagique" qui sème le trouble dans les codes relais.

    Ce sont tes routines aussi, prises in extenso, qui ont servi à placer quelques zones de programme sur une de mes eeprom.

    Ma routine fonctionne bien une fois, pour trouver la première zone bien trouvée et bien délimitée, et correctement affichée.

    C'est au relancement par la touche 3 que la première lecture (un zéro) devrait être ignorée comme zone, explorée jusqu'au prochain 1 sur cette piste.

    Le destinataire détermine quel est le masque à utiliser pour le relais considéré, puisque la routine une fois lancée, conserve cette valeur jusqu'au bout de l'exploration.

    C'est alors que le choix pourra être fait d'un autre destinataire, avec un autre masque.

    C'est la variable bitRelais qui contient ce masque. Il est 1 ou 2 ou 4 ou 8 suivant que le destinataire est 0, 1, 2 ou 3. Ce bitRelais est initialisé au début de la routine, après la validation du destinataire, et sera modifié lorsque le choix d'un autre destinataire à contrôler sera choisi.

    Dans l'état actuel, si je fais abstraction de cette vérification (du programme), si cela a été programmé (et c'est déjà le cas, ça fonctionne) le fonctionnement des relais fonctionne déjà en fonction de l'horloge RTC sur toute la semaine.

    Je suis donc de plus en plus confiant sur l'aboutissement du projet. Je sens que je vais bientôt attaquer la réalisation du prototype. Là, je suis toujours sur maquette.


    Édit: dans mon tableau du bas du #3, la série de 0 entre le texte du début et le texte suivant, c'est l'état de l'eeprom entre dimanche 0h00 et dimanche 12h01. Comme rien n'est programmé, on "glisse" dessus mais on l'affiche pour pouvoir contrôler le fonctionnement.

    Le premier 1 qui arrive, passe à la recherche de la fin correctement trouvée.

    Pour des raisons historiques pour moi (mon programme PC), mon origine des temps est le dimanche à 0h00 qui correspond à l'agresse 0 de eeprom.

  6. #6
    Membre éclairé
    Homme Profil pro
    Enseignant
    Inscrit en
    Juin 2004
    Messages
    516
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Juin 2004
    Messages : 516
    Points : 706
    Points
    706
    Par défaut
    Désolé, mais je n'ai en effet pas suivi la discussion sur l'utilisation de l'eeprom, n'étant pas très calé avec le Arduino.
    Du coup, j'ai du mal à suivre ton processus.

  7. #7
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 711
    Points : 5 390
    Points
    5 390
    Par défaut
    OK donc vous n'avez que 4 relais pilotés, qui sont sur les bits 0 à 3 d'une case EEPROM et l'adresse "origine" c'est dimanche à 0h00

    Mon code d'origine met un 1 à la "minute" qui va bien si on active le relais et un 0 si on le désactive. Je me disais que pour des raisons d'économie d'écriture il n'y avait pas besoin de mettre des 1 partout pour représenter qu'à chaque minute le relais est actif ou pas.

    il faut donc rajouter une petite fonction qui prend une date de début et une date de fin et active ou désactive les bits sur la plage

    - j'ai rajouté les 2 fonctions suivantes pour cela:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    activerRelais(byte relais, tJour jourDebut, byte heureDebut, byte minuteDebut, tJour jourFin, byte heureFin, byte minuteFin)
    desactiverRelais(byte relais, tJour jourDebut, byte heureDebut, byte minuteDebut, tJour jourFin, byte heureFin, byte minuteFin)
    il faut pouvoir chercher la prochaine date d'activation d'ici la fin de la semaine (un bit à 1 pour un relais donné) à partir d'une certaine date.
    --> j'ai rajouté la fonction suivante pour cela:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    afficherProchaineActivation(tRelais relais, tJour jourDebut, byte heureDebut, byte minuteDebut)
    --> attention cette fonction qui va lire un par un les octets de l'EEPROM est forcément lente.

    Voici le code avec à la fin du setup() quelques exemples, l'affichage se fait dans le moniteur Série à 115200 bauds
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    #include <I2C_eeprom.h>  // https://github.com/RobTillaart/I2C_EEPROM/blob/master/I2C_eeprom.cpp
    I2C_eeprom memoire(0x50, I2C_DEVICESIZE_24LC256); // AT24C256 en 0x50
     
    /* METHODES PRATIQUES (un retour de 0 veut dire OK pour les fonctions d'écriture)
      bool      begin();
      bool      isConnected();
      int       writeByte(const uint16_t memoryAddress, const uint8_t value);
      int       writeBlock(const uint16_t memoryAddress, const uint8_t* buffer, const uint16_t length);
      int       setBlock(const uint16_t memoryAddress, const uint8_t value, const uint16_t length);
      uint8_t   readByte(const uint16_t memoryAddress);
      uint16_t  readBlock(const uint16_t memoryAddress, uint8_t* buffer, const uint16_t length);
      int       updateByte(const uint16_t memoryAddress, const uint8_t value);
      int       updateBlock(const uint16_t memoryAddress, const uint8_t* buffer, const uint16_t length);
    */
     
    const uint16_t adresseMotMagique = 0;
    const uint32_t motMagique = 0xB0CAD0;
    const uint16_t adresseOrigine = adresseMotMagique + sizeof motMagique;
    const uint16_t tailleRequise = 10080; // 7 jours * 24 heures * 60 minutes
     
    enum tRelais : byte  {AucunRelais = 0, Relais0 = 1, Relais1 = 2, Relais2 = 4, Relais3 = 8, Relais4 = 16, Relais5 = 32, Relais6 = 64, Relais7 = 128};
    enum tJour : byte  {Dimanche = 0, Lundi, Mardi, Mercredi, Jeudi, Vendredi, Samedi};
    const char * jours[] = { "Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"};
     
     
    // imprime le jour et l'heure de la semaine pour un nombre de minutes nbMinutes = 1440u * jour + 60 * heure + minuteDebut
    void afficherDate(uint16_t nbMinutes) {
      if (nbMinutes > tailleRequise) return; // incohérent on ignore
      uint16_t jour   = nbMinutes / 1440;
      uint16_t heure  = (nbMinutes % 1440) / 60;
      uint16_t minute =  nbMinutes - jour * 1440 - heure * 60;
      Serial.print(jours[jour]); Serial.print(F(", "));
      Serial.print(heure); Serial.write(':');
      if (minute < 10) Serial.write('0');
      Serial.print(minute);
      Serial.write(' ');
    }
     
     
    inline bool premierUsage() {
      uint32_t motTest;
      memoire.readBlock(adresseMotMagique, (uint8_t*) &motTest, sizeof motTest);
      return (motTest != motMagique);
    }
     
    void formater() {
      memoire.setBlock(adresseOrigine, 0, tailleRequise); // on met tout à 0
      memoire.writeBlock(adresseMotMagique, (uint8_t*) &motMagique, sizeof motMagique);
    }
     
    inline byte lireEtat(tJour jour, byte heure, byte minute) {
      return memoire.readByte(adresseOrigine + 1440u * jour + 60u * heure + minute);
    }
     
    // retourne 0 si tout s'est bien passé, sinon un code d'erreur (celui de Wire.endTransmission())
    inline int ecrireEtat(byte etat, tJour jour, byte heure, byte minute) {
      return memoire.updateByte(adresseOrigine + 1440u * jour + 60u * heure + minute, etat) == 0;
    }
     
    // retourne 0 si tout s'est bien passé, sinon un code d'erreur (celui de Wire.endTransmission())
    inline int activerRelais(byte relais, tJour jour, byte heure, byte minute) {
      byte etat = lireEtat(jour, heure, minute);
      etat |= relais;
      return ecrireEtat(etat, jour, heure, minute);
    }
     
    // retourne 0 si tout s'est bien passé, sinon un code d'erreur (celui de Wire.endTransmission())
    int activerRelais(byte relais, tJour jourDebut, byte heureDebut, byte minuteDebut, tJour jourFin, byte heureFin, byte minuteFin) {
      int operationOK = 0;
      uint16_t adresseMomentDebut = adresseOrigine + 1440u * jourDebut + 60u * heureDebut + minuteDebut;
      uint16_t adresseMomentFin   = adresseOrigine + 1440u * jourFin + 60u * heureFin + minuteFin;
      if (adresseMomentDebut <= adresseMomentFin) {
        for (uint16_t adresse = adresseMomentDebut; adresse <= adresseMomentFin; adresse++) {
          byte etat = memoire.readByte(adresse);
          etat |= relais;
          operationOK = memoire.updateByte(adresse, etat);
          if (operationOK != 0) break; // erreur d'écriture on ne va pas plus loin
        }
      } else { // c'est une activation à cheval sur la fin de la semaine, par exemple du Vendredi au Lundi. On le fait en deux fois sachant que Dimanche est le premier jour
        operationOK = activerRelais(relais, jourDebut, heureDebut, minuteDebut, Samedi, 23, 59); // jusqu'au Samedi soir
        if (operationOK == 0)
          operationOK = activerRelais(relais, Dimanche, 0, 0, jourFin, heureFin, minuteFin); // du dimanche jusqu'à la date de fin
      }
     
      return operationOK;
    }
     
    // retourne 0 si tout s'est bien passé, sinon un code d'erreur(celui de Wire.endTransmission())
    inline int desactiverRelais(byte relais, tJour jour, byte heure, byte minute) {
      byte etat = lireEtat(jour, heure, minute);
      etat &= ~relais;
      return ecrireEtat(etat, jour, heure, minute);
    }
     
    // retourne 0 si tout s'est bien passé, sinon un code d'erreur (celui de Wire.endTransmission())
    int desactiverRelais(byte relais, tJour jourDebut, byte heureDebut, byte minuteDebut, tJour jourFin, byte heureFin, byte minuteFin) {
      int operationOK = 0;
      uint16_t adresseMomentDebut = adresseOrigine + 1440u * jourDebut + 60u * heureDebut + minuteDebut;
      uint16_t adresseMomentFin   = adresseOrigine + 1440u * jourFin + 60u * heureFin + minuteFin;
      if (adresseMomentDebut <= adresseMomentFin) {
        for (uint16_t adresse = adresseMomentDebut; adresse <= adresseMomentFin; adresse++) {
          byte etat = memoire.readByte(adresse);
          etat &= ~relais;
          operationOK = memoire.updateByte(adresse, etat);
          if (operationOK != 0) break; // erreur d'écriture on ne va pas plus loin
        }
      } else { // c'est une désactivation à cheval sur la fin de la semaine, par exemple du Vendredi au Lundi. On le fait en deux fois sachant que Dimanche est le premier jour
        operationOK = desactiverRelais(relais, jourDebut, heureDebut, minuteDebut, Samedi, 23, 59); // jusqu'au Samedi soir
        if (operationOK == 0)
          operationOK = desactiverRelais(relais, Dimanche, 0, 0, jourFin, heureFin, minuteFin); // du dimanche jusqu'à la date de fin
      }
      return operationOK;
    }
     
    // affiche la prochaine date d'activation d'un relais à partir d'une certaine date
    void afficherProchaineActivation(tRelais relais, tJour jourDebut, byte heureDebut, byte minuteDebut)
    {
      const uint16_t adresseSamedi23h59 = adresseOrigine + 1440u * Samedi + 60u * 23 + 59;
     
      bool debutTrouve = false;
      uint16_t minDebut = 0;
      uint16_t adresseMomentDebut = adresseOrigine + 1440u * jourDebut + 60u * heureDebut + minuteDebut;
     
      if (relais == AucunRelais) return;
     
      // on cherche le prochain bit à 1 pour ce relais d'ici Samedi 23h59
      for (uint16_t a = adresseMomentDebut; a <= adresseSamedi23h59; a++) {
        debutTrouve = (memoire.readByte(a) & relais) != 0; // le relais est il actif à ce moment?
        if (debutTrouve) {
          minDebut = a - adresseOrigine;
          break;
        }
      }
      if (debutTrouve) {
        Serial.print(F("Prochaine activation Relais "));
        Serial.print(__builtin_ctz(relais));    // la fonction __builtin_ctz dit combien de 0 on a en poids faible de l'octet (= le N° du relais)
        Serial.print(F(" : "));
        afficherDate(minDebut);
      } else {
        Serial.print(F("Le Relais "));
        Serial.print(__builtin_ctz(relais));    // la fonction __builtin_ctz dit combien de 0 on a en poids faible de l'octet (= le N° du relais)
        Serial.print(F(" ne sera pas activé entre "));
        afficherDate(1440u * jourDebut + 60u * heureDebut + minuteDebut);
        Serial.print(F(" et Samedi 23h59"));
      }
      Serial.println();
    }
     
     
    void afficher(tJour jour, byte heure, byte minute) {
      byte etat = lireEtat(jour, heure, minute);
      Serial.print(jours[jour]); Serial.write(' ');
      Serial.print(heure); Serial.write(':');
      if (minute < 10) Serial.write('0');
      Serial.print(minute);
      for (byte relais = 0; relais < 8; relais++) {
        Serial.print(F("\tR")); Serial.print(relais); Serial.write(':');
        Serial.print(bitRead(etat, relais) ? F("ON") : F("OFF"));
      }
      Serial.println();
    }
    void setup() {
      Serial.begin(115200);
      memoire.begin();
      if (! memoire.isConnected()) {
        Serial.println(F("EEPROM absente."));
        while (true);
      }
     
      if (premierUsage()) formater();
     
      // --------------- POUR TESTER --------------
      Serial.println(F("-- TEST ETAT PONCTUEL --"));
      // activer uniquement les relais 1,3,5 et 7 le Lundi à 17h30 (uniquement sur 1 minute)
      ecrireEtat(Relais1 | Relais3 | Relais5 | Relais7, Lundi, 17, 30);
      afficher(Lundi, 17, 30); // vérification
     
      // on active en plus le relais 0 le Lundi à 17h30 (uniquement sur 1 minute)
      activerRelais(Relais0, Lundi, 17, 30);
      afficher(Lundi, 17, 30); // vérification
     
      // on désactive les relais 5 et 7 (uniquement sur 1 minute)
      desactiverRelais( Relais5 | Relais7, Lundi, 17, 30);
      afficher(Lundi, 17, 30); // vérification
     
      Serial.println(F("-- TEST PLAGE HORAIRE --"));
      // On peut aussi activer une plage horaire
     
      Serial.println(F("ACTIVATION RELAIS 4 de 17h30 à 17h45"));
      activerRelais(Relais4, Jeudi, 17, 30, Jeudi, 17, 45); // on active le relais 4 pendant 15 minutes entre Jeudi 17h30 et 17h45
      for (byte m = 25; m <= 50; m++) afficher(Jeudi, 17, m); // vérification, on affiche l'état entre Jeudi 17h25 et Jeudi 17h50
     
      // ou désactiver une plage
     
      Serial.println(F("DESACTIVATION RELAIS 4 de 17h40 à 17h45"));
      desactiverRelais(Relais4, Jeudi, 17, 40, Jeudi, 17, 45); // on active le relais 4 pendant 15 minutes entre Jeudi 17h30 et 17h45
      for (byte m = 25; m <= 50; m++) afficher(Jeudi, 17, m); // vérification, on affiche l'état entre Jeudi 17h25 et Jeudi 17h50
     
      // on vérifie quelle est la prochaine activation du relais 4  --> Jeudi, 17:30
      Serial.println(F("ANALYSE PROCHAINE ACTIVATION"));
      afficherProchaineActivation(Relais4, Dimanche, 0, 0);
     
      // on vérifie quelle est la prochaine activation du relais 6 --> jamais activé
      Serial.println(F("ANALYSE PROCHAINE ACTIVATION"));
      afficherProchaineActivation(Relais6, Dimanche, 0, 0);
    }
     
    void loop() {}
    voici la fin de ce que vous devriez voir dans le moniteur série (à 115200 bauds)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    ANALYSE PROCHAINE ACTIVATION
    Prochaine activation Relais 4 : Jeudi, 17:30 
    ANALYSE PROCHAINE ACTIVATION
    Le Relais 6 ne sera pas activé entre Dimanche, 0:00  et Samedi 23h59
    vous verrez un certain temps de latence avant l'affichage de la réponse à chacune des 2 questions, c'est le temps de parcours de l'EEPROM.

    je vous laisse lire tout cela, ça devrait vous donner des idées sur le parcours de la mémoire.


    PS: Le mot magique n'est là que pour traiter le cas où l'EEPROM n'a jamais été initialisée par votre code. Si vous le faites "à la main" avec un autre bout de code et que ce décalage vous gêne vous pouvez le virer (mais se mettre en relatif en ajoutant partout une adresse origine ne doit pas être insurmontable).

  8. #8
    Membre du Club
    Homme Profil pro
    retraité
    Inscrit en
    Décembre 2019
    Messages
    122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : retraité

    Informations forums :
    Inscription : Décembre 2019
    Messages : 122
    Points : 60
    Points
    60
    Par défaut
    Bonsoir à tous

    Citation Envoyé par Jay M Voir le message
    ... je vous laisse lire tout cela, ça devrait vous donner des idées sur le parcours de la mémoire ...
    Pardon d'être têtu, et de m'obstiner à poursuivre mon idée. Celle que tu me proposes est peut-être moins sûre. Un seul bit, qui ne peut être que 1 ou 0, ne peut pas signifier allumage et arrêt. A moins de n'avoir pas bien creusé ton idée.

    Comme j'ai repris et remis sur le chantier le dump complet de l'eeprom, il m'est venu à l'idée de le reprendre et de n'isoler que les bits différents de zéro, et de les grouper pour apercevoir toutes mes zones (très peu nombreuses pour le moment, mais assez pour détecter les problèmes. L'idée était de partir de quelque chose d’éprouvé et qui fonctionne bien.

    Et justement, il y en a, qui restent inexplicables sauf à baver dans la pile, ce qui demeure ma seule hypothèse.

    Voilà les éléments que j'apporte qui me semblent des preuves "irréfutables".

    J'ai créé une fonction listingNonZero () qui recense toutes les zones non zéro, en donne le nombre et les adresses et me les traduit en horodatage.

    J'appelle cette fonction par une touche de mon clavier.

    J'ai copié cette fonction mot pour mot, avec un nom complété listingNonZeroProgramme (), celle qui devra être insérée dans mon programme, simplement, je lui ajoute un testclavier (debugClavier ()) pour arrêter la boucle dès qu'une zone est trouvée et délimitée.

    L'action sur une troisième touche clavier permet d'aller à la zone suivante.
    Voilà cette fonction qui fonctionne très bien et qui me sort la partie supérieure du listing qui suit:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    void listingNonZero ()  // Liste des zones non à zéro (inventaire détaillé)
    {
      int tempo ; // var temporaire
      int compteur ;  // comptage des octets affichés
      int nouvelleSerie ;  // nouvelle serie de NZ
      lcd.setCursor ( 0 , 0 ) ;
      lcd.print ( "LISTING DES NON ZERO" ) ;
      lcd.setCursor ( 0 , 1 ) ; lcd.print ( "Taper 1 pour SORTIR   " ) ; // ligne 2
      debugClavier () ;
      if ( KB == 1 ) return ; // +1 adresse
      compteur = 0 ; nouvelleSerie = 0 ;  // initialisations
      allumeRouge () ;
      Serial.print ( "\n\n" ) ;  // sauts de ligne initiaux
      for ( memoryAddress = 0 ; memoryAddress < 10090 ; memoryAddress ++ )
      {
        octetLu = memoire.readByte ( memoryAddress ) ;  // lecture
        if ( octetLu != 0 )
        {
          compteur ++ ;
          nouvelleSerie ++ ;
          if ( octetLu < 16 ) Serial.print ( "0" ) ;
          Serial.print ( octetLu , HEX ) ; Serial.print ( " " ) ;
          if ( nouvelleSerie % 40 == 0 )  Serial.print ( "\n" ) ;
        }
        if ( octetLu == 0 )  // c'est zero on ne s'en occupe pas
        {
          if ( nouvelleSerie != 0 )  // donc après une série de NZ
          {
            Serial.print ( "\nNombre de NZ = " ) ; Serial.print ( nouvelleSerie ) ;
            Serial.print ( "\t" ) ;  // séparateur
            tempo = memoryAddress - nouvelleSerie ;  // pour utilisation ultérieure
            Serial.print ( "memoryAddress début = " ) ; Serial.print ( tempo ) ; 
            cpt = tempo / 1440 ; // jour
            Serial.print ( "\t" ) ;  // séparateur
            if ( cpt == 0 ) Serial.print ( "DIM " ) ;
            if ( cpt == 1 ) Serial.print ( "LUN " ) ;
            if ( cpt == 2 ) Serial.print ( "MAR " ) ;
            if ( cpt == 3 ) Serial.print ( "MER " ) ;
            if ( cpt == 4 ) Serial.print ( "JEU " ) ;
            if ( cpt == 5 ) Serial.print ( "VEN " ) ;
            if ( cpt == 6 ) Serial.print ( "SAM " ) ;
            if ( cpt >  6 ) Serial.print ( "ERR " ) ;
            minuteDebutAllumage = tempo ;  // pour conversion
            decodageJHM () ;  // pour connaître Heure et Minutes
            if ( Heure < 10 ) Serial.print ( "0" ) ;
            Serial.print ( Heure , DEC ) ; Serial.print ( "H" ) ;
            if ( Minute < 10 ) Serial.print ( "0" ) ;
     
            Serial.print ( Minute , DEC ) ; Serial.print ( "\n\n" ) ;
     
            nouvelleSerie = 0 ;  // seule RAZ de nouvelleSerie
          }
        }
        compteur = 0 ;
      }
      eteintRouge () ;
    }
    Le listing généré

    D0 CA B0
    Nombre de NZ = 3 memoryAddress début = 0 DIM 00H00

    0F FF 0F
    Nombre de NZ = 3 memoryAddress début = 5 DIM 00H05

    01 01 01
    Nombre de NZ = 3 memoryAddress début = 725 DIM 12H05

    02
    Nombre de NZ = 1 memoryAddress début = 784 DIM 13H04

    02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
    02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
    Nombre de NZ = 59 memoryAddress début = 786 DIM 13H06

    02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
    02 02 02 02 02 02 02 02
    Nombre de NZ = 48 memoryAddress début = 846 DIM 14H06

    AA
    Nombre de NZ = 1 memoryAddress début = 1054 DIM 17H34

    08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08
    08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08
    Nombre de NZ = 60 memoryAddress début = 2045 LUN 10H05

    01 01 01
    Nombre de NZ = 3 memoryAddress début = 2285 LUN 14H05

    01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
    01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
    01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01

    Nombre de NZ = 120 memoryAddress début = 3245 MAR 06H05

    02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
    02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
    02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02

    Nombre de NZ = 120 memoryAddress début = 5045 MER 12H05

    04 04 04 04 04 04 04 04 04 04 04 04
    Nombre de NZ = 12 memoryAddress début = 5185 MER 14H25

    08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08
    08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08
    08 08 08 08 08 08 08 08 08 08
    Nombre de NZ = 90 memoryAddress début = 6125 JEU 06H05

    08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08
    08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08
    Nombre de NZ = 60 memoryAddress début = 9545 SAM 15H05

    FF
    Nombre de NZ = 1 memoryAddress début = 10084 ERR 00H04

    FF FF FF FF
    Il finit sur une erreur, puisque volontairement, je déborde sur l'eeprom et les FF ne sont pas à prendre en compte.

    La seconde fonction est celle-ci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    void listingNonZeroProgramme ()  // Liste des zones non à zéro (inventaire détaillé)
    {
      int tempo ; // var temporaire
      int compteur ;  // comptage des octets affichés
      int nouvelleSerie ;  // nouvelle serie de NZ
      lcd.setCursor ( 0 , 0 ) ;
      lcd.print ( "LISTING DES NON ZERO" ) ;
      lcd.setCursor ( 0 , 1 ) ; lcd.print ( "Taper 1 pour SORTIR   " ) ; // ligne 2
      debugClavier () ;
      if ( KB == 1 ) return ; // +1 adresse
      compteur = 0 ; nouvelleSerie = 0 ;  // initialisations
      allumeRouge () ;
      Serial.print ( "\n\n" ) ;  // sauts de ligne initiaux
      for ( memoryAddress = 0 ; memoryAddress < 10090 ; memoryAddress ++ )
      {
        octetLu = memoire.readByte ( memoryAddress ) ;  // lecture
        if ( octetLu != 0 )
        {
          compteur ++ ;
          nouvelleSerie ++ ;
          if ( octetLu < 16 ) Serial.print ( "0" ) ;
          Serial.print ( octetLu , HEX ) ; Serial.print ( " " ) ;
          if ( nouvelleSerie % 40 == 0 )  Serial.print ( "\n" ) ;
        }
        if ( octetLu == 0 )  // c'est zero on ne s'en occupe pas
        {
          if ( nouvelleSerie != 0 )  // donc après une série de NZ
          {
            Serial.print ( "\nNombre de NZ = " ) ; Serial.print ( nouvelleSerie ) ;
            Serial.print ( "\t" ) ;  // séparateur
            tempo = memoryAddress - nouvelleSerie ;  // pour utilisation ultérieure
            Serial.print ( "memoryAddress début = " ) ; Serial.print ( tempo ) ; 
            cpt = tempo / 1440 ; // jour
            Serial.print ( "\t" ) ;  // séparateur
            if ( cpt == 0 ) Serial.print ( "DIM " ) ;
            if ( cpt == 1 ) Serial.print ( "LUN " ) ;
            if ( cpt == 2 ) Serial.print ( "MAR " ) ;
            if ( cpt == 3 ) Serial.print ( "MER " ) ;
            if ( cpt == 4 ) Serial.print ( "JEU " ) ;
            if ( cpt == 5 ) Serial.print ( "VEN " ) ;
            if ( cpt == 6 ) Serial.print ( "SAM " ) ;
            if ( cpt >  6 ) Serial.print ( "ERR " ) ;
            minuteDebutAllumage = tempo ;  // pour conversion
            decodageJHM () ;  // pour connaître Heure et Minutes
            if ( Heure < 10 ) Serial.print ( "0" ) ;
            Serial.print ( Heure , DEC ) ; Serial.print ( "H" ) ;
            if ( Minute < 10 ) Serial.print ( "0" ) ;
     
            Serial.print ( Minute , DEC ) ; Serial.print ( "\n\n" ) ;
     
            nouvelleSerie = 0 ;  // seule RAZ de nouvelleSerie
            // condition clavier 3 pour continuer
            delay ( 500 ) ; // pour voir si rouge allumé
            KB = 0 ; // sécurité
            eteintRouge () ; // temoin de zone explorée
            while (KB != 3 )
            {
              debugClavier () ;
            }
            delay ( 500 ) ; //  pour avoir relâché le clavier
          }
        }
        compteur = 0 ;
      }
      eteintRouge () ;
    }
    Strictement la même, sauf les tests après impression

    Ça marche trois fois et ça se bloque on ne sait où. Voilà le listing qui s'arrête tout seul, bien que la demande suivante soit faite. C'est déjà ce que j'avais avant d'ouvrir cette discussion.

    D0 CA B0
    Nombre de NZ = 3 memoryAddress début = 0 DIM 00H00

    0F FF 0F
    Nombre de NZ = 3 memoryAddress début = 5 DIM 00H05

    01 01 01
    Nombre de NZ = 3 memoryAddress début = 725 DIM 12H05
    Si vous avez des idées pour mettre en évidence le problème et surtout le contourner, vous êtes tous les bienvenus.

  9. #9
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 711
    Points : 5 390
    Points
    5 390
    Par défaut
    Et justement, il y en a, qui restent inexplicables sauf à baver dans la pile
    votre LCD est en I2C aussi? est-ce que ça ne jouerait pas des tours à la lecture de l'EEPROM? vous n'avez pas de récession (mais je ne vois pas tout le code) ni d'allocation dynamique, donc il n'y a pas de raison pour que la pile déborde.

    --> sérialisez les problèmes et enlever le LCD, utilisez juste le moniteur Série pour les affichages.
    Un bouton branché sur une PIN en INPUT_PULLUP peut servir pour créer une attente bloquante simplement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    while (digitalRead(pinBouton) == HIGH) ; delay(15); // attente active d'appui, suivie d'un anti-rebond

    Citation Envoyé par gienas Voir le message
    Pardon d'être têtu, et de m'obstiner à poursuivre mon idée. Celle que tu me proposes est peut-être moins sûre. Un seul bit, qui ne peut être que 1 ou 0, ne peut pas signifier allumage et arrêt. A moins de n'avoir pas bien creusé ton idée.
    faut pas vous excuser, c'est votre projet et l'idée de mettre des 1 partout où un relai doit être activé se tient tout à fait et simplifie les choses. (J'avais en tête l'idée de bascule, on met un 1 quand on veut changer d'état. c'est moins consommateur d'écriture dans l'EEPROM mais pour connaître l'état du relai à un instant T il faut remonter dans le temps pour voir s'il y a eu un nombre pair ou impair de 1).

    pour le reste il faudrait un sketch complet, pour bien se rendre compte (vous utilisez par exemple une variable globale `memoryAddress` dont on ne connait pas le type).


    pour vous donnez une idée du parcours pour afficher les plages d'activités, voici un petit code qui n'a pas besoin de l'EEPROM (elle est simulée en mémoire RAM, c'est pour montrer le concept, il suffit de remplacer l'accès au tableau par une lecture de la case mémoire en EEPROM)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    const byte memoire[] = {
      0b00000000,  0b00000010,  0b00000010,  0b00000010,  0b00000010,  0b00000010,  0b00000110, 0b00000110,  0b00000110,  0b00000110,
      0b00000110,  0b00000110,  0b00000110,  0b00000110,  0b00000110,  0b00000110,  0b00000110, 0b00000110,  0b00000110,  0b00000110,
      0b00001110,  0b00001110,  0b00001110,  0b00001110,  0b00001110,  0b00001110,  0b00001110, 0b00001110,  0b00001110,  0b00001110,
      0b00001110,  0b00001110,  0b00001110,  0b00001110,  0b00001110,  0b00001110,  0b00001110, 0b00001110,  0b00001110,  0b00001110,
      0b00001010,  0b00001010,  0b00001010,  0b00001010,  0b00001010,  0b00001010,  0b00001010, 0b00001010,  0b00001010,  0b00001010,
      0b00001000,  0b00001000,  0b00001000,  0b00001000,  0b00001000,  0b00000000,  0b00000000, 0b00000000,  0b00000000,  0b00000000, // 0:59
     
      0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000, 0b00000000,  0b00000000,  0b00000000,
      0b00000001,  0b00000001,  0b00000001,  0b00000001,  0b00000001,  0b00000001,  0b00000001, 0b00000001,  0b00000001,  0b00000001,
      0b00000001,  0b00000001,  0b00000001,  0b00000001,  0b00000001,  0b00000001,  0b00000001, 0b00000001,  0b00000001,  0b00000001,
      0b00000001,  0b00000001,  0b00000001,  0b00000001,  0b00000001,  0b00000001,  0b00000001, 0b00000001,  0b00000001,  0b00000001,
      0b00000001,  0b00000001,  0b00000001,  0b00000001,  0b00000001,  0b00000001,  0b00000001, 0b00000001,  0b00000001,  0b00000001,
      0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000, 0b00000000,  0b00000000,  0b00000000, // 1:59
     
      0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000, 0b00000000,  0b00000000,  0b00000000,
      0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000, 0b00000000,  0b00000000,  0b00000000,
      0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000, 0b00000000,  0b00000000,  0b00000000,
      0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000, 0b00000000,  0b00000000,  0b00000000,
      0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000, 0b00000000,  0b00000000,  0b00000000,
      0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000, 0b00000000,  0b00000000,  0b00000000, // 2:59
     
      0b00000000,  0b00000010,  0b00000010,  0b00000010,  0b00000010,  0b00000010,  0b00000110, 0b00000110,  0b00000110,  0b00000110,
      0b00000110,  0b00000110,  0b00000110,  0b00000110,  0b00000110,  0b00000110,  0b00000110, 0b00000110,  0b00000110,  0b00000110,
      0b00001110,  0b00001110,  0b00001110,  0b00001110,  0b00001110,  0b00001110,  0b00001110, 0b00001110,  0b00001110,  0b00001110,
      0b00001110,  0b00001110,  0b00001110,  0b00001110,  0b00001110,  0b00001110,  0b00001110, 0b00001110,  0b00001110,  0b00001110,
      0b00001010,  0b00001010,  0b00001010,  0b00001010,  0b00001010,  0b00001010,  0b00001010, 0b00001010,  0b00001010,  0b00001010,
      0b00001000,  0b00001000,  0b00001000,  0b00001000,  0b00001000,  0b00000000,  0b00000000, 0b00000000,  0b00000000,  0b00000000, // 3:59
     
      0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000, 0b00000000,  0b00000000,  0b00000000,
      0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000, 0b00000000,  0b00000000,  0b00000000,
      0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000, 0b00000000,  0b00000000,  0b00000000,
      0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000, 0b00000000,  0b00000000,  0b00000000,
      0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000, 0b00000000,  0b00000000,  0b00000000,
      0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000,  0b00000000, 0b00000000,  0b00000000,  0b00000000, // 4:59
     
      0b00000000,  0b00000010,  0b00000010,  0b00000010,  0b00000010,  0b00000010,  0b00000110, 0b00000110,  0b00000110,  0b00000110,
      0b00000110,  0b00000110,  0b00000110,  0b00000110,  0b00000110,  0b00000110,  0b00000110, 0b00000110,  0b00000110,  0b00000110,
      0b00001110,  0b00001110,  0b00001110,  0b00001110,  0b00001110,  0b00001110,  0b00001110, 0b00001110,  0b00001110,  0b00001110,
      0b00001110,  0b00001110,  0b00001110,  0b00001110,  0b00001110,  0b00001110,  0b00001110, 0b00001110,  0b00001110,  0b00001110,
      0b00001010,  0b00001010,  0b00001010,  0b00001010,  0b00001010,  0b00001010,  0b00001010, 0b00001010,  0b00001010,  0b00001010,
      0b00001000,  0b00001000,  0b00001000,  0b00001000,  0b00001000,  0b00000000,  0b00000000, 0b00000000,  0b00000000,  0b00000000, // 5:59
    };
     
    enum tRelais : byte  {AucunRelais = 0, Relais0 = 1, Relais1 = 2, Relais2 = 4, Relais3 = 8, Relais4 = 16, Relais5 = 32, Relais6 = 64, Relais7 = 128};
    enum tJour : byte  {Dimanche = 0, Lundi, Mardi, Mercredi, Jeudi, Vendredi, Samedi};
    const char * jours[] = { "Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"};
     
    const size_t tailleRequise = sizeof memoire / sizeof memoire[0];
    const byte maxRelais = 8;
     
    void afficherDate(size_t nbMinutes) {
      if (nbMinutes > tailleRequise) return; // incohérent on ignore
      uint16_t jour   = nbMinutes / 1440;
      uint16_t heure  = (nbMinutes % 1440) / 60;
      uint16_t minute =  nbMinutes - jour * 1440 - heure * 60;
      Serial.print(jours[jour]); Serial.print(F(", "));
      Serial.print(heure); Serial.write(':');
      if (minute < 10) Serial.write('0');
      Serial.print(minute);
      Serial.write(' ');
    }
     
     
    void afficherPlages() {
      size_t indexStart[maxRelais];
      byte etatPrecedent = 0b00000000;
     
      for (size_t adresse = 1; adresse < tailleRequise; adresse++) {
        byte etatCourant = memoire[adresse];
        for (byte relais = 0; relais < maxRelais; relais++) {
          if (bitRead(etatCourant, relais) != bitRead(etatPrecedent, relais)) {         // changement d'état
            if (bitRead(etatCourant, relais) == 1) {                                    // allumage
              indexStart[relais] = adresse;
            } else {                                                                    // extinction
              Serial.print(F("Relais ")); Serial.print(relais+1);
              Serial.print(F(", Allumage ")); afficherDate(indexStart[relais]);
              Serial.print(F(", Extinction ")); afficherDate(adresse);
              Serial.println();
            }
          }
        }
        etatPrecedent = etatCourant;
      }
    }
     
    void setup() {
      Serial.begin(115200);
      afficherPlages();
    }
     
    void loop() {}
    le moniteur série va dire (par l'appel à la fonction afficherPlages())

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Relais 3, Allumage Dimanche, 0:06 , Extinction Dimanche, 0:40 
    Relais 2, Allumage Dimanche, 0:01 , Extinction Dimanche, 0:50 
    Relais 4, Allumage Dimanche, 0:20 , Extinction Dimanche, 0:55 
    Relais 1, Allumage Dimanche, 1:10 , Extinction Dimanche, 1:50 
    Relais 3, Allumage Dimanche, 3:06 , Extinction Dimanche, 3:40 
    Relais 2, Allumage Dimanche, 3:01 , Extinction Dimanche, 3:50 
    Relais 4, Allumage Dimanche, 3:20 , Extinction Dimanche, 3:55 
    Relais 3, Allumage Dimanche, 5:06 , Extinction Dimanche, 5:40 
    Relais 2, Allumage Dimanche, 5:01 , Extinction Dimanche, 5:50 
    Relais 4, Allumage Dimanche, 5:20 , Extinction Dimanche, 5:55

  10. #10
    Membre du Club
    Homme Profil pro
    retraité
    Inscrit en
    Décembre 2019
    Messages
    122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : retraité

    Informations forums :
    Inscription : Décembre 2019
    Messages : 122
    Points : 60
    Points
    60
    Par défaut
    Bonjour à tous

    Cette problématique est résolue, sans que je sache encore quel était le véritable problème ni même d'ailleurs si vraiment problème il y avait.

    J'ai testé le même programme sur Mega, avec le même comportement.

    J'ai choisi de reprendre toute cette partie sur des bases nouvelles et c'est reparti, complété ...

    Je n'exclus pas que je me sois fait piéger par un temps d'exécution "incompatible". J’avais coutume de fonctionner à 9600 bauds alors que Jay M conseillait 115200. Depuis, j'y ai pris goût et j'ai constaté dans mes simulations que l 'exploration eeprom pouvait être très longue, sur des longues distances à 115200 alors que probablement, à 9600 c'était une éternité.

    Justement, ces longues périodes apparaissaient après les troisièmes ou quatrièmes occurrences des zones programmées.

  11. #11
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 711
    Points : 5 390
    Points
    5 390
    Par défaut
    Je pense que le souci était sur la contention du bus et des interruptions (juste une intuition)

Discussions similaires

  1. Est il possible de créer un .py qui installe des bibliothèques python
    Par yannannou dans le forum Déploiement/Installation
    Réponses: 4
    Dernier message: 12/12/2019, 16h39
  2. Réponses: 0
    Dernier message: 06/10/2015, 14h52
  3. Réponses: 12
    Dernier message: 04/12/2013, 21h22
  4. Réponses: 1
    Dernier message: 08/07/2013, 22h59
  5. Réponses: 3
    Dernier message: 20/10/2011, 10h55

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo