Cours:TPS 2103 1 : Différence entre versions

De troyesGEII
Aller à : navigation, rechercher
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

Retour à la liste des Tps

Éléments de correction


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 !).

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

Question.jpg 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 !
}
Bluebg.png
Aidesmall.png
À propos de cette image

Version simple pour la led f0


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

Question.jpg Modifier le programme précédent pour ajouter une deuxième led (f1) s'allumant et s'éteignant au même rythme

Question.jpg 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;
  }
  ...
}

Question.jpg Écrire le programme répondant au cahier des charges

Question.jpg 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 !

Question.jpg 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).

Question.jpg 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.

Bluebg.png
Aidesmall.png
À propos de cette image

Debuggage

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 !
}

Question.jpg 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é.

Question.jpg 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 !

Todo.jpg Commencer par comprendre et exécuter le code donné en exemple

Question.jpg 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

Bluebg.png
Aidesmall.png
À propos de cette image

EICRA


Il suffit pour cela de choisir le bon mode de déclenchement dans le registre EICRA

Et pour 2 leds ??

Question.jpg 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 :

Question.jpg 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

Question.jpg 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

Question.jpg É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