I know there are already many forums about this same problem but I couldn't find the solution in them.
When I start running the program, an error message is displayed and it says: "invalid header file". I know however that all of the libraries I am using are available in Tinkercad. I haven't tried this in real life yet so I don't know if this is a Tinkercad error or my code's.
My project is a small game between 2 players in which I need to connect 3 arduino uno cards together. In order to do that I am using the I2C communication method. Here is the 3 codes for the 3 arduino cards and a picture of the setup:
Good luck to the best out there. This will be a nice challenge for you!
Code of the master arduino:
#include <Wire.h>
#include <LiquidCrystal.h>
// Configuration LCD du joueur 1 (pins: RS = 2, E = 3, DB4 = 4, DB5 = 5, DB6 = 6, DB7 = 7)
LiquidCrystal lcd1(2, 3, 4, 5, 6, 7);
// Configuration LCD du joueur 2 (pins: RS = 8, E = 9, DB4 = 10, DB5 = 11, DB6 = 12, DB7 = 13)
LiquidCrystal lcd2(8, 9, 10, 11, 12, 13);
// Adresses I2C des esclaves
const byte slave1Address = 8; // Joueur 1
const byte slave2Address = 9; // Joueur 2
// Durée du jeu en millisecondes (2 minutes)
const unsigned long gameDuration = 120000;
unsigned long startTime;
bool gameOver = false;
int score1 = 0;
int score2 = 0;
void setup() {
Wire.begin();
Serial.begin(9600);
lcd1.begin(16, 2);
lcd2.begin(16, 2);
startTime = millis();
}
void loop() {
unsigned long elapsed = millis() - startTime;
int timeRemaining = 0;
if (elapsed < gameDuration) {
timeRemaining = (gameDuration - elapsed) / 1000;
} else {
timeRemaining = 0;
gameOver = true;
}
// Envoi du temps restant aux deux esclaves
sendTimeToSlave(slave1Address, timeRemaining);
sendTimeToSlave(slave2Address, timeRemaining);
// Récupération des scores des esclaves
score1 = requestScoreFromSlave(slave1Address);
score2 = requestScoreFromSlave(slave2Address);
// Mise à jour de l'écran du joueur 1
lcd1.clear();
lcd1.setCursor(0, 0);
lcd1.print("P1: ");
lcd1.print(score1);
lcd1.setCursor(10, 0);
lcd1.print("P2: ");
lcd1.print(score2);
lcd1.setCursor(4, 1);
if (!gameOver) {
lcd1.print("Time: ");
} else {
lcd1.print("GAME OVER");
}
lcd1.setCursor(10, 1);
lcd1.print(timeRemaining);
// Mise à jour de l'écran du joueur 2
lcd2.clear();
lcd2.setCursor(0, 0);
lcd2.print("P2: ");
lcd2.print(score2);
lcd2.setCursor(10, 0);
lcd2.print("P1: ");
lcd2.print(score1);
lcd2.setCursor(4, 1);
if (!gameOver) {
lcd2.print("Time: ");
} else {
lcd2.print("GAME OVER");
}
lcd2.setCursor(10, 1);
lcd2.print(timeRemaining);
delay(200);
}
void sendTimeToSlave(byte slaveAddress, int timeRemaining) {
Wire.beginTransmission(slaveAddress);
Wire.write(highByte(timeRemaining));
Wire.write(lowByte(timeRemaining));
Wire.endTransmission();
}
int requestScoreFromSlave(byte slaveAddress) {
int score = 0;
// Correction : cast du second argument en uint8_t pour correspondre à la bonne surcharge
Wire.requestFrom((uint8_t)slaveAddress, (uint8_t)2);
if (Wire.available() >= 2) {
byte high = Wire.read();
byte low = Wire.read();
score = (high << 8) | low;
}
return score;
}
Code of the slave arduino cards (The code for the 2 other cards are the same. Only the adress changes from 8 to 9.)
#include <Wire.h>
#include <Adafruit_NeoPixel.h>
#define SLAVE_ADDRESS 8 // Adresse pour le joueur 1
// Pins pour boutons dynamiques et leurs LEDs NeoPixel
const int dynButton1Pin = 7; // Bouton dynamique 1
const int dynLEDPin1 = 3; // LED NeoPixel associée
const int dynButton2Pin = 4; // Bouton dynamique 2
const int dynLEDPin2 = 2; // LED NeoPixel associée
// Boutons pour malus et bingo
const int malusButtonPin = 6; // Bouton malus (-2 points)
const int bingoButtonPin = 5; // Bouton bingo (+8 points)
// Initialisation des NeoPixels (1 pixel chacun)
Adafruit_NeoPixel dynLED1 = Adafruit_NeoPixel(1, dynLEDPin1, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel dynLED2 = Adafruit_NeoPixel(1, dynLEDPin2, NEO_GRB + NEO_KHZ800);
// Variables de score et de valeur initiale des boutons dynamiques
int score = 0;
int dynValue1 = 5; // Valeur initiale = 5 (puis passe à 2, puis à 1)
int dynValue2 = 5;
// Temps restant reçu du maître (en secondes)
volatile int timeRemaining = 120;
// Variables pour le debounce
unsigned long lastDebounce1 = 0;
unsigned long lastDebounce2 = 0;
unsigned long lastDebounceMalus = 0;
unsigned long lastDebounceBingo = 0;
const unsigned long debounceDelay = 50;
void setup() {
Wire.begin(SLAVE_ADDRESS);
Wire.onReceive(receiveEvent);
Wire.onRequest(requestEvent);
// Configuration des boutons en INPUT_PULLUP
pinMode(dynButton1Pin, INPUT_PULLUP);
pinMode(dynButton2Pin, INPUT_PULLUP);
pinMode(malusButtonPin, INPUT_PULLUP);
pinMode(bingoButtonPin, INPUT_PULLUP);
// Les LEDs malus et bingo sont câblées directement sur le 5V/GND, pas besoin de les configurer ici.
// Initialisation des NeoPixels
dynLED1.begin();
dynLED1.show();
dynLED2.begin();
dynLED2.show();
// Initialisation de la couleur des LEDs dynamiques (valeur 5 = vert)
setDynLEDColor(dynLED1, dynValue1);
setDynLEDColor(dynLED2, dynValue2);
}
void loop() {
if (timeRemaining > 0) {
// Vérification des boutons dynamiques
checkDynamicButton(dynButton1Pin, dynLED1, &dynValue1);
checkDynamicButton(dynButton2Pin, dynLED2, &dynValue2);
// Vérification des boutons simples (malus et bingo)
checkSimpleButton(malusButtonPin, -2);
checkSimpleButton(bingoButtonPin, 8);
}
}
void checkDynamicButton(int buttonPin, Adafruit_NeoPixel &led, int *dynValue) {
int reading = digitalRead(buttonPin);
unsigned long currentMillis = millis();
// Si le bouton est pressé (LOW) et que le debounce est passé
if (reading == LOW && (currentMillis - (buttonPin == dynButton1Pin ? lastDebounce1 : lastDebounce2) > debounceDelay)) {
score += *dynValue; // Ajout de la valeur actuelle au score
// Réduire la valeur : 5 -> 2, 2 -> 1 (1 reste 1)
if (*dynValue == 5) {
*dynValue = 2;
} else if (*dynValue == 2) {
*dynValue = 1;
}
setDynLEDColor(led, *dynValue);
if (buttonPin == dynButton1Pin) {
lastDebounce1 = currentMillis;
} else {
lastDebounce2 = currentMillis;
}
delay(200);
}
}
void checkSimpleButton(int buttonPin, int points) {
int reading = digitalRead(buttonPin);
unsigned long currentMillis = millis();
if (buttonPin == malusButtonPin) {
if (reading == LOW && (currentMillis - lastDebounceMalus > debounceDelay)) {
score += points; // -2 points pour malus
lastDebounceMalus = currentMillis;
delay(200);
}
} else if (buttonPin == bingoButtonPin) {
if (reading == LOW && (currentMillis - lastDebounceBingo > debounceDelay)) {
score += points; // +8 points pour bingo
lastDebounceBingo = currentMillis;
delay(200);
}
}
}
void setDynLEDColor(Adafruit_NeoPixel &led, int value) {
uint32_t color;
if (value == 5) {
color = led.Color(0, 255, 0); // Vert
} else if (value == 2) {
color = led.Color(255, 255, 0); // Jaune
} else {
color = led.Color(0, 0, 0); // Éteint
}
led.setPixelColor(0, color);
led.show();
}
void receiveEvent(int howMany) {
if (howMany >= 2) {
byte high = Wire.read();
byte low = Wire.read();
timeRemaining = (high << 8) | low;
}
}
void requestEvent() {
Wire.write(highByte(score));
Wire.write(lowByte(score));
}
Thank you for your time!