Auteur Sujet: LaunchPad tuto 003 : Gérer un bouton (et par extension, les interrupts)  (Lu 13295 fois)

Hors ligne KodeIn

  • Grand Pilier
  • *
  • Messages: 929
  • Localisation: Reims
  • Adepte du Level 1… quand il passe le level tuto…
    • Voir le profil
Une première interface de dialogue homme-machine : le bouton
Et oui, tout le monde le sait, surtout sur un forum dédié à l'arcade, que le bouton-poussoir est la plus belle invention de l'homme pour se faire comprendre d'une machine.
La seconde plus belle étant, à mon avis, le microswitch qui a grandement amélioré la première!   :P
Et donc, nous allons utiliser un bouton pour faire comprendre à notre µC qu'à certains moments, on veut que nos leds clignotent et pas à d'autres. (et je cite Balladur: "Je vous demande de vous arrêter!")


Tout d'abord, un rappel des opérateurs bitwise.
Parce que c'est toujours utile!  :D
AND : &
|
OR : |
|
XOR : ^
|
NOT : ~
BitA BitB BitA&BitB
0
0
0
0
1
0
1
0
0
1
1
1
|
BitA BitB BitA|BitB
0
0
0
0
1
1
1
0
1
1
1
1
|
BitA BitB BitA^BitB
0
0
0
0
1
1
1
0
1
1
1
0
|
BitA ~BitA
0
1
1
0
Et n'oubliez pas que ces opérations s'effectuent bit à bit!

Les éléments du MSP430G2231 que nous utiliserons lors de ce tuto.




Intro
Pour cet exercice, on va partir du tuto-002 avec de légères modifications pour rendre le code plus "solide".
#include <msp430g2231.h>

void main(void)
{
 WDTCTL = WDTPW | WDTHOLD; // désactivation du watchdog
 P1OUT &= ~(BIT0 | BIT6); // bits de sorties correspondants à P1.0 et P1.6 à 0
 P1DIR |= (BIT0 | BIT6); // définit P1.0 et P1.6 en tant que sorties

 for (;;)
 {
  P1OUT ^= (BIT0 | BIT6); // inversion de l'état des bits de sorties 0 et 6
  __delay_cycles(250000); // de manière a réduire la vitesse de clignotement
 }
}

Vous remarquerez que l'opérateur de concaténation/addition "+" a disparu.
La raison est simple, cet opérateur additionne bêtement les valeurs : 0000‿0001₂ + 0000‿0001₂ = 0000‿0010₂.
Hors, vu que nous manipulons majoritairement des valeurs binaires, les opérateurs bitwise permettent d'éviter des bourdes : 0000‿0001₂ | 0000‿0001₂ = 0000‿0001₂.
Donc si par erreur on tape P1OUT ^= (BIT0 | BIT0); seul le BIT0 de P1OUT sera modifié.
Alors qu'avec P1OUT ^= (BIT0 + BIT0); on se serait retrouvé avec le BIT1 de P1OUT modifié… bonjour le merdier!
(Merci a Keube pour m'avoir signalé ça dans le tuto-002  ^-)

Premiers pas dans la gestion du bouton poussoir
Pour que notre µC sache que notre bouton, raccordé à P1.3, est une entrée, il suffit de définir le BIT3 de P1DIR à 0. Ou de ne pas toucher au BIT3 de P1DIR, par défaut tous les bits de registres sont réinitialisés à 0 à chaque démarrage du µC (mon choix personnel).
 
Comment récupérer l'état du bouton? Deux solutions se présentent à nous.
La première, est d'aller voir "manuellement" quel est l'état du BIT3 de P1IN dans une boucle. Cette méthode est tout à fait fonctionnelle, mais un peu laborieuse et on va gaspiller pas mal de ressources.

Les MSP430 nous permettent une seconde solution bien plus "raffinée" et performante pour gérer ce genre d'événements. Et ce sont les interruptions.
Une interruption, comme son nom l'indique, interrompt le processus en cours d'exécution, "note" l'endroit où il en était dans son processus, et exécute le code lié à l'interruption, puis reprend là où il en était. Je ne rentrerai pas dans les détails de ce processus, cette petite explication rapide est suffisante pour comprendre le principe fondamental. Dans notre cas, l'interruption se déclenchera lorsque l'on poussera sur le bouton.
Conclusion, nous allons nous oublier P1IN en faveur de P1IE (Port 1 Interrupt) et passer le BIT3 de ce dernier à 1 pour définir P1.3 comme déclencheur d'interruption. P1IE |= BIT3;Mais il faut aussi activer le gestionnaire d'interrupts dans le µC, pour ça, il est nécessaire de rajouter la ligne suivante après l'assignation du BIT3 au gestionnaire d'interruptions du port 1__enable_interrupt();
Le corps du code
Bon, on a définit la condition de déclenchement de l'événement, maintenant, il faut définir modifier la boucle de clignotement des leds.
Le plus simple est d'utiliser une variable et une condition. On initialise cette variable à 0, on va utiliser une variable globale de type nombre entier non signé.
(Variable globale = variable définie en dehors des fonctions. Nombre entier non signé ça signifie que si on lui assigne un chiffre négatif, il ne tiendra pas compte du "-")
unsigned int blinking = 0;Dans la boucle, si cette variable est plus grande que 0, alors le changement d'état des deux bits contrôlant les leds se produit, sinon, on continue la boucle.
for (;;)
 {
  if(blinking > 0){
   P1OUT ^= (BIT0 | BIT6); // inversion de l'état des bits de sorties 0 et 6
  __delay_cycles(250000); // de manière a réduire la vitesse de clignotement
  }
 }

Ce qui s'exécute durant l'interruption
Il nous reste encore à produire le code qui va s'exécuter lors d'une interruption.
#pragma vector=PORT1_VECTOR
De façon générale dans les microcontroleurs on trouve une table de vecteurs d'interruptions à une adresse donnée de la mémoire. Sur le msp430 (celui du tuto?) elle se trouve entre 0x0FFFFh et 0xFFC0h.
A chaque adresse correspond une fonction à appeler quand l'interruption tombe.  Par exemple, toujours sur le même micro, l'interruption correspondant au port 1 se trouve en 0x0FFE4h.
Ton #pragma vector=PORT1_VECTOR va donc placer une "redirection" vers l'interruption __interrupt void Port_1(void) à cette adresse.

Note qu'elle est commune à tout le port 1, et tu dois donc y gérer les interruptions des 8 pins si tu en actives plusieurs.

__interrupt void Port_1(void)
{
Le "__interrupt" préviens que ce n'est pas une simple fonction, mais le code de gestion de l'interruption. Cette fonction particulière, ne renverra rien - le "void" - et ne prends rien comme argument - le (void) -.

blinking ^= 0x01;
Alors, le préfixe 0x indique au compilateur que la valeur est une valeur haxadécimale. Par défaut, les valeurs hexadécimales sont codées sur 16 bits, juste ce qu'il nous faut pour "remplir" un unsigned int. 0x01 vaut donc 0000‿0000‿0000‿0001₂.
Pour le reste, vous devriez être capable de comprendre l'effet de cette ligne de code.

P1IFG &= ~BIT3;
P1IFG (Port 1 Interrupt FlaG) est - semble-t-il - le registre dans lequel sont stockés le fait qu'un interrupt s'est déclenché sur un des bits. Pour que l'interrupt puisse à nouveau se produire, il faut nettoyer le registre, d'après ce que j'ai compris.

//OPTIONNEL
P1IES ^= BIT3;
P1IES - Port 1 Interrupt Edge Select - ce registre va permettre de sélectionner sur quel flanc du signal l'interruption va se produire. Si un bit est à 0 (par défaut), c'est le flanc montant, à 1 c'est le flanc descendant.
Ce que cette ligne de code fait, c'est que les leds ne clignoteront que lorsque le bouton sera enfoncé.
//OPTIONNEL

P1OUT &= ~(BIT0 | BIT6);
}
Et on s'assure que les leds soient éteintes.

Résultat
Ce qui nous donne, au démarrage du µC, les leds sont éteintes, on appuie sur le bouton P1.3 , les leds se mettent à clignoter. Et si on appuie à nouveau, les leds s'éteignent.

#include <msp430g2231.h>

unsigned int blinking = 0; //variable globale contrôlant le clignotement

void main(void)
{
 WDTCTL = WDTPW | WDTHOLD; // désactivation du watchdog
 P1OUT &= ~(BIT0 | BIT6); // bits de sorties correspondants à P1.0 et P1.6 à 0
 P1DIR |= (BIT0 | BIT6); // définit P1.0 et P1.6 en tant que sorties
 P1IE |= BIT3;

 __enable_interrupt();

 for (;;)
 {
  if(blinking > 0){ // si blinking est plus grand que 0, alors on clignote, sinon, on ne fait rien
   P1OUT ^= (BIT0 | BIT6); // inversion de l'état des bits de sorties 0 et 6
  __delay_cycles(250000); // de manière a réduire la vitesse de clignotement
  }
 }
}

#pragma vector=PORT1_VECTOR // Joker
__interrupt void Port_1(void) // initialisation de la fonction interrupt
{
 blinking ^= 0x01 // blinking étant une variable globale, elle est aussi accessible depuis l'interrupt et ici, on inverse l'état de son BIT0
 P1IFG &= ~BIT3; // Remise à 0 du flag d'interrupt
 // P1IES ^= BIT3; // Changement de flanc pour la génération d'interruption
 P1OUT &= ~(BIT0 | BIT6); // on s'assure que les leds sont bien éteintes après un appuis sur le bouton
}

Challenge!
Je vais corser un peu par rapport au précédent.
Pour ce challenge, vous allez partir de votre solution au challenge précédent.
Ensuite, il faut qu'au démarrage les 2 leds soient éteintes.
Au premier appuis sur le bouton, les leds doivent clignoter alternativement.
Au second appuis, les deux doivent être éteintes.
Et bien sur, ça doit fonctionner plus de 2 fois sans reset  ;)

Si vous voulez pousser le vice à fond, il y a une requête supplémentaire, il faut qu'au troisième appuis, le clignotement reprenne là où il avait été interrompu!
(Challenge battu, même la partie vicieuse =:)) )



Encore merci à Keube, il m'est d'une grande aide, aussi bien pour la rédaction que pour améliorer ma façon de coder  ^-^



Méthodes pour me contacter
Au cas où vous rencontriez une embûche, si vous voulez discuter ou approfondir les explications ou les explorations à propos de ces tutos, voici quelques méthodes pour me contacter :
- par ce sujet
- par MP
- par mail
- par jabber
- par msn
J'utilise la même adresse mail pour msn et jabber: kodein AT reflexd.com (j'essaye d'éviter les moissonneurs automatiques d'adresse ;) ).
« Modifié: Dimanche 10 Juillet 2011, 23:12:41 pm par KodeIn »
Atari 2600 | Spectravideo SV-328 :'( | Amiga 500 | NES - SNES - N64 - NGC - Wii - GBA - GBAsp - DSi | PS1 - PS2 - PS3 - PSP 2000 | MD - DC | XBox - 360 | MacBook | OpenPandora GHZ edition \o/
WIP [pause] : Borne Euro générique de chez Jeux COURTET
Tutos LaunchPad MSP430 001 - 002 - 003 - 004 en attente

Hors ligne CuBe

  • Addict
  • *
  • Messages: 345
  • Localisation: Lyon
  • Insert coin
    • Voir le profil
LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
« Réponse #1 le: Mercredi 25 Mai 2011, 10:54:19 am »
  • Sympa tes tutos comme toujours!

    Je sens que je vais craquer d'ici peu pour un kit ^^

    Sinon une petite erreur sur la colonne "XOR : |" au lieux de "XOR : ^"  ^-
    WIP Cocktail PacMan Midway :D
    RoadTrip New Astro City

    Recherche :
    -Metal Slug 5
    -Thunder Hoop

    Hors ligne KodeIn

    • Grand Pilier
    • *
    • Messages: 929
    • Localisation: Reims
    • Adepte du Level 1… quand il passe le level tuto…
      • Voir le profil
    LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
    « Réponse #2 le: Mercredi 25 Mai 2011, 11:16:42 am »
  • Haha, bourde spotted :D

    Bah écoute, sans vouloir passer pour un marchand de tapis… c'est le kit "ready to program" le moins cher que j'aie trouvé.
    En plus, il a le gros avantage d'être en USB, mon ordi principal étant un portable récent, nanapu de port série!
    Donc mon vieux programmateur de PIC (donné par un pote) était resté à l'abandon.
    Il aurait fallu acheter convertisseur USB to Serial, mais ça m'aurait couté plus cher que le launchpad complet. :P
    Atari 2600 | Spectravideo SV-328 :'( | Amiga 500 | NES - SNES - N64 - NGC - Wii - GBA - GBAsp - DSi | PS1 - PS2 - PS3 - PSP 2000 | MD - DC | XBox - 360 | MacBook | OpenPandora GHZ edition \o/
    WIP [pause] : Borne Euro générique de chez Jeux COURTET
    Tutos LaunchPad MSP430 001 - 002 - 003 - 004 en attente

    Hors ligne Maitre_Poulpi

    • ✌ Donateur depuis 2018
    • Alien
    • *
    • Messages: 4945
    • Localisation: Loire - Firminy
    • Consoles au fil je suis, ordis aussi
      • Voir le profil
    LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
    « Réponse #3 le: Mercredi 25 Mai 2011, 11:35:17 am »
  • bah t'as intérêt de continuer  :-*
    Dès que je vais m'y mettre je vais tous les faire  ;)
    May the Gamooforce be with you !
    À partir du moment où un fou sait qu'il l'est, peut-on toujours le nommer ainsi ?
    Boulot, rétro, dodo... et un peu (beaucoup) de TATC...

    Hors ligne KodeIn

    • Grand Pilier
    • *
    • Messages: 929
    • Localisation: Reims
    • Adepte du Level 1… quand il passe le level tuto…
      • Voir le profil
    LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
    « Réponse #4 le: Mercredi 25 Mai 2011, 14:31:47 pm »
  • Et ben j'espère que mes tutos t'aideront à bien débuter! ;)
    Bon, c'est pas tout ça, faut que je comprenne à quoi servent certaines lignes de codes dans la partie gestion de l'interrupt, moi  =:))
    Atari 2600 | Spectravideo SV-328 :'( | Amiga 500 | NES - SNES - N64 - NGC - Wii - GBA - GBAsp - DSi | PS1 - PS2 - PS3 - PSP 2000 | MD - DC | XBox - 360 | MacBook | OpenPandora GHZ edition \o/
    WIP [pause] : Borne Euro générique de chez Jeux COURTET
    Tutos LaunchPad MSP430 001 - 002 - 003 - 004 en attente

    Hors ligne KodeIn

    • Grand Pilier
    • *
    • Messages: 929
    • Localisation: Reims
    • Adepte du Level 1… quand il passe le level tuto…
      • Voir le profil
    LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
    « Réponse #5 le: Jeudi 26 Mai 2011, 10:31:09 am »
  • Désolé pour le double post, mais après relecture de mon tuto, je pense que le contenu essentiel est présent.
    Donc je fais un petit up pour vous demander ce que vous en pensez.
    Et vous invite à dénicher mes fautes de grammaire, d'orthographe, et autres fautes de frappes.

    Dans le coin des bémols :
    Il me reste encore à trouver l'explication exacte de deux lignes de code, par contre.
    Donc si vous trouver des explications potables et pas juste "bon faut mettre ça parce que c'est comme ça qu'on fait et c'est tout", j'apprécierais ;)
    Et je n'ai toujours pas eu le temps de réaliser mon challenge à 100% lol

    EDIT:
    Tien, si on fait le déclenchements d'interrupts sur le flanc montant et sur le flanc descendant du poussage de bouton, y aurait même moyen de fabriquer un… AUTOFIRE :D
    En l'état, c'est un autofire avec "cruise control" ;)
    Et pour piloter la vitesse de l'autofire, on pourrait ajouter un potentiomètre branché sur le convertisseur "analog-to-digital" (ADC) du MSP430G2231, combiné avec un Timer, ça pourrait le faire! (ça vous rappelle rien? ;D)
    M'en vais étudier la question…

    EDIT 2:
    Ou on pourrait prévoir un espèce de "mode d'apprentissage" pendant lequel on appuie 2 fois sur le bouton pour définir l'intervalle de l'autofire.
    Ça nous permettrait de faire tout depuis le panel de la borne et nous passer du potard.  :P
    (C'est quel voltage sur les boutons d'un panel? 5V?)
    « Modifié: Jeudi 26 Mai 2011, 16:07:15 pm par KodeIn »
    Atari 2600 | Spectravideo SV-328 :'( | Amiga 500 | NES - SNES - N64 - NGC - Wii - GBA - GBAsp - DSi | PS1 - PS2 - PS3 - PSP 2000 | MD - DC | XBox - 360 | MacBook | OpenPandora GHZ edition \o/
    WIP [pause] : Borne Euro générique de chez Jeux COURTET
    Tutos LaunchPad MSP430 001 - 002 - 003 - 004 en attente

    Hors ligne keube

    • Passionné
    • *
    • Messages: 160
    • Localisation: Asnières sur Seine / Metz
      • Voir le profil
    LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
    « Réponse #6 le: Jeudi 26 Mai 2011, 23:54:18 pm »
  • De façon générale dans les microcontroleurs on trouve une table de vecteurs d'interruptions à une adresse donnée de la mémoire. Sur le msp430 (celui du tuto?) elle se trouve entre 0x0FFFFh et 0xFFC0h. A chaque adresse correspond une fonction à appeler quand l'interruption tombe. Par exemple, toujours sur le même micro, l'interruption correspondant au port 1 se trouve en 0x0FFE4h. Ton #pragma vector=PORT1_VECTOR va donc placer l'interruption __interrupt void Port_1(void) à cette adresse. Note qu'elle est commune à tout le port 1, et tu dois donc y gérer les interruptions des 8 pins si tu en actives plusieurs.
    Autre remarque sur ta façon de coder: il n'est pas prudent de gérer l'état de la sortie dans le corps principale et dans l'interruption: dans des codes un peu plus compliqués c'est le meilleur moyen pour se retrouver avec une incohérence à un moment donné. Je ne sais pas trop ce que fait la fonction __delay_cycles() (des nop()?) mais on peut très bien imaginer que l'interruption tombe 2 fois pendant ce temps. Ta variable blinking et ta sortie vont se contredire...
     

    Hors ligne KodeIn

    • Grand Pilier
    • *
    • Messages: 929
    • Localisation: Reims
    • Adepte du Level 1… quand il passe le level tuto…
      • Voir le profil
    LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
    « Réponse #7 le: Vendredi 27 Mai 2011, 01:39:58 am »
  • Merci pour l'explication au sujet de #pragma et des vecteurs d'interruption! Après une bonne nuit de sommeil, je mettrai à jour le tuto avec ton explication. Et effectivement, tu fais bien de préciser que pour le port 1, l'interruption est commune pour les 8 I/O (et ça doit être pareil pour tous les Port# des MSP430, si je ne m'abuse).

    Pour ma façon de coder, effectivement, ça ne doit pas être la manière la plus fiable ou prudente.
    J'espère m'améliorer avec le temps, et ne pas apprendre trop de bêtises aux gens auxquels j'explique :-[
    Franchement, je me fais un peu l'impression d'un imposteur avec mes tutos alors que je ne sais pas vraiment de quoi je parle :P
    Je me rends compte qu'il faudrait peut-être que je cède la place à un rédacteur qui s'y connaisse vraiment.
    (j'ai l'impression d'avoir mal expliqué les interruption, à trop vouloir rentrer dans les détails et il me semble que je me suis planté)

    Sinon, je ne sais pas ce que produit nop(), mais d'après ce que j'ai compris, __delay_cycles() va insérer du code "dummy" qui va occuper le processeur durant le nombre de cycles d'horloge spécifié entre les parenthèses, sans aucun autre effet.
    Et donc, toujours si j'ai bien compris, l'interruption peut se déclencher 2, 3, 4 fois pendant __delay_cycles, sans poser de soucis.
    Il faudrait que j'essaye d'augmenter le nombres de cycles et d'appuyer plusieurs fois sur le bouton pour vérifier ça.
    « Modifié: Vendredi 27 Mai 2011, 01:43:31 am par KodeIn »
    Atari 2600 | Spectravideo SV-328 :'( | Amiga 500 | NES - SNES - N64 - NGC - Wii - GBA - GBAsp - DSi | PS1 - PS2 - PS3 - PSP 2000 | MD - DC | XBox - 360 | MacBook | OpenPandora GHZ edition \o/
    WIP [pause] : Borne Euro générique de chez Jeux COURTET
    Tutos LaunchPad MSP430 001 - 002 - 003 - 004 en attente

    Hors ligne keube

    • Passionné
    • *
    • Messages: 160
    • Localisation: Asnières sur Seine / Metz
      • Voir le profil
    LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
    « Réponse #8 le: Vendredi 27 Mai 2011, 08:21:42 am »
  • nop() => no operation, ça fait rien en clair!
    Les interruptions ce n'ait pas bien compliqué comme concept mais la mise en œuvre est toujours source de surprises! Il faut être super prudent et imaginer les cas tordus, ils finiront toujours par arriver et plus on y pense tôt mieux c'est...
    Ton tuto te permet aussi d'apprendre, et si un débutant le lit il pourra bénéficier des conseils de programmeurs plus aguerris, chose qu'on ne vois pas si le tuto est trop parfait!

    Hors ligne KodeIn

    • Grand Pilier
    • *
    • Messages: 929
    • Localisation: Reims
    • Adepte du Level 1… quand il passe le level tuto…
      • Voir le profil
    LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
    « Réponse #9 le: Vendredi 27 Mai 2011, 09:27:54 am »
  • Okay, maintenant, je sais ce qu'est nop() :D

    Je ferai plus attention aux problèmes que peuvent faire apparaitre les interruptions, merci pour le soutient et les conseils que tu m'apportes.
    En peu de temps, j'ai déjà l'impression d'avoir appris pas mal de choses.

    Je t'ai directement cité - j'espère que ça ne te dérange pas - pour l'explication du pragma etc., ce que tu as écrit me parait particulièrement clair et bien détaillé.


    Il me semble qu'on peut considérer ce tuto comme finalisé… Il est temps de passer au suivant  :D
    « Modifié: Vendredi 27 Mai 2011, 09:32:25 am par KodeIn »
    Atari 2600 | Spectravideo SV-328 :'( | Amiga 500 | NES - SNES - N64 - NGC - Wii - GBA - GBAsp - DSi | PS1 - PS2 - PS3 - PSP 2000 | MD - DC | XBox - 360 | MacBook | OpenPandora GHZ edition \o/
    WIP [pause] : Borne Euro générique de chez Jeux COURTET
    Tutos LaunchPad MSP430 001 - 002 - 003 - 004 en attente

    Hors ligne keube

    • Passionné
    • *
    • Messages: 160
    • Localisation: Asnières sur Seine / Metz
      • Voir le profil
    LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
    « Réponse #10 le: Vendredi 27 Mai 2011, 12:09:41 pm »
  • pas de soucis ;)
    Je reviens un peu sur mon explication (rapide) du #pragma:
    l'interruption n'est pas copiée à l'adresse du vecteur d'interruption puisqu'il n'y de la place que pour un opcode, par contre tu devrais y trouver un code assembleur pour sauter vers ton vers ton interruption (jmp?). On doit pouvoir vérifier ça en regardant le code assembleur généré dans un .quelquechose (.lst?) si tu le demandes au copmpilateur. Enfin bref d'une façon ou d'une autre c'est cette directive de compilation qui va faire le lien entre le vecteur d'interruption et ton __interrupt.
    Le __interrupt spécifie également au compilateur le code assembleur à ajouter par rapport à des fonctions classique: il y a vraisemblablement un mot clé pour définir si on veut ou non faire la sauvegarde des contextes, faire le retour de l'interruption etc... mais là on tape dans le niveau très avancé! Par défaut (99,9% des cas) le __interrupt suffira.
    « Modifié: Vendredi 27 Mai 2011, 12:24:55 pm par keube »

    Hors ligne gc339

    • Beta Testeur
    • *
    • Messages: 2222
    • Localisation: Lyon
      • Voir le profil
    LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
    « Réponse #11 le: Vendredi 27 Mai 2011, 12:23:22 pm »
  • Bonjour.

    Le problème avec un bouton mécanique, c'est que son contact rebondit lors de son établissement/relâchement générant ainsi des parasites qui peuvent semer la confusion dans le programme d'un µC.
    La solution généralement employée consiste à lire périodiquement les "keys" ou "switches" (toutes les 8/10 ms)  à l'aide d'un délai réalisé soit par une boucle logicielle soit par l'interruption d'un timer interne.
    Un changement d'état d'un bouton ne sera effectif que quand ce dernier aura été vu au moins deux fois de suite dans le même état. A partir de ce ce moment là, l'état du bouton sera considéré comme à nouveau stable.
    Cet algorithme nécessite de stocker les états des boutons à chaque lecture afin de comparer les états qui viennent juste d'être lus avec ceux de la lecture antérieure, c'est à dire ceux lus 8/10 ms avant.
    La "e"littérature fourmille d'exemples à ce sujet, il suffit de faire une recherche avec les mots clefs suivants :
    • key, keys, switch ou switches.
    • debounce ou debouncing.
    • et éventuellement "multiple".
    « Modifié: Vendredi 27 Mai 2011, 18:18:13 pm par gc339 »
    Le repos, c'est fait pour les jeunes. Ils ont toute la vie devant eux. J. Gabin/M. Audiard



    Hors ligne keube

    • Passionné
    • *
    • Messages: 160
    • Localisation: Asnières sur Seine / Metz
      • Voir le profil
    LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
    « Réponse #12 le: Vendredi 27 Mai 2011, 12:31:56 pm »
  • Bonjour.

    Le problème avec un bouton mécanique, c'est que son contact rebondit lors de son établissement/relâchement générant ainsi des parasites qui peuvent semer la confusion dans le programme d'un µC.
    La solution généralement employée consiste à lire périodiquement les "keys" ou "switches" (toutes les 8/10 ms)  à l'aide d'un délai réalisé soit par une boucle logicielle soit par l'interruption d'un timer interne.
    Un changement d'état d'un bouton ne sera effectif que quand ce dernier aura été vu au moins deux fois de suite dans le même état. A partir de ce ce moment là, l'état du bouton sera considéré comme à nouveau stable.
    Cet algorithme nécessite de stocker les états des boutons à chaque lecture afin de comparer les états qui viennent juste d'être lus avec ceux de la lecture précédente, c'est à dire ceux lus 8/10 ms avant.
    La "e"littérature fourmille d'exemples à ce sujet, il suffit de faire une recherche avec les mots clefs suivants :
    • key, keys, switch ou switches.
    • debounce ou debouncing.
    • et éventuellement "multiple".

    Tu vas nous le perdre avec le filtrage sur les entrées!
    Comme quoi un exercice a priori tout bête peut se relever plus complexe que prévu.

    Hors ligne KodeIn

    • Grand Pilier
    • *
    • Messages: 929
    • Localisation: Reims
    • Adepte du Level 1… quand il passe le level tuto…
      • Voir le profil
    LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
    « Réponse #13 le: Vendredi 27 Mai 2011, 12:51:16 pm »
  • Effectivement, j'avais lu - en diagonale rapide :) - l'histoire du debounce sur les boutons.
    Mais il me semblait avoir vu quelques circuits simples qui permettait de filtrer ces rebonds parasites.
    Ce qui éviterait de faire du polling - je n'aime vraiment pas cette méthode pour les boutons - et d'encombrer la mémoire avec le précédent état.

    Un montage rudimentaire de ce genre ne ferait-il pas l'affaire?

    Ça permettrait de libérer le µC pour d'autres fonctions plus intéressantes.

    Je vais rectifier pour la "copie", ça doit effectivement être un saut vers l'adresse mémoire où est stocké le code à exécuter lors l'interruption.
    « Modifié: Vendredi 27 Mai 2011, 12:54:26 pm par KodeIn »
    Atari 2600 | Spectravideo SV-328 :'( | Amiga 500 | NES - SNES - N64 - NGC - Wii - GBA - GBAsp - DSi | PS1 - PS2 - PS3 - PSP 2000 | MD - DC | XBox - 360 | MacBook | OpenPandora GHZ edition \o/
    WIP [pause] : Borne Euro générique de chez Jeux COURTET
    Tutos LaunchPad MSP430 001 - 002 - 003 - 004 en attente

    Hors ligne gc339

    • Beta Testeur
    • *
    • Messages: 2222
    • Localisation: Lyon
      • Voir le profil
    LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
    « Réponse #14 le: Vendredi 27 Mai 2011, 13:31:17 pm »
  • je n'aime vraiment pas cette méthode pour les boutons - et d'encombrer la mémoire avec le précédent état.
    Un seul octet pour 8 boutons, c'est quand même pas dispendieux.

    Un montage rudimentaire de ce genre ne ferait-il pas l'affaire?
    Ça permettrait de libérer le µC pour d'autres fonctions plus intéressantes.

    Utiliser une interruption générée par le timer du µC pour lire cycliquement les états des boutons puis leurs appliquer un algorithme anti-rebonds, ce ne serait pas un exercice de programmation intéressant par ce que d'après toi le code nécessaire encombrerait trop la mémoire programme ?

    Debouncing 8 Buttons in 7 Clock Cycles : http://ww1.microchip.com/downloads/en/AppNotes/5_001.pdf
    « Modifié: Vendredi 27 Mai 2011, 17:36:35 pm par gc339 »
    Le repos, c'est fait pour les jeunes. Ils ont toute la vie devant eux. J. Gabin/M. Audiard



    Hors ligne KodeIn

    • Grand Pilier
    • *
    • Messages: 929
    • Localisation: Reims
    • Adepte du Level 1… quand il passe le level tuto…
      • Voir le profil
    LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
    « Réponse #15 le: Vendredi 27 Mai 2011, 14:03:02 pm »
  • Erf, c'est là qu'on voit clairement la différence de niveau entre toi -l'une des référence en matière d'électronique sur ce forum- et moi -petit newbie qui bricole vaguement son µC-.
    J'ai rien dit m'sieur! :-[
    J'ai le droit d'aller me cacher loin dans un tout petit recoin?

    En 7 cycles pour 8 boutons, c'est impressionnant, je n'avais pas réalisé que ça pouvait se faire aussi rapidement et en utilisant aussi peu de code (7byte de rom…).
    Effectivement, ça serait un exercice intéressant à réaliser dans le cadre de cet autofire MSP430 powered.
    Atari 2600 | Spectravideo SV-328 :'( | Amiga 500 | NES - SNES - N64 - NGC - Wii - GBA - GBAsp - DSi | PS1 - PS2 - PS3 - PSP 2000 | MD - DC | XBox - 360 | MacBook | OpenPandora GHZ edition \o/
    WIP [pause] : Borne Euro générique de chez Jeux COURTET
    Tutos LaunchPad MSP430 001 - 002 - 003 - 004 en attente