/*! \file cesi1.ino \brief Premier TD pour le CESI. \author Bertrand Vandeportaele IUT GEII \date 28/10/2021 */ #include "lib_io_tp.h" /** Variable globale permettant de stocker la dernière valeur écrite sur le port de sortie, pour pouvoir en modifier uniquement certains bits */ unsigned char imageSortie = 0; /** Variable globale indiquant la broche Arduino connectée à la LED */ const unsigned int LEDPIN = 3; //////////////////////////////////////////////////////////////////// class CStateMachine // déclaration de la classe { //! membres accessibles depuis l'extérieur de la classe, il s'agit de l'interface d'interaction de la classe public: //! Constructeur CStateMachine(); //! méthode pour redémarrer la machine à état void reset(); //! méthode pour cadencer la machine à état (faire 1 coup d'horloge) void clock(); //! méthode manipulateur pour fournir les entrées void setEntree(unsigned char entreeval) { entree = entreeval; } //! méthode manipulateur pour fournir les entrées individuellement void setEntreeBit(unsigned char nbit, unsigned char entreeval) { entree = (entree & ~(1 << nbit)) | ((entreeval & 1) << nbit); } // Serial.println(entree,HEX); //! méthode accesseur pour accéder aux sorties unsigned char getSortie() { return sortie; } //! méthode accesseur pour accéder à une sortie individuellement unsigned char getSortieBit(unsigned char nbit) { return (sortie >> nbit) & 1; } //! méthode accesseur pour accéder à l'état courant unsigned char getEtat() { return etat; } //! membres privés pour réaliser l'encapsulation: ces attributs sont inacessibles directement depuis l'extérieur de la classe private: //! numéro de l'état actif unsigned char etat; //! valeur des entrées unsigned char entree; //! valeur des sorties unsigned char sortie; }; //////////////////////////////////////////////////////////////////// CStateMachine ::CStateMachine() { reset(); } //////////////////////////////////////////////////////////////////// void CStateMachine ::reset() { etat = 0; } //////////////////////////////////////////////////////////////////// void CStateMachine ::clock() { // if (etat==0) sortie=entree; // delay(20); // variables intérmédiaires pour les entrées unsigned char entree0 = (entree >> 0) & 1; unsigned char entree1 = (entree >> 1) & 1; unsigned char entree2 = (entree >> 2) & 1; unsigned char entree3 = (entree >> 3) & 1; // variables intérmédiaires pour les sorties // codage des sorties // Sortie0 est une AMZI unsigned char sortie0; if (etat == 3) sortie0 = entree1; else sortie0 = 0; // Sortie1 est une AMZI unsigned char sortie1; if (etat == 1) sortie1 = entree1; else if ((etat == 3) && (entree0 == 0)) sortie1 = entree2; else sortie1 = 0; // Sortie2 est une AMZE unsigned char sortie2 = (sortie >> 2) & 1; // récupère la valeur précédente if ((etat == 0) && ((entree0 == 1) && (entree1 == 0))) sortie2 = entree2; // Sortie3 est une AMZE unsigned char sortie3 = (sortie >> 3) & 1; // récupère la valeur précédente if ((etat == 1) && (entree2 == 0)) sortie3 = entree0; else if ((etat == 2) && (entree2 == 1) && (entree0 == 0)) sortie3 = 0; // codage de l'évolution de l'état switch (etat) { default: case 0: if ((entree0 == 1) && (entree1 == 0)) etat = 1; break; case 1: if (entree2 == 0) etat = 2; break; case 2: if (entree0 == 1) etat = 3; else if (entree2 == 1) // entree0==0 implicite par le else etat = 0; break; case 3: if (entree0 == 0) etat = 0; break; } // reconstruction de sortie à partir des variables intermédiaires sortie = (sortie3 << 3) | (sortie2 << 2) | (sortie1 << 1) | (sortie0 << 0); } //////////////////////////////////////////////////////////////////// CStateMachine mae; //////////////////////////////////////////////////////////////////// //! fonction d'affichage d'un message de debug bien pratique, //! qui affiche un message texte, le nom du fichier et le numéro de la ligne //! depuis où la fonction a été appelée void debugMessage(const char *chaineMsg, const char *chaineFile, const unsigned int line) { Serial.print("DEBUG "); Serial.print(chaineFile); Serial.print(" : l "); Serial.print(line); Serial.print(" : "); Serial.print(chaineMsg); Serial.println(); } //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// //! Un programme pour tester notre composant (logiciel) void programmeDeTest1() { //! Le composant à tester CStateMachine mae; Serial.print("Test lancé le "); Serial.print(__DATE__); Serial.print(" à "); Serial.println(__TIME__); Serial.print("Fonction de test: "); Serial.println(__func__); // boucle pour gérer les différents cas à tester for (unsigned int ntest = 0; ntest < 4; ntest++) { Serial.print("début du test numéro: "); Serial.println(ntest); mae.reset(); mae.setEntree(0); /* mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,1); mae.setEntreeBit(0,0); mae.setEntreeBit(2,0); mae.setEntreeBit(1,0); mae.setEntreeBit(3,0); */ // test du maintien dans l'état 0 mae.clock(); // ici on teste la mae sans considération de timing, donc clock() n'est pas conditionné à un timer mae.clock(); // la MAE doit être dans l'état 0 if (mae.getEtat() != 0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); if (mae.getSortieBit(1) != 0) debugMessage("Erreur: La SORTIE n'est pas à la valeur prévue", __FILE__, __LINE__); mae.setEntreeBit(0, 1); // équivalent ici à mae.setEntree(1); // reglage de entree2 à mémoriser dans sortie2 mae.setEntreeBit(2, ntest & 1); mae.clock(); // transition de 0 à 1 if (mae.getEtat() != 1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); if (mae.getSortieBit(2) != (ntest & 1)) debugMessage("Erreur: La SORTIE n'est pas à la valeur prévue", __FILE__, __LINE__); mae.setEntreeBit(1, (ntest>>1) & 1); //// A COMPLETER!!!! // TEST DU MAINTIEN EN 1 mae.setEntreeBit(2, 1); mae.clock(); if (mae.getEtat() != 1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); if (mae.getSortieBit(1) != ((ntest>>1) & 1)) debugMessage("Erreur: La SORTIE n'est pas à la valeur prévue", __FILE__, __LINE__); // TEST DU PASSAGE EN 2 mae.setEntreeBit(2, 0); mae.clock(); if (mae.getEtat() != 2) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); if (mae.getSortieBit(2) != (ntest & 1)) debugMessage("Erreur: La SORTIE n'est pas à la valeur prévue", __FILE__, __LINE__); // TEST DU MAINTIEN EN 2 mae.setEntreeBit(2, 0); mae.setEntreeBit(0, 0); mae.clock(); if (mae.getEtat() != 2) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); // TEST DU PASSAGE EN 0 mae.setEntreeBit(2, 1); mae.setEntreeBit(0, 0); mae.clock(); if (mae.getEtat() != 0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); if (mae.getSortieBit(2) != (ntest & 1)) debugMessage("Erreur: La SORTIE n'est pas à la valeur prévue", __FILE__, __LINE__); // on ramene la mae dans l'etat 2 // la MAE doit être dans l'état 0 if (mae.getEtat() != 0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //on reregle entree2 correctement mae.setEntreeBit(2, ntest & 1); mae.setEntreeBit(0, 1); // équivalent ici à mae.setEntree(1); mae.setEntreeBit(1, 0); // équivalent ici à mae.setEntree(1); mae.clock(); // transition de 0 à 1 if (mae.getEtat() != 1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //// A COMPLETER!!!! // TEST DU MAINTIEN EN 1 mae.setEntreeBit(2, 1); mae.clock(); if (mae.getEtat() != 1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); // TEST DU PASSAGE EN 2 mae.setEntreeBit(2, 0); mae.clock(); if (mae.getEtat() != 2) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); // passage vers 3 mae.setEntreeBit(0, 1); mae.clock(); if (mae.getEtat() != 3) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); if (mae.getSortieBit(2) != (ntest & 1)) debugMessage("Erreur: La SORTIE n'est pas à la valeur prévue", __FILE__, __LINE__); // mantien en 3 mae.setEntreeBit(0, 1); mae.clock(); if (mae.getEtat() != 3) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); // passage vers 0 mae.setEntreeBit(0, 0); mae.clock(); if (mae.getEtat() != 0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); if (mae.getSortieBit(2) != (ntest & 1)) debugMessage("Erreur: La SORTIE n'est pas à la valeur prévue", __FILE__, __LINE__); Serial.println("fin du test"); // vidage de la FIFO d'affichage: // flush(std::cout); } } //////////////////////////////////////////////////////////////////// //------------------------------------------------------------------- // prototypes de toutes les fonctions de ce fichier //------------------------------------------------------------------- /*! \fn void setup() \brief Initialisation des périphériques et des variables globales */ void setup() { //------------------------------------------------------------------- // CODE A COMPLETER PAR LES ETUDIANTS //------------------------------------------------------------------- SetupES(); mae.reset(); Serial.begin(115200); pinMode(LEDPIN, OUTPUT); digitalWrite(LEDPIN, HIGH); // Normalement le programme de test est un programme à part programmeDeTest1(); } //------------------------------------------------------------------- /*! * \fn void loop() * \brief La fonction loop doit appeler une seule fonction exo... à la * fois, vous devez conserver le code de tous les exercices mais n'en * utiliser qu'un à la fois */ void loop() { //------------------------------------------------------------------- // CODE A COMPLETER PAR LES ETUDIANTS //------------------------------------------------------------------- unsigned int periodicite = 10; static unsigned long timer = millis(); if (millis() - timer >= (periodicite * 1.2)) digitalWrite(LEDPIN, LOW); // allume une LED dès que la MAE est en // retard de plus de 20% d'une période d'horloge if (millis() - timer >= periodicite) { timer += periodicite; mae.setEntree(readPort()); mae.clock(); writePort(mae.getSortie()); // Serial.println(mae.getEtat()); // delay(20); } }