Cours:TPS 2103 tp1 : Différence entre versions

De troyesGEII
Aller à : navigation, rechercher
m ({{Rouge|Ex 5: Drapeaux}})
m ({{Rouge|Ex 5: Drapeaux}})
 
(19 révisions intermédiaires par le même utilisateur non affichées)
Ligne 2 : Ligne 2 :
  
 
[[Cours:TPS_2103_tp1_corrige|{{Vert|<big>'''Éléments de correction'''</big>}}]]
 
[[Cours:TPS_2103_tp1_corrige|{{Vert|<big>'''Éléments de correction'''</big>}}]]
 +
 +
*******************************************************************
 +
Lancer avrCodeGenerator dans un terminal pour un générateur de code
 +
*******************************************************************
  
  
Ligne 10 : Ligne 14 :
 
Nous commencerons simplement de façon analogue au [[Cours:ArduinoBoutons|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 !).
 
Nous commencerons simplement de façon analogue au [[Cours:ArduinoBoutons|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 !).
  
={{Rouge|Ex 1: mise en jambe !}}=
+
=Ex 1: mise en jambe !=
  
 
On considère [[Cours:Shieldinfo|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 :
 
On considère [[Cours:Shieldinfo|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 :
Ligne 72 : Ligne 76 :
 
{{finAide}}
 
{{finAide}}
  
={{Rouge|Ex 2: plusieurs leds ...}}=
+
=Ex 2: Chenillard=
  
=={{Bleu|Plusieurs leds simultanées }}==
+
{{Cours:ShieldinfoTableauLeds}}
{{Question|Modifier le programme précédent pour ajouter une deuxième led (f1) s'allumant et s'éteignant au même rythme}}
 
 
 
{{Question|Faire en sorte que les 2 leds soient allumées en alternance}}
 
 
 
=={{Bleu|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 :
 
 
 
<source lang=c>
 
#include <avr/io.h>
 
#include <util/delay.h>
 
 
 
int main()
 
{
 
  uint8_t n=0;
 
  // configuration
 
  ...
 
  while(1)
 
  {
 
      n++;
 
      PORTx .....;
 
      if (n==Nb)  // toutes les Nb itérations
 
      {
 
        ...
 
        n=0;
 
      }
 
      _delay_ms(???); // un seul delay dans le programme
 
  }
 
  return 0;
 
}
 
</source>
 
Comme le commentaire l'indique le programme ne doit comporter '''qu'un seul delay !!!''' Il faut donc bien le choisir !
 
  
{{Question|Écrire le programme répondant au cahier des charges}}
+
On souhaite réaliser un chenillard. On utilisera seulement les {{Rouge|6 leds du PORTB}}.
  
{{Question|Essayer ensuite de modifier le programme pour avoir un changement d'état toutes les 225ms pour l'une des leds et 190ms pour l'autre.}}
+
{{Question|Ecrire un programme chenillard avec la led qui se "déplace" de PB0 vers PB5}}
  
{{Aide| principe :}}
+
{{Question|Même question avec un déplacement dans l'autre sens}}
  
 
+
=Ex 3: bouton et led=
Il faut trouver un commun diviseur aux 2 périodes, que l'on nommera T.
 
 
 
Ensuite, il suffit d'<u>utiliser 2 variables n1 et n2</u>, telles que :
 
*225=n1.T
 
*190=n2.T
 
{{finAide}}
 
 
 
={{Rouge|Ex 3: bouton et led}}=
 
  
 
Nous considérons pour le moment [[Cours:Shieldinfo|le bouton A et la led de droite (p0)]].
 
Nous considérons pour le moment [[Cours:Shieldinfo|le bouton A et la led de droite (p0)]].
Ligne 150 : Ligne 112 :
 
}
 
}
 
</source>
 
</source>
 
 
 
<big>'''Il vous reste moins d'1h pour terminer le TP, passez à la partie suivante !'''</big>
 
  
 
{{Question|On ajoute un 2ème bouton (bp B) et une 2ème led (led p1) et modifier le programme pour que :}}
 
{{Question|On ajoute un 2ème bouton (bp B) et une 2ème led (led p1) et modifier le programme pour que :}}
Ligne 160 : Ligne 118 :
 
*dans les autres cas, les leds sont éteintes.
 
*dans les autres cas, les leds sont éteintes.
  
={{Rouge|Ex 4: Changement d'état}}=
 
  
=={{Bleu|Entrées et interruptions}}==
+
{{Aide|Observer une entrée}}
 +
 
 +
 
 +
 
 +
 
 +
On inclura le fichier {{Rouge|avr/sfr_defs.h}} qui contient 2 macros :
 +
* bit_is_set(registre,numero_bit)
 +
* bit_is_clear(registre,numero_bit)
 +
*utilisation :
 +
<source lang=cpp>
 +
#include <avr/sfr_defs.h>
 +
...
 +
if ( bit_is_set(PINA,PA5) )  // if ( (PINA & (1<<PA5)) != 0) ou si l'entrée PA5 est à 1
 +
if ( bit_is_clear(PINA,PA5) ) // if ( (PINA & (1<<PA5)) == 0) ou si l'entrée PA5 est à 0
 +
...
 +
 
 +
</source>
 +
{{finAide}}
 +
 
 +
=Ex 4: Changement d'état=
 +
 
 +
==Entrées et interruptions==
  
 
Nous allons utiliser une {{Bleu|interruption}}, dont [[Cours:Atmega328p#Interruptions|{{Rouge|vous devez comprendre le fonctionnement en lisant ce lien !}}]]
 
Nous allons utiliser une {{Bleu|interruption}}, dont [[Cours:Atmega328p#Interruptions|{{Rouge|vous devez comprendre le fonctionnement en lisant ce lien !}}]]
Ligne 197 : Ligne 175 :
 
#include <avr/interrupt.h>
 
#include <avr/interrupt.h>
  
volatile unsigned char chg = 0; // les variables partagées entre interruption et programme principale doivent être de type volatile
+
volatile uint8_t 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,
 
ISR(INT0_vect)    // programme d'interruption : le programme principal est interrompu,
Ligne 207 : Ligne 185 :
 
{
 
{
 
   DDRB |= (1<<PB0);      // configuration de PB0 en sortie
 
   DDRB |= (1<<PB0);      // configuration de PB0 en sortie
  cli();          // arrêt des interruptions
 
 
   EICRA |= (1<<ISC00);    // mode de déclenchement de l'interruption
 
   EICRA |= (1<<ISC00);    // mode de déclenchement de l'interruption
 
   EIMSK |= (1<<INT0);    // choix des interruptions actives
 
   EIMSK |= (1<<INT0);    // choix des interruptions actives
Ligne 229 : Ligne 206 :
 
*Changer l'état de la led tous les 5 appuis
 
*Changer l'état de la led tous les 5 appuis
  
=={{Bleu|Clignotement}}==
+
==Clignotement==
  
 
{{Question|Écrire le programme répondant au cahier des charges suivant :}}
 
{{Question|Écrire le programme répondant au cahier des charges suivant :}}
Ligne 235 : Ligne 212 :
 
*Chaque appui sur A double la fréquence de clignotement
 
*Chaque appui sur A double la fréquence de clignotement
 
*Chaque appui sur D divise par 2 la fréquence de clignotement
 
*Chaque appui sur D divise par 2 la fréquence de clignotement
 
+
*Voici comment faire une pause dont la durée varie selon la valeur d'une variable :
{{Rouge|'''Attention''', il faut ajouter obligatoirement __DELAY_BACKWARD_COMPATIBLE__ :}}
 
 
<source lang=c>
 
<source lang=c>
#include <avr/io.h>
+
uint8_t periodeLed=xxx;
#define __DELAY_BACKWARD_COMPATIBLE__
 
#include <util/delay.h>
 
#include <avr/interrupt.h>
 
  
 +
...
 +
for (uint8_t i=0;i<periodeLed;i++) _delay_ms(1);
 +
...
 
</source>
 
</source>
  
={{Rouge|Complément : Changement d'état sans interruptions}}=
+
=Ex 6 : Sens de rotation d'un moteur=
  
=={{Bleu|Explication}}==
+
Cette partie sera simulée sur tinkercad. Vous trouverez sur le lien suivant le [https://www.tinkercad.com/things/hUxJEy8PWxE circuit tinkercad].
  
Malheureusement, toutes les entrées ne peuvent déclencher une interruption spécifique.
+
[[Fichier:Codeur incremental disque.gif]]
  
Dès lors, il peut être utile de changer de technique pour détecter les changements d'état des entrées.
+
Pour connaître le sens de rotation on utilise un codeur incrémental.
  
C'est ce que nous proposons d'étudier dans cette parties.
+
Vous pouvez consulter le lien suivant sur lequel une animation présente le fonctionnement : http://stephane.genouel.free.fr/FT/0%20Dossier%20technique/1%20Texte/RobotEricc_web2/co/module_Robot_Ericc_13.html
  
=={{Bleu|Passé Présent}}==
+
Le codeur utilisé n'a pas de top tour, seulement les 2 voies A et B.
  
On souhaite maintenant changer l'état de la led (p0) à chaque appui sur le bouton poussoir A (PD2).
 
 
On rappelle [[Cours:ArduinoBoutons#D.C3.A9tection_de_changement_d.27.C3.A9tat|comme vu en module M1103]] que l'une des méthodes repose sur la notion de présent et passé.
 
 
{{Question|Le code suivant (à compléter) répond à ce cahier des charges}}
 
 
<source lang=c>
 
#include <avr/io.h>
 
#include <util/delay.h>
 
#include <avr/sfr_defs.h>
 
uint8_t etatPresent=0,etatPasse=0;
 
unsigned char etatSortie=0;
 
int main()
 
{
 
  DDRD |= (1<<...);            // configuration des e/s
 
  while(1)
 
  {
 
      etatPasse=etatPresent;
 
      if ( bit_is_clear(PINx,....) )                  // si le bouton est relâché
 
          etatPresent = 0;
 
      else etatPresent = 1;
 
  
      if ((etatPresent != 0) && (etatPasse == 0))  PORTD ^= (1<<...);  // modifier la sortie associée à la led p0
+
{{Question|Utilisez 2 leds pour visualiser le sens de rotation du moteur}}
  }
 
  
}
+
'''Remarque :''' Le principe est assez simple
</source>
+
* au front montant sur l'une des voies
 
+
* on regarde la valeur de l'autre voie
{{Aide|Ou plus compact :}}
 
 
 
 
 
 
 
 
 
<source lang=c>
 
#include <avr/sfr_defs.h>
 
uint8_t etatPresent=0,etatPasse=0;
 
unsigned char etatSortie=0;
 
 
 
int main()
 
{
 
  DDRD |= (1<<...);            // configuration des e/s
 
  while(1)
 
  {
 
      etatPasse=etatPresent;
 
      etatPresent = bit_is_set(PIND,.... );                        // 2 valeurs possibles pour etatPresent : 0 ou "différent de 0"
 
      if ((etatPresent != 0) && (etatPasse == 0))  PORTD ^= (1<<..);  // modifier la sortie associée à la led p0
 
  }
 
 
 
}
 
</source>
 
{{finAide}}
 
  
=={{Bleu|Utilisation}}==
 
  
En utilisant ce principe, écrire le programme répondant à la question suivante :
+
{{Question|Modifier votre programme pour réaliser un compte tour, on affichera la valeur sur les leds.}}
  
{{Question|La led (à choisir) s'allume à l'appui sur le bouton B, et s'éteint à l'appui sur C}}
+
=Supplément=
  
=[[Cours:TPS_2103_Grafcet|{{Rouge|Prolongement possible : Grafcet}}]]=
+
***************************************************
 +
****          [[Cours:TPS_2103_tp1_supplement|Pour aller plus  loin]]           ****
 +
***************************************************

Version actuelle datée du 11 février 2022 à 16:43

Retour à la liste des Tps

Éléments de correction

*******************************************************************
Lancer avrCodeGenerator dans un terminal pour un générateur de code
*******************************************************************


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

On rappelle la connexion des LEDs et couleur avec les PORTs correspondants pour le shield de l'IUT de Troyes :

Numéro f5 f4 f3 f2 f1 f0 p1 p0
Couleur r o v r o v v r
Arduino Pin 13 12 11 10 9 8 7 6
Port Arduino UNO PB5 PB4 PB3 PB2 PB1 PB0 PD7 PD6
Port Arduino LEONARDO PC7 PD6 PB7 PB6 PB5 PB4 PE6 PD7

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 ^

#include <avr/io.h>
#include <util/delay.h>

int main()
{
   DDRB |= ... ;         // configuration des e/s (registre de direction DDRx) sur le port D.
   while(1)
   {
      PORTB ???? ;          // on modifie en conséquence l'état de la sortie
      ....                  // il faudra utiliser la fonction _delay_ms() !
   }
}
Bluebg.png
Aidesmall.png
À propos de cette image

Version simple pour la led f0


#include <avr/io.h>
#include <util/delay.h>

int main()
{  // setup()
   DDRB |= 1<<PB0 ;         // configuration des e/s (registre de direction DDRx) sur le port D.
   // loop() 
   while(1)   {
     PORTB &=~ (1<<PB0) ;          // mise à zéro de la sortie
     _delay_ms(500);
     PORTB |= 1<<PB0 ;         // mise à un de la sortie
     _delay_ms(500);
   }
   return 0;
}

Notez encore la présence de deux parties différentes dans ce programme :

  • ancien setup()destiné à la configuration des PORTs et exécuté une seuls fois
  • ancien loop() matérialisé ici par while(1) exécuté en permanence (boucle infinie)

Ex 2: Chenillard

Numéro f5 f4 f3 f2 f1 f0 p1 p0
Couleur r o v r o v v r
Arduino Pin 13 12 11 10 9 8 7 6
Port Arduino UNO PB5 PB4 PB3 PB2 PB1 PB0 PD7 PD6
Port Arduino LEONARDO PC7 PD6 PB7 PB6 PB5 PB4 PE6 PD7

On souhaite réaliser un chenillard. On utilisera seulement les 6 leds du PORTB.

Question.jpg Ecrire un programme chenillard avec la led qui se "déplace" de PB0 vers PB5

Question.jpg Même question avec un déplacement dans l'autre sens

Ex 3: bouton et led

Nous considérons pour le moment le bouton A et la led de droite (p0).

Le tableau suivant donne les caractéristiques utiles sur les 4 boutons poussoirs d'entrée pour le shield de l'IUT :

Bouton Position Arduino Pin Port Interruption Niveau logique si bouton appuyé
A Bas Gauche 2 PD2 int0 1
D Haut Gauche 3 PD3 int1 1
B Bas Droite A0 PC0 0
C Haut Droite A1 PC1 0

Question.jpg Complétez le programme suivant pour que la led s'allume si le bouton est appuyé

#include <avr/io.h>
#include <util/delay.h>
#include <avr/sfr_defs.h>
int main()
{
   DDRD |= .... ;                 // configuration des e/s (registre de direction DDRx) sur le port D.
   while(1)
   {
     if ( bit_is_set(PIND,???? ) )    // on observe l'état de l'entrée
           PORTD ..... ;          // on modifie en conséquence l'état de la sortie
     else
           PORTD ..... ;
   }
}

Question.jpg On ajoute un 2ème bouton (bp B) et une 2ème led (led p1) et modifier le programme pour que :

  • si le bp B est appuyé, la led p0 s'allume
  • la led p1 ne s'allume que si les 2 boutons sont appuyés
  • dans les autres cas, les leds sont éteintes.


Bluebg.png
Aidesmall.png
À propos de cette image

Observer une entrée



On inclura le fichier avr/sfr_defs.h qui contient 2 macros :

  • bit_is_set(registre,numero_bit)
  • bit_is_clear(registre,numero_bit)
  • utilisation :
#include <avr/sfr_defs.h>
...
if ( bit_is_set(PINA,PA5) )   // if ( (PINA & (1<<PA5)) != 0) ou si l'entrée PA5 est à 1
if ( bit_is_clear(PINA,PA5) ) // if ( (PINA & (1<<PA5)) == 0) ou si l'entrée PA5 est à 0
...

Ex 4: Changement d'état

Entrées et interruptions

Nous allons utiliser une interruption, dont vous devez comprendre le fonctionnement en lisant ce lien !

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 D (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 D 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 :

#include <avr/io.h>
#include <avr/interrupt.h>

volatile uint8_t 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 continue normalement son exécution
   chg = 1;       // on positionne le drapeau/flag
}

int main()
{
  DDRB |= (1<<PB0);      // configuration de PB0 en sortie
  EICRA |= (1<<ISC00);     // mode de déclenchement de l'interruption
  EIMSK |= (1<<INT0);     // choix des interruptions actives
  sei();          // autorisation des interruptions
  while(1)
  {
    if (chg == 1)
    {
      PORTB ^= (1<<PB0);
      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 drapeau à chaque interruption
  • Changer l'état de la led tous 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 D divise par 2 la fréquence de clignotement
  • Voici comment faire une pause dont la durée varie selon la valeur d'une variable :
uint8_t periodeLed=xxx;

...
for (uint8_t i=0;i<periodeLed;i++) _delay_ms(1);
...

Ex 6 : Sens de rotation d'un moteur

Cette partie sera simulée sur tinkercad. Vous trouverez sur le lien suivant le circuit tinkercad.

Codeur incremental disque.gif

Pour connaître le sens de rotation on utilise un codeur incrémental.

Vous pouvez consulter le lien suivant sur lequel une animation présente le fonctionnement : http://stephane.genouel.free.fr/FT/0%20Dossier%20technique/1%20Texte/RobotEricc_web2/co/module_Robot_Ericc_13.html

Le codeur utilisé n'a pas de top tour, seulement les 2 voies A et B.


Question.jpg Utilisez 2 leds pour visualiser le sens de rotation du moteur

Remarque : Le principe est assez simple

  • au front montant sur l'une des voies
  • on regarde la valeur de l'autre voie


Question.jpg Modifier votre programme pour réaliser un compte tour, on affichera la valeur sur les leds.

Supplément

***************************************************
****           Pour aller plus  loin           ****
***************************************************