feuille d'appel 2023-2024: https://docs.google.com/spreadsheets/d/1kKCpiorHDFjv1qaqAmXEYFw1ch6o_PHPEUAOY5iQtk4/edit#gid=0
=====emplacements des fichiers étudiants====
en 2024, ils ont ~/adfscesi monté
ils travaillent dans ~/ en local sur la machine, mais lié à leur compte.
ils peuvent faire copie vers ~/adfscesi
si jamais ils n'arrivent pas à se loguer, => ge2i mais faire le ménage sur la session et leur dire de sauver sur clef usb
=====Fichiers à télécharger pour développer chez l'étudiant=====
-> sous windows, ne marchera pas car j'ai utilisé les sockets linux pour la com avec le simulateur..
peut marcher uniquement pour le test unitaire sans communication avec le simultateur
Télécharger QTcreator:
https://www.qt.io/cs/c/?cta_guid=074ddad0-fdef-4e53-8aa8-5e8a876d6ab4&signature=AAH58kHfzUyp-YRHTGOQcji2bAkyHXCbiQ&pageId=12602948080&placement_guid=99d9dd4f-5681-48d2-b096-470725510d34&click=4b673b83-45c8-4f76-8565-3e53147ac801&hsutk=908fda3b2e6463692ece973aa2eeba3f&canon=https%3A%2F%2Fwww.qt.io%2Fdownload-open-source&portal_id=149513&redirect_url=APefjpE2-mzcsyLwibfbCsw2geX8WPkjo3SqRj5KpGbzDAYxQyQhnKPaUYflYOXA763Ez9nln_NctEBuN1N4VgmEKlRl77gINUGFMafl16Vq9BYNwMVqalERUU2S0P-mn-nXcI8g9Dau&__hstc=152220518.908fda3b2e6463692ece973aa2eeba3f.1679924698033.1679924698033.1679924698033.1&__hssc=152220518.1.1679924698033&__hsfp=1588722302&contentType=standard-page
créer un compte
A l'installation cocher:
Design Tools
Qt 6.4 pour le développement
récupérer le squelette d'application sur: https://bvdp.inetdoc.net/files/cesi/tp2/mae_etudiant_vide.zip
dézipper puis effacer manuellement les dossiers build.... et les fichiers .pro.user
ouvrir le fichier .pro depuis qtcreator et cliquer sur "configurer le projet"
dans le fichier sketch.cpp, commenter
#include "lib_io_tp.h"
dans le fichier tcp_client.pro, supprimer:
lib_io_tp.cpp \
et
lib_io_tp.h \
ouvrir le fichier .pro
cliquer sur "configurer le projet"
ajouter std:: devant les end
pour le projet tcp_server_simulator, copier les *.png dans ..\Build...
pour le projet mae_etudiant/tcp_client
Probleme j'ai utilisé des fonctions unix pour le client TCP, ce n'est pas compatible windows
https://bvdp.inetdoc.net/files/cesi/tp2/tcp_server.zip
https://bvdp.inetdoc.net/files/cesi/tp2/tcp_server_simulator.zip
TODO:
mettre tous les fichiers telechargés et dossier dans ~/TP_InfoEmbarquee
====Corrections que j'ai fait sur le projet mae_etudiant_vide====
corriger lib_io_tp.cpp dans mae_etudiant pour virer de \ devant \o
int setupES(char *ipAddressInit,char *portNumInit){
std::cout << "\ouverture socket vers : " << ipAddressInit << " : " <
setName(strdup((std::string("Bertrand Vandeportaele").data())));
int r=setupES(strdup((std::string(ip).data())),strdup((std::string(port).data())));
if (r!=0){
printf("erreur ouverture socket, merci de lancer le simulateur ou d'allumer la carte téléopérée\n");
exit(-1);
}
setName(strdup((std::string(nom).data())));
printf("Elapsed time: %ld milliseconds\n", millis());
}
===Il faudra faire les mêmes corrections sur mes projets solutions sur rapid dans ~/Bureau/emul_arduino/===
Idée: générer fichier vcd pour le test unitaire et regarder avec gtkwave????
=====TP 2 Informatique Embarquée Avancée CESI=====
=====Informations avant de commencer!=====
{{https://bvdp.inetdoc.net/files/iut/tp_pic/warning.jpeg}}
Pour faire le TP, vous devrez bien lire le sujet, ne pas sauter de parties, ne pas inventer de prototypes de fonctions mais bien respecter ce qui est demandé, car les fonctions que vous écrirez devront pouvoir être substituées à d'autres fonctions ayant les mêmes prototypes. Les marges de manœuvre dont vous disposez sont au niveau de l'implémentation de ces fonctions, mais les prototypes font partie du cahier des charges et ne sont pas négociables!
Le TP se déroulera sur plusieurs séances, il est de votre responsabilité de conserver les fichiers que vous aurez produits; pour cela, vous pourrez vous envoyer par mail ou via clef USB une archive zip de votre dossier de projet à chaque fin de séance pour éviter toute perte.
De plus cette archive devra être fournie à l'enseignant pour évaluation en fin de projet.
=====Description du dispositif à piloter et du système de commande=====
====Dispositif à piloter====
Vous allez devoir réaliser un système de commande d'un dispositif de tri industriel doté de capteurs et d'actionneurs. Ce dispositif est visible sur la figure suivante:
{{https://bvdp.inetdoc.net/files/cesi/tp2/station_rempli.png}}
Les informations fournies par les capteurs sont accessibles pour votre système de commande sur différents bits d'un port d'entrée 8 bits tel qu'indiqué sur la figure, les bits étant positionnés à 0 lorsque le capteur s'active.
Les commandes des actionneurs sont réalisées par votre système de commande sur différents bits d'un port de sortie 8 bits tel qu'indiqué sur la figure, les bits étant positionnés à 1 pour activer un actionneur.
====Système de commande====
L'interaction entre votre système de commande et la maquette à piloter se résume donc à un port d'entrée et un port de sortie, comme lors du TD1: [[cesitd1]]. De plus le système de commande intègre un écran LCD à deux lignes qui vous permettra d'afficher vos noms et des messages pendant l'exécution du programme.
Dans le TP, nous réaliserons le système de commande en plusieurs étapes:
- Vous écrirez le système de commande sur PC et simulerez les entrées/sorties à l'aide d'une application graphique dotée de boutons et d'afficheurs (mode simulé). Vous pourrez également utiliser une application simulant le processus industriel pour tester votre système de commande.
- Vous réaliserez des programmes de tests sur PC pour vérifier (et dans une certaine mesure prouver) le bon fonctionnement de votre système de commande (mode test unitaire).
- Vous réaliserez depuis le PC la commande à distance des entrées/sorties physiques d'un microcontrôleur vers le dispositif réel (mode télé-opéré).
- Vous réaliserez finalement la commande directement depuis le microcontrôleur simulé avec Wokwi (mode embarqué simulé).
- Vous réaliserez finalement la commande directement depuis le microcontrôleur raccordé au dispositif à piloter (mode embarqué).
=====Analyse pour le tri des pièces par type=====
===Détermination du type de pièce en fonction de l'activation des capteurs===
Les trois capteurs permettant de détecter les pièces sont positionnés en différents lieux sur le tapis roulant, et afin de déterminer si une pièce est Noire, Rouge ou Metallique, il est nécessaire de scruter l'activation successive des différents capteurs. Le tableau suivant récapitule la séquence d'activation des capteurs pour les différentes pièces:
Type de pièce, capteur NON_NOIR, capteur METAL, capteur PRESENT
Noire , , , X
Rouge , X, , X
Métal , X, X , X
====Machine à états====
Nous proposons d'utiliser une machine à états pour trier les pièces, afin de piloter les différents actionneurs du dispositif en fonction des informations fournies par les capteurs et du comportement souhaité:
* La station de tri doit amener dans la glissière 2 les pièces noires.
* La station de tri doit amener dans la glissière 1 les pièces métalliques.
* La station de tri doit amener dans la glissière 0 les pièces rouges.
* Le tapis roulant doit s’arrêter lorsque la glissière est pleine.
Il est vivement recommandé de raisonner sur l'activation des capteurs en utilisant des variables qui seront affectées au complément des valeurs lues sur les entrées correspondantes car les capteurs fournissent des signaux actifs à 0. Voir avec l'enseignant une machine à état (sans les actions) permettant de préparer ce comportement. Vous devrez par la suite réaliser vous même les actions.
{{https://bvdp.inetdoc.net/files/cesi/tp2/cesifesto1sansactions.gif}}
/*
Copyright (c) 2022, Bertrand Vandeportaele, LAAS/CNRS
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the University of California, Berkeley nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
0;
/*
1: marche=Inter0:sens:A8;
2: marche=Inter0;
3: marche=Inter0:sens:A9;
4: marche=Inter0:A9;
5: marche=Inter0:sens;
6: marche=Inter0:A8;
*/
//on raisonne avec les activations de capteurs, pas les états (car actif à niveau bas)
0 -> 1 ?NON_NOIR AND NOT PRESENT;
1 -> 2 ?METAL AND NOT PRESENT;
2 -> 3 ?PRESENT;
3 -> 4 ?NOT PLEIN;
4 -> 5 ?PLEIN;
5 -> 0 ?NOT PLEIN;
1 -> 6 ?PRESENT;
6 -> 7 ?NOT PLEIN;
7 -> 8 ?PLEIN;
8 -> 0 ?NOT PLEIN;
0 -> 9 ?PRESENT;
9 ->10 ?NOT PLEIN;
10->11 ?PLEIN;
11-> 0 ?NOT PLEIN;
//Actions toujours vraies
%I,stoppeur_retracte;
0:MOTEUR=NOT PLEIN;
1:MOTEUR=NOT PLEIN;
2:MOTEUR=NOT PLEIN;
3:SWITCH2;
4:MOTEUR=NOT PLEIN:SWITCH2;
5;
6:SWITCH1;
7:MOTEUR=NOT PLEIN:SWITCH1;
8;
9;
10:MOTEUR=NOT PLEIN;
11;
#pragma_dot_global_directive{
rankdir=TB; ranksep=0.1; nodesep=0.2;
}#pragma
//to testbench this file, just type ./run_tb.sh train 10000us in example/ghdl directory
#pragma_vhdl_testbench{
---------------------------------------
---------------------------------------
}#pragma
{{https://bvdp.inetdoc.net/files/cesi/tp2/cesifesto1avecactions.gif}}
=====Étapes pour démarrer le projet====
VIRE, date de l'époque ou les étudiants travaillaient sur session locale GEII
====Ménage sur la session utilisateur local====
A faire uniquement à la première séance
rm -rf ~/*.zip* ~/tcp_server_simulator ~/tcp_server ~/mae_etudiant_vide
====Récupération du simulateur d'entrées/sorties====
Copier coller dans un terminal les commandes suivantes A LA PREMIERE SEANCE UNIQUEMENT, afin de récupérer le projet et de le compiler:
cd ~
wget https://bvdp.inetdoc.net/files/cesi/tp2/tcp_server.zip
unzip tcp_server.zip
rm tcp_server.zip
cd tcp_server
rm -rf build*
cd tcp_server
qmake
make clean
make
./tcp_server &
Par la suite, pour lancer le simulateur, il vous suffira de saisir dans un terminal:
~/tcp_server/tcp_server/tcp_server &
Vous devez voir la fenêtre suivante s'ouvrir, qui vous permet de piloter l'état des entrées et de visualiser l'état des sorties. Elle permet également l'affichage de votre nom ainsi que de différents messages pendant l’exécution de votre programme.
{{https://bvdp.inetdoc.net/files/cesi/tp2/tcp_server.png}}
====Récupération du simulateur d'entrées/sorties et de la maquette====
Copier coller dans un terminal les commandes suivantes A LA PREMIERE SEANCE UNIQUEMENT, afin de récupérer le projet et de le compiler:
cd ~
wget https://bvdp.inetdoc.net/files/cesi/tp2/tcp_server_simulator.zip
unzip tcp_server_simulator.zip
rm tcp_server_simulator.zip
cd tcp_server_simulator
rm -rf build* .git tcp_server_simulator.pro.user station_rempli.png station_vide2.png station_vide.png 'switch*$.png'
qmake
make clean
make
./tcp_server_simulator &
Par la suite, pour lancer le simulateur, il vous suffira de saisir dans un terminal:
cd ~/tcp_server_simulator/ && ./tcp_server_simulator &
====Récupération du projet de départ====
Copier coller dans un terminal les commandes suivantes A LA PREMIERE SEANCE UNIQUEMENT, afin de récupérer le projet de départ et d'initialiser l'outils de gestion de versions:
echo commence
cd ~
wget https://bvdp.inetdoc.net/files/cesi/tp2/mae_etudiant_vide.zip
unzip mae_etudiant_vide.zip
rm mae_etudiant_vide.zip
mv mae_etudiant_vide mae_etudiant
cd mae_etudiant/tcp_client
git init
git add *
git commit -m'Version initiale fournie par B.Vandeportaele'
qtcreator tcp_client.pro &
gitk &
echo fini
A l'ouverture de Qtcreator, cliquer sur le bouton "Configurer le projet", le choix de kit proposé étant normalement correct.
====Structure du projet====
Le projet que vous avez récupéré comporte plusieurs fichiers permettant de générer un exécutable pour le PC:
- Arduino.cpp et Arduino.h forment une librairie permettant d'émuler la fonction de gestion du temps **millis()** de l'Arduino sur le PC.
- lib_io_tp.cpp et lib_io_tp.h forment une librairie permettant de piloter des ports d'entrées/sorties 8 bits ainsi qu'un écran à cristaux liquide via le réseau à l'aide de socket TCP. Cette librairie communique soit avec une vrai carte Arduino soit avec un programme permettant de l'émuler.
- sketch.cpp et sketch.h forment votre librairie contenant les fonctions **setup()** et **loop()** qui seront par la suite portées sur l'Arduino. Le projet fourni contient un code d'exemple qui illustre l'utilisation des fonctions des librairies Arduino et lib_io_tp et qui vous servira de base de départ pour votre propre programme.
- main.cpp contient le programme principal.
- tcp_client.pro est un fichier décrivant le projet QT, les règles de compilation, les librairies à utiliser etc...
====Présentation de la librairie pour les Entrées/Sorties====
Voici la description des fonctions disponibles dans la libraire pour piloter les E/S:
/*! \file lib_io_tp.h
\brief Librairie E/S via TCP pour le CESI.
\author Bertrand Vandeportaele IUT GEII
\date 14/02/2022
*/
#ifndef LIB_IO_TP_H
#define LIB_IO_TP_H
// Bertrand Vandeportaele 2022
// inspiré d'un exemple de client TCP simple sans QT:
// https://riptutorial.com/cplusplus/example/24000/hello-tcp-client
#include "Arduino.h"
#include
#include
#include
#include
#include
#include
#include
#include
/*!
* \brief setupES Configure les entrées sorties émulées ou télé-opérées vers l'hôte ipAddressInit via le port TCP portNumInit
* \param ipAddressInit
* \param portNumInit
* \return
*/
int setupES(char *ipAddressInit,char *portNumInit);
/*!
* \brief closeES Libère les ressources de communications utilisées par la librairie
*/
void closeES();
/*!
* \brief readPort Lit l'état du port d'entrée 8 bits
* \return l'état du port d'entrée 8 bits
*/
unsigned char readPort(void);
/*!
* \brief writePort Pilote l'état du port de sortie 8 bits
* \param value l'état du port de sortie 8 bits
*/
void writePort(unsigned char value);
/*!
/*! * \brief setName Règle votre nom à afficher sur l'écran LCD ou dans la zone de texte de l'émulateur
/*! * \param value la chaine de caractères contenant votre nom
/*! */
void setName(char *value);
/*!
* \brief setMsg Règle un message à afficher sur l'écran LCD ou dans la zone de texte de l'émulateur
* \param value la chaine de caractères contenant le message
*/
void setMsg(char *value);
// formats de requetes TCP:
// g \n pour lecture port
// s val\n pour ecriture port
// n nom\n pour affichage nom
// m message\n pour affichage message
#endif // LIB_IO_TP_H
Pour l'émulation des E/S sur votre PC en local, vous utilisez l'IP de la boucle locale: 127.0.0.1 et le numéro de port: 4242.
Pour la télé-opération des E/S sur la carte microcontrôleur, vous utilisez l'IP: 172.16.6.60 et le numéro de port: 4242. L'adaptateur Ethernet du microcontrôleur est connecté sur une prise VLAN bleue.
====Notice d'utilisation de l'outils QTCreator====
Une fois le projet ouvert, l'utilisateur peut choisir entre plusieurs mode d'affichages, notamment "Editer" et "Debogage" à l'aide des boutons sur la gauche de la fenêtre.
La fenêtre Projets fait apparaître les fichiers du (des) projet(s) ouvert(s), triés selon leur type. Sur la droite, la fenêtre affiche le contenu d'un fichier sélectionné.
**CTRL+Click souris gauche** sur un mot du programme permet de se déplacer à la déclaration d'une variable, d'un objet, d'une fonction, d'un type ou autre. Cela sera très utile pour connaître par exemple les méthodes utilisables sur un objet d'une certaine classe.
**CTRL+B** permet de compiler l'application, la fenêtre Sortie de compilation permet alors d'observer les éventuelles erreurs, sur lesquelles vous pourrez cliquer pour aller à la ligne correspondante dans le code.
**CTRL+R** permet d’exécuter le programme. Le programme devra être fermé en cliquant sur le bouton croix de la fenêtre avant de le recompiler ou de l’exécuter à nouveau.
**F5** permet d'exécuter le programme en mode DEBUG. L'utilisateur passe alors en mode Debug, ce qui ajoute à l'affichage une zone à droite dans laquelle l'utilisateur pourra observer les variables et leurs valeurs. L'utilisateur pourra placer ou retirer des points d'arrêt en cliquant à gauche du numéro de ligne d'un fichier. Il pourra exécuter en pas à pas sans rentrer dans les fonctions à l'aide de **F10** ou bien en entrant dans les fonctions à l'aide de **F11**. Il pourra ajouter une variable particulière à la liste des variables affichées en Debug en selectionant le nom de la variable dans le fichier programme et en cliquant droit dessus puis clic gauche sur **ajouter un évaluateur d'expression**.
====Utilisation de l'outil de gestion de version depuis QT====
Pour créer une version, au moins à chaque validation, vous devrez cliquer sur Outils->Git->Dépot local->Commit, cliquer sur Fichiers->Select all, et saisir un texte descriptif dans le champ Description. Ensuite cliquer sur Soumettre.
Pour visualiser les différentes versions, vous devrez cliquer sur Outils->Git->Outils Git->gitk
====Test du projet de départ====
Compiler et exécuter le projet de départ, alors que l'application tcp_server est en cours d'exécution. Jouer sur les entrées et observer le comportement de l'application. Relier ce comportement au code du projet de départ pour en comprendre le fonctionnement.
====Implémentation de la machine à états====
Implémenter la machine à états dans le fichier sketch.cpp comme cela a été montré en [[cesitd3]] (s'identifier en login:au , mot de passe: au pour voir les solutions du td3). Modifier le code de la fonction **loop()** pour que votre machine soit reliée aux entrées/sorties et soit cadencée à 200Hz. Faire en sorte d'afficher votre nom et un message indiquant l'état actif de la machine à état à chaque évolution. Tester complètement le bon fonctionnement de votre programme en jouant sur les entrées et en déduire des séquences de tests.
{{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}}{{https://bvdp.inetdoc.net/files/imageschiffres/chiffre-1.jpg?40%}}}
Appeler un enseignant pour valider votre travail et sauver une version.
====Réalisation de la fonction de test unitaire de la machine à états====
A partir des séquences de tests déterminées à l'exercice précédent, écrire et exécuter un programme de test complet **void programmeDeTest1()** faisant apparaître le maintien dans chaque état et toutes les transitions comme montré en [[cesitd3]].
Pour cela, vous devrez adapter le code pour que l'affichage se fasse sur la console du PC au lieu de celle de l'arduino. Vous utiliserez donc la fonction **debugMessage** suivante:
////////////////////////////////////////////////////////////////////
//! 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){
printf("DEBUG %s : l %d : %s\n",chaineFile,line,chaineMsg);
flush(std::cout);
}
et vous remplacerez les affichages réalisés avec Serial.print par des appels à la fonction **printf**.
Vous pourrez utiliser ce squelette de programme de test et le compléter. Cette fonction devra être appelée par la fonction **setup()**:
void programmeDeTest1(){
//! Le composant à tester
CStateMachine mae;
printf("\nTest lancé le ");
printf("%s",__DATE__ );
printf(" à ");
printf("%s",__TIME__ );
printf("\nFonction de test: ");
printf(__func__);
//boucle pour gérer les différents cas à tester
int ntest=1;
printf("\ndébut du test numéro: ");
printf("%d\n",ntest);
mae.reset();
mae.setEntree(0xF);
mae.clock(); //ici on teste la mae sans considération de timing, donc clock() n'est pas conditionné à un timer
mae.clock();
//Compléter le test ici:
if (mae.getEtat()!=......) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
//fin du test
debugMessage("\nFin du test\n", __FILE__, __LINE__);
exit(0); //commenter cette ligne pour ne pas quitter le programme après la fin du test
}
//////////////////////////////////////////////////////
{{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}}{{https://bvdp.inetdoc.net/files/imageschiffres/chiffre-2.jpg?40%}}}
Appeler un enseignant pour valider votre travail et sauver une version.
====Test en mode télé-opéré====
Adapter le programme pour le tester en mode télé-opéré sur la maquette réelle. Vous veillerez à indiquer au tableau le nom du binôme utilisant la maquette à un instant donné pour éviter qu'un autre binôme n'interfère.
{{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}}{{https://bvdp.inetdoc.net/files/imageschiffres/chiffre-3.jpg?40%}}}
Appeler un enseignant pour valider votre travail et sauver une version.
====Test en mode embarqué (tout simulé)=====
Insérer le code de vos fonctions **setup()** et **loop()** dans le projet du TD1: [[cesitd1]] et tester avec wokwi le bon fonctionnement en embarqué dans le simulateur.
Vous devrez dans setup(), après avoir appelé setupES(), appeler 1 fois readPort() et writePort(0);
Vous aurez besoin d'ajouter à la librairie du TD1 les fonctions suivantes:
///////////////////////////////////////////////////////
void setName(char *value) {
Serial.println(value);
}
///////////////////////////////////////////////////////
void setMsg(char *value) {
Serial.println(value);
}
///////////////////////////////////////////////////////
{{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}}{{https://bvdp.inetdoc.net/files/imageschiffres/chiffre-4.jpg?40%}}}
Appeler un enseignant pour valider votre travail et sauver une version (sous Wokwi).
====Test en mode embarqué (E/S simulé)=====
Programmer une vraie carte Arduino dotée d'entrées/sorties telle que visible sur la carte [[tdcom2]] en utilisant la librairie d'entrées/sortie suivante et tester:
/*! \file lib_io_tp.h
\brief Premier TD pour le CESI.
\author Bertrand Vandeportaele IUT GEII
\date 28/10/2021
*/
#include
void SetupES(void);
unsigned char readPort(void);
void writePort(unsigned char value);
void setName(char *value);
void setMsg(char *value);
/*! \file lib_io_tp.cpp
\brief Premier TD pour le CESI.
\author Bertrand Vandeportaele IUT GEII
\date 28/10/2021
*/
#include "lib_io_tp.h"
bool SIMULATION=false; //si cette variable est true, alors la librairie utilise les composants registres
//à décalage en simulation sur Wokwi, sinon elle utilise les composants PCF8574 de la carte de TP
//Pour les composants I2C:
#include
#define SLAVE_ADDR_8574_A (0x38+6)
#define SLAVE_ADDR_8574_B (0x38+7)
//Pour les composants en simulation:
//Librairie pour registres à décalage sur Wokwi.com
/*mix de
https://wokwi.com/arduino/projects/313005664351814210
et de
https://wokwi.com/arduino/projects/301188813482361352
*/
// Pin definitions:
const int datapin_in = 9; /* Q7 */
const int clockpin_in = 8; /* CP */
const int latchpin_in = 4; /* PL */
const int datapin_out = 5;
const int clockpin_out = 6;
const int latchpin_out = 7;
///////////////////////////////////////////////////////
/*!
* \brief Fonction d'initialisation des ressources matérielles pour accéder aux ports d'entrée/sortie
*/
void SetupES(void){
Wire.begin();
delay(100);
//teste si un composant 8574 est présent sur la carte
for (byte addr=0x38;addr<=0x3f;addr++){
Wire.requestFrom(addr, (byte)1);// demande la lecture d'1 octet depuis l'adresse du pérpiphérique
if (Wire.available()==1) {
Wire.read();
SIMULATION=false; //Utilisation des composants I2C plutot que des registres à décalage
//Serial.print("premier composant i2c trouvé a:");Serial.println(addr,HEX);
break;
}
}
if (SIMULATION==false){
delay(100);
Wire.beginTransmission((byte)SLAVE_ADDR_8574_B);Wire.write((byte)0xff);Wire.endTransmission();//configure le composant B en entrée
}else{
pinMode(datapin_in, INPUT);
pinMode(clockpin_in, OUTPUT);
pinMode(latchpin_in, OUTPUT);
// Set the three SPI pins to be outputs:
pinMode(datapin_out, OUTPUT);
pinMode(clockpin_out, OUTPUT);
pinMode(latchpin_out, OUTPUT);
}
}
///////////////////////////////////////////////////////
/*!
* \brief Fonction de lecture du port d'entrée
* @return valeur 8 bits lue sur le port
*/
unsigned char readPort(void){
if (SIMULATION==false){
Wire.requestFrom((byte)SLAVE_ADDR_8574_B, (byte)1);// demande la lecture d'1 octet depuis l'adresse du pérpiphérique
if (Wire.available()==1) //si l'octet est disponible
return Wire.read(); // lire l'octet
else
return 0;
}else{
unsigned char val=0;
// Step 1: Sample
digitalWrite(latchpin_in, LOW);
digitalWrite(latchpin_in, HIGH);
for (int i = 0; i < 8; i++) {
int bit = digitalRead(datapin_in);
val=(val<<1)|bit;
digitalWrite(clockpin_in, HIGH); // Shift out the next bit
digitalWrite(clockpin_in, LOW);
}
return val;
}
}
///////////////////////////////////////////////////////
/*!
* \brief Fonction d'écriture vers le port de sortie
* @param value valeur 8 bits à écrire sur le port
*/
void writePort(unsigned char value){
//cette fonction pilote les 8 leds avec la valeur 8bits fournie dans le paramètre valeur
if (SIMULATION==false){
Wire.beginTransmission((byte)SLAVE_ADDR_8574_A);//démarre la transmission avec l'adresse du pérpiphérique
Wire.write(~(byte)value); //envoie la donnée complémentée car les LEDs s'allument à l'état 0
Wire.endTransmission();
}else{
shiftOut(datapin_out, clockpin_out, MSBFIRST, value); //Send "data" to the shift register
//Toggle the latchpin_out to make "data" appear at the outputs
digitalWrite(latchpin_out, HIGH);
digitalWrite(latchpin_out, LOW);
}
}
///////////////////////////////////////////////////////
void setName(char *value) {
Serial.println(value);
}
///////////////////////////////////////////////////////
void setMsg(char *value) {
Serial.println(value);
}
///////////////////////////////////////////////////////
{{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}}{{https://bvdp.inetdoc.net/files/imageschiffres/chiffre-5.jpg?40%}}}
Appeler un enseignant pour valider votre travail et sauver une version.
====Test en mode embarqué complet=====
Installer la librairie LiquidCrystal_I2C dans Arduino.
Pour cela, cliquer dans l'IDE arduino sur Croquis->Inclure une Bibliothèque->Gérer les Bibliothèques et copier coller "LiquidCrystal_I2C" dans le champ "Filtrer votre recherche". Selectionner dans la liste "LiquidCrystal_I2C by Frank Brabander" en version 1.1.2 et cliquer sur Installer.
Avec l'enseignant, programmer LA carte Arduino raccordée à la station de tri en utilisant la librairie d'entrées/sortie suivante et tester:
/*! \file lib_io_tp.h
\brief Librairie IO+LCD pour FESTO
\author Bertrand Vandeportaele IUT GEII
\date 14/02/2022
*/
#include
#include
void SetupES(void);
unsigned char readPort(void);
void writePort(unsigned char value);
void setName(char *value);
void setMsg(char *value);
/*! \file lib_io_tp.cpp
\brief Librairie IO+LCD pour FESTO
\author Bertrand Vandeportaele IUT GEII
\date 14/02/2022
*/
#include "lib_io_tp.h"
//pour utiliser carte d'interface et gérer inversion des quartets + E et S inversées A/B par rapports aux inter et led..
#define FESTO
#include
#define SLAVE_ADDR_8574_A (0x38+6)
#define SLAVE_ADDR_8574_B (0x38+7)
LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display
//doc sur https://github.com/johnrickman/LiquidCrystal_I2C/blob/master/LiquidCrystal_I2C.h
#ifdef FESTO
//////////////////////////////////////////
char swapNibles(char in) { //le port de sortie est cablé en inversant les 4 bits MSB avec les LSB
return (( (in & 0x0f) << 4) | ((in >> 4) & 0x0f));
}
//////////////////////////////////////////
#endif
///////////////////////////////////////////////////////
/*!
\brief Fonction d'initialisation des ressources matérielles pour accéder aux ports d'entrée/sortie
*/
void SetupES(void) {
Wire.begin();
delay(100);
#ifdef FESTO
Wire.beginTransmission((byte)SLAVE_ADDR_8574_A); Wire.write((byte)0xff); Wire.endTransmission(); //configure le composant A en entrée
Wire.beginTransmission((byte)SLAVE_ADDR_8574_B); Wire.write((byte)0x00); Wire.endTransmission(); //configure le composant B en sortie
#else
Wire.beginTransmission((byte)SLAVE_ADDR_8574_A); Wire.write((byte)0x00); Wire.endTransmission(); //configure le composant A en sortie
Wire.beginTransmission((byte)SLAVE_ADDR_8574_B); Wire.write((byte)0xff); Wire.endTransmission(); //configure le composant B en entrée
#endif
// Wire.beginTransmission((byte)SLAVE_ADDR_8574_B); Wire.write((byte)0xff); Wire.endTransmission(); //configure le composant B en entrée
lcd.init(); // initialize the lcd
lcd.backlight();
lcd.print("Nom:");
lcd.setCursor(0, 1);
lcd.print("Msg:");
}
///////////////////////////////////////////////////////
/*!
\brief Fonction de lecture du port d'entrée
@return valeur 8 bits lue sur le port
*/
unsigned char readPort(void) {
#ifdef FESTO
Wire.requestFrom((byte)SLAVE_ADDR_8574_A, (byte)1);// demande la lecture d'1 octet depuis l'adresse du pérpiphérique
#else
Wire.requestFrom((byte)SLAVE_ADDR_8574_B, (byte)1);// demande la lecture d'1 octet depuis l'adresse du pérpiphérique
#endif
if (Wire.available() == 1) //si l'octet est disponible
return Wire.read(); // lire l'octet
else
return 0;
}
///////////////////////////////////////////////////////
/*!
\brief Fonction d'écriture vers le port de sortie
@param value valeur 8 bits à écrire sur le port
*/
void writePort(unsigned char value) {
//cette fonction pilote les 8 leds avec la valeur 8bits fournie dans le paramètre valeur
#ifdef FESTO
Wire.beginTransmission((byte)SLAVE_ADDR_8574_B);//démarre la transmission avec l'adresse du pérpiphérique
Wire.write((byte)swapNibles(value)); //envoie la donnée non complémentée
#else
Wire.beginTransmission((byte)SLAVE_ADDR_8574_A);//démarre la transmission avec l'adresse du pérpiphérique
Wire.write(~(byte)value); //envoie la donnée complémentée car les LEDs s'allument à l'état 0
#endif
Wire.endTransmission();
}
///////////////////////////////////////////////////////
void printlcd(char *value, int nligne) {
lcd.setCursor(4, nligne);
int i;
for (i = 0; i < 12; i++) {
if ((value[i] == '\0') || (value[i] == '\n'))
break;
else
lcd.write( value[i]);
}
//si i<12; on efface avec des ' '
while (i < 12) {
lcd.write(' ');
i++;
}
}
///////////////////////////////////////////////////////
void setName(char *value) {
printlcd(value, 0);
}
///////////////////////////////////////////////////////
void setMsg(char *value) {
printlcd(value, 1);
}
{{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}}{{https://bvdp.inetdoc.net/files/imageschiffres/chiffre-6.jpg?40%}}}
Appeler un enseignant pour valider votre travail et sauver une version.
====Evolution de la MAE pour réaliser des séquences de pièces=====
Proposer une adaptation de la machine à états permettant de réaliser:
-dans la glissière 2, une séquence de pièces rouge/noire/rouge.
-dans la glissière 1, deux métalliques et une noire, dans n'importe quel ordre.
-dans la glissière 0, le stockage des pièces non utilisables.
Réaliser la démarche de test comme précédemment.
{{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}}{{https://bvdp.inetdoc.net/files/imageschiffres/chiffre-7.jpg?40%}}}
Appeler un enseignant pour valider votre travail et sauver une version.
====Parallélisme de tâches=====
Pour illustrer le parallélisme de tâches, vous allez scinder la machine à états en 2 machines à états séparées afin de permettre au système de gérer l'arrivée d'une pièce en amont du tapis alors qu'une pièce est en cours de transit vers une glissière:
- La première permet de déterminer le type de pièce, et bloque la pièce en attente grâce au stoppeur.
- La deuxième permet d'acheminer une pièce du stoppeur jusqu'à la bonne glissière.
Les deux machines a états doivent communiquer: La première doit informer la deuxième du type de pièce détectée et attendre que la deuxième lui demande d'envoyer la pièce.
Proposer un dessin des deux machines à états et après validation par l'enseignant, réaliser la démarche de test comme précédemment.
{{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}}{{https://bvdp.inetdoc.net/files/imageschiffres/chiffre-8.jpg?40%}}}
Appeler un enseignant pour valider votre travail et sauver une version.
=====Annexes=====
=====Projet solution=====
cd ~
wget https://bvdp.inetdoc.net/files/cesi/tp2/mae_etudiant.zip
unzip mae_etudiant.zip
rm mae_etudiant.zip
cd mae_etudiant/tcp_client
qmake
make clean
qtcreator tcp_client.pro &
=====Application Arduino TCPServerIO=====
/*! \file TCPServerIO.ino
\brief Distant Input/Output via TCP for Arduino
\author Bertrand Vandeportaele IUT GEII
\date 14/02/2022
*/
/*
Inspired from Web Server demo application
created 18 Dec 2009
by David A. Mellis
modified 9 Apr 2012
by Tom Igoe
modified 02 Sept 2015
by Arturo Guadalupi
*/
#include "lib_io_tp.h"
//activer ce flag pour débugguer les requetes/réponses
#define DEBUG_TCP_REQ
//voir la doc: file:///home/bvandepo/T%C3%A9l%C3%A9chargements/arduino-1.8.13/reference/www.arduino.cc/en/Reference/Ethernet.html
#include
#include
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x05
};
//maison: IPAddress ip(192, 168, 1, 177);
//IUT gomette bleue:
IPAddress ip(172,16,6,60);
// Initialize the Ethernet server library
// with the IP address and port you want to use
EthernetServer server(4242);
void setup() {
// You can use Ethernet.init(pin) to configure the CS pin
//Ethernet.init(10); // Most Arduino shields
//Ethernet.init(5); // MKR ETH shield
//Ethernet.init(0); // Teensy 2.0
//Ethernet.init(20); // Teensy++ 2.0
//Ethernet.init(15); // ESP8266 with Adafruit Featherwing Ethernet
//Ethernet.init(33); // ESP32 with Adafruit Featherwing Ethernet
SetupES();
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
Serial.println("TCPServerIO Bertrand Vandeportaele 2022");
// start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
// Check for Ethernet hardware present
if (Ethernet.hardwareStatus() == EthernetNoHardware) {
Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :(");
while (true) {
delay(1); // do nothing, no point running without Ethernet hardware
}
}
if (Ethernet.linkStatus() == LinkOFF) {
Serial.println("Ethernet cable is not connected.");
}
// start the server
server.begin();
Serial.print("server is at ");
Serial.println(Ethernet.localIP());
}
void loop() {
static char chaine[100];
static int nb_received = 0;
// listen for incoming clients
EthernetClient client = server.available();
if (client) {
Serial.println("new client");
// an http request ends with a blank line
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
unsigned char entree;
char c = client.read();
#ifdef DEBUG_TCP_REQ
Serial.write(c);
#endif
chaine[nb_received] = c; //TODO : avoid leaks
nb_received++;
if (c == '\n') {
unsigned char v;
chaine[nb_received] = '\0';
switch ( chaine[0]) {
case 's':
v = atoi(chaine + 2);
#ifdef DEBUG_TCP_REQ
Serial.print(" -> requete s ");
Serial.println(v);
#endif
writePort(v);
entree = v;
break;
case 'g':
v = atoi(chaine + 2);
#ifdef DEBUG_TCP_REQ
Serial.print(" -> requete g ");
Serial.println(v);
#endif
entree = readPort();
break;
case 'm':
#ifdef DEBUG_TCP_REQ
Serial.print(" -> requete m ");
Serial.println(chaine + 2);
#endif
setMsg(chaine + 2);
entree = 0;
break;
case 'n':
#ifdef DEBUG_TCP_REQ
Serial.print(" -> requete n ");
Serial.println(chaine + 2);
#endif
setName(chaine + 2);
entree = 0;
break;
}
//envoi reponse à la requete:
//itoa(entree, chaine, 10);
sprintf(chaine, "%03d\n", entree);
client.print(chaine);
#ifdef DEBUG_TCP_REQ
Serial.print(" -> réponse ");
Serial.println(chaine);
#endif
nb_received = 0; //reinit pour la requete suivante
}
}
}
delay(1);
// close the connection:
client.stop();
Serial.println("client disconnected");
}
}
/*! \file lib_io_tp.cpp
\brief Librairie IO+LCD pour FESTO
\author Bertrand Vandeportaele IUT GEII
\date 14/02/2022
*/
#include "lib_io_tp.h"
//pour utiliser carte d'interface et gérer inversion des quartets + E et S inversées A/B par rapports aux inter et led..
#define FESTO
#include
#define SLAVE_ADDR_8574_A (0x38+6)
#define SLAVE_ADDR_8574_B (0x38+7)
LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display
//doc sur https://github.com/johnrickman/LiquidCrystal_I2C/blob/master/LiquidCrystal_I2C.h
#ifdef FESTO
//////////////////////////////////////////
char swapNibles(char in) { //le port de sortie est cablé en inversant les 4 bits MSB avec les LSB
return (( (in & 0x0f) << 4) | ((in >> 4) & 0x0f));
}
//////////////////////////////////////////
#endif
///////////////////////////////////////////////////////
/*!
\brief Fonction d'initialisation des ressources matérielles pour accéder aux ports d'entrée/sortie
*/
void SetupES(void) {
Wire.begin();
delay(100);
#ifdef FESTO
Wire.beginTransmission((byte)SLAVE_ADDR_8574_A); Wire.write((byte)0xff); Wire.endTransmission(); //configure le composant A en entrée
Wire.beginTransmission((byte)SLAVE_ADDR_8574_B); Wire.write((byte)0x00); Wire.endTransmission(); //configure le composant B en sortie
#else
Wire.beginTransmission((byte)SLAVE_ADDR_8574_A); Wire.write((byte)0x00); Wire.endTransmission(); //configure le composant A en sortie
Wire.beginTransmission((byte)SLAVE_ADDR_8574_B); Wire.write((byte)0xff); Wire.endTransmission(); //configure le composant B en entrée
#endif
// Wire.beginTransmission((byte)SLAVE_ADDR_8574_B); Wire.write((byte)0xff); Wire.endTransmission(); //configure le composant B en entrée
lcd.init(); // initialize the lcd
lcd.backlight();
lcd.print("Nom:");
lcd.setCursor(0, 1);
lcd.print("Msg:");
}
///////////////////////////////////////////////////////
/*!
\brief Fonction de lecture du port d'entrée
@return valeur 8 bits lue sur le port
*/
unsigned char readPort(void) {
#ifdef FESTO
Wire.requestFrom((byte)SLAVE_ADDR_8574_A, (byte)1);// demande la lecture d'1 octet depuis l'adresse du pérpiphérique
#else
Wire.requestFrom((byte)SLAVE_ADDR_8574_B, (byte)1);// demande la lecture d'1 octet depuis l'adresse du pérpiphérique
#endif
if (Wire.available() == 1) //si l'octet est disponible
return Wire.read(); // lire l'octet
else
return 0;
}
///////////////////////////////////////////////////////
/*!
\brief Fonction d'écriture vers le port de sortie
@param value valeur 8 bits à écrire sur le port
*/
void writePort(unsigned char value) {
//cette fonction pilote les 8 leds avec la valeur 8bits fournie dans le paramètre valeur
#ifdef FESTO
Wire.beginTransmission((byte)SLAVE_ADDR_8574_B);//démarre la transmission avec l'adresse du pérpiphérique
Wire.write((byte)swapNibles(value)); //envoie la donnée non complémentée
#else
Wire.beginTransmission((byte)SLAVE_ADDR_8574_A);//démarre la transmission avec l'adresse du pérpiphérique
Wire.write(~(byte)value); //envoie la donnée complémentée car les LEDs s'allument à l'état 0
#endif
Wire.endTransmission();
}
///////////////////////////////////////////////////////
void printlcd(char *value, int nligne) {
lcd.setCursor(4, nligne);
int i;
for (i = 0; i < 12; i++) {
if ((value[i] == '\0') || (value[i] == '\n'))
break;
else
lcd.write( value[i]);
}
//si i<12; on efface avec des ' '
while (i < 12) {
lcd.write(' ');
i++;
}
}
///////////////////////////////////////////////////////
void setName(char *value) {
printlcd(value, 0);
}
///////////////////////////////////////////////////////
void setMsg(char *value) {
printlcd(value, 1);
}
/*! \file lib_io_tp.h
\brief Librairie IO+LCD pour FESTO
\author Bertrand Vandeportaele IUT GEII
\date 14/02/2022
*/
#include
#include
void SetupES(void);
unsigned char readPort(void);
void writePort(unsigned char value);
void setName(char *value);
void setMsg(char *value);
void loop(){
unsigned int periodiciteTache1=1000;
static unsigned long timerTache1 = millis();
if (millis() - timerTache1 >= periodiciteTache1) {
timerTache1 += periodiciteTache1;
static char c=0;
std::cin >>c;
std::cin.get();
std::cout << "c vaut:" << c;
if ((c>='0') && (c<='9')){
c=c-'0';
writePort(c);
}else if ((c>='A') && (c<='F')){
c=c-'A'+10;
writePort(c);
}else if ((c>='a') && (c<='f')){
c=c-'f'+10;
writePort(c);
}
//c=(c+1)%16;
//writePort(c);
//=getkey();
//readPort();
}
/*unsigned int periodiciteTache2=1000;
static unsigned long timerTache2 = millis();
if (millis() - timerTache2 >= periodiciteTache2) {
timerTache2 += periodiciteTache2;
static unsigned int cpt=0;
cpt++;
char chaine[100];
sprintf(chaine,"cpt=%d",cpt);
printf(chaine);
setMsg(chaine);
}*/
}
Programme de test simple pour verifier les E/S depuis teleopération:
/*! \file sketch.cpp
\brief Emulation sketch Arduino pour le CESI.
\author Bertrand Vandeportaele IUT GEII
\date 14/02/2022
*/
#include "sketch.h"
#include "lib_io_tp.h"
//////////////////////////////////////////////////////
void setup(){
init_millis();
//boucle locale pour simu
//int r=setupES("127.0.0.1","4242");
//arduino iut gomette bleue
int r=setupES("172.16.6.60","4242");
setName("Bertrand Vandeportaele");
if (r!=0)
printf("erreur ouverture socket\n");
printf("Elapsed time: %ld milliseconds\n", millis());
}
//////////////////////////////////////////////////////
void loop(){
unsigned int periodiciteTache1=2000;
static unsigned long timerTache1 = millis();
static unsigned char cptTache1=0;
if (millis() - timerTache1 >= periodiciteTache1) {
timerTache1 += periodiciteTache1;
// writePort(readPort());
writePort(1<= periodiciteTache2) {
timerTache2 += periodiciteTache2;
static unsigned int cpt=0;
cpt++;
char chaine[100];
unsigned char E=readPort();
for (int i=0;i<8;i++)
chaine[7-i]=((E>>i)&1)+'0';
chaine[8]=0;
//sprintf(chaine,"cpt=%d,E=%02X",cpt, readPort());
printf(chaine);
setMsg(chaine);
}
}
Solution pour téléopération (à tester, récupérée sur compte IUT/bvdp/mae_etudiant/tcp_client):
#include "sketch.h"
#include "lib_io_tp.h"
////////////////////////////////////////////////////////////////////
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)&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;
};
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
//Implémentation de la méthode constructeur
CStateMachine::CStateMachine(){
// à compléter si besoin, allocation etc...
reset();
}
////////////////////////////////////////////////////////////////////
//Implémentation de la méthode reset, tout ce qui est fait pour (re)démarrer la machine à états
void CStateMachine::reset(){
etat=0;
sortie=0; //mettre des valeurs initiales correctes
}
////////////////////////////////////////////////////////////////////
//Implémentation de la méthode clock
void CStateMachine::clock(){
//variables intérmédiaires pour les entrées
unsigned char present =( (entree>>0)&1 ) ^1;
unsigned char metal =( (entree>>1)&1 ) ^1;
unsigned char non_noir =( (entree>>2)&1 ) ^1;
unsigned char plein =( (entree>>3)&1 ) ^1;
//AMZI
unsigned char moteur=0;
unsigned char switch1=0;
unsigned char switch2=0;
unsigned char stoppeur_retracte=1; //toujours rétracté
//variables intérmédiaires pour les sorties
//codage des sorties
//moteur est une AMZI
//if ( (etat==0) || (etat==1) || (etat==2) || (etat==3) || (etat==4) || (etat==6) || (etat==7) || (etat==9) || (etat==10) )
if ( ( (etat==0) || (etat==1) || (etat==2) || (etat==4) || (etat==7) || (etat==10) ) && (plein==0))
moteur=1;
else
moteur=0;
if ( (etat==6) || (etat==7) )
switch1=1;
else
switch1=0;
if ( (etat==3) || (etat==4) )
switch2=1;
else
switch2=0;
/*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 ( (non_noir==1) && (present==0))
etat=1;
else if (present==1)
etat=9;
break;
case 1: if ( (metal==1) && (present==0))
etat=2;
else if (present==1)
etat=6;
break;
case 2: if (present==1)
etat=3;
break;
case 3: if (plein==0)
etat=4;
break;
case 4: if (plein==1)
etat=5;
break;
case 5: if (plein==0)
etat=0;
break;
case 6: if (plein==0)
etat=7;
break;
case 7: if (plein==1)
etat=8;
break;
case 8: if (plein==0)
etat=0;
break;
case 9: if (plein==0)
etat=10;
break;
case 10: if (plein==1)
etat=11;
break;
case 11: if (plein==0)
etat=0;
break;
}
//pour le premier exercice:
//sortie=0;
//reconstruction de sortie à partir des variables intermédiaires
//sortie=(sortie3<<3) | (sortie2<<2) | (sortie1<<1) | (sortie0<<0) ;
//stoppeur est en logique inverse, la commande est pour rétracter le stoppeur
sortie=((stoppeur_retracte)<<3) | (switch2<<2) | (switch1<<1) | (moteur<<0) ;
}
////////////////////////////////////////////////////////////////////
CStateMachine mae;
//////////////////////////////////////////////////////
void setup(){
init_millis();
//boucle locale pour simu
//int r=setupES("127.0.0.1","4242");
//arduino maison
//int r=setupES("192.168.1.177","4242");
//arduino iut gomette bleue
int r=setupES("172.16.6.60","4242");
setName("Bertrand etu");
if (r!=0)
printf("erreur ouverture socket\n");
printf("Elapsed time: %ld milliseconds\n", millis());
}
//////////////////////////////////////////////////////
void loop(){
/*
for (int nbrport=0;nbrport<10;nbrport++){
writePort(123+nbrport);
unsigned char e=readPort();
//std::cout << e << endl;
}*/
unsigned int periodiciteTache1=10;
static unsigned long timerTache1 = millis();
if (millis() - timerTache1 >= periodiciteTache1) {
timerTache1 += periodiciteTache1;
mae.setEntree(readPort());
mae.clock();
writePort(mae.getSortie());
char chaine[100];
sprintf(chaine,"etat %d", mae.getEtat());
setMsg(chaine);
}
/*
unsigned int periodiciteTache2=1000;
static unsigned long timerTache2 = millis();
if (millis() - timerTache2 >= periodiciteTache2) {
timerTache2 += periodiciteTache2;
static unsigned int cpt=0;
cpt++;
char chaine[100];
sprintf(chaine,"cpt=%d",cpt);
printf(chaine);
setMsg(chaine);
}
*/
}
Programme de test étudiant à vérifier:
/*! \file sketch.cpp
\brief Emulation sketch Arduino pour le CESI.
\author Bertrand Vandeportaele IUT GEII
\date 14/02/2022
*/
#include "sketch.h"
#include "lib_io_tp.h"
//////////////////////////////////////////////////////
//! 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){
printf("DEBUG %s : l %d : %s\n",chaineFile,line,chaineMsg);
flush(std::cout);
}
//////////////////////////////////////////////////////
void programmeDeTest1(){
//! Le composant à tester
CStateMachine mae;
printf("Test lancé le ");
printf("%s",__DATE__ );
printf(" à ");
printf("%s",__TIME__ );
printf("\nFonction de test: ");
printf(__func__);
//boucle pour gérer les différents cas à tester
int ntest=1;
printf("début du test numéro: ");
printf("%d\n",ntest);
mae.reset();
mae.setEntree(0xFF); //OxF
mae.clock(); //ici on teste la mae sans considération de timing, donc clock() n'est pas conditionné à un timer
if (mae.getSortieBit(0)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 0
if (mae.getSortieBit(1)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 0
if (mae.getSortieBit(2)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 0
if (mae.getSortieBit(3)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 0
mae.setEntreeBit(0,0);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,1);
if (mae.getEtat()!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,0);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,1);
if (mae.getEtat()!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,0);
if (mae.getEtat()!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,0);
mae.setEntreeBit(3,1);
mae.clock(); //passage à l'etat 1
if (mae.getEtat()!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(0)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(1)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(2)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(3)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
mae.setEntreeBit(0,0);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,1);
if (mae.getEtat()!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,0);
mae.setEntreeBit(3,1);
if (mae.getEtat()!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,0);
if (mae.getEtat()!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,0);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,1);
mae.clock(); //passage à l'etat 2
if (mae.getEtat()!=2) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
if (mae.getSortieBit(0)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(1)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(2)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(3)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,0);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,0);
mae.clock();
if (mae.getEtat()!=2) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,0);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,0);
mae.clock();
if (mae.getEtat()!=2) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,0);
mae.setEntreeBit(3,0);
mae.clock();
if (mae.getEtat()!=2) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,1);
mae.clock(); //passage à l'etat 3
if (mae.getEtat()!=3) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
if (mae.getSortieBit(0)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(1)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(2)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(3)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
mae.setEntreeBit(0,0);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,1);
mae.clock();
if (mae.getEtat()!=3) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,0);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,1);
mae.clock();
if (mae.getEtat()!=3) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,0);
mae.setEntreeBit(3,1);
mae.clock();
if (mae.getEtat()!=3) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,0);
mae.clock(); //passage à l'état 4
if (mae.getEtat()!=4) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
if (mae.getSortieBit(0)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(1)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(2)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(3)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,0);
mae.setEntreeBit(3,0);
mae.clock();
if (mae.getEtat()!=4) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,0);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,0);
mae.clock();
if (mae.getEtat()!=4) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,0);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,0);
mae.clock();
if (mae.getEtat()!=4) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);//passage à l'etat 0
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,1);
mae.clock();
if (mae.getEtat()!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
//boucle 5,6,7,8
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,0);
mae.setEntreeBit(3,1);
mae.clock(); //passage à l'etat 1
//Compléter le test ici
if (mae.getEtat()!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
mae.setEntreeBit(0,0);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,1);
mae.clock();
if (mae.getEtat()!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,0);
mae.setEntreeBit(3,1);
mae.clock();
if (mae.getEtat()!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,0);
mae.clock();
if (mae.getEtat()!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,0);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,1);
mae.clock(); //passage à l'etat 5
if (mae.getEtat()!=5) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
if (mae.getSortieBit(0)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(1)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(2)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(3)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,0);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,1);
mae.clock();
if (mae.getEtat()!=5) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,0);
mae.setEntreeBit(3,1);
mae.clock();
if (mae.getEtat()!=5) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,0);
mae.clock();
if (mae.getEtat()!=5) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,0);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,0);
mae.clock(); //passage à l'etat 6
if (mae.getEtat()!=6) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
if (mae.getSortieBit(0)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(1)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(2)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(3)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
mae.setEntreeBit(0,0);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,0);
mae.clock();
if (mae.getEtat()!=6) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,0);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,0);
mae.clock();
if (mae.getEtat()!=6) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,0);
mae.setEntreeBit(3,0);
mae.clock();
if (mae.getEtat()!=6) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,1);
mae.clock(); //passage à l'état 7
if (mae.getEtat()!=7) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
if (mae.getSortieBit(0)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(1)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(2)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(3)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
mae.setEntreeBit(0,0);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,1);
mae.clock();
if (mae.getEtat()!=7) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,0);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,1);
mae.clock();
if (mae.getEtat()!=7) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,0);
mae.setEntreeBit(3,1);
mae.clock();
if (mae.getEtat()!=7) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);//passage à l'etat 8
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,0);
mae.clock();
if (mae.getEtat()!=8) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
if (mae.getSortieBit(0)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(1)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(2)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(3)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
mae.setEntreeBit(0,0);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,0);
mae.clock();
if (mae.getEtat()!=8) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,0);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,0);
mae.clock();
if (mae.getEtat()!=8) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,0);
mae.setEntreeBit(3,0);
mae.clock();
if (mae.getEtat()!=8) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);//passage à l'etat 0
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,1);
mae.clock();
//boucle 9,10,11
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,0);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,1);
mae.clock();
if (mae.getEtat()!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 0
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,0);
mae.setEntreeBit(3,1);
mae.clock();
if (mae.getEtat()!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 0
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,0);
mae.clock();
if (mae.getEtat()!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 0
mae.setEntreeBit(0,0);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,0);
mae.clock(); //passage à l'etat 9
//Compléter le test ici
if (mae.getEtat()!=9) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
if (mae.getSortieBit(0)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(1)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(2)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(3)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
mae.setEntreeBit(0,0);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,0);
mae.clock();
if (mae.getEtat()!=9) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,0);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,0);
mae.clock();
if (mae.getEtat()!=9) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,0);
mae.setEntreeBit(3,0);
mae.clock();
if (mae.getEtat()!=9) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,1);
mae.clock(); //passage à l'etat 10
if (mae.getEtat()!=10) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
if (mae.getSortieBit(0)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(1)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(2)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(3)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
mae.setEntreeBit(0,0);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,1);
mae.clock();
if (mae.getEtat()!=10) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,0);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,1);
mae.clock();
if (mae.getEtat()!=10) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,0);
mae.setEntreeBit(3,1);
mae.clock();
if (mae.getEtat()!=10) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,0);
mae.clock(); //passage à l'etat 11
if (mae.getEtat()!=11) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
if (mae.getSortieBit(0)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(1)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(2)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
if (mae.getSortieBit(3)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1
mae.setEntreeBit(0,0);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,0);
mae.clock();
if (mae.getEtat()!=11) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,0);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,0);
mae.clock();
if (mae.getEtat()!=11) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,0);
mae.setEntreeBit(3,0);
mae.clock();
if (mae.getEtat()!=11) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__);
mae.setEntreeBit(0,1);//passage à l'etat 0
mae.setEntreeBit(1,1);
mae.setEntreeBit(2,1);
mae.setEntreeBit(3,1);
mae.clock();
exit(0); //commenter cette ligne pour ne pas quitter le programme après la fin du test
}
//////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
//Implémentation de la méthode constructeur
CStateMachine::CStateMachine(){
// à compléter si besoin, allocation etc...
reset();
}
////////////////////////////////////////////////////////////////////
//Implémentation de la méthode reset, tout ce qui est fait pour (re)démarrer la machine à états
void CStateMachine::reset(){
etat=0;
sortie=0; //mettre des valeurs initiales correctes
}
////////////////////////////////////////////////////////////////////
//Implémentation de la méthode clock
void CStateMachine::clock(){
//variables intérmédiaires pour les entrées
unsigned char P_non_noir=(entree>>2)&1;
unsigned char P_metallique=(entree>>1)&1;
unsigned char P_presente=(entree>>0)&1;
unsigned char G_pleine=(entree>>3)&1;
unsigned char moteur = (sortie>>0)&1;
unsigned char sw1 = (sortie>>1)&1;
unsigned char sw2 = (sortie>>2)&1;
unsigned char stoppeur = (sortie>>3)&1;
//variables intérmédiaires pour les sorties
//codage des sorties
//Sortie0 est une AMZI
if (etat==4 || etat==8 || etat==11)
moteur = 0;
else
moteur = 1;
if (etat==10)//tous les switchs sont ouverts
{
sw1=0;
sw2=0;
}
else if (etat==7)
{
sw1=0;
sw2=1;
}
else if (etat==3)
{
sw1=1;
}
else {
sw1=0;
sw2=0;
}
if ((etat==11)||(etat==4)||(etat==8))
{
stoppeur=0;
}
else
{
stoppeur=1;
}
//codage de l'évolution de l'état
switch (etat){
default:
case 0: if (P_non_noir==0)
etat=1;
else if (P_presente==0)
etat=9;
break;
case 1: if (P_metallique==0)
etat=5;
else if (P_presente==0)
etat=2;
break;
case 2: if (G_pleine==1) //piece grise
etat=3;
break;
case 3: if (G_pleine==0)
etat=4;
break;
case 4: if (G_pleine==1)
etat=0;
break;
case 5: if (P_presente==0) //piece rouge
etat=6;
break;
case 6: if (G_pleine==1)
etat=7;
break;
case 7: if (G_pleine==0)
etat=8;
break;
case 8: if (G_pleine==1)
etat=0;
break;
case 9: if (G_pleine==1) //piece noire
etat=10;
break;
case 10: if (G_pleine==0)
etat=11;
break;
case 11: if (G_pleine==1)
etat=0;
break;
}
//reconstruction de sortie à partir des variables intermédiaires
sortie=(stoppeur<<3) | (sw2<<2) | (sw1<<1) | (moteur<<0) ;
}
CStateMachine MAE;
////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////
void setup(){
init_millis();
//boucle locale pour simu
int r=setupES("127.0.0.1","4242");
//arduino iut gomette bleue
//int r=setupES("172.16.6.60","4242");
setName("Xanxo Besse");
if (r!=0)
printf("erreur ouverture socket\n");
printf("Elapsed time: %ld milliseconds\n", millis());
programmeDeTest1();
}
//////////////////////////////////////////////////////
void loop(){
unsigned int periodiciteTache1=20;
static unsigned long timerTache1 = millis();
if (millis() - timerTache1 >= periodiciteTache1) {
timerTache1 += periodiciteTache1;
MAE.setEntree(readPort());
MAE.clock();
writePort(MAE.getSortie());
char chaine[100];
sprintf(chaine, "Etat=%d", MAE.getEtat());
printf(chaine);
setMsg(chaine);
}
unsigned int periodiciteTache2=1000;
static unsigned long timerTache2 = millis();
if (millis() - timerTache2 >= periodiciteTache2) {
timerTache2 += periodiciteTache2;
static unsigned int cpt=0;
cpt++;
char chaine[100];
sprintf(chaine,"cpt=%d",cpt);
printf(chaine);
setMsg(chaine);
}
}