Kidule Ascenseur/Faire le programme Ascenseur
Programme Ascenseur
[modifier | modifier le wikicode]C'est le moment de s'attaquer au programme proprement dit pour faire bouger notre ascenseur.
Mais avant de programmer, il faut réfléchir à ce que l’on veut faire. Première chose à remarquer, c’est que l’on devra faire plusieurs choses à la fois: lire des boutons, actionner le moteur, allumer et éteindre les Leds et se rappeler ce que l'ascenseur doit faire (monter au 1er étage par exemple).
Lorsque l’on a ce genre de problème (ce qui est très fréquent dans une machine ou dans un robot), la solution est souvent de dessiner un graphe d'états. Un graphe d'état est un dessin où on met une bulle par état possible de la machine. par exemple ici AuRez pour dire que l’on est au rez à attendre, ou encore Monte2eme pour dire que l’on va au 2eme.
Puis on trace avec des flèches tout ce qui est possible de faire en termes de changement d'état et à côté de la flèche on marque sous quelle condition on va changer d'état. Par exemple, on peut passer de AuRez à Monter1er si on a Bouton1er==Presse.
Exercice
[modifier | modifier le wikicode]Essaie de tracer toutes les transitions qui sont possibles dans le cas de notre ascenseur. Pour cet exercice, on va imaginer que notre ascenseur est très simple:
- On ne peut lui donner qu'un ordre à la fois.
Traduction d'un graphe d'états en C
[modifier | modifier le wikicode]Pour traduire un graphe d'états en C, il nous faut:
- déclarer tous les états possibles
- déclarer une variable qui contient l'état
- avoir une instruction qui nous permet de faire un bout de programme différent pour chaque état
Pour le 1er point, il existe en C une instruction pour déclarer un type énuméré (qui énumère toutes les possibilités d'une variable de ce type)
enum permet de déclarer une énumération, et pour chaque énumération de lui attribuer la valeur qui sera utilisée dans le microprocesseur (optionnel). Dans notre cas, on peut écrire cela de la manière suivante:
enum {Au2eme =0b00000100,
Au1er =0b00000010,
AuRez =0b00000001,
Monte2eme =0b00000111,
Monte1er =0b00000011,
Descend1er=0b00000110,
DescendRez=0b00000000}
pour le 2eme point, comme on vient de déclarer ce nouveau type, on peut juste après déclarer la variable Etat et lui donner sa valeur initiale.
Etat = DescendRez;
pour le 3eme point, il existe une instruction un peu compliquée, mais qui fait exactement ce qu’il nous faut:
l'instruction switch permet de faire un bout de code ou un autre suivant la valeur d'une variable. On l'utilise de la manière suivante:
switch (variable)
{
case valeurA:
instruction;
instruction;
break;
case valeurB:
instruction;
break;
default:
instruction;
}
Pour chaque valeur qui nous intéresse, on met un case suivit de la valeur puis d'un : les instructions qui suivent ne seront exécutées si la variable du switch == la valeur. À la fin de ces instructions, on doit écrire un break; qui indique que l’on peut sauter à la fin de l'} du switch
Pour traduire notre graphe d'états en code, nous allons écrire un état par case du switch. Dans la première partie de l'état, on va mettre ce que l’on doit faire dans cet état comme par exemple Monter=..., Descendre=..., allumer des leds etc. Puis nous allons regarder s'il a a une transition possible avec un if(...) { Etat = nouvel_etat}.
De cette manière, à chaque fois que la fonction GererAscenseur() est appelée, on va effectuer les actions de cet état, puis regarder si la prochaine fois on doit exécuter un autre état.
Exercice
[modifier | modifier le wikicode]Il faut maintenant coder notre programme. Pour pas trop se fatiguer, On peut copier le squelette de programme ci-dessous, et on remplacera tous les _A_CHANGER par quelque chose d'utile
#include "hardwareAsc.h"
enum {Au2eme =0b00000100,
Au1er =0b00000010,
AuRez =0b00000001,
Monte2eme =0b00000111,
Monte1er =0b00000011,
Descend1er=0b00000110,
DescendRez=0b00000000} Etat = Monte2eme;
void AfficherEtat()
{
if (Etat & 0b00000001) Led3=Allume; else Led3=Eteint;
if (Etat & 0b00000010) Led4=Allume; else Led4=Eteint;
if (Etat & 0b00000100) Led5=Allume; else Led5=Eteint;
}
void GererAscenseur()
{
switch (Etat)
{
case Au2eme:
Monter = 0;
Descendre = 0;
Led2eme = Eteint; //si on est au 2eme, on éteint la LED qui indique qu'on veut aller au 2eme
if (Bouton1er==Presse) {
Etat = Descend1er;
}
else if (BoutonRez==Presse) {
Etat = DescendRez;
}
break;
case Au1er:
Monter = A_CHANGER;
Descendre = A_CHANGER;
Led1er = Eteint;
if (Bouton2eme==Presse) {
Etat = A_CHANGER;
}
else if (Bouton_A_CHANGER==Presse) {
Etat = DescendRez;
}
break;
case AuRez:
Monter = A_CHANGER;
Descendre = A_CHANGER;
LedRez = A_CHANGER;
if (Bouton2eme==Presse) {
Etat = A_CHANGER;
}
else if (Bouton1er==Presse) {
Etat = A_CHANGER;
}
break;
case Monte2eme:
Monter = A_CHANGER;
Descendre = A_CHANGER;
Led2eme = Allume;
if (Switch2eme==Presse) {
Etat = A_CHANGER;
}
break;
case Monte1er:
Monter = A_CHANGER;
Descendre = A_CHANGER;
Led1er = Allume;
if (Bouton_A_CHANGER==Presse) {
Etat = Au1er;
}
break;
case Descend1er:
Monter = 0;
Descendre = 1;
Led1er = Allume;
if (Switch1er==Presse) {
Etat = Au1er;
}
break;
case DescendRez:
Monter = 0;
Descendre = 1;
LedRez = Allume;
if (SwitchRez==Presse) {
Etat = AuRez;
}
break;
default:
Led6=Allume; // pour montrer que l’on a un gros problème
}
}
void loop ()
{
GererAscenseur();
AfficherEtat();
}
#include "hardwareAsc.h"
enum {Au2eme =0b00000100,
Au1er =0b00000010,
AuRez =0b00000001,
Monte2eme =0b00000111,
Monte1er =0b00000011,
Descend1er=0b00000110,
DescendRez=0b00000000} Etat = Monte2eme;
void AfficherEtat()
{
if (Etat & 0b00000001) Led3=Allume; else Led3=Eteint;
if (Etat & 0b00000010) Led4=Allume; else Led4=Eteint;
if (Etat & 0b00000100) Led5=Allume; else Led5=Eteint;
}
void GererAscenseur()
{
switch (Etat)
{
case Au2eme:
Monter = 0;
Descendre = 0;
Led2eme = Eteint;
if (Bouton1er==Presse) {
Etat = Descend1er;
}
else if (BoutonRez==Presse) {
Etat = DescendRez;
}
break;
case Au1er:
Monter = 0;
Descendre = 0;
Led1er = Eteint;
if (Bouton2eme==Presse) {
Etat = Monte2eme;
}
else if (BoutonRez==Presse) {
Etat = DescendRez;
}
break;
case AuRez:
Monter = 0;
Descendre = 0;
LedRez = Eteint;
if (Bouton2eme==Presse) {
Etat = Monte2eme;
}
else if (Bouton1er==Presse) {
Etat = Monte1er;
}
break;
case Monte2eme:
Monter = 1;
Descendre = 0;
Led2eme = Allume;
if (Switch2eme==Presse) {
Etat = Au2eme;
}
break;
case Monte1er:
Monter = 1;
Descendre = 0;
Led1er = Allume;
if (Switch1er==Presse) {
Etat = Au1er;
}
break;
case Descend1er:
Monter = 0;
Descendre = 1;
Led1er = Allume;
if (Switch1er==Presse) {
Etat = Au1er;
}
break;
case DescendRez:
Monter = 0;
Descendre = 1;
LedRez = Allume;
if (SwitchRez==Presse) {
Etat = AuRez;
}
break;
default:
Led6=Allume;
}
}
void loop ()
{
GererAscenseur();
AfficherEtat();
}