// ========== Arduino Nano unique : Software I2C (Master) + Hardware I2C (Slave) ==========
// Le Nano s'envoie des messages à lui-même via I2C !
#include <Wire.h>
#include <SoftwareWire.h>
// Adresse I2C du slave (hardware)
#define SLAVE_ADDR 0x08
// Pins pour le Software I2C (Master)
#define SOFT_SDA_PIN 2
#define SOFT_SCL_PIN 3
// Créer l'objet Software I2C
SoftwareWire softWire(SOFT_SDA_PIN, SOFT_SCL_PIN);
// Structure de 32 octets
struct Message {
char text[16]; // 16 octets
int16_t value; // 2 octets
uint32_t timestamp; // 4 octets
uint8_t padding[10]; // 10 octets de padding
};
// Variables pour l'émetteur (Software I2C)
Message msgEnvoi;
unsigned long compteur = 0;
unsigned long dernierEnvoi = 0;
// Variables pour le récepteur (Hardware I2C)
Message msgRecu;
volatile bool nouveauMessage = false;
void setup() {
Serial.begin(115200);
while(!Serial) {}
Serial.println("OK, Let's go!");
// Initialise Hardware I2C en mode SLAVE (récepteur)
Wire.begin(SLAVE_ADDR);
Wire.onReceive(receiveEvent);
// Initialise Software I2C en mode MASTER (émetteur)
softWire.begin();
// Prépare le premier message
strncpy(msgEnvoi.text, "Hello I2C!", 16);
msgEnvoi.value = 0;
msgEnvoi.timestamp = 0;
memset(msgEnvoi.padding, 0xAA, 10);
Serial.println("========================================");
Serial.println("=== Arduino Nano I2C Loopback Test ===");
Serial.println("========================================");
Serial.print("Taille structure: ");
Serial.print(sizeof(msgEnvoi));
Serial.println(" octets");
Serial.print("Adresse slave (Hardware I2C): 0x");
if(SLAVE_ADDR < 0x10) Serial.print('0');
Serial.println(SLAVE_ADDR, HEX);
Serial.print("Software I2C Master sur pins: D");
Serial.print(SOFT_SDA_PIN);
Serial.print(" (SDA), D");
Serial.print(SOFT_SCL_PIN);
Serial.println(" (SCL)");
Serial.println("========================================\n");
Serial.println("IMPORTANT: Connectez physiquement:");
Serial.print(" - D");
Serial.print(SOFT_SDA_PIN);
Serial.println(" vers A4 (SDA hardware)");
Serial.print(" - D");
Serial.print(SOFT_SCL_PIN);
Serial.println(" vers A5 (SCL hardware)");
Serial.println();
delay(1000);
}
void loop() {
// Envoi d'un message toutes les 2 secondes
if (millis() - dernierEnvoi >= 2000) {
dernierEnvoi = millis();
// Met à jour le message
msgEnvoi.timestamp = millis();
msgEnvoi.value = compteur;
snprintf(msgEnvoi.text, 16, "Message #%lu", compteur);
compteur++;
// Envoie via Software I2C
Serial.println(">>> ENVOI via Software I2C:");
Serial.print(" Text: ");
Serial.println(msgEnvoi.text);
Serial.print(" Value: ");
Serial.println(msgEnvoi.value);
Serial.print(" Timestamp: ");
Serial.println(msgEnvoi.timestamp);
// IMPORTANT: Désactive temporairement le Hardware I2C slave
Wire.end();
delay(10); // Petit délai pour stabiliser
// Envoie via Software I2C
softWire.beginTransmission(SLAVE_ADDR);
softWire.write((uint8_t*)&msgEnvoi, sizeof(msgEnvoi));
uint8_t error = softWire.endTransmission();
delay(10); // Délai pour laisser le temps au transfert
// Réactive le Hardware I2C slave
Wire.begin(SLAVE_ADDR);
Wire.onReceive(receiveEvent);
Serial.print(" Statut envoi: ");
if (error == 0) {
Serial.println("OK");
} else {
Serial.print("ERREUR ");
Serial.println(error);
Serial.println(" (Verifiez les connexions D2->A4 et D3->A5)");
}
Serial.println();
}
// Traite les messages reçus
if (nouveauMessage) {
nouveauMessage = false;
Serial.println("<<< RECEPTION via Hardware I2C:");
Serial.print(" Text: ");
char textTemp[17];
memcpy(textTemp, msgRecu.text, 16);
textTemp[16] = '\0';
Serial.println(textTemp);
Serial.print(" Value: ");
Serial.println(msgRecu.value);
Serial.print(" Timestamp: ");
Serial.println(msgRecu.timestamp);
Serial.print(" Padding: ");
for(int i = 0; i < 5; i++) { // Affiche seulement les 5 premiers
Serial.print("0x");
if(msgRecu.padding[i] < 16) Serial.print("0");
Serial.print(msgRecu.padding[i], HEX);
Serial.print(" ");
}
Serial.println("...");
// Vérifie l'intégrité
bool integrite = true;
if (msgRecu.value != msgEnvoi.value - 1) { // -1 car on a déjà incrémenté
integrite = false;
}
Serial.print(" Integrite: ");
Serial.println(integrite ? "OK ✓" : "ERREUR ✗");
Serial.println();
}
}
// Fonction appelée lors de la réception sur Hardware I2C
void receiveEvent(int howMany) {
if (howMany == sizeof(msgRecu)) {
uint8_t* ptr = (uint8_t*)&msgRecu;
int i = 0;
while (Wire.available() && i < sizeof(msgRecu)) {
ptr[i] = Wire.read();
i++;
}
nouveauMessage = true;
} else {
// Vide le buffer si taille incorrecte
while (Wire.available()) {
Wire.read();
}
Serial.print("!!! ERREUR Reception: taille incorrecte (");
Serial.print(howMany);
Serial.print(" octets au lieu de ");
Serial.print(sizeof(msgRecu));
Serial.println(")");
}
}