Salut,
J'ouvre ce fil pour "discuter" sur la librairie IRremote...
J'ai vu qu'il y avait déjà ce fil : Problèmes nouvelle librairie IRremote version 3.0 mais je ne voulais pas faire de HS.
----------
Salut,
J'ouvre ce fil pour "discuter" sur la librairie IRremote...
J'ai vu qu'il y avait déjà ce fil : Problèmes nouvelle librairie IRremote version 3.0 mais je ne voulais pas faire de HS.
----------
J'ai une première question au sujet de la fonction bool IRrecv::decodeNEC ici.
Regardez cette condition (ligne 188) : if (decodedIRData.rawDataPtr->rawlen == 4) si elle vraie on quitte forcément la fonction soit à la ligne 194 :return false; soit à la ligne 196 return true;, non ?
Si oui alors à quoi sert cette partie (ligne 207):
Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 // Check for repeat if (decodedIRData.rawDataPtr->rawlen == 4) { if (MATCH_MARK(decodedIRData.rawDataPtr->rawbuf[3], NEC_BIT_MARK)) { decodedIRData.flags = IRDATA_FLAGS_IS_REPEAT | IRDATA_FLAGS_IS_LSB_FIRST; decodedIRData.address = lastDecodedAddress; decodedIRData.command = lastDecodedCommand; return true; } return false; }
C'est la même condition (que celle en ligne 188) or si on arrive à la ligne 207 c'est que cette condition est forcément fausse et donc je ne vois pas l’intérêt de ce bout de code ci-dessus (ligne 207)...
Quelque chose doit m'échapper...
votre lien ne fonctionne pas
Parlez Vous de ce fichier ir_NEC.cpp?
vos N° de lignes ne correspondent pas à ceux de GitHub (votre if semble être ligne 184)
pouvez vous clarifier?
Merci.
Oui mais c'est celui-là ici qui correspond au zip que j'ai téléchargé version 3.0.1...
Ah je ne comprend pas les fichiers sont différents...
Salut,
Ah ben j'ai une autre question à propos de la variable irparams...
Apparemment la structure irparams_struct est définie ici :
Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 struct irparams_struct { // The fields are ordered to reduce memory over caused by struct-padding volatile uint8_t StateForISR; ///< State Machine state uint8_t IRReceivePin; ///< Pin connected to IR data from detector uint8_t FeedbackLEDPin; ///< if 0, then take board specific FEEDBACK_LED_ON() and FEEDBACK_LED_OFF() functions bool LedFeedbackEnabled; ///< true -> enable blinking of pin on IR processing #if RAW_BUFFER_LENGTH <= 255 // saves around 75 bytes program space and speeds up ISR uint8_t rawlen; ///< counter of entries in rawbuf #else unsigned int rawlen; ///< counter of entries in rawbuf #endif uint16_t TickCounterForISR; ///< Counts 50uS ticks. The value is copied into the rawbuf array on every transition. bool OverflowFlag; ///< Raw buffer OverflowFlag occurred uint16_t rawbuf[RAW_BUFFER_LENGTH]; ///< raw data / tick counts per mark/space, first entry is the length of the gap between previous and current command }; extern struct irparams_struct irparams;
On a ensuite une instance de cette structure ici :
Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 #include "IRremoteInt.h" struct irparams_struct irparams; // the irparams instance
Mais j'aimerais savoir quand le champs StateForISR est initialisé ?
Apparemment il vaut 0 au départ mais est-ce parce que c'est la valeur par défaut ?
On utilise irparams quand on lance la fonction IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK);, la fonction begin est définie ici :
Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 void IRrecv::begin(uint8_t aReceivePin, bool aEnableLEDFeedback, uint8_t aFeedbackLEDPin) { irparams.IRReceivePin = aReceivePin; irparams.FeedbackLEDPin = aFeedbackLEDPin; // default is 0 LEDFeedback(aEnableLEDFeedback); enableIRIn(); }
J'ai lu que lorsque un des champs d'une structure était initialisée les autres champs étaient "automatiquement" initialisés à 0 or ici c'est ce qu'on a à la première ligne : irparams.IRReceivePin = aReceivePin;...
Mais bon j'ai fait un test et avant cette ligne on a déjà le champs StateForISR qui vaut 0 !
Une structure en variable globale est initialisée à 0 sauf si des valeurs sont données à la déclaration / définition (comme toute variables globale. Ce n’est pas le cas des variables locales). Ici il n’y en a pas donc le compilateur initialise tout la zone memoire de la structure à 0
Lorsque vous affectez un membre de la structure ensuite dans une fonction/méthode comme begin, rien d’autre n’est touché (heureusement !!)
StateForISR est utilisé lors des interruptions pour conserver l’état courant.
Merci.
Oui c'est ce que j'ai constaté et cela me semble logique mais j'ai été induit en erreur en lisant certaines réponses d'un autre forum, en gros j'avais compris que la règle pour les structures est la même que pour les variables primitives: en l'absence d'initialisation elles seraient indéfinies et un bon compilateur devrait lancer un avertissement si on utilise une variable avant qu'elle ne soit initialisée...
Mais j'ai fait un test et le compilateur ne dit rien...
Oui heureusement !
Oui j'ai vu ça et elle a changé de nom récrément... La librairie est active on a déjà plusieurs nouvelles versions depuis mon premier téléchargement...
comme c’est une variable globale elle est bien initialisée à 0, donc c’est normal de ne pas avoir de warning.un bon compilateur devrait lancer un avertissement si on utilise une variable avant qu'elle ne soit initialisée...
Oui du changement en cours pour cette bibliothèque, c’est un peu dommage car ça va casser pas mal d’anciens codes. Ils auraient dû faire une version avec un nom différent
Salut,
J'ai encore une question...
J'ai placé des Serial.print() dans les trois constructeurs de la classe IRrecv (cf. irReceive.cpp.h) ainsi que dans la méthode begin ... Mais seul le Serial.print() de la méthode IRrecv::begin est exécutée... Comment cela se fait-il ? Est-ce que cela signifie qu'aucun des trois constructeurs n'est exécutés ? Est-ce possible ?
Merci.
Les constructeurs sont appelés avant que Serial soit activé dans le setup.
C’est pour cela qu’il ne faut rien mettre dans les constructeurs qui dépende du hardware, et que l’on met cela dans begin() pour les bonnes bibliothèques (quand la classe est prévue d’être instanciée comme variable globale).
Merci.
Ouais je me suis aussi dit ça... Au début je croyais qu'on n'avait pas ce problème puisque Serial.begin(2000000); est placé avant IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK); mais en fait je suppose que le constructeur est exécuté avant à cause du #include<IRremote.h> qui au début du fichier...
J'ai aussi mis Serial.begin(2000000); dans les constructeurs mais cela ne fonctionne pas non plus...
Ce qui m'étonne c'est qu'aucune erreur n'est signalée...
Sinon oui finalement j'ai pu voir l'exécution du constructeur en déclarant une autre variable : IRrecv IrReceiver1; (à la place de IRrecv IrReceiver;), la déclaration étant placée après le #include<IRremote.h>...
Il n’y a pas d’erreur informatique si vous appelez Serial dans le constructeur mais ça ne sert à rien car init() n’a pas encore été appelé et donc ce que vous faites et qui touche au hardware peut être Ensuite défait.
Ce n’est pas lié à la place dans le fichier mais vraiment au fonctionnement du C++.
Quand vous déclarez une variable globale, l’allocation de sa mémoire se fait au tout début du code généré par le compilateur. Pour l’instance d’une classe ça veut dire que la mémoire est allouée dans le segment dédié aux données et le constructeur est appelé pour initialiser l’objet. Tout cela se passe avant même que main() ne soit appelé et donc avant l’execution de init() de la carte et bien avant donc le setup().
Bonjour,
Je possède ces petits modules Infrarouge : https://www.amazon.fr/gp/product/B07...?ie=UTF8&psc=1
Je pense utiliser les deux modules pour réaliser l'identification de quelques unes de mes télécommandes et des tests sur un Arduino dédié à cet usage.
Ensuite, je compte utiliser seulement le module émetteur infrarouge sur mon server Arduino qui sera déjà bien "chargé" (shield Ethernet, RTC, ...)
Il est probable que j'adapte la bibliothèque pour avoir une version simplifiée uniquement pour l'émission.
Quelques petites choses m'inquiètent un peu :
- usage d'une broche PWM en modifiant sa fréquence de base
- usage hardware d'un timer
- usage des interruptions (mais ce n'est que pour la réception donc à priori pas de problèmes)
Il faudra être prudent et "encadrer" le fonctionnement du module infrarouge pour ne pas perturber le fonctionnement des autres périphériques connectés à l'Arduino :
- initialiser les bons paramètres avant une émission IR
- restaurer les paramètres "normaux" après une émission IR
Etant donné que je vais simplement "copier et coller" certaines fonctions de mes télécommandes, je pense que je n'aurais pas besoin de connaitre le protocole ; juste trouver un moyen efficace et fiable d'enregistrer la liste des impulsions et leur durée.
A bientôt
Salut,
J'ai pu tester deux télécommandes et les deux utilisent le protocole NEC (ce qui ne m'étonne pas...), pour l'instant on a juste commandé l'allumage et le clignotement de quelques diodes ensuite on passera à la commande d'un moteur pas à pas...
Je remarque qu'il y a plusieurs fréquences possibles pour la porteuse, apparemment il existe des récepteur IR pour chaque fréquence alors je me demande si on peut vraiment décoder les différents protocoles avec le même récepteur, c'est à vérifier...
Ceux que tu indiques sont pour une fréquence de 38 Khz (c'est ce qu'il faut pour le protocole NEC me semble-t-il)...
Bonjour,
L'émetteur c'est juste une LED IR. C'est l'Arduino avec le PWM qui génère la porteuse.
En revanche, le récepteur intègre un filtre... reste à savoir si la bande passante de filtre ne laisse passer que le 38KHz ou bien aussi les autres fréquences...
Le but de ce filtre est avant tout de rendre les récepteurs insensibles à la lumière ambiante et à la chaleur.
Il reste possible, pour l'identification des télécommandes, d'utiliser une simple photodiode en l'isolant bien de la lumière ambiante tout en la rapprochant de la télécommande.
L'Arduino devra alors lire les impulsions. Un signal d'un bit à 38Khz ou 50Khz, pour un Arduino à 16Mhz ça reste facile.
Ce qui va être compliqué, c'est de ne pas saturer la petite RAM de 2ko
On peut procéder en deux étapes : d'abord mesurer la fréquence de la porteuse, et ensuite mémoriser les données proprement dites.
Evidemment le sketch de lecture ne sera pas optimisé pour un usage dans une application, mais juste pour l'identification de télécommandes.
On peut aussi faire cette identification des télécommandes avec une petite interface ou un oscilloscope numérique pour ordinateur.
Il y a longtemps j'avais bricolé le "CIR" qui fonctionnait sur port parallèle (https://www.ziplabel.com/cir/schem.html http://www.midondesign.com/CIR-II/CIR-II.html)
C'était l'époque où Arduino et Raspberry Pi n'existaient pas, mais où on pouvait piloter des montages électroniques facilement avec un PC et le port parallèle.
Ces montages n'avaient pas de microcontrôleurs, c'est le logiciel sur l'ordinateur qui faisait tout. Exemple ici : http://electroremy.free.fr/elec-mo-gl27.html
Un électronicien faisait souvent l'acquisition de cartes PCI ou ISA permettant d'avoir deux ou trois ports parallèle sur son ordinateur. Un PC avec deux ports parallèles et deux lecteurs de disquettes, c'était une machine de "pro"
D'ailleurs les Arduino et Raspberry Pi ont eu du succès aussi à cause de ça, beaucoup s'en sont servit comme "passerelle" pour permettre à un PC de communiquer avec de l'électronique via Ethernet ou USB.
Certains utilisent même la carte son de l'ordinateur, car certaines ont une fréquence d'échantillonnage qui monte à 96Khz et même à 192KHz.
Pour un signal carré de 50KHz c'est pas terrible mais ça fonctionne.
A bientôt
Salut,
Oui justement ça m'intéresse de visualiser les signaux avant et après démodulation. J'ai la possibilité d'utiliser des oscilloscopes mais j'aimerais quand même me procurer un analyseur logique (j'ai d'ailleurs ouvert ce fil récemment : Analyseur logique ?).
Oui la RAM est limitée alors je me disais qu'à ces fréquences il devrait être possible d'envoyer les données en temps réel via la liaison série : on aurait qu'un seul byte à envoyer et on peut aller jusqu'à 2 millions de bauds avec la liaison série...
Bonjour,
j'ai pu tester cette bibliothèque avec mes modules IR
https://www.amazon.fr/gp/product/B07...ustomerReviews
et un clone Arduino UNO / W5500 Keyestudio : https://www.keyestudio.com/keyestudi...poe-p0368.html
Ce code permet d'identifier les télécommandes (l'Arduino se comporte en récepteur IR)
Il fonctionne même avec la télécommande de ma pompe à chaleur (ces télécommandes sont réputées difficiles)
Mais il bouffe pas mal de flash et de RAM - quand on regarde les fichiers de la bibliothèque, on constate qu'il y a beaucoup de code :
Cet autre code permet de piloter un appareil.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123 // Permet d'identifier les télécommandes // 9850 octets de flash (30%) // 708 octets de RAM (34%) pour les variables globales /* * ReceiveDump.cpp * * Dumps the received signal in different flavors. * Since the printing takes so much time, repeat signals may be skipped or interpreted as UNKNOWN. * * This file is part of Arduino-IRremote https://github.com/Arduino-IRremote/Arduino-IRremote. * ************************************************************************************ * MIT License * * Copyright (c) 2020-2021 Armin Joachimsmeyer * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is furnished * to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ************************************************************************************ */ #include <Arduino.h> /* * Define macros for input and output pin etc. */ #include "PinDefinitionsAndMore.h" /* * You can change this value accordingly to the receiver module you use. * The required value can be derived from the timings printed here. * Keep in mind that the timings may change with the distance * between sender and receiver as well as with the ambient light intensity. */ #define MARK_EXCESS_MICROS 20 // recommended for the cheap VS1838 modules #include <IRremote.h> //+============================================================================= // Configure the Arduino // void setup() { pinMode(LED_BUILTIN, OUTPUT); pinMode(IR_SEND_PIN, OUTPUT); Serial.begin(115200); // Status message will be sent to PC at 9600 baud #if defined(__AVR_ATmega32U4__) || defined(SERIAL_USB) || defined(SERIAL_PORT_USBVIRTUAL) || defined(ARDUINO_attiny3217) delay(4000); // To be able to connect Serial monitor after reset or power up and before first printout #endif // Just to know which program is running on my Arduino Serial.println(F("START " __FILE__ " from " __DATE__ "\r\nUsing library version " VERSION_IRREMOTE)); IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK); // Start the receiver, enable feedback LED, take LED feedback pin from the internal boards definition Serial.print(F("Ready to receive IR signals at pin ")); Serial.println(IR_RECEIVE_PIN); } uint8_t sRepeats = 0; //+============================================================================= // The repeating section of the code // void loop() { if (IrReceiver.decode()) { // Grab an IR code // Check if the buffer overflowed if (IrReceiver.decodedIRData.flags & IRDATA_FLAGS_WAS_OVERFLOW) { Serial.println("IR code too long. Edit IRremoteInt.h and increase RAW_BUFFER_LENGTH"); } else { Serial.println(); // 2 blank lines between entries Serial.println(); IrReceiver.printIRResultShort(&Serial); Serial.println(); Serial.println(F("Raw result in internal ticks (50 us) - with leading gap")); IrReceiver.printIRResultRawFormatted(&Serial, false); // Output the results in RAW format Serial.println(F("Raw result in microseconds - with leading gap")); IrReceiver.printIRResultRawFormatted(&Serial, true); // Output the results in RAW format Serial.println(); // blank line between entries Serial.println(F("Result as internal ticks (50 us) array - compensated with MARK_EXCESS_MICROS")); IrReceiver.compensateAndPrintIRResultAsCArray(&Serial, false); // Output the results as uint8_t source code array of ticks Serial.println(F("Result as microseconds array - compensated with MARK_EXCESS_MICROS")); IrReceiver.compensateAndPrintIRResultAsCArray(&Serial, true); // Output the results as uint16_t source code array of micros IrReceiver.printIRResultAsCVariables(&Serial); // Output address and data as source code variables IrReceiver.compensateAndPrintIRResultAsPronto(&Serial); /* * Example for using the compensateAndStorePronto() function. * Creating this String requires 2210 bytes program memory and 10 bytes RAM for the String class. * The String object itself requires additional 440 Bytes RAM from the heap. * This values are for an Arduino UNO. */ // Serial.println(); // blank line between entries // String ProntoHEX = F("Pronto HEX contains: "); // Assign string to ProtoHex string object // if (int size = IrReceiver.compensateAndStorePronto(&ProntoHEX)) { // Dump the content of the IReceiver Pronto HEX to the String object // // Append compensateAndStorePronto() size information to the String object (requires 50 bytes heap) // ProntoHEX += F("\r\nProntoHEX is "); // Add codes size information to the String object // ProntoHEX += size; // ProntoHEX += F(" characters long and contains "); // Add codes count information to the String object // ProntoHEX += size / 5; // ProntoHEX += F(" codes"); // Serial.println(ProntoHEX.c_str()); // Print to the serial console the whole String object // Serial.println(); // blank line between entries // } } IrReceiver.resume(); // Prepare for the next value } }
J'ai créé un petit programme qui utilise les codes identifiés précédemment pour piloter mon ampli tuner HiFi à l'aide de mon ordinateur via le moniteur série.
Heureusement la consommation de flash est de RAM est moindre - il est possible de la réduire en éditant la bibliothèque pour ne prendre que les fonctions dont on a besoin.
Prochaine étape : intégrer le code de pilotage de mon ampli hifi à mon serveur Arduino
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 // Permet d'identifier les télécommandes // 3868 octets de flash (11%) // 399 octets de RAM (19%) pour les variables globales /* * IRsendDemo.cpp * Demonstrates sending IR codes in standard format with address and command * An IR LED must be connected to Arduino PWM pin 3 (IR_SEND_PIN). * Copyright (C) 2020-2021 Armin Joachimsmeyer * armin.joachimsmeyer@gmail.com * This file is part of Arduino-IRremote https://github.com/z3t0/Arduino-IRremote. */ //#define EXCLUDE_EXOTIC_PROTOCOLS // saves around 240 bytes program space if IrSender.write is used #include <IRremote.h> #if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__) #include "ATtinySerialOut.h" #endif // On the Zero and others we switch explicitly to SerialUSB #if defined(ARDUINO_ARCH_SAMD) #define Serial SerialUSB #endif void setup() { pinMode(LED_BUILTIN, OUTPUT); Serial.begin(115200); #if defined(__AVR_ATmega32U4__) || defined(SERIAL_USB) || defined(SERIAL_PORT_USBVIRTUAL) || defined(ARDUINO_attiny3217) delay(2000); // To be able to connect Serial monitor after reset or power up and before first printout #endif // Just to know which program is running on my Arduino Serial.println(F("START " __FILE__ " from " __DATE__ "\r\nUsing library version " VERSION_IRREMOTE)); Serial.print(F("Ready to send IR signals at pin ")); Serial.println(IR_SEND_PIN); IrSender.begin(true); // Enable feedback LED, } uint8_t sRepeats = 0; void loop() { byte incomingByte; if (Serial.available() > 0) { incomingByte = Serial.read(); // Telecommande ampli YAMAHA switch (incomingByte) { case 'o': IrSender.sendNECRaw(0xD42A817E, sRepeats); Serial.println(F("ON/OFF")); break; // Protocol=NEC Address=0x7E Command=0x2A Parity fail Raw-Data=0xD42A817E (32 bits) LSB first case '+': IrSender.sendNECRaw(0xE41A857A, sRepeats); Serial.println(F("Volume +")); break; // Protocol=NEC Address=0x7A Command=0x1A Parity fail Raw-Data=0xE41A857A (32 bits) LSB first case '-': IrSender.sendNECRaw(0xE51B857A, sRepeats); Serial.println(F("Volume -")); break; // Protocol=NEC Address=0x7A Command=0x1B Parity fail Raw-Data=0xE51B857A (32 bits) LSB first case 'a': IrSender.sendNECRaw(0x649A857A, sRepeats); Serial.println(F("Speakers A")); break; // Protocol=NEC Address=0x7A Command=0x9A Parity fail Raw-Data=0x649A857A (32 bits) LSB first case 'b': IrSender.sendNECRaw(0x659B857A, sRepeats); Serial.println(F("Speakers B")); break; // Protocol=NEC Address=0x7A Command=0x9B Parity fail Raw-Data=0x659B857A (32 bits) LSB first case '1': IrSender.sendNECRaw(0xEA14857A, sRepeats); Serial.println(F("Phono")); break; // Protocol=NEC Address=0x7A Command=0x14 Parity fail Raw-Data=0xEA14857A (32 bits) LSB first case '2': IrSender.sendNECRaw(0xB44A017F, sRepeats); Serial.println(F("Dock")); break; // Protocol=NEC Address=0x17F Command=0x4A Parity fail Raw-Data=0xB44A017F (32 bits) LSB first case '3': IrSender.sendNECRaw(0x2658017F, sRepeats); Serial.println(F("FM")); break; // Protocol=NEC Address=0x17F Command=0x58 Parity fail Raw-Data=0x2658017F (32 bits) LSB first case '4': IrSender.sendNECRaw(0x2B55017F, sRepeats); Serial.println(F("AM")); break; // Protocol=NEC Address=0x17F Command=0x55 Parity fail Raw-Data=0x2B55017F (32 bits) LSB first case '5': IrSender.sendNECRaw(0xEB15857A, sRepeats); Serial.println(F("CD")); break; // Protocol=NEC Address=0x7A Command=0x15 Parity fail Raw-Data=0xEB15857A (32 bits) LSB first case '6': IrSender.sendNECRaw(0xE618857A, sRepeats); Serial.println(F("Tape")); break; // Protocol=NEC Address=0x7A Command=0x18 Parity fail Raw-Data=0xE618857A (32 bits) LSB first case '7': IrSender.sendNECRaw(0xE719857A, sRepeats); Serial.println(F("Line 1")); break; // Protocol=NEC Address=0x7A Command=0x19 Parity fail Raw-Data=0xE719857A (32 bits) LSB first case '8': IrSender.sendNECRaw(0x3FC1857A, sRepeats); Serial.println(F("Line 2")); break; // Protocol=NEC Address=0x7A Command=0xC1 Parity fail Raw-Data=0x3FC1857A (32 bits) LSB first case '/': IrSender.sendNECRaw(0x205E017F, sRepeats); Serial.println(F("Preset <")); break; // Protocol=NEC Address=0x17F Command=0x5E Parity fail Raw-Data=0x205E017F (32 bits) LSB first case '*': IrSender.sendNECRaw(0x255B017F, sRepeats); Serial.println(F("Preset >")); break; // Protocol=NEC Address=0x17F Command=0x5B Parity fail Raw-Data=0x255B017F (32 bits) LSB first } delay(5); } }
A bientôt
J'ai pu intégrer la fonction émission IR à mon serveur sans difficulté
Mieux, après avoir épluché la librairie, je n'ai conservé que les fonctions utiles pour envoyer des ordres en 'RAW' avec ma télécommande NEC
J'ai gagné environ 1300 octets de flash, mais surtout j'ai gagné près de 450 octets de RAM (soit 1/4 de la RAM disponible sur Arduino UNO)
Voici le code des fonctions "extraites" :
Il n'y a plus besoin de faire un .begin()
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106 #define NEC_ADDRESS_BITS 16 // 16 bit address or 8 bit address and 8 bit inverted address #define NEC_COMMAND_BITS 16 // Command and inverted command #define NEC_BITS (NEC_ADDRESS_BITS + NEC_COMMAND_BITS) #define NEC_UNIT 560 #define NEC_HEADER_MARK (16 * NEC_UNIT) // 9000 #define NEC_HEADER_SPACE (8 * NEC_UNIT) // 4500 #define NEC_BIT_MARK NEC_UNIT #define NEC_ONE_SPACE (3 * NEC_UNIT) // 1690 #define NEC_ZERO_SPACE NEC_UNIT #define NEC_REPEAT_HEADER_SPACE (4 * NEC_UNIT) // 2250 #define NEC_AVERAGE_DURATION 62000 // NEC_HEADER_MARK + NEC_HEADER_SPACE + 32 * 2,5 * NEC_UNIT + NEC_UNIT // 2.5 because we assume more zeros than ones #define NEC_REPEAT_DURATION (NEC_HEADER_MARK + NEC_HEADER_SPACE + NEC_BIT_MARK) #define NEC_REPEAT_PERIOD 110000 // Commands are repeated every 110 ms (measured from start to start) for as long as the key on the remote control is held down. #define PROTOCOL_IS_LSB_FIRST false #define SEND_STOP_BIT true #define TIMER_RESET_INTR_PENDING #define TIMER_ENABLE_SEND_PWM TCNT2 = 0; (TCCR2A |= _BV(COM2B1)) // Clear OC2B on Compare Match #define TIMER_DISABLE_SEND_PWM (TCCR2A &= ~(_BV(COM2B1))) // Normal port operation, OC2B disconnected. #define TIMER_ENABLE_RECEIVE_INTR (TIMSK2 = _BV(OCIE2B)) // Output Compare Match A Interrupt Enable #define TIMER_DISABLE_RECEIVE_INTR (TIMSK2 = 0) #define TIMER_INTR_NAME TIMER2_COMPB_vect // We use TIMER2_COMPB_vect to be compatible with tone() library #define SYSCLOCK F_CPU // main Arduino clock #define IR_SEND_DUTY_CYCLE 30 // 30 saves power and is compatible to the old existing code // The top value for the timer. The modulation frequency will be SYSCLOCK / 2 / OCR2A. #pragma GCC diagnostic ignored "-Wunused-function" static void timerConfigForSend(uint8_t aFrequencyKHz) { const uint16_t pwmval = (SYSCLOCK / 2000) / (aFrequencyKHz); // 210,52 for 38 kHz @16 MHz clock, 2000 instead of 1000 because of Phase Correct PWM TCCR2A = _BV(WGM20); // PWM, Phase Correct, Top is OCR2A TCCR2B = _BV(WGM22) | _BV(CS20); // CS20 -> no prescaling OCR2A = pwmval - 1; OCR2B = ((pwmval * IR_SEND_DUTY_CYCLE) / 100) - 1; TCNT2 = 0; // not really required, since we have an 8 bit counter, but makes the signal more reproducible } void IRsend_sendNECRaw(uint32_t aRawData) { IRsend_enableIROut(38); noInterrupts(); IRsend_mark(NEC_HEADER_MARK); IRsend_space(NEC_HEADER_SPACE); IRsend_sendPulseDistanceWidthData(NEC_BIT_MARK, NEC_ONE_SPACE, NEC_BIT_MARK, NEC_ZERO_SPACE, aRawData, NEC_BITS, PROTOCOL_IS_LSB_FIRST, SEND_STOP_BIT); // LSB first + stop bit interrupts(); } void IRsend_enableIROut(uint8_t aFrequencyKHz) { TIMER_DISABLE_RECEIVE_INTR; pinMode(3, OUTPUT); digitalWrite(3, LOW); //SENDPIN_OFF(3); // When not sending, we want it low timerConfigForSend(aFrequencyKHz); } void IRsend_mark(unsigned int timeMicros) { TIMER_ENABLE_SEND_PWM; // Enable pin 3 PWM output if (timeMicros >= 0x4000) { // The implementation of Arduino delayMicroseconds() overflows at 0x4000 / 16.384 @16MHz (wiring.c line 175) // But for sendRaw() and external protocols values between 16.384 and 65.535 might be required // Use delay(), this in calls yield which is required on some platforms to work properly delay(timeMicros / 1000); } else { delayMicroseconds(timeMicros); } } void IRsend_space(unsigned int timeMicros) { TIMER_DISABLE_SEND_PWM; // Disable PWM output if (timeMicros >= 0x4000) { // The implementation of Arduino delayMicroseconds() overflows at 0x4000 / 16.384 @16MHz (wiring.c line 175) // But for sendRaw() and external protocols values between 16.384 and 65.535 might be required // Use delay(), this in calls yield which is required on some platforms to work properly delay(timeMicros / 1000); } else { delayMicroseconds(timeMicros); } } void IRsend_sendPulseDistanceWidthData(unsigned int aOneMarkMicros, unsigned int aOneSpaceMicros, unsigned int aZeroMarkMicros, unsigned int aZeroSpaceMicros, uint32_t aData, uint8_t aNumberOfBits, bool aMSBfirst, bool aSendStopBit) { if (aMSBfirst) { // Send the MSB first. // send data from MSB to LSB until mask bit is shifted out for (uint32_t tMask = 1UL << (aNumberOfBits - 1); tMask; tMask >>= 1) { if (aData & tMask) { IRsend_mark(aOneMarkMicros); IRsend_space(aOneSpaceMicros); } else { IRsend_mark(aZeroMarkMicros); IRsend_space(aZeroSpaceMicros); } } } else { // Send the Least Significant Bit (LSB) first / MSB last. for (uint_fast8_t bit = 0; bit < aNumberOfBits; bit++, aData >>= 1) if (aData & 1) { // Send a 1 IRsend_mark(aOneMarkMicros); IRsend_space(aOneSpaceMicros); } else { // Send a 0 IRsend_mark(aZeroMarkMicros); IRsend_space(aZeroSpaceMicros); } } if (aSendStopBit) { IRsend_mark(aZeroMarkMicros); // seems like this is used for stop bits IRsend_ledOff(); // Always end with the LED off } } void IRsend_ledOff() { TIMER_DISABLE_SEND_PWM; // Disable PWM output }
Juste a appeler la fonction IRsend_sendNECRaw()
Il est préférable de mettre les codes des télécommande en PROGMEM
Voici un exemple :
Sur les petites cartes, on gagne vraiment à "forker" les librairies pour ne conserver que les fonctions utiles.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 const uint32_t IR_Remote_Codes[] PROGMEM = { 0xD42A817E, // ON/OFF Protocol=NEC Address=0x7E Command=0x2A Parity fail Raw-Data=0xD42A817E (32 bits) LSB first 0xE51B857A, // Volume - Protocol=NEC Address=0x7A Command=0x1B Parity fail Raw-Data=0xE51B857A (32 bits) LSB first 0xE41A857A, // Volume + Protocol=NEC Address=0x7A Command=0x1A Parity fail Raw-Data=0xE41A857A (32 bits) LSB first 0x649A857A, // Speakers A Protocol=NEC Address=0x7A Command=0x9A Parity fail Raw-Data=0x649A857A (32 bits) LSB first 0x659B857A, // Speakers B Protocol=NEC Address=0x7A Command=0x9B Parity fail Raw-Data=0x659B857A (32 bits) LSB first 0xEA14857A, // Phono Protocol=NEC Address=0x7A Command=0x14 Parity fail Raw-Data=0xEA14857A (32 bits) LSB first 0xB44A017F, // Dock Protocol=NEC Address=0x17F Command=0x4A Parity fail Raw-Data=0xB44A017F (32 bits) LSB first 0x2658017F, // FM Protocol=NEC Address=0x17F Command=0x58 Parity fail Raw-Data=0x2658017F (32 bits) LSB first 0x2B55017F, // AM Protocol=NEC Address=0x17F Command=0x55 Parity fail Raw-Data=0x2B55017F (32 bits) LSB first 0xEB15857A, // CD Protocol=NEC Address=0x7A Command=0x15 Parity fail Raw-Data=0xEB15857A (32 bits) LSB first 0xE618857A, // Tape Protocol=NEC Address=0x7A Command=0x18 Parity fail Raw-Data=0xE618857A (32 bits) LSB first 0xE719857A, // Line 1 Protocol=NEC Address=0x7A Command=0x19 Parity fail Raw-Data=0xE719857A (32 bits) LSB first 0x3FC1857A, // Line 2 Protocol=NEC Address=0x7A Command=0xC1 Parity fail Raw-Data=0x3FC1857A (32 bits) LSB first 0x205E017F, // Preset < Protocol=NEC Address=0x17F Command=0x5E Parity fail Raw-Data=0x205E017F (32 bits) LSB first 0x255B017F, // Preset > Protocol=NEC Address=0x17F Command=0x5B Parity fail Raw-Data=0x255B017F (32 bits) LSB first 0xE21C857A // Mute Protocol=NEC Address=0x7A Command=0x1C Parity fail Raw-Data=0xE21C857A (32 bits) LSB first }; IRsend_sendNECRaw(pgm_read_dword(&IR_Remote_Codes[j])); delay(5);
En effet, bien que la bibliothèque contienne de nombreux #define, le compilateur a du mal à éliminer les codes "morts" ou "inutiles".
Le meilleur outil d'optimisation c'est votre cerveau.
A bientôt
Partager