[Programmation] Gestion d'un bouton poussoir sur microcontrôleur [Résolu]
Répondre à la discussion
Page 1 sur 3 12 DernièreDernière
Affichage des résultats 1 à 30 sur 76

Gestion d'un bouton poussoir sur microcontrôleur [Résolu]



  1. #1
    scaypapa

    Gestion d'un bouton poussoir sur microcontrôleur [Résolu]


    ------

    Bonjour,

    Je débute avec les microcontrôleurs. Pour jouer avec les différentes fonctions qu'ils offrent et bien comprendre comment gérer ces petites bestioles, je suis en train de faire un petit métronome visuel (une LED pour indiquer les mesures et une pour les temps). J'utilise un PIC 18F46K22, qui dispose de beaucoup de fonctions différentes à tester.

    Actuellement, le tempo n'est réglable que par une constante enregistrée dans le programme. J'en suis en fait à regarder comment se gèrent les interruptions.
    Un bouton poussoir sert à modifier le nombre de temps par mesure (2tps, 3tps, 4tps). Il est branché sur une des broches INT0,1 ou 2. Le circuit étant réalisé sur un platine d'essai, je peux déplacer la broche de l'interrupteur sur l'une ou l'autre des entrées du µC.
    Donc quand on appuie sur le BP, le PIC réagit comme ceci :
    • interruption HP sur la patte INTx
    • si le nombre de temps par mesure actuel est inférieur à 4, l'incrémenter, sinon, redescendra à des mesures de 2 temps.
    • écriture du résultat dans l'EEPROM pour ne pas avoir à reparamétrer en cas de coupure, ceci sans attendre (fin d'interruption dès le début de l'écriture)
    • interruption HP sur la fin d'écriture EEPROM
    • relecture de la mémoire EEPROM et contrôle que la valeur correspond bien à la valeur qu'on voulait écrire
    • si la valeur est bonne, confirmation par clignotement de la LED verte, sinon clignotement de la LED jaune.
    • interruption LP sur le timer 0 pour incrémenter un compteur et mettre le PIC en sommeil à partir d'une certaine valeur

    Dans l'ensemble, ceci fonctionne. Mes souci viennent de la gestion des interrupteurs :
    • Sauf que si l'interruption se passe sur la patte INT0, ça fonctionne bien.
    • si je déplace le BP sur INT1, plus rien ne se passe ! ?
    • si je déplace le BP sur la patte INT2, il fait l'inverse de ce qu'il devrait : le nombre de temps par mesure est décrémenté au lieu d'être incrémenté. Je pense plutôt qu'au lieu de ne voir qu'un front, il en voit deux.
    • Aussi j'ai essayé de créer des interruptions de type InterruptOnChange sur RB4 ou RB5 qui ne fonctionnent pas du tout (quelle que soit la patte utilisée). Pour faire des essais, le principe était simplement de faire clignoter la LED verte en cas d'appui et la LED jaune en cas de relâchement. Sauf que rien ne se passe du tout.

    Voici le shéma de branchement de mes boutons poussoirs :
    Nom : fs_0547507Capturede769cran20160622a768004218.png
Affichages : 1022
Taille : 17,1 Ko
    Je vous joint aussi le code complet de mon petit programme :
    Code:
    /*
     * File:   main.c - Metronome
     * Author: anard
     *
     * Created on June 13, 2016, 4:52 PM
     * Metronome à LEDs avec indication des mesures
     */
     
     
    // PIC18F46K22 Configuration Bit Settings
     
    // 'C' source line config statements
     
    #include <xc.h>
     
    // #pragma config statements should precede project file includes.
    // Use project enums instead of #define for ON and OFF.
     
    // CONFIG1H
    #pragma config FOSC = HSMP      // Oscillator Selection bits (HS oscillator (medium power 4-16 MHz))
    #pragma config PLLCFG = OFF     // 4X PLL Enable (Oscillator used directly)
    #pragma config PRICLKEN = ON    // Primary clock enable bit (Primary clock is always enabled)
     
    // CONFIG2H
    #pragma config WDTEN = OFF      // Watchdog Timer Enable bits (Watch dog timer is always disabled. SWDTEN has no effect.)
     
    // CONFIG3H
    #pragma config PBADEN = OFF     // PORTB A/D Enable bit (PORTB<5:0> pins are configured as digital I/O on Reset)
     
    // CONFIG4L
    #pragma config LVP = ON         // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled if MCLRE is also 1)
     
     
    ///////////////// ------    PARAMETERS TO PROGRAM    ------ /////////////////
    #define BPS 180             // Tempo (bpm)
    #define TEMPS_AV_SLEEP 10   // Temps avant arrêt (s)
    #define TPS_ALLUME 30       // Temps d'allumage des LEDs (ms)
    ///////////////// ------    PARAMETERS TO PROGRAM    ------ /////////////////
     
    #define _XTAL_FREQ 8000000      // Osc frequency
    #define TEMPS PORTDbits.RD1     // Green LED
    #define MESURE PORTDbits.RD2    // Yellow LED
     
    #define NB_PASSAGES (((60000/BPS) - TPS_ALLUME)/95) // la durée d'un __delay_ms est limitée à ~95ms à 8MHz
    #define TPS_ETEINT (((60000/BPS) - TPS_ALLUME)%95)
    #define OVERFLOW_COUNTER TEMPS_AV_SLEEP*_XTAL_FREQ/262144   // Tmr0 overflow = 256*256*4 = 262144
     
    unsigned char nb_tps;
    unsigned int iCount;
     
    // Appui sur un bouton et écriture dans la mémoire non volatile
    void high_priority interrupt UserSignal_and_EEWrite(void)
    {
        char k;
        
        // Se réveiller si en sommeil, sinon changement du nombre de temps par mesure et enregistrement dans l'EEPROM
        if (INTCONbits.INT0IF || INTCON3bits.INT1IF || INTCON3bits.INT2IF) {
        //if (INTCONbits.RAIF) {
            INTCONbits.INT0IF = INTCON3bits.INT1IF = INTCON3bits.INT2IF = 0;
            
            if (iCount < OVERFLOW_COUNTER) {    // désactivation de smodifiactions en cas de réveil
     
                if (nb_tps < 4)
                    nb_tps ++;
                else
                    nb_tps = 2;
     
                // EEPROM Write
                EECON1bits.WREN = 1;
                INTCONbits.GIEL = INTCONbits.INT0IE = INTCON3bits.INT1IE = INTCON3bits.INT2IE = 0;
                EEADRH = EEADR = 0;
                EEDATA = nb_tps;
                EECON2 = 0x55;
                EECON2 = 0x0AA;
                EECON1bits.WR = 1;
            }
            // Reset sleep timer
            iCount = TMR0L = 0;
        }
        
        /* Essai sur les interruptions IOCB
         * Devrait faire cignoter 10 fois la LED jaune en cas d'appui ou la LED verte en cas de relâchement.
         *
    //////////////////     * NE FONCTIONNE PAS DU TOUT *     /////////////////
                          * -------------------------- */
        else if (INTCONbits.RBIF) {
            if (PORTBbits.RB4 == 1) {
                for (k=0; k<10; k++) {
                    TEMPS = 1; __delay_ms(10);
                    TEMPS = 0; __delay_ms(50);
                }
            } else {
                for (k=0; k<10; k++) {
                    MESURE = 1; __delay_ms(10);
                    MESURE = 0; __delay_ms(50);
                }
            }
            INTCONbits.RBIF = 0;
        }
        
        // Fin d'écriture EEPROM
        else if (PIR2bits.EEIF)
        {
            // Lecture de l'adresse courante
            EECON1bits.RD;
            // Contrôle de la correspondance de la lecture avec la valeur à écrire et confirmation par scintillement de la LED
            if (EEDATA == nb_tps) { //  OK
                for (k=0; k<5; k++) {
                    TEMPS = 1; __delay_ms(10);
                    TEMPS = 0; __delay_ms(50);
                }
            } else {                // ERREUR
                for (k=0; k<5; k++) {
                    MESURE = 1; __delay_ms(10);
                    MESURE = 0; __delay_ms(50);
                }
            }
            // Récativation des interruptions, fin d'écriture.
            INTCONbits.GIEL = INTCONbits.INT0IE = INTCON3bits.INT1IE = INTCON3bits.INT2IE = 1;
            EECON1bits.WREN = PIR2bits.EEIF = 0;
        }
    }
     
    // Incrémente le compteur de Sleep
    void low_priority interrupt SleepTimer(void)
    {
        if (INTCONbits.TMR0IF) {
            iCount++;
            INTCONbits.TMR0IF = 0;
        }
    }
     
    // ------------------    MAIN    ---------------
    void main(void) {
        char i, j;
        
        // Initialisation
        ANSELA = ANSELB = ANSELC = ANSELD = ANSELE = 0; // All digital
        TRISB = 1;              // Config PORTB en entrée
        TRISD = 0;              // Config PORTD en sortie
        
        // EEPROM READING
        EECON1 = 0;             // Situe les écritures dans l'EEPROM
        EEADRH = EEADR = 0;   
        EECON1bits.RD = 1;      // Read
        nb_tps = EEDATA;
        if (nb_tps > 4) nb_tps = 4;
     
        // INTERRUPTS
        // Enable prioritary interrupts
        RCONbits.IPEN = 1;
        
        // EEPROM Interrupts High Priority
        PIE2bits.EEIE = IPR2bits.EEIP = 1;
        
        // Tmr0 & Int0 & Rb4-OnChange
        INTCON = 0b00111000;    // GIEH GIEL Tmr0IE INT0IE RBIE Tmr0IF INT0IF RBIF
        IOCB = 0b00010000;      // Rb4
     
        // Pullups, edges and priorities
        INTCON2 = 0b00000001;   // Pull-upEnable   INT0,1,2   onFallingEdge   -   Tmr0LowPriority   -   IOC HighPriority
        WPUB = 0xFF;            // Pull-up enabled for all PortB
        
        // Int1 & Int2 High Priority
        INTCON3 = 0b11011000;   // INT2IP INT1IP - INT2IE INT1IE - INT2IF INT1IF
     
        // Timer0 init
        T0CON = 0b01000111;     // OFF 8bits onCLKOut - PrescalerEnabled PS=256 ==> Overflow on 256*256/2.000.000 = 32,768 ms
        TMR0L = iCount = 0;
        
        // Activation
        INTCONbits.GIEH = 1;
        INTCONbits.GIEL = 1;
        T0CONbits.TMR0ON = 1;
     
    // ----------    MAIN LOOP    ---------- //  
        while(1)
        {
            // Test prouvant que Rb4 est correctement reconnu.
            if (PORTBbits.RB4 == 1) // Si Rb4 est enfoncé, le code est bien ignoré.
            {
                // LED de mesure
                MESURE = 1;
                __delay_ms(TPS_ALLUME);
                MESURE = 0;
                for (j=0; j<NB_PASSAGES; j++)
                    __delay_ms(95);
                __delay_ms(TPS_ETEINT);
     
                // LED de temps
                for (i=0; i<nb_tps-1; i++) {
                    TEMPS = 1;
                    __delay_ms(TPS_ALLUME);
                    TEMPS = 0;
                    for (j=0; j<NB_PASSAGES; j++)
                        __delay_ms(95);
                    __delay_ms(TPS_ETEINT);
                }
     
                // Go to sleep...
                // Fonctionne aussi dans l'interruption du Tmr0 (en basse priorité) mais, ici, on attend une fin de mesure pour la mise en sommeil
                if (iCount >= OVERFLOW_COUNTER) {
                    SLEEP();
                    NOP();
                }
            }
        }
    }
    Si une bonne âme pouvait m'expliquer ce que je fais mal ou ce que je n'ai pas compris, je lui en serait très reconnaissant.
    Merci beaucoup.

    -----
    Dernière modification par Antoane ; 27/06/2016 à 12h27. Motif: Rapatriement des PJ sur le serveur

  2. #2
    scaypapa

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    PS : une petite erreur s'est glissée dans le shéma des interrupteurs mais je en peux plus modifier mon message : c'est évidemment vers la broche RBx et non RAx que les boutons poussoirs sont connectés...

  3. #3
    terriblement

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    Première chose qui SAUTE aux yeux:
    On ne met jamais de delay dans une fonction d'interruption, on les garde toujours les plus courtes/rapide possible.
    Une bonne pratique étant de mettre un flag dans la fonction d'interruption et de traiter l'action une fois de retour au main

  4. #4
    DAUDET78

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    Citation Envoyé par scaypapa Voir le message
    Voici le shéma de branchement de mes boutons poussoirs :
    le bon schéma :
    Nom : Anti-rebond Hard.JPG
Affichages : 1029
Taille : 26,2 Ko
    On ne court-circuite JAMAIS un condensateur par un contact !
    J'aime pas le Grec

  5. A voir en vidéo sur Futura
  6. #5
    invite03481543

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    Bonjour,

    ta capa est inutile pour un µC.
    Un bouton se gère uniquement par soft.

  7. #6
    invite03481543

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    Comme le dit terriblement, en général on ne fait que de détecter la source d'interruption puis on retourne dans le prog principal pour faire l'action.

    Le principe de détection d'un bouton par un µC a déjà été expliqué des dizaines de fois ici, je te conseille donc de faire une recherche sur le forum.

    Grosso modo voici un principe de prise en compte de l'appui bouton sous interruption (il y en a plein):

    -> on choisit par exemple INT0, on active les interruptions, on active le pull-up interne.
    -> on pré-charge une tempo, par exemple TEMPO_bouton sur 100ms
    -> dès que l'interruption est activée on active la tempo TEMPO_bouton que l'on décrémente.
    -> à la fin de la tempo on regarde si l'entrée bouton est toujours ON ou OFF.

    Si OFF on oublie, si ON on considère que l'appui n'est pas accidentel et on valide par l'action qu'il convient de faire.
    Ca s'appelle un filtrage (tout comme le condo).

    Comme déjà dit il y a plein d'autres façon de voir la chose, ça dépend du contexte.

  8. #7
    DAUDET78

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    Citation Envoyé par HULK28 Voir le message
    Un bouton se gère uniquement par soft.
    Moi, je considère que les gens ne savent pas faire l'antirebond par soft .
    J'aime pas le Grec

  9. #8
    scaypapa

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    Citation Envoyé par terriblement Voir le message
    Première chose qui SAUTE aux yeux:
    On ne met jamais de delay dans une fonction d'interruption, on les garde toujours les plus courtes/rapide possible.
    Une bonne pratique étant de mettre un flag dans la fonction d'interruption et de traiter l'action une fois de retour au main
    Merci, en effet, c'est pas très clean. Après ce n'est que pour vérifier que le code a été exécuté correctement. Quand je ferai un programme réel (pas des essais), j'y ferai plus attention...

    On ne court-circuite JAMAIS un condensateur par un contact !
    Ah bon ? J'ai pourtant vu ça à de nombreuse reprises, y compris sur des circuits finis et fonctionnels :
    http://www.fantaspic.fr/viewtopic.php?t=37
    http://pila.fr/wordpress/?p=77
    http://djelectro71.com/theories-rebonds-anti-rebonds/
    On pourrait en trouver d'autres...
    J'utilise des condensateurs céramiques, donc non polarisés.
    C'est dans le cas d'un condensateur électrolytique qu'il ne faut pas court-circuiter l'inter avec ou qu'est-ce que j'ai raté ?

    En effet, certains utilisent un trigger de Schmitt en plus, mais ça n'a pas l'air systématique... J'ai sous les yeux des montages commandant des microcontrôleurs avec seulement un condensateur et éventuellement une résistance si le pullup n'est pas interne.
    Quelque chose doit m'échapper.

    EDIT : De nouvelles réponses sont arrivées entre temps
    Ca me paraissait bien plus clean de ne gérer le rebond que de façon matérielle. En effet, l'intéret d'un microcontrôleur est de simplifier les fonctions qui seraient matériellement très complexes. Si le simple ajout d'un condensateur peut gérer l'anti-rebond (par exemple, quand on n'utilise pas de µC), pourquoi devoir le faire par soft ?
    D'autant que du coup, ça impose d'intégrer un délai dans l'interruption justement...
    Dernière modification par scaypapa ; 27/06/2016 à 15h05.

  10. #9
    antek

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    Citation Envoyé par scaypapa Voir le message
    Merci, en effet, c'est pas très clean. Après ce n'est que pour vérifier que le code a été exécuté correctement. Quand je ferai un programme réel (pas des essais), j'y ferai plus attention...


    Ah bon ? J'ai pourtant vu ça à de nombreuse reprises, y compris sur des circuits finis et fonctionnels :

    En effet, certains utilisent un trigger de Schmitt en plus, mais ça n'a pas l'air systématique... J'ai sous les yeux des montages commandant des microcontrôleurs avec seulement un condensateur et éventuellement une résistance si le pullup n'est pas interne.

    EDIT : De nouvelles réponses sont arrivées entre temps
    Ca me paraissait bien plus clean de ne gérer le rebond que de façon matérielle. En effet, l'intéret d'un microcontrôleur est de simplifier les fonctions qui seraient matériellement très complexes. Si le simple ajout d'un condensateur peut gérer l'anti-rebond (par exemple, quand on n'utilise pas de µC), pourquoi devoir le faire par soft ?
    D'autant que du coup, ça impose d'intégrer un délai dans l'interruption justement...
    Vaut mieux faire des essaies avec un programme non guignolesque.
    C'est juste pour ne pas détruire le BP prématurément.
    Dans ton cas un RC comme sur le schéma de DAUDET78 me semble suffisent, le trigger est luxueux (si tu as un faux déclenchement, c'est pas grave).
    Dans d'autres cas on peut aller jusqu'à la bascule avec contact inverseur.
    Même dans un traitement logiciel du rebond on ne place pas d'attente dans le traitement de l'interruption.

  11. #10
    invite03481543

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    Ca me paraissait bien plus clean de ne gérer le rebond que de façon matérielle. En effet, l'intéret d'un microcontrôleur est de simplifier les fonctions qui seraient matériellement très complexes. Si le simple ajout d'un condensateur peut gérer l'anti-rebond (par exemple, quand on n'utilise pas de µC), pourquoi devoir le faire par soft ?
    D'autant que du coup, ça impose d'intégrer un délai dans l'interruption justement...
    Simplement parce que quand on utlise un µC et bien on s'en sert bien ou on continue à jouer avec des 555.
    En plus c'est très simple, c'est de la mauvaise volonté.
    Je crois que tu n'as pas bien compris le principe des interruptions.
    Dernière modification par HULK28 ; 27/06/2016 à 15h34.

  12. #11
    invite03481543

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    Citation Envoyé par DAUDET78 Voir le message
    Moi, je considère que les gens ne savent pas faire l'antirebond par soft .
    Mais ça n'implique pas qu'ils ne peuvent pas apprendre.
    Surtout si ils utilisent un µC.

  13. #12
    DAUDET78

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    Citation Envoyé par HULK28 Voir le message
    Mais ça n'implique pas qu'ils ne peuvent pas apprendre.
    Tii, tu es un optimiste !
    Quand tu vois un delay dans un programme d'interruption ..... Moi, je tire l'échelle !
    J'aime pas le Grec

  14. #13
    invite03481543

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    Dans ce cas mieux vaut qu'il oublie son µC, vu que le reste va aussi impliquer des tempos...

  15. #14
    scaypapa

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    Désolé de vous avoir embêté, je pensais juste trouver des explications intéressantes ici afin d'avancer dans l'étude des µC.

    Bonjour à toute la communauté,

    Quelques règles générales sur la participation au forum :

    La réponse à toutes les questions n'est pas obligatoire, si celle-ci n'est pas faite pour faire avancer le schmilblick.
    Si la seule réponse que l'on a à faire est de critiquer la question, on doit s'abstenir de le faire.
    Quand un débutant pose une question, même naïve ou maladroite on lui répond courtoisement en cherchant à le guider. Les réponses désagréables, méprisantes ou arrogantes ne font progresser personne : elles font fuir.
    Dernière modification par scaypapa ; 27/06/2016 à 17h24.

  16. #15
    lpt1com2

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    Je ne suis pas certain qu'il soit nécessaire de passer par une interruption. Dans le main, si le bouton est appuyé, on verrouille jusqu'à ce qu'il soit relâché (en n'incrémentant qu'une seule fois évidemment).
    Il vaut mieux être le deuxième mari d'une veuve, que le premier

  17. #16
    scaypapa

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    Bonjour,

    Je suis d'accord, qu'il est possible de faire sans interruption. Mais ce que je cherche à faire ici n'est pas un programme réellement utile. Je cherche juste à apprendre à utiliser des boutons poussoirs avec des interruptions de type Int et de type IOC. L'intérêt des interruptions étant de laisser travailler le programme principal en attendant l'appui sur un bouton poussoir (d'où l'absurdité de placer des delais au cœur d'une interruption, bloquant ainsi le programme principal).

    En plaçant le code lié à l'appui ou au relâchement d'un bouton dans le main, d'abord, on teste à chaque boucle l'appui ou non du bouton (ce qui est inutile dans les faits et consomme du temps de calcul, même s'il est minime), ensuite l'appui sur le bouton ne sera pris en compte qu'au moment où on le teste (si je veux couper mon programme au milieu en cas d'appui, ça ne pourra se faire qu'à un moment précis en testant le bouton à ce moment là) et si le bouton est appuyé très brièvement pendant le déroulement du programme (entre deux tests), l'appui ne sera pas pris en compte.

    J'ai d'ailleurs fait ce que tu disais avec RB4 pour vérifier que la position du bouton poussoir était correctement détectée par le µC (ce qui est bien le cas). Mais bizarrement, le drapeau RBIF, qui est censé indiquer un changement d'état quelconque sur RB4,5,6 ou 7 (si j'ai bien compris la doc), reste toujours bloqué à 0...

  18. #17
    lpt1com2

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    J'ai proposé cette solution parce que tu parlais d'un métronome, ça ne pédale pas à 10 MHz ! Le test d'un IF est dérisoire dans ce cas-là. Pour la consommation du temps de "calcul", c'est vrai, sauf que le traitement de l'anti-rebond (obligatoire) te consommera du temps aussi. Maintenant, si c'est pour t'entraîner à gérer les interruptions, c'est autre chose. Perso, je n'utilise les interruptions que quand elles sont incontournables, par exemple pour sauvegarder des variables en EEPROM quand il y a une coupure de jus.
    Il vaut mieux être le deuxième mari d'une veuve, que le premier

  19. #18
    antek

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    Citation Envoyé par scaypapa Voir le message
    En plaçant le code lié à l'appui ou au relâchement d'un bouton dans le main, d'abord, on teste à chaque boucle l'appui ou non du bouton (ce qui est inutile dans les faits et consomme du temps de calcul, même s'il est minime), ensuite l'appui sur le bouton ne sera pris en compte qu'au moment où on le teste (si je veux couper mon programme au milieu en cas d'appui, ça ne pourra se faire qu'à un moment précis en testant le bouton à ce moment là) et si le bouton est appuyé très brièvement pendant le déroulement du programme (entre deux tests), l'appui ne sera pas pris en compte.
    Comme ça ne demande pas un temps de réaction critique :
    - dans la gestion INT tu places une variable bit (var_bit0)
    - dans le programme tu testes cette variable
    - si 0 ne rien faire
    - si 1 remettre var_bit0 à 0 puis executer le changement

  20. #19
    scaypapa

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    Citation Envoyé par lpt1com2 Voir le message
    J'ai proposé cette solution parce que tu parlais d'un métronome, ça ne pédale pas à 10 MHz ! Le test d'un IF est dérisoire dans ce cas-là. Pour la consommation du temps de "calcul", c'est vrai, sauf que le traitement de l'anti-rebond (obligatoire) te consommera du temps aussi. Maintenant, si c'est pour t'entraîner à gérer les interruptions, c'est autre chose. Perso, je n'utilise les interruptions que quand elles sont incontournables, par exemple pour sauvegarder des variables en EEPROM quand il y a une coupure de jus.
    Oui, mon "métronome" n'a strictement aucun autre intérêt que d'apprendre à utiliser les différentes fonctions dont je pourrais avoir besoin à l'avenir Si j'avais par exemple l'intention d'utiliser le convertisseur analogique/numérique, je pense que j'aurai ajouté un potar sur une entrée pour régler le tempo (c'est ridicule d'utiliser un métronome dont le tempo n'est réglable que par programmation du µC !), mais pour le moment je n'en vois pas l'intérêt pour mes éventuelles applications.

    Ce que je comprends mal dans mon cas, c'est que mon montage puisse fonctionner à merveille sur une patte (INT0) et plus du tout sur les autres (INT1 ou INT2) et que je ne parvienne pas à faire varier le drapeau RBIF. En effet, même s'il reste quelques oscillations lors de l'appui sur mon bouton poussoir, le drapeau devrait avoir été placé à 1 puisqu'il y a bien eu un changement (dans le main, la ligne "if (PORTBbits.RB4 == 1)" est parfaitement prise en compte).
    Dernière modification par scaypapa ; 27/06/2016 à 18h31.

  21. #20
    antek

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    Citation Envoyé par scaypapa Voir le message
    J'ai d'ailleurs fait ce que tu disais avec RB4 pour vérifier que la position du bouton poussoir était correctement détectée par le µC (ce qui est bien le cas). Mais bizarrement, le drapeau RBIF, qui est censé indiquer un changement d'état quelconque sur RB4,5,6 ou 7 (si j'ai bien compris la doc), reste toujours bloqué à 0...
    Si RBIF ne passe pas à 1 ton programme ne passe pas dans l'interruption.
    Si tu constates qu'il est à 0 c'est parce que tu le testes en dehors du programme interruption.
    On le remet à 0 avant retfie

  22. #21
    scaypapa

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    Citation Envoyé par antek Voir le message
    Si RBIF ne passe pas à 1 ton programme ne passe pas dans l'interruption.
    Si tu constates qu'il est à 0 c'est parce que tu le testes en dehors du programme interruption.
    On le remet à 0 avant retfie
    Je dis qu'il ne passe pas à 1 parce que justement, le programme ne rentre pas dans l'interruption : je fais clignoter un LED dans l'interruption (pas très catholique puisque j'y introduit des délais, mais c'est uniquement une vérification) quelque soit la valeur de RB4 testée mais rien ne se passe...
    Aussi, j'ai voulu essayer le mode debugger et je peux bien vérifier que RB4 passe de 0 à 1 et qu'il est parfois différent de LATB4. En revanche, INTCONbits.RBIF est toujours indiqué à 0 dans mes variables suivies.

  23. #22
    DAUDET78

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    Citation Envoyé par scaypapa Voir le message
    je fais clignoter un LED dans l'interruption (pas très catholique puisque j'y introduit des délais, mais c'est uniquement une vérification)
    Retire tes délais !
    Quand tu passes dans l'interruption , tu allumes la LED si elle est éteinte, tu l’éteins si elle est allumée .
    J'aime pas le Grec

  24. #23
    antek

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    Citation Envoyé par scaypapa Voir le message
    Je dis qu'il ne passe pas à 1 parce que justement, le programme ne rentre pas dans l'interruption : je fais clignoter un LED dans l'interruption (pas très catholique puisque j'y introduit des délais, mais c'est uniquement une vérification) quelque soit la valeur de RB4 testée mais rien ne se passe...
    Aussi, j'ai voulu essayer le mode debugger et je peux bien vérifier que RB4 passe de 0 à 1 et qu'il est parfois différent de LATB4. En revanche, INTCONbits.RBIF est toujours indiqué à 0 dans mes variables suivies.
    Alors c'est un problème de configuration des entrées.

    Fait un programme archi-simple : une entrée pour INT, une sortie pour led et rien d'autre, en procédant comme dans le #18.

  25. #24
    scaypapa

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    Merci beaucoup. Mais j'avoue que je ne comprends pas du tout :
    J'ai essayé de suivre à la lettre vos conseils. Donc voici mon programme tout raccourci (j'ai même désactivé l'oscillateur externe) :
    Code:
    /* 
     * File:   main.c
     * Essai InterruptOnChange
     *
     * Created on June 27, 2016, 10:24 PM
     */
    
    #include <xc.h>
    
    // CONFIG1H
    #pragma config FOSC = INTIO67   // Oscillator Selection bits (Internal Oscillator Block))
    
    // CONFIG2H
    #pragma config WDTEN = OFF      // Watchdog Timer Enable bits (Watch dog timer is always disabled. SWDTEN has no effect.)
    
    // CONFIG3H
    #pragma config PBADEN = OFF     // PORTB A/D Enable bit (PORTB<5:0> pins are configured as digital I/O on Reset)
    #pragma config MCLRE = EXTMCLR  // MCLR Pin Enable bit (MCLR pin enabled, RE3 input pin disabled)
    
    #define _XTAL_FREQ  1000000
    // I/O
    #define BP          PORTBbits.RB4
    #define LED         PORTDbits.RD0
    
    char interTouche;
    
    void interrupt IOC(void)
    {
        if (INTCONbits.RBIF) {
            interTouche = 1;
            if (BP);    // juste histoire de le lire pour pouvoir effacer le drapeau
            INTCONbits.RBIF = 0;
        }
    }
    
    void main(void)
    {
        //Init
        TRISB = 1;              // Config PORTB en entrée
        LATB = 0XFF;
        TRISA = TRISD = 0;      // Config PORTD en sortie
        PORTA = 0;
        LED = 1;
        
        // Rb4-7 onChangeInterrupt
        INTCONbits.RBIE = 1;
        if(!BP) BP = 1;                 // juste histoire de le lire pour pouvoir effacer le drapeau
        INTCONbits.RBIF = 0;
        
        // Pullup
        INTCON2bits.RBPU = 1;
        
        interTouche = 0;
        INTCONbits.GIE = 1;
        
        while (1)
        {
            if (interTouche) {
                interTouche = 0;
                for (i=0; i<5; i++) {
                    LED = 0;
                    __delay_ms(20);
                    LED = 1;
                    __delay_ms(20);
                }
            }
    
        }
    }
    Et j'ai branché l'interrupteur sur Rb4 comme sur le shéma de Daudet #4 à quelques différences près.
    • je n'ai pas de trigger de Schmitt tout fait, donc ça va direct à l'entrée
    • j'ai eu peur de mettre un condo polarisé (il y a des risques de courants inverses ?) et en non polarisé, mon maximum est 220nF
    • avec une résistance de 115Ω , la tension à Rb4 était de 2,2V et était vue comme un état haut, donc j'ai baissé la résistance à 16Ω (valeurs mesurées) et cette fois Rb4 change d'état quand on actionne l'inter
    Du coup, vu que j'ai mis une résistance de pullup de 10k, j'ai désactivé le pullup interne.

    Résultat : toujours rien. J'ai essayé pour voir de remplacer dans la boucle principale if (interTouche) par if (!BP). La LED se met bien à clignoter quand le bouton est enfoncé.

    Pour illustrer le tout, j'ai essayé le mode debuggage et avancé en pas à pas dans la boucle principale, voici les valeurs pour RBIF, RB4 et LATB (j'ai ajouté RBIE pour montrer qu'il est bien activé).

    Capture d’écran 2016-06-28 à 00.29.59.png
    Appuie sur le BP
    Capture d’écran 2016-06-28 à 00.30.35.pngCapture d’écran 2016-06-28 à 00.30.50.png
    Relâchement
    Capture d’écran 2016-06-28 à 00.31.03.pngCapture d’écran 2016-06-28 à 00.31.11.png

    Il y a en effet probablement quelque chose que j'ai mal configuré, mais j'ai l'impression d'avoir fait le tour un millier de fois et d'arriver toujours au même point...

  26. #25
    scaypapa

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    J'ai fait également un essai sur les Int 0, 1 et 2 avec le même code (hormis les lectures répétées du bouton puisqu'eux n'ont pas besoin d'être lus pour réinitialiser le drapeau.
    Ca fonctionne très bien hormis qu'au lieu de prendre un front unique (montant par défaut). Certainement à cause des rebonds non gérés de manière logicielle.

  27. #26
    scaypapa

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    C'est bien ça, avec un délai avant la lecture, ça fonctionne bien. C'est à cause de la fréquence d'horloge trop élevée qu'un condensateur ne peut pas suffire à gérer ça ?
    Du coup, inutile de préciser si l'on veut une interruption sur un front montant ou descendant quand on utilise ce type d'interruptions.
    Dernière modification par scaypapa ; 28/06/2016 à 00h25.

  28. #27
    scaypapa

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    Désolé pour les messages à répétition mais je ne peux pas modifier mes messages après 5mn, ce qui ne laisse pas bcp de temps pour les essais

    J'ai essayé de faire tourner le programme en debuggage pas à pas en faisant fonctionner le Int2. Du coup, les interruptions sont zappées, ça doit être dû au mode pas à pas (ou à ma mauvaise gestion de ce mode).
    Donc mes copies d'écran sur les valeurs instantanées de RBIF, RB4 et LATB4 ne donnent pas grand chose. Ce qui n'empêche pas que le mode interrupt on change ne fait strictement rien avec mon code (même en laissant tourner le programme en continu)…

  29. #28
    scaypapa

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    Ca avance : j'ai modifié le code pour pouvoir passer le BP d'une patte à l'autre et tester les différentes réactions :

    Code:
    #define BP          PORTBbits.RB2
    #define BP2         PORTBbits.RB4
    #define LED         PORTDbits.RD0
    
    char interTouche;
    
    void interrupt IOC(void)
    {
        if (INTCONbits.RBIF) {
            interTouche = 1;
            if (BP2) NOP();    // juste histoire de le lire pour pouvoir effacer le drapeau
            INTCONbits.RBIF = 0;
        }
        if (INTCON3bits.INT2IF) {
            interTouche = 1;
            INTCON3bits.INT2IF = 0;
        }
    }
    
    void main(void)
    {
        int i;
        
        //Init
        TRISB = 1;              // Config PORTB en entrée
        LATB = 0XFF;
        ANSELD = 0;
        TRISD = 0;      // Config PORTD en sortie
        LED = 1;
        
        // Int2 Interrupt
        INTCON3bits.INT2IE = 1;
        INTCON3bits.INT2IF = 0;
        
        
        // Rb4-7 onChangeInterrupt
        INTCONbits.RBIE = 1;
        if(BP2);                 // juste histoire de le lire pour pouvoir effacer le drapeau
        INTCONbits.RBIF = 0;
        
        // Pullup
        INTCON2bits.RBPU = 1;
        
        interTouche = 0;
        INTCONbits.GIE = 1;
        
        while (1)
        {
            if (interTouche) __delay_ms (20);
            if (interTouche && (!BP || !BP2))
            {
                interTouche = 0;
                LED = !LED;
            }
        }
    }
    Désormais, la LED change d'état si l'on appuie sur RB2 (interruption int).
    Dans l'idée, je pensais qu'elle ferait pareil pour RB4 après avoir déplacé l'inter sur cette patte (interruption ioc).

    Mais elle ne change d'état qu'une seule fois. Au second appui sur RB4, rien ne se passe.
    En revanche, si je remets l'inter sur RB2 et l'actionne, la LED change à nouveau. Puis si je le remet sur RB4, il refonctionne bien... une fois seulement.

    Aussi, avec cette méthode (gestion de l'anti-rebond du BP dans le main), en effet les interruptions sur les inter ne servent à rien puisqu'il faudra appuyer sur l'interrupteur au moment de la vérification. Si le main est un peu plus long et qu'on appuie à un moment quelconque, il y a peu de chances que l'appui soit pris en compte, quelque soit la patte utilisée.

    Sur ce, au lit.
    Dernière modification par scaypapa ; 28/06/2016 à 02h00.

  30. #29
    invite03481543

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    Citation Envoyé par scaypapa Voir le message
    Désolé de vous avoir embêté, je pensais juste trouver des explications intéressantes ici afin d'avancer dans l'étude des µC.
    Ecoute mon petit gars, si tu viens ici pour apprendre et que tu n'écoutes que ce qui t'arrange dans ce cas débrouille toi tout seul.
    Maintenant je te laisse entre les mains des fameux "spécialistes" ci-dessus.
    Une méthode de polling d'un coté et de l'autre un gars qui n'utilisent les interruptions que quand il n'a pas le choix
    Avec ça tu vas apprendre c'est sur.
    Allez, bon vent.

  31. #30
    lpt1com2

    Re : Gestion d'un bouton poussoir sur microcontrôleur

    Citation Envoyé par HULK28 Voir le message
    Maintenant je te laisse entre les mains des fameux "spécialistes" ci-dessus.
    Une méthode de polling d'un coté et de l'autre un gars qui n'utilisent les interruptions que quand il n'a pas le choix
    Avec ça tu vas apprendre c'est sur.
    Mes oreilles ont sifflé en lisant ton message. Je précise que je ne suis pas « spécialiste », et que je ne faisais part que d’une convenance personnelle. Evidemment que j’utilise les interruptions pour un timer, l’UART, ou d’autres tâches prioritaires. En tous cas, j’évite quand c’est possible leur usage immodéré (certes ce n’est pas le cas ici, et encore moins d’interruptions imbriquées), mais il est vrai que j’applique peut-être un peu trop à la lettre les recommandations des vrais « spécialistes » qui ont conçu le compilateur que j’utilise :
    “If an interrupt nesting is undispensable, the compiler switch {$NOSAVE} must be used. So only the flags and the main work registers are saved. The procedures PushAllRegs and PopAllRegs can be used to save the remaining registers via the stack if necessary. Interrupt nesting is very dangerous and ends frequently in a system crash. It should be avoided whenever possible. At least a very careful planning an absolute necessity.”

    Cela dit, je ne sais pas si tu faisais allusion, dans ta critique, au post #18 de antek. Sa solution me semble pourtant adéquate, mais je n’en vois peut-être pas les inconvénients.
    Il vaut mieux être le deuxième mari d'une veuve, que le premier

Page 1 sur 3 12 DernièreDernière

Discussions similaires

  1. Bouton poussoir farçeur (énervant) [résolu]
    Par invite424deccd dans le forum Bricolage et décoration
    Réponses: 29
    Dernier message: 10/09/2012, 17h53
  2. Bouton poussoir et minuterie ? [résolu]
    Par crobe dans le forum Bricolage et décoration
    Réponses: 15
    Dernier message: 03/04/2011, 14h42
  3. Gestion de bouton poussoir - différencier appui bref ou long
    Par micr0m dans le forum Électronique
    Réponses: 3
    Dernier message: 07/09/2010, 09h31
  4. [C/PIC] - Gestion bouton poussoir
    Par jorg1n dans le forum Électronique
    Réponses: 6
    Dernier message: 29/04/2009, 07h07
  5. Gestion Bouton poussoir ON/OFF
    Par jorg1n dans le forum Électronique
    Réponses: 22
    Dernier message: 19/10/2007, 15h24
Découvrez nos comparatifs produits sur l'informatique et les technologies.