Gamoover

Forums " WORKSHOP" => Jamma, cablages, contrôleurs, interfaces & hacks => Microcontrôleurs et électronique => Discussion démarrée par: KodeIn le Mercredi 25 Mai 2011, 10:41:36 AM

Titre: LaunchPad tuto 003 : Gérer un bouton (et par extension, les interrupts)
Posté par: KodeIn le Mercredi 25 Mai 2011, 10:41:36 AM
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.
(http://hico-srv022.pixhotel.fr/sites/default/files/gamoovernet/20110528015704-KodeIn-tuto3.png)




Intro
Pour cet exercice, on va partir du tuto-002 (http://www.gamoover.net/Forums/index.php?topic=23752.msg355685#msg355685) 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
Citation de: keube 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 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 ;) ).
Titre: LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
Posté par: CuBe 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 : ^"  ^-
Titre: LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
Posté par: KodeIn 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
Titre: LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
Posté par: Maitre_Poulpi 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  ;)
Titre: LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
Posté par: KodeIn 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  =:))
Titre: LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
Posté par: KodeIn 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?)
Titre: LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
Posté par: keube 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...
Titre: LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
Posté par: KodeIn 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.
Titre: LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
Posté par: keube 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!
Titre: LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
Posté par: KodeIn 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
Titre: LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
Posté par: keube 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.
Titre: LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
Posté par: gc339 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 :
Titre: LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
Posté par: keube le Vendredi 27 Mai 2011, 12:31:56 PM
Citation de: gc339 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 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.
Titre: LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
Posté par: KodeIn 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?
(http://hico-srv022.pixhotel.fr/sites/default/files/gamoovernet/20110527124616-KodeIn-RC-debounce.gif)
Ç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.
Titre: LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
Posté par: gc339 le Vendredi 27 Mai 2011, 13:31:17 PM
Citation de: KodeIn le Vendredi 27 Mai 2011, 12:51:16 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.

Citation de: KodeIn le Vendredi 27 Mai 2011, 12:51:16 PM
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
Titre: LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
Posté par: KodeIn 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.
Titre: LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
Posté par: KodeIn le Dimanche 29 Mai 2011, 19:11:51 PM
Bon, tout petit ajout : une ligne de code intéressante qui permet de jouer avec le choix du flanc du signal sur lequel va se provoquer l'interruption.

Voilà voilà.
Je continue à bosser petit à petit sur le tuto 4 :D
Titre: LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
Posté par: AsPiC le Dimanche 29 Mai 2011, 19:38:06 PM
Je pense que tu veux dire front et non pas flanc ;)
Titre: LaunchPad Tuto-003 : Gérer un bouton (et par extension, les interrupts)
Posté par: KodeIn le Dimanche 29 Mai 2011, 21:10:35 PM
De ce que je sais, les deux termes sont admissibles.
Mais si vous préférez que j'utilise front plutôt que flanc, faites-le moi savoir ;)
Titre: LaunchPad tuto 003 : Gérer un bouton (et par extension, les interrupts)
Posté par: Taralom le Dimanche 31 Juillet 2011, 23:13:24 PM
Bonsoir,

je me suis mis au msp430

J'ai essayé ta gestion des interruptions mais j'ai une erreur de compilation
(je fait ca à l'ancienne avec Gvim, make et mspdebug.)

Lors de la compilation de ton code (copier coller)
j'ai le message suivant :

$ make
msp430-gcc -Wall -g -mmcu=msp430g2231 -c pushButton.c
pushButton.c:55:6: warning: return type of 'main' is not 'int'
pushButton.c:73:0: warning: ignoring #pragma vector
pushButton.c:74:15: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'void'
make: *** [pushButton.o] Error 1


la deuxième ligne indique mes options de compilation.
la troisième que tu a écrit void main(void)
la quatrième que la commande #pragma vector sera ignoré (c'est pas cool, ca veut dire qu'en assembleur, ca ne va pas mettre le code interruption à l'endroit souhaité)
la quatrième que la définition du code d'interruption est incorrect.

Je n'ai pas cherché de solution et demain c'est lundi.

Je regarderai de plus près quand j'aurais le temps.
(A priori dans la doc de 650 pages tu devrais trouver la réponse. Aux alentours de la page 40 :p

mon code est différent (int main(void) par exemple ce qui evite le warning ...)
mais j'ai les même retour d'erreur (1 erreur et 1 warning qui fera tous planter)
Titre: LaunchPad tuto 003 : Gérer un bouton (et par extension, les interrupts)
Posté par: KodeIn le Lundi 01 Août 2011, 09:56:25 AM
Effectivement, le compilateur de l'IDE de TI et MSPGCC4 sous linux (et os X) ne possèdent pas exactement le même comportement (certainement une histoire de librairies).
Et donc, nécessitent un code source légèrement différent. Quel bonheur intense >:(

Après une rapide recherche sur google, je suis tombé sur ces pages http://mspgcc.sourceforge.net/manual/x918.html  et  http://justinstech.org/2010/09/msp430-coding-interrupts-for-mspgcc/ (http://justinstech.org/2010/09/msp430-coding-interrupts-for-mspgcc/) .
Le PRAGMA serait donc, avec MSPGG, remplacé par
interrupt (INTERRUPT_VECTOR) IntServiceRoutine(void)
{
   /* Any normal C code */
}


Un peu plus complet :
/*WDT interval timer- code based on msp430 examples*/
//compiler=mspgcc
#include<msp430x22x2.h>
#include<signal.h> //interrupt service routine
#include <io.h> //usually included on msp430 header, but for sfr register access.
void main(void) {
WDTCTL = WDT_MDLY_32; //~30mS intervals
P1DIR |=BIT1;
IE1 |= WDTIE; //enable interrupt
_BIS_SR(LPM0_bits + GIE); //not low power mode and enable interrupts
}//end of main
//interrupt service routine
interrupt(WDT_VECTOR) watchdog_timer(void)
{
P1OUT ^= BIT1;
}//end of interrupt


Après un coup de lecture plus poussé, si tu utilises MSPGC uniarch, il semble que ça sera encore différent. :?
Vous comprendrez aisément que je n'ai pas spécialement envie de passer mon temps à chercher et trouver la manière dont il faut coder mes tutos pour tous les compilateurs existants…
Je vais m'en tenir à CCS et éventuellement MSPGCC si je me décide à m'y mettre (enfant gâté, je suis habitué aux IDE où on fait tout à la souris, vi/vim/nano etc. c'est un choc brutal pour moi  :D).



pushButton.c:55:6: warning: return type of ‘main’ is not ‘int’

A ce sujet, je suis surpris tu peux peut-être envisager d'utiliser
int main(void)
avec un
return 0;
à la fin de ta boucle main.

Au fait, Taralom, pourrais-tu nous dire comment tu es arrivé sur ce forum dédié à l'arcade pour des tutos de MSP430?
(puis éventuellement faire une petit post de présentation ici (http://www.gamoover.net/Forums/index.php?topic=541.2288) ;) )




Et au sujet du 4ème tuto, il sera en attente jusqu'à ce que j'aie réussi à faire mon petit interpréteur SNES, désolé.
Titre: LaunchPad tuto 003 : Gérer un bouton (et par extension, les interrupts)
Posté par: Taralom le Lundi 01 Août 2011, 18:39:29 PM
Bien vu.
Plus d'erreur de compilation.

par contre au niveau des includes, je n'utilise que les deux suivant et ca semble suffir

#include <msp430.h>
#include <legacymsp430.h>

j'aurais plus de temps ce week end. Donc d'ici là : patience

(comment je suis tomber ici ?
tape "led verte launchapd msp430" dans google.)
Titre: LaunchPad tuto 003 : Gérer un bouton (et par extension, les interrupts)
Posté par: Taralom le Lundi 01 Août 2011, 23:30:26 PM
Bonsoir,

je n'ai pas eu beaucoup de temps aujourd'hui.
J'ai quand même tester mon code (l'impatience !!)

Eh ben ca marche pas !!  ;)

Je suis quand même aller et plus loin.
Il semblerai que la ligne
_BIS_SR(LPM0_bits + GIE); //not low power mode and enable interrupts

Fasse basculer le µC dans un mode différent et fasse planter le code "classique".
Je m'explique :

Sans cette ligne, les interruptions ne sont pas gérés mais un code de type HelloWorld fonctionne sans problème.
Le simple fait de dé commenter cette ligne ne va plus faire fonctionner celui ci.

Comme dit précedement, je manque cruellement de temps en semaine. (et surtout en début de semaine !!) (env. 30 minutes aujourd'hui sur ce µC)
Je ferai donc mes recherches ce week end.

Bonne soirée.
Je vous tiendrez au courant
Titre: LaunchPad tuto 003 : Gérer un bouton (et par extension, les interrupts)
Posté par: KodeIn le Mardi 02 Août 2011, 01:01:11 AM
 :-((
J'ai essayé de mon coté plusieurs bouts de code... comme toi, j'arrive à compiler, mais il refuse de lire l'état des boutons. :?
C'est frustrant, je n'ai pas trouvé de tutos vraiment clairs au sujet des interruptions utilisant MSPGCC comme compilateur.

Désolé de ne pas pouvoir t'aider plus que ça, je vais continuer à chercher, au cas où.