This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
in202:seance_5:component_led [2021/04/29 08:47] bmonsuez [Navigation] |
in202:seance_5:component_led [2022/11/18 10:46] (current) |
||
---|---|---|---|
Line 31: | Line 31: | ||
Tout ceci vous permettra de réaliser les opérations classiques sur la Led. | Tout ceci vous permettra de réaliser les opérations classiques sur la Led. | ||
+ | |||
+ | <hidden Correction> | ||
+ | |||
+ | L'état de la diode est caractérisé par deux variables : | ||
+ | * le port sur lequel la diode est connectée (c'est un numéro de port, soit un nombre entier), | ||
+ | * l'état de la diode, soit allumée, soit éteinte (c'est une valeur booléen, ''true'' est allumée, ''false'' est éteinte). | ||
+ | |||
+ | Ceci donne deux champs internes de la classe ''Led'', soit : | ||
+ | |||
+ | <code cpp> | ||
+ | class Led | ||
+ | { | ||
+ | private: | ||
+ | bool m_isSwitchedOn; | ||
+ | uint32_t m_portNumber; | ||
+ | }; | ||
+ | </code> | ||
+ | |||
+ | Pour les constructeurs, il faut initialiser les variables d'états : | ||
+ | * le port (essentiel) | ||
+ | * l'état de la diode (soit on, soit off, par défaut, nous pouvons dire ''off''). | ||
+ | |||
+ | Ceci nous donne deux constructeurs : | ||
+ | |||
+ | <code cpp> | ||
+ | class Led | ||
+ | { | ||
+ | private: | ||
+ | bool m_isSwitchedOn; | ||
+ | uint32_t m_portNumber; | ||
+ | public: | ||
+ | Led(uint32_t thePort): Led(thePort, false) {} | ||
+ | Led(uint32_t thePort, bool switchOnWhenStarted): m_portNumber(thePort), m_isSwitchedOn(switchOnWhenStarted) | ||
+ | {} | ||
+ | }; | ||
+ | </code> | ||
+ | |||
+ | Il faut ensuite ajouter les fonctions qui permette de questionner l'état de la diode. Il y en a deux, l'une | ||
+ | qui demande l'état de la diode ''isSwitchOn() const'' et une autre qui récupère le port ''getPort() const''. | ||
+ | Ces deux fonctions ne modifient pas l'objet ''Led'' et elle sont donc marquées comme constante. | ||
+ | |||
+ | <code cpp> | ||
+ | class Led | ||
+ | { | ||
+ | private: | ||
+ | bool m_isSwitchedOn; | ||
+ | uint32_t m_portNumber; | ||
+ | public: | ||
+ | Led(uint32_t thePort): Led(thePort, false) {} | ||
+ | Led(uint32_t thePort, bool switchOnWhenStarted): m_portNumber(thePort), m_isSwitchedOn(switchOnWhenStarted) | ||
+ | {} | ||
+ | | ||
+ | bool isSwitchOn() const { return m_isSwitchedOn; } | ||
+ | bool getPort() const { return m_portNumber; } | ||
+ | }; | ||
+ | </code> | ||
+ | |||
+ | Ensuite, nous avons les fonctions correspondant à des actions que supporte le composant diode. Nous vons deux actions, l'une correspondant à //allumer la diode// et l'autre à //éteindre la diode//. | ||
+ | |||
+ | <code cpp> | ||
+ | class Led | ||
+ | { | ||
+ | private: | ||
+ | bool m_isSwitchedOn; | ||
+ | uint32_t m_portNumber; | ||
+ | public: | ||
+ | Led(uint32_t thePort): Led(thePort, false) {} | ||
+ | Led(uint32_t thePort, bool switchOnWhenStarted): m_portNumber(thePort), m_isSwitchedOn(switchOnWhenStarted) | ||
+ | {} | ||
+ | | ||
+ | bool isSwitchOn() const { return m_isSwitchedOn; } | ||
+ | bool getPort() const { return m_portNumber; } | ||
+ | | ||
+ | void switchOn() | ||
+ | { | ||
+ | m_isSwitchedOn = true; | ||
+ | } | ||
+ | void switchOff() | ||
+ | { | ||
+ | m_isSwitchedOn = false; | ||
+ | } | ||
+ | }; | ||
+ | </code> | ||
+ | |||
+ | Nous avons pour l'instant créer un composant ''virtuel'', il correspond à une diode mais ne commande pas la diode physique. Pour commander la diode physique, il reste deux étapes à faire : | ||
+ | |||
+ | * Les constructeurs doivent initaliser la diode physique. | ||
+ | * Les fonctions correspondant à des actions doivent exécuter l'action sur la diode physique. | ||
+ | |||
+ | Pour ce faire, il faut modifier le constructeur principal en ajoutant la configuration du port : | ||
+ | |||
+ | <code cpp> | ||
+ | Led(uint32_t thePort, bool switchOn): m_portNumber(thePort), m_isSwitchedOn(switchOn) | ||
+ | { | ||
+ | pinMode(m_portNumber, OUTPUT); | ||
+ | if(switchOnWhenStarted) | ||
+ | switchOn(); | ||
+ | } | ||
+ | <code> | ||
+ | |||
+ | ainsi que les deux fonctions ''switchOn()'' et ''switchoff()'' : | ||
+ | |||
+ | <code cpp> | ||
+ | void switchOn() | ||
+ | { | ||
+ | if(!m_isSwitchedOn) | ||
+ | { | ||
+ | m_isSwitchedOn = true; | ||
+ | digitalWrite(m_portNumber, HIGH); | ||
+ | } | ||
+ | } | ||
+ | void switchOff() | ||
+ | { | ||
+ | if(m_isSwitchedOn) | ||
+ | { | ||
+ | m_isSwitchedOn = false; | ||
+ | digitalWrite(m_portNumber, LOW); | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Et voilà, la classe est terminée. | ||
+ | |||
+ | <code cpp> | ||
+ | class Led | ||
+ | { | ||
+ | private: | ||
+ | bool m_isSwitchedOn; | ||
+ | uint32_t m_portNumber; | ||
+ | public: | ||
+ | Led(uint32_t thePort): Led(thePort, false) {} | ||
+ | Led(uint32_t thePort, bool switchOnWhenStarted): m_portNumber(thePort), m_isSwitchedOn(switchOnWhenStarted) | ||
+ | { | ||
+ | pinMode(m_portNumber, OUTPUT); | ||
+ | if(switchOnWhenStarted) | ||
+ | switchOn(); | ||
+ | } | ||
+ | | ||
+ | bool isSwitchOn() const { return m_isSwitchedOn; } | ||
+ | bool getPort() const { return m_portNumber; } | ||
+ | | ||
+ | void switchOn() | ||
+ | { | ||
+ | if(!m_isSwitchedOn) | ||
+ | { | ||
+ | m_isSwitchedOn = true; | ||
+ | digitalWrite(m_portNumber, HIGH); | ||
+ | } | ||
+ | } | ||
+ | void switchOff() | ||
+ | { | ||
+ | if(m_isSwitchedOn) | ||
+ | { | ||
+ | m_isSwitchedOn = false; | ||
+ | digitalWrite(m_portNumber, LOW); | ||
+ | } | ||
+ | } | ||
+ | }; | ||
+ | </code> | ||
+ | |||
+ | |||
+ | </hidden> | ||
===== Etape 2 : Implanter le code de la classe Led ===== | ===== Etape 2 : Implanter le code de la classe Led ===== | ||
Line 38: | Line 200: | ||
- Compiler & télécharger le code sur la carte. | - Compiler & télécharger le code sur la carte. | ||
+ | <hidden Correction> | ||
+ | |||
+ | En fait, nous allons désormais déclarer la diode ''builtinLed'' comme une variable globale. En effet, c'est un composant physique, ce n'est pas quelque chose que l'on va ajouter ou enlever. On peut donc le créer au moment du chargement du programme, puisque qu'il serait toujours accessible. | ||
+ | |||
+ | <code cpp> | ||
+ | class Led | ||
+ | { | ||
+ | private: | ||
+ | bool m_isSwitchedOn; | ||
+ | uint32_t m_portNumber; | ||
+ | public: | ||
+ | Led(uint32_t thePort): Led(thePort, false) {} | ||
+ | Led(uint32_t thePort, bool switchOnWhenStarted): m_portNumber(thePort), m_isSwitchedOn(switchOnWhenStarted) | ||
+ | { | ||
+ | pinMode(m_portNumber, OUTPUT); | ||
+ | if(switchOnWhenStarted) | ||
+ | switchOn(); | ||
+ | } | ||
+ | |||
+ | bool isSwitchOn() const { return m_isSwitchedOn; } | ||
+ | bool getPort() const { return m_portNumber; } | ||
+ | |||
+ | void switchOn() | ||
+ | { | ||
+ | if(!m_isSwitchedOn) | ||
+ | { | ||
+ | m_isSwitchedOn = true; | ||
+ | digitalWrite(m_portNumber, HIGH); | ||
+ | } | ||
+ | } | ||
+ | void switchOff() | ||
+ | { | ||
+ | if(m_isSwitchedOn) | ||
+ | { | ||
+ | m_isSwitchedOn = false; | ||
+ | digitalWrite(m_portNumber, LOW); | ||
+ | } | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | Led builtinLed(LED_BUILTIN); | ||
+ | |||
+ | </code> | ||
+ | |||
+ | Ensuite, la fonction ''setup()'' va être simplifié, il n'y a plus besoin d'initialiser le port, c'est le constructeur de la classe ''Led'' qui le fait. Donc le contenu de ''setup()'' devient trivial. | ||
+ | |||
+ | |||
+ | <code cpp> | ||
+ | void setup() | ||
+ | {} | ||
+ | </code> | ||
+ | |||
+ | Reste ensuite le code de la boucle où l'on appelle désormais les méthodes ''switchOn()'' et ''switchOff()'' de la classe ''Led''. | ||
+ | |||
+ | <code cpp> | ||
+ | void loop() | ||
+ | { | ||
+ | builtinLed.switchOn(); | ||
+ | delay(1000); | ||
+ | builtinLed.switchOff(); | ||
+ | delay(1000); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | C'est vrai que la lecture du code en devient évidente. Plus besoin même de commentaire. | ||
+ | |||
+ | </hidden> | ||
===== Etape 3 : Ajouter une option ''debug'' à la classe ''Led'' ===== | ===== Etape 3 : Ajouter une option ''debug'' à la classe ''Led'' ===== | ||
Line 46: | Line 275: | ||
* Ajouter ensuite les messages indiquant que la diode s'allume ou s'éteint lorsque le mode ''debug'' est activé sur la diode. Le message doit contenir le nom de la diode ainsi que le nouvel état de celle-ci. | * Ajouter ensuite les messages indiquant que la diode s'allume ou s'éteint lorsque le mode ''debug'' est activé sur la diode. Le message doit contenir le nom de la diode ainsi que le nouvel état de celle-ci. | ||
+ | |||
+ | |||
+ | <hidden Correction> | ||
+ | Pour ce faire, nous devons ajoutons des informations complémentaires notre classe ''Led'' : | ||
+ | * le nom de la diode (une chaîne de caractères), | ||
+ | * une variable booléenne qui indique si le mode //debug// est actif ou non. | ||
+ | |||
+ | Donc nous ajoutons **deux champs privés** à la classe : | ||
+ | |||
+ | <code cpp> | ||
+ | const char* m_name; | ||
+ | bool m_debug; | ||
+ | </code> | ||
+ | |||
+ | Nous devons modifier les constructeurs pour initialiser ces champs supplémentaires. | ||
+ | |||
+ | <code cpp> | ||
+ | Led(uint32_t thePort, const char* theName, bool debugIsActive = false): | ||
+ | Led(thePort, false, theName, debugIsActive) | ||
+ | {} | ||
+ | Led(uint32_t thePort, bool switchOnWhenStarted, const char* theName, bool debugIsActive = false): | ||
+ | m_portNumber(thePort), m_isSwitchedOn(switchOnWhenStarted), | ||
+ | m_name(theName), m_debug(debugIsActive) | ||
+ | { | ||
+ | pinMode(m_portNumber, OUTPUT); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Nous modifions aussi les actions puisque nous souhaitons envoyer un message si le mode **debug** est actif : | ||
+ | |||
+ | <code cpp> | ||
+ | |||
+ | void switchOn() | ||
+ | { | ||
+ | if(!m_isSwitchedOn) | ||
+ | { | ||
+ | m_isSwitchedOn = true; | ||
+ | digitalWrite(m_portNumber, HIGH); | ||
+ | if(m_debug) | ||
+ | Serial << "Led: " << m_name << ": switch on"; | ||
+ | } | ||
+ | } | ||
+ | void switchOff() | ||
+ | { | ||
+ | if(m_isSwitchedOn) | ||
+ | { | ||
+ | m_isSwitchedOn = false; | ||
+ | digitalWrite(m_portNumber, LOW); | ||
+ | if(m_debug) | ||
+ | Serial << "Led: " << m_name << ": switch off"; | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Voilà, il ne reste plus qu'à penser à initialiser ''Serial'' dans la fonction ''setup()'', ce qui donne le code complet suivant : | ||
+ | |||
+ | <code cpp> | ||
+ | |||
+ | template<class T> | ||
+ | UARTClass& operator << (UARTClass& theSerial, const T& theValue) | ||
+ | { | ||
+ | theSerial.print(theValue); | ||
+ | return theSerial; | ||
+ | } | ||
+ | |||
+ | class Led | ||
+ | { | ||
+ | private: | ||
+ | bool m_isSwitchedOn; | ||
+ | uint32_t m_portNumber; | ||
+ | const char* m_name; | ||
+ | bool m_debug; | ||
+ | public: | ||
+ | Led(uint32_t thePort, const char* theName, bool debugIsActive = false): | ||
+ | Led(thePort, false, theName, debugIsActive) | ||
+ | {} | ||
+ | Led(uint32_t thePort, bool switchOnWhenStarted, const char* theName, bool debugIsActive = false): | ||
+ | m_portNumber(thePort), m_isSwitchedOn(switchOnWhenStarted), | ||
+ | m_name(theName), m_debug(debugIsActive) | ||
+ | { | ||
+ | pinMode(m_portNumber, OUTPUT); | ||
+ | } | ||
+ | bool isSwitchOn() const { return m_isSwitchedOn; } | ||
+ | bool getPort() const { return m_portNumber; } | ||
+ | |||
+ | void switchOn() | ||
+ | { | ||
+ | if(!m_isSwitchedOn) | ||
+ | { | ||
+ | m_isSwitchedOn = true; | ||
+ | digitalWrite(m_portNumber, HIGH); | ||
+ | if(m_debug) | ||
+ | Serial << "Led: " << m_name << ": switch on\n"; | ||
+ | } | ||
+ | } | ||
+ | void switchOff() | ||
+ | { | ||
+ | if(m_isSwitchedOn) | ||
+ | { | ||
+ | m_isSwitchedOn = false; | ||
+ | digitalWrite(m_portNumber, LOW); | ||
+ | if(m_debug) | ||
+ | Serial << "Led: " << m_name << ": switch off\n"; | ||
+ | } | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | Led builtinLed(LED_BUILTIN, "Builtin", true); | ||
+ | |||
+ | // the setup function runs once when you press reset or power the board | ||
+ | void setup() | ||
+ | { | ||
+ | Serial.begin(9600); | ||
+ | } | ||
+ | |||
+ | // the loop function runs over and over again forever | ||
+ | void loop() | ||
+ | { | ||
+ | builtinLed.switchOn(); | ||
+ | delay(1000); | ||
+ | builtinLed.switchOff(); | ||
+ | delay(1000); | ||
+ | } | ||
+ | |||
+ | </code> | ||
+ | </hidden> | ||
===== Etape 4 : Profiter de l'héritage ===== | ===== Etape 4 : Profiter de l'héritage ===== | ||
Line 52: | Line 407: | ||
L'idée est de proposer une classe de base que l'on appellera ''CustomComponent'' dont héritera l'ensemble des autres classes composants comme par exemple ''Led''. | L'idée est de proposer une classe de base que l'on appellera ''CustomComponent'' dont héritera l'ensemble des autres classes composants comme par exemple ''Led''. | ||
+ | |||
+ | |||
+ | <code cpp> | ||
+ | bool isSwitchOn() const { return m_isSwitchedOn; } | ||
+ | bool getPort() const { return m_portNumber; } | ||
+ | | ||
+ | void switchOn() | ||
+ | { | ||
+ | if(!m_isSwitchedOn) | ||
+ | { | ||
+ | m_isSwitchedOn = true; | ||
+ | digitalWrite(m_portNumber, HIGH); | ||
+ | } | ||
+ | } | ||
+ | void switchOff() | ||
+ | { | ||
+ | if(m_isSwitchedOn) | ||
+ | { | ||
+ | m_isSwitchedOn = false; | ||
+ | digitalWrite(m_portNumber, LOW); | ||
+ | } | ||
+ | } | ||
+ | }; | ||
+ | </code> | ||
+ | |||
+ | |||
+ | </hidden> | ||
<code cpp> | <code cpp> | ||
Line 57: | Line 439: | ||
{ | { | ||
protected; | protected; | ||
- | CustomComponent(std::string name, bool debug) | + | CustomComponent(const char* name, bool debug) |
{} | {} | ||
public: | public: | ||
bool debugIsActive() const; | bool debugIsActive() const; | ||
- | std::string getName() const; | ||
| | ||
- | std::string header() const; // Génère l'entête de message avec le nom du composant. | + | const char* getName() const; |
+ | const char* header() const; // Génère l'entête de message avec le nom du composant. | ||
}; | }; | ||
</code> | </code> | ||
Line 72: | Line 454: | ||
* Tester votre code. | * Tester votre code. | ||
+ | |||
+ | <code cpp> | ||
+ | |||
+ | class CustomComponent | ||
+ | { | ||
+ | private: | ||
+ | bool m_Debug; | ||
+ | const char* m_Name; | ||
+ | protected; | ||
+ | CustomComponent(const char* theName, bool debug = false): | ||
+ | Name(theName), m_Debug(debug) | ||
+ | {} | ||
+ | public: | ||
+ | bool debugIsActive() const { return m_Debug; } | ||
+ | | ||
+ | bool EnableDebug() { m_Debug = true; } | ||
+ | bool DisableDebug() { m_Debug = false; } | ||
+ | |||
+ | const char* getName() const { return m_Name; } | ||
+ | String header() const { return (String)m_Name + ": "; } | ||
+ | |||
+ | }; | ||
+ | |||
+ | class Led: public CustomComponent | ||
+ | { | ||
+ | private: | ||
+ | bool m_isSwitchedOn; | ||
+ | uint32_t m_portNumber; | ||
+ | public: | ||
+ | Led(uint32_t thePort, const char* theName): Led(thePort, theName, false) {} | ||
+ | Led(uint32_t thePort, const char* theName, bool switchOnWhenStarted): CustomComponent(theName, false), | ||
+ | m_portNumber(thePort), m_isSwitchedOn(switchOnWhenStarted) | ||
+ | { | ||
+ | pinMode(m_portNumber, OUTPUT); | ||
+ | if(switchOnWhenStarted) | ||
+ | switchOn(); | ||
+ | } | ||
+ | | ||
+ | |||
+ | | ||
+ | }; | ||
+ | </code> | ||
====== Navigation ====== | ====== Navigation ====== |