Test 2 : Boîte Noire - Communication et Contrôle

Durée : 1 semaine

1. Introduction

Dans les secteurs de l'aéronautique, de l'automobile ou du ferroviaire, les boîtes noires sont essentielles pour l'enregistrement des données de fonctionnement. Inspirés de ces systèmes, nous avons conçu un dispositif capable d'enregistrer et de transmettre en temps réel les données de mouvement d'un robot grâce à un capteur MPU6050 (accéléromètre + gyroscope) intégré dans une boîte cubique.

2. Objectifs du test

  • Mettre en œuvre un système d'acquisition de données inertielle (MPU6050)
  • Transmettre les données via un bus I2C vers une station de contrôle
  • Afficher les données en temps réel sur un écran LCD
  • Utiliser des microcontrôleurs ATmega328P sans carte Arduino
  • Documenter la conception du circuit imprimé (PCB) et assurer une présentation professionnelle

3. Liste des composants utilisés

ATmega328P
2 × ATmega328P

Cœur du système, ces microcontrôleurs 8-bit gèrent :

  • La communication I2C entre modules
  • Le traitement des données du capteur
  • L'affichage sur l'écran LCD

Caractéristiques : 32KB Flash, 2KB SRAM, 16MHz

1 × Module MPU6050

Capteur 6 axes (gyroscope + accéléromètre) utilisé pour :

  • Détection de l'orientation spatiale
  • Mesure des mouvements brusques
  • Référence à la gravité terrestre

Communication via I2C (adresse 0x68)

MPU6050
1 × Écran LCD 16x2

Interface de visualisation des données :

  • Affiche les données en temps réel
  • Contrôlé via interface I2C
  • Adresse typique : 0x27 ou 0x3F

Consommation : ~1mA

LCD 16x2
1 × Régulateur de tension 5V

Stabilise l'alimentation électrique :

  • Protège les composants sensibles
  • Type : LM7805

Courant max : 1A (avec dissipateur)

Régulateur 5V
Résistances, condensateurs, quartz 16MHz

Éléments essentiels au fonctionnement :

  • Résistances 10kΩ et 220Ω
  • Condensateurs de découplage (100nF)
  • Quartz pour l'horloge du microcontrôleur

Précision requise : ±5%

Résistance 220Ω Condensateur 100nF Quartz 16MHz

4. Architecture du système

Le système est réparti en deux modules :

  • Module capteur (la boîte noire) : contient l'ATmega328P maître I2C et le MPU6050
  • Station de contrôle : contient l'ATmega328P esclave I2C et l'écran LCD

5. Schémas électroniques (réalisés sur KiCad)

Les circuits ont été conçus avec KiCad pour chaque sous-système du projet.

6. Circuit imprimé

Support physique du circuit : PCB personnalisé pour chaque module : alimentation, boîte noire et station de contrôle

Téléchargement des fichiers KiCad

Téléchargez ici tous les fichiers sources KiCad regroupant les schémas et PCB du projet :

Télécharger le dossier KiCad complet (RAR)

7. Simulation dans Proteus

Le module MPU6050 n'étant pas présent dans la bibliothèque officielle de Proteus, nous avons simulé son comportement en injectant directement des données constantes dans le microcontrôleur maître (ATmega328P). Cela permet de vérifier le bon fonctionnement du bus I2C, la transmission des données et l'affichage sur l'écran LCD.

Structure du dossier de simulation
📁 Simulation_Proteus_Boite_Noire
├── 📁 maitre
│   ├── maitre.ino
└── 📁 esclave
    └── esclave.ino
Téléchargement du dossier complet
Télécharger le projet de simulation (.zip)
Vidéo de démonstration de la simulation

8. Codes

Côté "boîte noire" (maître I2C, avec MPU6050)

#define F_CPU 16000000UL
#include 
#include 
#include 

#define MPU6050_ADDR 0x68
#define SLAVE_ADDR 0x20

// === I2C Maître ===
void I2C_Init() {
    TWSR = 0x00;
    TWBR = 72; // 100kHz à 16MHz
}

void I2C_Start() {
    TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
    while (!(TWCR & (1 << TWINT)));
}

void I2C_Stop() {
    TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
    _delay_us(10);
}

void I2C_Write(uint8_t data) {
    TWDR = data;
    TWCR = (1 << TWINT) | (1 << TWEN);
    while (!(TWCR & (1 << TWINT)));
}

uint8_t I2C_Read_ACK() {
    TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
    while (!(TWCR & (1 << TWINT)));
    return TWDR;
}

uint8_t I2C_Read_NACK() {
    TWCR = (1 << TWINT) | (1 << TWEN);
    while (!(TWCR & (1 << TWINT)));
    return TWDR;
}

// === MPU6050 ===
void MPU6050_Init() {
    I2C_Start();
    I2C_Write(MPU6050_ADDR << 1);  // Write mode
    I2C_Write(0x6B); // PWR_MGMT_1
    I2C_Write(0);    // Wake up
    I2C_Stop();
}

int16_t MPU6050_ReadAxis(uint8_t regH) {
    I2C_Start();
    I2C_Write(MPU6050_ADDR << 1);  // Write
    I2C_Write(regH);               // Register to read
    I2C_Start();
    I2C_Write((MPU6050_ADDR << 1) | 1); // Read
    uint8_t high = I2C_Read_ACK();
    uint8_t low = I2C_Read_NACK();
    I2C_Stop();
    return (int16_t)(high << 8 | low);
}

int main() {
    DDRB |= (1 << PB5); // Debug LED
    I2C_Init();
    MPU6050_Init();

    while (1) {
        int16_t accX = MPU6050_ReadAxis(0x3B);
        int16_t accY = MPU6050_ReadAxis(0x3D);
        int16_t accZ = MPU6050_ReadAxis(0x3F);

        // Envoi des données à l'esclave
        I2C_Start();
        I2C_Write(SLAVE_ADDR << 1); // Esclave
        I2C_Write(accX >> 8); I2C_Write(accX & 0xFF);
        I2C_Write(accY >> 8); I2C_Write(accY & 0xFF);
        I2C_Write(accZ >> 8); I2C_Write(accZ & 0xFF);
        I2C_Stop();

        PORTB ^= (1 << PB5);
        _delay_ms(300);
    }
}
Côté "station de contrôle" (esclave I2C + LCD 4 bits)

#define F_CPU 16000000UL
#include 
#include 
#include 
#include 

#define LCD_PORT PORTD
#define LCD_DDR DDRD
#define RS PD0
#define EN PD1

volatile int16_t accX, accY, accZ;
volatile uint8_t data_received = 0;

// === Fonctions LCD en 4 bits ===
void LCD_Command(uint8_t cmd) {
    LCD_PORT = (LCD_PORT & 0x0F) | (cmd & 0xF0);
    LCD_PORT &= ~(1 << RS);
    LCD_PORT |= (1 << EN);
    _delay_us(1);
    LCD_PORT &= ~(1 << EN);
    _delay_us(200);

    LCD_PORT = (LCD_PORT & 0x0F) | (cmd << 4);
    LCD_PORT |= (1 << EN);
    _delay_us(1);
    LCD_PORT &= ~(1 << EN);
    _delay_ms(2);
}

void LCD_Char(char data) {
    LCD_PORT = (LCD_PORT & 0x0F) | (data & 0xF0);
    LCD_PORT |= (1 << RS);
    LCD_PORT |= (1 << EN);
    _delay_us(1);
    LCD_PORT &= ~(1 << EN);
    _delay_us(200);

    LCD_PORT = (LCD_PORT & 0x0F) | (data << 4);
    LCD_PORT |= (1 << RS);
    LCD_PORT |= (1 << EN);
    _delay_us(1);
    LCD_PORT &= ~(1 << EN);
    _delay_ms(2);
}

void LCD_Init() {
    LCD_DDR = 0xFF;
    _delay_ms(50);
    LCD_Command(0x02);
    LCD_Command(0x28);
    LCD_Command(0x0C);
    LCD_Command(0x06);
    LCD_Command(0x01);
}

void LCD_Print(char *str) {
    while (*str) {
        LCD_Char(*str++);
    }
}

// === ISR pour réception I2C ===
ISR(TWI_vect) {
    static uint8_t buffer[6];
    static uint8_t index = 0;

    switch (TWSR & 0xF8) {
        case 0x60: // Adresse esclave reçue (Write)
            index = 0;
            TWCR |= (1 << TWEA) | (1 << TWINT);
            break;
        case 0x80: // Donnée reçue
            buffer[index++] = TWDR;
            if (index >= 6) {
                accX = (buffer[0] << 8) | buffer[1];
                accY = (buffer[2] << 8) | buffer[3];
                accZ = (buffer[4] << 8) | buffer[5];
                data_received = 1;
                index = 0; // Reset index après réception
            }
            TWCR |= (1 << TWEA) | (1 << TWINT);
            break;
        default:
            TWCR |= (1 << TWEA) | (1 << TWINT);
            break;
    }
}

int main() {
    DDRB |= (1 << PB1); // LED debug pour signal réception
    LCD_Init();

    // I2C en esclave
    TWAR = (0x20 << 1);  // Adresse esclave 0x20
    TWCR = (1 << TWEA) | (1 << TWEN) | (1 << TWIE);
    sei(); // Interruptions globales

    char text[16];

    while (1) {
        if (data_received) {
            LCD_Command(0x80); // Ligne 1
            sprintf(text, "X:%4d Y:%4d", accX, accY);
            LCD_Print(text);

            LCD_Command(0xC0); // Ligne 2
            sprintf(text, "Z:%4d", accZ);
            LCD_Print(text);

            PORTB ^= (1 << PB1);  // Clignote LED pour debug
            data_received = 0;
        }
    }
}

9. Explication : Simulation vs Réalité

Cette section vise à établir une correspondance claire entre ce qui a été simulé dans Proteus et ce qui se passe dans la mise en œuvre réelle du projet.

a. Simulation dans Proteus
  • Dans l'environnement de simulation, deux microcontrôleurs ATmega328P communiquent via le bus I2C :
    • Le microcontrôleur maître génère des données aléatoires simulant les valeurs de l'accéléromètre (accX, accY, accZ).
    • Ces données sont transmises via I2C à un microcontrôleur esclave, qui les affiche sur un écran LCD 16x2.
  • Des LEDs permettent de visualiser l'activité du système :
    • La LED du maître s'allume après chaque transmission.
    • La LED de l'esclave clignote à chaque réception complète des données.
  • La simulation permet donc de valider la logique du protocole de communication (I2C), la réception, et l'affichage des données, sans avoir besoin de matériel réel.
b. Implémentation réelle avec MPU6050
  • Dans la version physique :
    • Le maître n'utilise plus de données aléatoires, mais récupère les vraies valeurs d'accélération du capteur MPU6050, connecté via I2C.
    • Les données lues depuis le MPU6050 sont ensuite envoyées exactement de la même manière à l'esclave via I2C.
  • L'esclave reste inchangé : il reçoit 6 octets (2 par axe) et les affiche sur le même écran LCD.

10. Vidéo de démonstration

11. Contraintes et recommandations

  • Ne pas utiliser de carte Arduino ou breadboard dans la version finale
  • Boîte cubique de 7 cm avec ouverture sur le dessus si opaque
  • Câblage propre et composants fixés solidement
  • Station de contrôle séparée avec écran bien lisible

12. Critères d'évaluation

CritèreDétailsPoints
CircuiterieQualité du schéma, soudure, alimentation, présentation du circuit25
CodeLisibilité, commentaires, logique du code25
Réalisation physiqueEsthétique de la boîte et du poste de contrôle10
FonctionnementQualité de la démonstration du système25
DocumentationStructure, clarté, rigueur technique10
Présentation oraleSlides, expression orale, réponse aux questions5

13. Références techniques

Voici les liens vers les documents techniques (datasheets) utilisés dans ce projet

14. Conclusion

Ce test a permis de mettre en œuvre un système embarqué capable de mesurer et transmettre des données inertielle en temps réel. Il s'inscrit dans une logique de fiabilité, de rigueur technique et d'intégration dans une solution robotique autonome.