[TUTORIEL] Manipulation des ports

[TUTORIEL] Manipulation des ports

Message non lude Laetitia » Jeu 13 Juin 2013 17:48

Bonjour,

Aujourd'hui nous allons regarder de plus près la configuration de l'Arduino. Nous savons déjà manipuler les entrées/sorties avec quelques commandes basiques (pinMode, digitalWrite, digitalRead, analogRead...), mais il existe d'autres manières de les contrôler, qui nécessitent un peu de théorie.

L'ATmega328, le "cerveau" de l'Arduino (voir datasheet), possède trois ports auxquels sont connectées les broches d'entrées/sortie :
- le Port B (broches numériques 8 à 13),
- le Port C (broches analogiques),
- le Port D (broches numériques 0 à 7).
Chaque port est contrôlé par trois registres :
- DDRx (détermine si les broches sont des INPUT ou des OUTPUT),
- PORTx (détermine l'état (HIGH ou LOW) des sorties, et active les résistances de tirage internes des entrées),
- PINx (lit l'état des entrées),
où "x" est la lettre du port correspondant : il faudra manipuler le registre DDRB pour configurer les entrées/sorties sur les broches 8 à 13, etc.

Chaque registre, au niveau logiciel, correspond à une variable, en l’occurrence un octet, que l'on peut définir à loisir. Un octet est composé de 8 bits, chacun correspondant à une broche du port concerné, et l'état du bit (0 ou 1, LOW ou HIGH) correspond à son état physique. Comme on ne peut pas définir l'état de PINx, on dit qu'il est en lecture seule, DDRx et PORTx peuvent par contre être lus ou écrits.
Le bit B0 correspond à la broche 8, B1 à la broche 9, B2 à la broche 10... et le "x" de chaque "Bx" correspond au poids du bit (à sa position) dans l'octet du registre : 76543210. Pour configurer une broche en entrée il faut mettre le bit à 1 (In) et en sortie à 0 (Out).

Code: Tout sélectionner
DDRB = 0b00110000 // configure les broches 13 et 12 en entrées et le reste en sorties

-> Note : les deux bits de poids fort du port B (B7 et B6) ne sont reliés à aucune broche et ne sont pas utilisables.

:!: Attention : Lors de la configuration du port D, ne pas modifier l'état des broches 0 et 1 (RX et TX), elles servent à la communication série !

Le préfixe "0b" sert à indiquer un nombre écrit en binaire. De la même manière, "0x" indique un nombre en hexadécimal. Vous pouvez tout aussi bien entrer un nombre en décimal, sans besoin de préfixe.
00110000 en binaire correspond à 30 en hexadécimal et à 48 en décimal. Pour configurer les broches 13 et 12 en entrée et le reste en sorties, on peut donc écrire indifféremment:

Code: Tout sélectionner
DDRB = 0b00110000
ou
Code: Tout sélectionner
DDRB = 0x30
ou
Code: Tout sélectionner
DDRB = 48

-> Voir lien pour une explication plus détaillée sur les conversions binaire/décimal/hexadécimal

Bon, passons à la pratique.
Le montage sera relativement simple puisqu'il s'agit de comprendre le fonctionnement de différents morceaux de code : juste deux boutons dont on recopiera l'état sur deux LEDs.

- MATÉRIEL -

- Arduino Uno (x1)
- Boutons poussoir (x2)
- LEDs (x2)
- Résistances 10 kOhms (x4)

- SCHÉMA DU MONTAGE -

Manip_ports_Montage.png
Manip_ports_Montage.png (40.7 Kio) Vu 1881 fois

- CODE -

On peut recopier l'état des boutons en stockant leur état dans des variables, puis en les envoyant sur les LEDs, comme ceci :
Code: Tout sélectionner
// Déclaration des constantes
const int bouton1 = 2;
const int bouton2 = 3;
const int LED1 = 10;
const int LED2 = 11;

void setup()
{
  // Configuration des pins en entrée/sortie
  pinMode(bouton1, INPUT);
  pinMode(bouton2, INPUT);
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
}

void loop()
{
  // lecture des boutons
  int etatBouton1 = digitalRead(bouton1);
  int etatBouton2 = digitalRead(bouton2);
 
  // écriture sur les LEDs
  digitalWrite(LED1, etatBouton1);
  digitalWrite(LED2, etatBouton2);
}

... maintenant que nous savons optimiser notre code en manipulant directement les ports, voilà à quoi ressemble le code, une fois réduit :

Code: Tout sélectionner
void setup()
{
  DDRB = 0b00001101; // pins 0, 2 et 3 en entrée, 1 et 4 à 7 en sortie
  DDRD = 0; // pins 8 à 13 en sortie
}

void loop()
{
  PORTB = PIND; // recopie de l'état du port D sur le port B
}

Note : Ici on se contente de recopier la valeur de PIND (état des broches du port D) dans PORTB, car les pins concernées sont au même emplacement sur chaque port (bits de poids 2 et 3). Si l'on avait mis les LEDs sur les pins 8 et 9, il aurait fallu manipuler les bits pour les envoyer au bon endroit, par exemple avec :

Code: Tout sélectionner
PORTB = PIND >> 2; // décaler deux fois vers la droite

La manipulation des ports permet d'écrire du code plus rapidement, peut permettre de sauvegarder de la mémoire pour d'autres applications, et de configurer plusieurs pins au même moment puisque tous les bits sont envoyés simultanément.
Elle peut cependant rendre le code moins facile à comprendre, moins portable si vous voulez exporter votre code vers d'autres microcontrôleurs Atmel, et il est généralement plus facile de voir que l'on s'est trompé dans un PinMode() que dans une suite de 0 et de 1... à faire avec précaution donc, mais ça peut être utile :mrgreen:

J'espère que ce petit tutoriel vous aura plu, bonne bidouille en attendant le prochain !
"If it's itchy, scratch it !" - "DIY or die"

RTFM (À lire avant de poster) - ANDb (Arduino Noob Database)
Avatar de l’utilisateur
Laetitia
 
Messages: 296
Inscription: Mar 7 Aoû 2012 15:07
Localisation: Toulouse

Retourner vers Logiciel Arduino

Qui est en ligne

Utilisateurs parcourant ce forum: Aucun utilisateur enregistré et 1 invité