🔌 Ports I/O et registres DDR

Contrôlez les broches de l'ATmega328P en accès direct : DDRx, PORTx, PINx

Le système de ports AVR

Sur les microcontrôleurs AVR, les broches GPIO sont organisées en ports de 8 bits. L'ATmega328P possède 3 ports : PORTB, PORTC et PORTD. Chaque broche d'un port peut être configurée individuellement comme entrée ou sortie.

Contrairement à Arduino qui utilise une numérotation continue (D0–D13, A0–A5), la programmation AVR utilise la notation native du microcontrôleur : PB0, PB1… PD7, PC0… etc. Cela correspond directement aux registres matériels.

📋 Les 3 registres par port

Chaque port est contrôlé par exactement 3 registres 8 bits. Comprendre ces registres est la clé de la programmation AVR :

1. DDRx — Data Direction Register

Définit la direction de chaque broche du port :

DDRB |= (1 << PB5);   // PB5 en sortie (broche 13 Arduino)
DDRD &= ~(1 << PD2);  // PD2 en entrée (broche 2 Arduino)
DDRB = 0xFF;            // Tout PORTB en sortie
DDRD = 0x00;            // Tout PORTD en entrée

2. PORTx — Port Data Register

Deux rôles selon la direction de la broche :

PORTB |= (1 << PB5);   // PB5 = HIGH (LED allumée)
PORTB &= ~(1 << PB5);  // PB5 = LOW (LED éteinte)
PORTD |= (1 << PD2);   // Activer pull-up sur PD2 (entrée)

3. PINx — Port Input Register (lecture seule)

Lit l'état logique actuel de chaque broche du port, quelle que soit sa direction :

if (PIND & (1 << PD2)) {   // Tester si PD2 est à HIGH
    // Bouton non pressé (avec pull-up)
} else {
    // Bouton pressé (PD2 = LOW)
}

💡 Astuce — Toggle rapide : Écrire un 1 dans le registre PINx permet de basculer (toggle) la sortie correspondante sur certains AVR récents : PINB |= (1 << PB5); inverse l'état de PB5. C'est une fonctionnalité spécifique aux AVR, plus rapide qu'un XOR sur PORTx.

🔧 Opérations bit à bit essentielles

La manipulation des registres AVR repose sur les opérations bit à bit du langage C. Voici les 4 opérations fondamentales :

OpérationSyntaxeEffet
Mettre un bit à 1REG |= (1 << n)SET bit n, les autres inchangés
Mettre un bit à 0REG &= ~(1 << n)CLEAR bit n, les autres inchangés
Basculer un bitREG ^= (1 << n)TOGGLE bit n (0→1 ou 1→0)
Tester un bitif (REG & (1 << n))Vrai si bit n = 1

Ces opérations sont identiques à celles utilisées sur les PIC (voir notre tutoriel Configuration Binaire PIC). Seuls les noms des registres changent.

💻 Exemple complet : LED + Bouton

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

int main(void) {
    // Configuration
    DDRB |= (1 << PB5);     // PB5 (D13) en sortie → LED
    DDRD &= ~(1 << PD2);    // PD2 (D2) en entrée → Bouton
    PORTD |= (1 << PD2);    // Activer pull-up sur PD2

    while (1) {
        if (!(PIND & (1 << PD2))) {    // Bouton pressé (LOW)
            PORTB |= (1 << PB5);        // LED ON
        } else {
            PORTB &= ~(1 << PB5);       // LED OFF
        }
    }
}

Ce programme allume la LED quand le bouton (connecté entre PD2 et GND) est pressé. Grâce à la pull-up interne, aucune résistance externe n'est nécessaire pour le bouton.

📌 Correspondance Arduino ↔ AVR

Arduino PinAVR PortArduino PinAVR Port
D0PD0D8PB0
D1PD1D9PB1
D2PD2D10PB2
D3PD3D11PB3
D4PD4D12PB4
D5PD5D13PB5
D6PD6A0PC0
D7PD7A5PC5