Formations à l'informatique et à l'électronique

Auteur : SD
Créé le : 30-01-2019

Comment programmer un diagramme d'état en C/C++ ?

Le principe est d'utiliser l'instruction "switch case" en créant un "case" pour chaque état.

Exemple :

Soit le diagramme d'état ci-dessous :

Diagramme d'état simple avec deux états

Le code C correspondant est :

enum Etat { ETAT_A, ETAT_B};

enum Etat etatCourant = ETAT_A;

void loop() {
switch(etatCourant) {
case ETAT_A :
// Insérer ici la/les action(s) à faire dans l’état A
break;

case ETAT_B :
// Insérer ici la/les action(s) à faire dans l’état B
break;
}
}

Les transitions dans un diagramme d'état

Rappel sur les transitions dans un diagramme d'état

Une transition indique le passage d’un état (état source) dans un autre (état cible). Elle est représentée par une flèche orientée de l’état source vers l’état cible.

Syntaxe générale d’une transition :

{ <événement> } { [ <condition de garde> ]} { / <effet> }

Programmation d'une condition de garde

La condition de garde est une expression booléenne entre crochets. Cette expression doit être vraie pour que la transition soit franchie.

Soit le diagramme d'état ci-dessous :

Diagramme d'état deux états deux transistions

Le code C correspondant est :

enum Etat { ARRET, MARCHE};

enum Etat etatCourant = ARRET;

const float seuil = 20;
const float hyst = 0.5;

void loop() {

float temperature = getTemperature();

switch(etatCourant) {
case ARRET :
// Action état ARRET
if(temperature < seuil) { // Condition de garde : [temperature < seuil]
etatCourant = MARCHE;
}
break;

case MARCHE :
// Action état MARCHE
if(temperature > seuil + hyst) { // Condition de garde : [temperature > seuil + hyst]
etatCourant = ARRET;
}
break;
}
}

Condition de garde avec effet

Un effet est une action réalisée au moment où la transition est franchie. C'est en général une action de courte durée.

Soit le diagramme d'état ci-dessous :

Diagramme d'état deux états deux transistions, condition de garde et effets

Le code C correspondant est :

enum Etat { ARRET, MARCHE};

enum Etat etatCourant = ARRET;

const float seuil = 20;
const float hyst = 0.5;

void loop() {

float temperature = getTemperature();

switch(etatCourant) {
case ARRET :
// Action état ARRET
if(temperature < seuil) { // Condition de garde : [temperature < seuil]
etatCourant = MARCHE;
activerRelais(); // Effet : Action faite au moment de la transition
}
break;

case MARCHE :
// Action état MARCHE
if(temperature > seuil + hyst) { // Condition de garde : [temperature > seuil + hyst]
etatCourant = ARRET;
desactiverRelais(); // Effet : Action faite au moment de la transition
}
break;
}
}

Transition sur événement

Généralement pour les transitions sur événement, on utilise les interruptions de manière à ce que le système soit réactif.

Le principe est le même que pour les conditions de garde sauf que c'est la routine d'interruption qui va modifier la valeur de la variable "etatCourant".

Événement temporel

Le code C correspondant est :

enum Etat { ARRET, MARCHE, MARCHE_FORCEE};

enum Etat etatCourant = ARRET;

const float seuil = 20;
const float hyst = 0.5;

unsigned int etatPrecedent = etatCourant;
unsigned long tempsTotalEcoule; // Temps (en ms) écoulé depuis le lancement du programme (! cette variable va revenir à 0 au bout d'eviron 50 jours)
unsigned long tempsAriveeDansEtatCourant = 0; // temps (en ms) du dernier changement d'état

const unsigned long _30_MINUTES = 1800000; // 30 min = 1 800 000 ms

void loop() {

float temperature = getTemperature();
bool etatBouton = getEtatBouton();

tempsTotalEcoule = millis(); // La fonction millis() renvoie le nombre de millisecondes depuis que le programme a démarré

if(etatPrecedent != etatCourant) { // On vient d'entrer dans un nouvel état
etatPrecedent = etatCourant;
tempsAriveeDansEtatCourant = tempsTotalEcoule; // Le temps d'arrivée dans le nouvel état est réinitialisé
}

switch(etatCourant) {
case ARRET : // Action état ARRET
if(temperature < seuil) { // Condition de garde : [temperature < seuil]
etatCourant = MARCHE;
activerRelais(); // Effet : Action faite au moment de la transition
}

if(etatBouton) { // Bouton appuyé
etatCourant = MARCHE_FORCEE;
activerRelais(); // Effet : Action faite au moment de la transition
}

break;

case MARCHE : // Action état MARCHE
if(temperature > seuil + hyst) { // Condition de garde : [temperature > seuil + hyst]
etatCourant = ARRET;
desactiverRelais(); // Effet : Action faite au moment de la transition
}

if(etatBouton) { // Bouton appuyé
etatCourant = MARCHE_FORCEE;
}

break;

case MARCHE_FORCEE : // Action état MARCHE_FORCEE
// Transition : After 30 min
if((tempsTotalEcoule - tempsAriveeDansEtatCourant) > _30_MINUTES) {
if(temperature >= seuil) {
etatCourant = ARRET;
desactiverRelais(); // Effet : Action faite au moment de la transition
}
else
etatCourant = MARCHE;
}

break;
}
}


Vous avez apprécié cet article ? Partagez le !

Article connexe : Les structures algorithmiques de base