AND : & | | | OR : | | | | XOR : ^ | | | NOT : ~ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| | |
| | |
| | |
|
#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.P1OUT ^= (BIT0 | BIT0);
seul le BIT0 de P1OUT sera modifié.P1OUT ^= (BIT0 + BIT0);
on se serait retrouvé avec le BIT1 de P1OUT modifié… bonjour le merdier!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();
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
}
}
#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₂. 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. 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. P1OUT &= ~(BIT0 | BIT6);
}
Et on s'assure que les leds soient éteintes.#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
}
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".
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.
interrupt (INTERRUPT_VECTOR) IntServiceRoutine(void)
{
/* Any normal C code */
}
/*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
pushButton.c:55:6: warning: return type of ‘main’ is not ‘int’
A ce sujet, je suis surpris tu peux peut-être envisager d'utiliserint main(void)
avec un return 0;
à la fin de ta boucle main._BIS_SR(LPM0_bits + GIE); //not low power mode and enable interrupts