Cours:TPS 2103 1 : Différence entre versions
m (→{{Rouge|Ex 3: bouton et led}}) |
m (→{{Bleu|ou mieux ...}}) |
||
Ligne 230 : | Ligne 230 : | ||
− | Il suffit pour cela de choisir le bon mode de déclenchement dans le registre EICRA | + | Il suffit pour cela de choisir le bon mode de déclenchement dans le registre '''EICRA''' |
{{finAide}} | {{finAide}} | ||
− | |||
=={{Bleu|Et pour 2 leds ??}}== | =={{Bleu|Et pour 2 leds ??}}== |
Version du 26 mars 2014 à 15:21
Nous avons abordé la programmation des cartes arduino au premier semestre en utilisant des fonctions de haut niveau ce qui, bien que pouvant simplifier certaine tâche, présente un certain nombre de limitation.
L'objectif de ces TPs est de découvrir le fonctionnement du µcontrôleur Atmega328p et d'en explorer les possibilités.
Nous commencerons simplement de façon analogue au premier TP du module M1102 en configurant des e/s (il est sans doute utile de jeter un coup d’œil au lien précédent !).
Sommaire
Ex 1: mise en jambe !
On considère la led f5. La patte correspondante (PB5) sera donc une sortie (commande) pour le µcontrôleur. On configure donc le registre de direction de la façon suivante :
DDRB bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
Valeur | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
Compléter le programme suivant pour que la led s'allume et s'éteigne pendant 500ms
Remarque : On utilisera astucieusement l'opérateur ^
void setup()
{
DDRB = 0x?? ; // configuration des e/s (registre de direction DDRx) sur le port D.
}
void loop()
{
PORTB ???? ; // on modifie en conséquence l'état de la sortie
.... // il faudra utiliser la fonction delay !
}
void setup()
{
DDRB = 0x01 ; // configuration des e/s (registre de direction DDRx) sur le port D.
}
void loop()
{
PORTB = 0x00 ; // mise à zéro de la sortie
delay(500);
PORTB = 0x01 ; // mise à un de la sortie
delay(500);
}
|
Ex 2: sans délais ...
Plusieurs leds simultanées
Modifier le programme précédent pour ajouter une deuxième led (f1) s'allumant et s'éteignant au même rythme
Faire en sorte que les 2 leds soient allumées en alternance
Les limites ...
On souhaite avoir 2 rythmes différents pour le clignotement. L'une des leds aura une période de 1s (2x500ms), et l'autre led de 200ms (2x100ms).
On constate aisément que le rapport entre les périodes est de 5, on choisira un "delay" de boucle de 100ms et il suffira de ne changer l'état de la 2ème led que toutes les 5 itérations, suivant le principe suivant :
unsigned char i;
void setup()
{
...
i=0;
}
void loop()
{
i++;
if (i==Nb) // toutes les Nb itérations
{
...
i=0;
}
...
}
Écrire le programme répondant au cahier des charges
Essayer ensuite de modifier le programme pour avoir une période de 225ms pour l'une des leds et 190ms pour l'autre.
Une autre possibilité
Plutôt que d'utiliser des "delay", nous allons utiliser une montre (le temps depuis le démarrage du µcontrôleur en fait).
Le principe est donné dans le programme suivant :
unsigned long dateActuelle, dateModification;
void setup()
{
}
void loop()
{
dateActuelle = millis();
if ( (dateActuelle - dateModification) > dureeSouhaitee ) // la condition est vraie si le dernier changement est trop vieux
{
... // on modifie alors les sorties
dateModification=dateActuelle; // et on mémorise l'heure du dernier changement
}
}
Autre explication : Si on lance la cuisson des pâtes à 20h15 et que celle ci dure 10 minutes il faut les sortir à 20h25 !
Sur cette base, écrire un programme répondant à la question précédente.
Ex 3: bouton et led
Nous considérons pour le moment le bouton A et la led de droite (p0).
Complétez le programme suivant pour que la led s'allume si le bouton est appuyé
void setup()
{
DDRD = 0x?? ; // configuration des e/s (registre de direction DDRx) sur le port D.
}
void loop()
{
if ( (PIND & 0x?? ) != 0 ) // on observe l'état de l'entrée
PORTD = 0x??; // on modifie en conséquence l'état de la sortie
else
PORTD = 0x??;
}
Pour le moment nos programmes sont petits et il est donc possible de les lire complètement pour imaginer les actions qu'il réalise. Mais que se passe-t-il lorsque la taille des programmes augmente (pour atteindre 700 lignes par exemple). Il faut alors mettre en place des techniques appropriées. Ces techniques sont appelées debuggage (le verbe francisé associé est déboguer) et nous en présentons une toute simple maintenant.
Il faut apprendre à debugger un programme. Le plus simple est de se servir de la liaison série : void setup()
{
Serial.begin(9600);
DDRD = 0x?? ; // configuration des e/s (registre de direction DDRx) sur le port D.
}
void loop()
{
unsigned char res;
res = PIND & 0x??;
Serial.print("res = ");
Serial.println(res,BIN);
if ( (res) != 0 )
{
Serial.println("le test est vrai.");
PORTD = 0x??; // on modifie en conséquence l'état de la sortie
}
else
{
Serial.println("le test est faux.");
PORTD = 0x??;
}
delay(200); // indispensable pour ne pas avoir un affichage trop rapide !
}
|
On peut simplifier le programme précédent en utilisant l'opérateur décalage : il suffit de "recopier" l'état du bouton poussoir (PD2) sur la led (PD6) en décalant de 4 bits (PD6-PD2) vers la gauche
void setup()
{
DDRD = 0x?? ; // configuration des e/s (registre de direction DDRx) sur le port D.
}
void loop()
{
PORTD = (PIND&0x??)<<4;
}
Ex 4: Changement d'état
passé et présent
On souhaite maintenant changer l'état de la led (p0) à chaque appui sur le bouton poussoir A (PD2).
On rappelle comme vu en module M1103 que l'une des méthodes repose sur la notion de présent et passé.
Le code suivant (à compléter) répond à ce cahier des charges
char etatPresent=0,etatPasse=0;
unsigned char etatSortie=0;
void setup()
{
DDRD= 0x??; // configuration des e/s
}
void loop()
{
etatPasse=etatPresent;
etatPresent = (PIND & ...)>>2; // 2 valeurs possibles pour etatPresent : 0 ou 1
if ((etatPresent==1)&&(etatPasse==0)) PORTD^=0x??; // modifier la sortie associée à la led p0
}
ou mieux ...
Nous allons utiliser une interruption, dont vous devez comprendre le fonctionnement !
Commencer par comprendre et exécuter le code donné en exemple
Modifier le programme pour que la led(p0) ne change d'état qu'à l'appui sur le bouton poussoir, et non à chaque changement d'état
|
Et pour 2 leds ??
Adapter le programme précédent en ajoutant le bouton B (INT1) et une led au choix avec un fonctionnement identique (chaque bouton commande 1 led)
Autre possibilité
Bien évidemment 2 interruptions peuvent modifier la même variable/registre :
On souhaite que l'appui sur le bouton A allume la led p0 et l'appui sur le bouton B l'éteigne. Écrire le programme.
Ex 5: Drapeaux
Les drapeaux sont très utilisés avec les fonctions d'interruption. Le principe est de positionner une variable à une valeur particulière au sein de l'interruption et de faire un test sur cette valeur dans le programme principal, exemple :
volatile unsigned char chg = 0; // les variables partagées entre interruption et programme principale doivent être de type volatile
ISR(INT0_vect) // programme d'interruption : le programme principal est interrompu,
{ // l'interruption exécutée et ensuite le programme principal continu normalement son exécution
chg = 1; // on positionne le drapeau
}
void setup()
{
DDRB=0x0F; // configuration de PB0 en sortie
cli(); // arrêt des interruptions
EICRA=0x01; // mode de déclenchement de l'interruption
EIMSK=0x01; // choix des interruptions actives
sei(); // autorisation des interruptions
}
void loop()
{
if (chg==1)
{
PORTB^=0x01;
chg=0;
}
}
Premier usage
Modifier le programme précédent pour :
- Ne déclencher l'interruption que sur un appui du bouton A
- Incrémenter le flag à chaque interruption
- Changer l'état de la led tout les 5 appuis
Clignotement
Écrire le programme répondant au cahier des charges suivant :
- Faire clignoter une led
- Chaque appui sur A double la fréquence de clignotement
- Chaque appui sur B double la fréquence de clignotement