diy:projets:tl_partieemetteur
Différences
Ci-dessous, les différences entre deux révisions de la page.
Les deux révisions précédentesRévision précédenteProchaine révision | Révision précédente | ||
diy:projets:tl_partieemetteur [2018/05/25 08:21] – [Interface avec le gpio] sdurand | diy:projets:tl_partieemetteur [2018/07/02 09:34] (Version actuelle) – [Le programme principal et la fonction qui gère la led] sdurand | ||
---|---|---|---|
Ligne 40: | Ligne 40: | ||
echo V > / | echo V > / | ||
</ | </ | ||
- | avec **V** qui peut valoir **1 pour éteindre la led** ou **0 pour allumer la led** (cela vous semble peut | + | avec **V** qui peut valoir **1 pour éteindre la led** ou **0 pour allumer la led** (**ceci dépend de la façon |
- | être contre intuitif, mais c'est comme ça) et **X** qui est toujours le **numéro du pin de la led**. | + | dont vous avez branché la led au raspberry**, notre branchement |
+ | est toujours le **numéro du pin de la led**. | ||
- | Et ça va se passer de la même manière en C++ ! Vous pouvez très bien **ouvrir ces fichiers dans votre code** pour y | + | Quand vous aurez fini de jouer, vous devrez dé-exportez la led. Là aussi, c'est très simple: |
+ | < | ||
+ | echo numero_du_pin_de_la_led > / | ||
+ | </ | ||
+ | Et voilà, le pin de la led est de nouveau " | ||
+ | |||
+ | Tout va se passer de la même manière en C++ ! En effet, vous pouvez très bien **ouvrir ces fichiers dans votre code** pour y | ||
**effectuer toutes les opérations** dont je viens de vous parler, c'est comme ça que je vous recommande de procéder. | **effectuer toutes les opérations** dont je viens de vous parler, c'est comme ça que je vous recommande de procéder. | ||
J'ai personnellement choisi de **créer une classe** pour encapsuler ces opérations. Le code de cette classe est | J'ai personnellement choisi de **créer une classe** pour encapsuler ces opérations. Le code de cette classe est | ||
- | disponible | + | disponible |
tout réécrire vous même. | tout réécrire vous même. | ||
Ligne 66: | Ligne 73: | ||
Si vous êtes arrivés jusqu' | Si vous êtes arrivés jusqu' | ||
==== Les changements d' | ==== Les changements d' | ||
+ | |||
+ | Dans cette partie, nous allons écrire un **main** qui va utiliser notre **API** pour allumer/ | ||
+ | en fonction de la valeur de **chaque bit** de **chaque caractère** d'un message. Nous avons décidé d' | ||
+ | **chaînes de caractères comme données à transmettre**, | ||
+ | visualiser les **erreurs de bits** sur des caractères que sur les valeurs des pixels d'une image ou tout autre | ||
+ | type de données qu'on aurait pu transmettre. | ||
+ | |||
+ | En concevant le code que je vais vous présenter, j'ai prévu **deux chaînes de caractères** particulières | ||
+ | qui **agirait comme des commandes**. Ces deux commandes sont // | ||
+ | proprement et **libérer les ressources** // | ||
+ | une séquence particulière de 0 et de 1 (qui sont en fait des **" | ||
+ | cyclique de 0 et de 1 va nous permettre de visualiser d' | ||
+ | |||
+ | Voyons à quoi ressemble **la boucle de notre main**: | ||
+ | <code C++> | ||
+ | int main() { | ||
+ | // GPIO_PIN est définie via un define par la valeur du pin de la led | ||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | // On récupère le premier message à envoyer, on n' | ||
+ | | ||
+ | |||
+ | // Tant qu'on a pas saisi le message d' | ||
+ | | ||
+ | std::cout << " | ||
+ | | ||
+ | // On vérifie si on a reçu la séquence de test, si c'est le cas, on envoie un certains nombre de U | ||
+ | if(message == "/ | ||
+ | // Attention, suivant la fréquence que vous sélectionnerai pour les bits, cette séquence peut être très longue | ||
+ | | ||
+ | } | ||
+ | else { | ||
+ | // Si on a un message lambda, on le trasnmet | ||
+ | | ||
+ | } | ||
+ | std::cout << " | ||
+ | } | ||
+ | |||
+ | | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Pour vous pouvez le voir, rien de bien compliqué là aussi. On récupère simplement des messages et on | ||
+ | les traite en conséquence. Notez que si vous souhaitez ajouter **plus de commandes**, | ||
+ | utiliser un // | ||
+ | |||
+ | Passons maintenant au coeur du programme, la **conversion de bits en signaux lumineux**. Nous allons commencer | ||
+ | par créer la boucle nous permettant d' | ||
+ | **la norme C++14**, vous pouvez faire ça comme suit: | ||
+ | <code C++> | ||
+ | for(const char& c: message) { | ||
+ | // ... | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Nous devons ensuite itérer //"sur les bits"// | ||
+ | bit à bit (via l' | ||
+ | à un (ex: 10000000, 01000000, 001 ...). J'ai donc déclaré un tableau constant en variable globale | ||
+ | qui contiendra tout ces octets. | ||
+ | <code C++> | ||
+ | const unsigned char powers_of_two[8] = {128, 64, 32, 16, 8, 4, 2, 1}; | ||
+ | </ | ||
+ | |||
+ | Nous pouvons maintenant tester pour tout les caractères (en utilisant une boucle) de cette façon: | ||
+ | <code C++> | ||
+ | const bool lightUp = c & powers_of_two[i]; | ||
+ | </ | ||
+ | |||
+ | Au final, **votre code devrait ressembler a quelque chose comme ça**: | ||
+ | <code C++> | ||
+ | void transmit(LedController& | ||
+ | // On initialise la variable timer comme le temps référence de notre transmission | ||
+ | auto timer = std:: | ||
+ | // On allume la led pour signaler au récepteur le début de la transmission | ||
+ | | ||
+ | |||
+ | // On parcourt le message | ||
+ | | ||
+ | // On parcourt les bits de chaque caractère | ||
+ | for(unsigned int i = 0; i < 8; i++) { | ||
+ | // On incrémente le timer d'un pas pré-calculé (dépendant le la fréquence de transmission choisie) | ||
+ | timer += time_step; | ||
+ | // On regarde avant la pause si on doit allumer ou non la led | ||
+ | const bool lightUp = c & powers_of_two[i]; | ||
+ | // On attend | ||
+ | | ||
+ | |||
+ | // On positionne la led dans le bon état | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | // On attend suffisamment pour que le récepteur reçoive un octet de zéros pour marquer la fin de transmission | ||
+ | | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | En ce qui concerne **les pauses**, je vous invite simplement à consulter le code ci-dessus, | ||
+ | vous avez sans doute remarquer que le " | ||
+ | détaillées. | ||
---- | ---- | ||
===== Sources du projet ===== | ===== Sources du projet ===== | ||
+ | |||
+ | ==== La classe pour contrôler le gpio ==== | ||
+ | |||
+ | <code C++> | ||
+ | #include " | ||
+ | |||
+ | |||
+ | // Private method that export the choosen gpio | ||
+ | void LedController:: | ||
+ | std:: | ||
+ | |||
+ | if(!exportFile.is_open()) { | ||
+ | std::cerr << " | ||
+ | throw ERR_EXPORT; | ||
+ | } | ||
+ | |||
+ | exportFile << this-> | ||
+ | exportFile.close(); | ||
+ | } | ||
+ | |||
+ | |||
+ | // Private method that unexport the previously opened gpio | ||
+ | void LedController:: | ||
+ | std:: | ||
+ | |||
+ | if(!unexportFile.is_open()) { | ||
+ | std::cerr << " | ||
+ | throw ERR_UNEXPORT; | ||
+ | } | ||
+ | |||
+ | unexportFile << this-> | ||
+ | unexportFile.close(); | ||
+ | } | ||
+ | |||
+ | |||
+ | // Constructor of our class: | ||
+ | // numero: numero of the gpio's pin we want to open | ||
+ | // dirOut: boolean indicating if the direction we want is out or not (as it is a LedController, | ||
+ | // litUp: boolean indicating if the led should be initially on or off | ||
+ | LedController:: | ||
+ | this-> | ||
+ | |||
+ | export_gpio(); | ||
+ | // Adding a little delay to make sure that the files created when exporting exists before we start working on them | ||
+ | std:: | ||
+ | |||
+ | std:: | ||
+ | |||
+ | if(!directionFile.is_open()) { | ||
+ | unexport_gpio(); | ||
+ | |||
+ | std::cerr << " | ||
+ | throw ERR_EXPORT; | ||
+ | } | ||
+ | |||
+ | // Setting the direction according to the boolean dirOut | ||
+ | directionFile << (dirOut ? " | ||
+ | directionFile.close(); | ||
+ | |||
+ | if(!litUp) { | ||
+ | turnOff(); | ||
+ | } | ||
+ | else { | ||
+ | turnOn(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | // Destructor that will unexport the gpio previously opened | ||
+ | LedController:: | ||
+ | unexport_gpio(); | ||
+ | } | ||
+ | |||
+ | |||
+ | // Public method lighting up the led | ||
+ | void LedController:: | ||
+ | std:: | ||
+ | |||
+ | value.open(std:: | ||
+ | |||
+ | if(!value.is_open()) { | ||
+ | unexport_gpio(); | ||
+ | |||
+ | std::cerr << " | ||
+ | throw ERR_VALUE; | ||
+ | } | ||
+ | |||
+ | value << " | ||
+ | |||
+ | value.close(); | ||
+ | } | ||
+ | |||
+ | |||
+ | // Public method turning off the led | ||
+ | void LedController:: | ||
+ | std:: | ||
+ | |||
+ | value.open(std:: | ||
+ | |||
+ | if(!value.is_open()) { | ||
+ | unexport_gpio(); | ||
+ | |||
+ | std::cerr << " | ||
+ | throw ERR_VALUE; | ||
+ | } | ||
+ | |||
+ | value << " | ||
+ | |||
+ | value.close(); | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ==== Son header ==== | ||
+ | |||
+ | <code C++> | ||
+ | #ifndef LEDCONTROLLER_HPP | ||
+ | #define LEDCONTROLLER_HPP | ||
+ | |||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | // Refer to the constructor source code for more info on this define | ||
+ | #define EXPORT_DELAY 400 | ||
+ | |||
+ | // A few define to make errors handling clearer | ||
+ | #define ERR_EXPORT -2 | ||
+ | #define ERR_UNEXPORT -3 | ||
+ | #define ERR_VALUE -4 | ||
+ | #define ERR_DIRECTION -5 | ||
+ | |||
+ | |||
+ | |||
+ | class LedController { | ||
+ | public: | ||
+ | LedController(int numero, bool dirOut = true, bool litUp = false); | ||
+ | ~LedController(); | ||
+ | |||
+ | void turnOn(); | ||
+ | void turnOff(); | ||
+ | |||
+ | private: | ||
+ | void export_gpio(); | ||
+ | void unexport_gpio(); | ||
+ | int numero; | ||
+ | }; | ||
+ | |||
+ | #endif | ||
+ | </ | ||
+ | |||
+ | ==== Le programme principal et la fonction qui gère la led ==== | ||
+ | |||
+ | <code C++> | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include " | ||
+ | |||
+ | #define GPIO_PIN 21 | ||
+ | #define BITRATE 20 | ||
+ | #define BITTIME static_cast< | ||
+ | |||
+ | #define ALL_GOOD 0 | ||
+ | |||
+ | |||
+ | const auto time_step = std:: | ||
+ | // We are asuming here that a char is always an octet, and we will assume in every part of the code | ||
+ | const unsigned char powers_of_two[8] = {128, 64, 32, 16, 8, 4, 2, 1}; | ||
+ | |||
+ | |||
+ | // Function that iterates over message and switch on and off the led of lc according to the bits | ||
+ | void transmit(LedController& | ||
+ | // Initializing timer as the reference time | ||
+ | auto timer = std:: | ||
+ | // Turning on the light to tell the receptor we're starting to emit | ||
+ | lc.turnOn(); | ||
+ | |||
+ | // Iterating over the message | ||
+ | for(const char& c: message) { | ||
+ | // Iterating over the bits of c (again, we're assuming that a char is an octet long) | ||
+ | for(unsigned int i = 0; i < 8; i++) { | ||
+ | // Incrementing the timer, computing wether we should lightUp the led or not, and sleeping until it's time to change the state of the led | ||
+ | timer += time_step; | ||
+ | const bool lightUp = c & powers_of_two[i]; | ||
+ | std:: | ||
+ | |||
+ | lightUp ? lc.turnOn() : lc.turnOff(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | std:: | ||
+ | lc.turnOff(); | ||
+ | |||
+ | // Sleeping long enough to make sure that the receptor received at least a full octet of zeros (it will mark the end of transmission for it) | ||
+ | std:: | ||
+ | } | ||
+ | |||
+ | // This main simply get the input from stdin and act in consequence | ||
+ | int main() { | ||
+ | LedController lc(GPIO_PIN); | ||
+ | std:: | ||
+ | |||
+ | // Getting the first string | ||
+ | std::cout << " | ||
+ | std:: | ||
+ | |||
+ | // Sending message if it is different of "/ | ||
+ | // "/ | ||
+ | while(message != "/ | ||
+ | // I feel like it's ok to not use a switch because I don't plan to add more commands, but if you plan to, you should definitely use one | ||
+ | if(message == "/ | ||
+ | // The test sequence is a sequence of upper case " | ||
+ | transmit(lc, | ||
+ | } | ||
+ | else { | ||
+ | transmit(lc, | ||
+ | } | ||
+ | |||
+ | std::cout << " | ||
+ | |||
+ | std::cout << " | ||
+ | std:: | ||
+ | } | ||
+ | |||
+ | return ALL_GOOD; | ||
+ | } | ||
+ | </ | ||
---- | ---- | ||
- | // | + | // |
diy/projets/tl_partieemetteur.1527236512.txt.gz · Dernière modification : 2018/05/25 08:21 de sdurand