IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Arduino Discussion :

La librairie IRremote.


Sujet :

Arduino

  1. #1
    Membre Expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 910
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 910
    Par défaut La librairie IRremote.
    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.

    ----------

  2. #2
    Membre Expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 910
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 910
    Par défaut
    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...

  3. #3
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 914
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 914
    Par défaut
    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?

  4. #4
    Membre Expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 910
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 910
    Par défaut
    Merci.
    Citation Envoyé par Jay M Voir le message
    Parlez Vous de ce fichier ir_NEC.cpp?
    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...

  5. #5
    Membre Expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 910
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 910
    Par défaut
    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 !

  6. #6
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 914
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 914
    Par défaut
    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.

  7. #7
    Membre Expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 910
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 910
    Par défaut
    Merci.

    Citation Envoyé par Jay M Voir le message
    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
    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...

    Citation Envoyé par Jay M Voir le message

    Lorsque vous affectez un membre de la structure ensuite dans une fonction/méthode comme begin, rien d’autre n’est touché (heureusement !!)
    Oui heureusement !

    Citation Envoyé par Jay M Voir le message
    StateForISR est utilisé lors des interruptions pour conserver l’état courant.
    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...

  8. #8
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 914
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 914
    Par défaut
    un bon compilateur devrait lancer un avertissement si on utilise une variable avant qu'elle ne soit initialisée...
    comme c’est une variable globale elle est bien initialisée à 0, donc c’est normal de ne pas avoir de warning.

    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

  9. #9
    Membre Expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 910
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 910
    Par défaut
    Citation Envoyé par Jay M Voir le message
    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
    Ouais du coup certains tuto se retrouvent vite dépassés, on peut voir que c'est une ancienne version de la lib qui est utilisée dans tel ou tel tuto...

  10. #10
    Membre Expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 910
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 910
    Par défaut
    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.

  11. #11
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 914
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 914
    Par défaut
    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).

  12. #12
    Membre Expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 910
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 910
    Par défaut
    Merci.

    Citation Envoyé par Jay M Voir le message
    Les constructeurs sont appelés avant que Serial soit activé dans le setup.
    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>...

  13. #13
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 914
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 914
    Par défaut
    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().

  14. #14
    Membre Expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 910
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 910
    Par défaut
    Merci.

  15. #15
    Membre chevronné Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    999
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 999
    Par défaut
    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

  16. #16
    Membre Expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 910
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 910
    Par défaut
    Salut,
    Citation Envoyé par electroremy Voir le message
    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.
    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)...

  17. #17
    Membre chevronné Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    999
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 999
    Par défaut
    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

  18. #18
    Membre Expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 910
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 910
    Par défaut
    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 ?).

    Citation Envoyé par electroremy Voir le message
    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
    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...

  19. #19
    Membre chevronné Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    999
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 999
    Par défaut
    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 :

    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
        }
    }
    Cet autre code permet de piloter un appareil.
    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.

    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);
    	}
    }
    Prochaine étape : intégrer le code de pilotage de mon ampli hifi à mon serveur Arduino

    A bientôt

  20. #20
    Membre chevronné Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    999
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 999
    Par défaut
    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" :

    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
    }
    Il n'y a plus besoin de faire un .begin()

    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 :

    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);
    Sur les petites cartes, on gagne vraiment à "forker" les librairies pour ne conserver que les fonctions utiles.

    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

Discussions similaires

  1. Problèmes nouvelle librairie IRremote version 3.0
    Par jmdel95 dans le forum Arduino
    Réponses: 10
    Dernier message: 09/02/2021, 23h25
  2. inclure une librairie *.lib
    Par darkbm dans le forum C
    Réponses: 2
    Dernier message: 16/12/2002, 22h48
  3. Réponses: 5
    Dernier message: 09/12/2002, 22h23
  4. [GTK]PB Librairie GTK+ sous dev-c++
    Par wozzy dans le forum Dev-C++
    Réponses: 15
    Dernier message: 05/11/2002, 14h55
  5. compatibilité des librairies directX8
    Par Freakazoid dans le forum DirectX
    Réponses: 3
    Dernier message: 23/05/2002, 21h33

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo