Hello everyone I am new to this forum and before starting everything I just want to say that I am french so please note that i can't express myself very well.
Okay so to summarize everything I have a project to do for school but the project relies on memory problems. The code itself is not hard to do, it's just long, but the problem is that we use a Arduino Uno which has not much FLASH memory and RAM. I have the project ready that i tested in different .ini files but if I put them all in one file, I have to put a big part of the code in commentary so that it's not used when compiling the code. I would love if someone can help me and help me gain RAM / FLASH memory. Thank you all.
#include <SoftwareSerial.h>
#include <Wire.h>
#include <RTClib.h>
#include <forcedClimate.h>
#include <ChainableLED.h>
#include <SdFat.h>
#include <EEPROM.h>
#define MODE_STANDARD 1
#define MODE_MAINTENANCE 2
#define MODE_ECO 3
#define MODE_CONFIGURATION 4
#define PIN_BOUTON_VERT 2
#define PIN_BOUTON_ROUGE 3
#define PIN_LUMIN A3
#define PIN_SD 4
#define TAILLE_TABLEAU 15
SdFat SD;
RTC_DS1307 rtc;
ForcedClimate climateSensor = ForcedClimate();
ChainableLED leds(8, 9, 1);
SoftwareSerial SoftSerial(6, 7);
int mode_actu = 0;
int mode_prec;
bool EtatBoutonVert = false;
unsigned long TempsBoutonVert;
bool EtatBoutonRouge = false;
unsigned long TempsBoutonRouge;
unsigned long TempsInactif;
int adresse = 0;
const int ParametresDefault[TAILLE_TABLEAU] =
{
10, // LOG_INTERVAL,
4096, // FILE_MAX_SIZE,
30, // TIMEOUT,
1, // LUMIN,
255, // LUMIN_LOW,
768, // LUMIN_HIGH,
1, // TEMP_AIR,
-10, // MIN_TEMP_AIR,
60, // MAX_TEMP_AIR,
1, // HYGR,
0, // HYGR_MINT,
50, // HYGR_MAXT,
1, // PRESSURE
850, // PRESSURE_MIN
1080 // PRESSURE_MAX
};
int ParametresConfig[TAILLE_TABLEAU] =
{
10, // LOG_INTERVAL,
4096, // FILE_MAX_SIZE,
30, // TIMEOUT,
1, // LUMIN,
255, // LUMIN_LOW,
768, // LUMIN_HIGH,
1, // TEMP_AIR,
-10, // MIN_TEMP_AIR,
60, // MAX_TEMP_AIR,
1, // HYGR,
0, // HYGR_MINT,
50, // HYGR_MAXT,
1, // PRESSURE
850, // PRESSURE_MIN
1080 // PRESSURE_MAX
};
#define LOG_INTERVAL_INDEX 0
#define FILE_MAX_SIZE_INDEX 1
#define TIMEOUT_INDEX 2
#define LUMIN_INDEX 3
#define LUMIN_LOW_INDEX 4
#define LUMIN_HIGH_INDEX 5
#define TEMP_AIR_INDEX 6
#define MIN_TEMP_AIR_INDEX 7
#define MAX_TEMP_AIR_INDEX 8
#define HYGR_INDEX 9
#define HYGR_MINT_INDEX 10
#define HYGR_MAXT_INDEX 11
#define PRESSURE_INDEX 12
#define PRESSURE_MIN_INDEX 13
#define PRESSURE_MAX_INDEX 14
File32 Fichier;
unsigned long TempsDerniereMesure = 0;
char RevisionFichier = '0';
bool VerificationEEPROM = false;
long LOG_INTERVAL = ParametresConfig[LOG_INTERVAL_INDEX];
String GPS;
void BoutonRougeInterruption(void);
void BoutonVertInterruption(void);
void Mode_standard();
void Mode_Maintenance();
void Mode_economique();
void Mode_config();
void LEDMode();
void Enregistrement_SD();
void ChangerHorloge(int annee, int mois, int jour, int heure, int minute, int seconde);
void GenerationDonnees();
void DonneesGPS();
void connexionSD();
void erreur_acces_horloge();
void erreur_acces_GPS();
void erreur_acces_donnees_capteurs();
void erreur_donnees_incoherentes();
void erreur_carte_SD_pleine();
void erreur_acces_ecriture();
void ModificationConfig();
void Affichage(String Donnees, bool ligne);
void PointVirgule();
void SeparateurHorloge();
void Creation();
void ClearMoniteurSerie();
void FaireEEPROM(int ParametresConfig[TAILLE_TABLEAU]);
void LireEEPROM(int ParametresConfig[TAILLE_TABLEAU]);
void setup()
{
Serial.begin(9600);
SoftSerial.begin(9600);
ClearMoniteurSerie();
pinMode(PIN_BOUTON_VERT, INPUT);
pinMode(PIN_BOUTON_ROUGE, INPUT);
Wire.begin();
leds.init();
climateSensor.begin();
connexionSD();
SD.begin();
Serial.println(F("Connexion à la carte SD réussie."));
leds.setColorRGB(0, 255, 255, 255);
while (!rtc.begin())
{
Serial.println(F("Module RTC pas trouvé"));
erreur_acces_horloge();
}
rtc.adjust(DateTime((__DATE__), (__TIME__)));
attachInterrupt(digitalPinToInterrupt(PIN_BOUTON_VERT), BoutonVertInterruption, CHANGE);
attachInterrupt(digitalPinToInterrupt(PIN_BOUTON_ROUGE), BoutonRougeInterruption, CHANGE);
LireEEPROM(ParametresConfig);
for (int i = 0; i < TAILLE_TABLEAU; i++)
{
if (ParametresConfig[i] != ParametresDefault[i])
{
VerificationEEPROM = true;
break;
}
}
if (!VerificationEEPROM)
{
int adresse = 0;
for (int i = 0; i < TAILLE_TABLEAU; i++)
{
EEPROM.put(adresse + i * sizeof(long), ParametresDefault[i]);
}
}
if (digitalRead(PIN_BOUTON_ROUGE) == LOW)
{
mode_actu = MODE_CONFIGURATION;
}
else
{
mode_actu = MODE_STANDARD;
}
}
void loop()
{
switch (mode_actu)
{
case MODE_STANDARD:
Mode_standard();
break;
case MODE_MAINTENANCE:
Mode_Maintenance();
break;
case MODE_ECO:
Mode_economique();
break;
case MODE_CONFIGURATION:
// Mode_config();
break;
}
}
void BoutonVertInterruption(void)
{
if ((digitalRead(PIN_BOUTON_VERT) == LOW) && (!EtatBoutonVert))
{
EtatBoutonVert = true;
TempsBoutonVert = millis();
}
else if ((digitalRead(PIN_BOUTON_VERT) == HIGH) && (EtatBoutonVert))
{
EtatBoutonVert = false;
if ((millis() - TempsBoutonVert) >= (5000))
{
if (mode_actu == MODE_STANDARD)
{
mode_actu = MODE_ECO;
LEDMode();
}
else if (mode_actu == MODE_ECO)
{
mode_actu = MODE_STANDARD;
LEDMode();
}
}
}
}
void BoutonRougeInterruption(void)
{
if ((digitalRead(PIN_BOUTON_ROUGE) == LOW) && (!EtatBoutonRouge))
{
EtatBoutonRouge = true;
TempsBoutonRouge = millis();
}
else if (digitalRead(PIN_BOUTON_ROUGE) == HIGH && (EtatBoutonRouge))
{
EtatBoutonRouge = false;
if ((millis() - TempsBoutonRouge) >= 5000)
{
TempsBoutonRouge = millis();
switch (mode_actu)
{
case MODE_CONFIGURATION:
mode_actu = MODE_STANDARD;
LEDMode();
break;
case MODE_STANDARD:
case MODE_ECO:
mode_prec = mode_actu;
mode_actu = MODE_MAINTENANCE;
LEDMode();
break;
case MODE_MAINTENANCE:
mode_actu = mode_prec;
mode_prec = 0;
switch (mode_actu)
{
case MODE_STANDARD:
LEDMode();
break;
case MODE_ECO:
LEDMode();
break;
}
}
}
}
}
void Mode_standard()
{
LEDMode();
connexionSD();
TempsDerniereMesure = millis();
if ((millis() - TempsDerniereMesure) >= (LOG_INTERVAL * 60 * 1000))
{
Creation();
// Enregistrement_SD();
TempsDerniereMesure = millis();
LEDMode();
}
}
void Mode_Maintenance()
{
LEDMode();
delay(1000);
Creation();
LEDMode();
delay(9000);
}
void Mode_economique()
{
LEDMode();
connexionSD();
TempsDerniereMesure = millis();
if ((millis() - TempsDerniereMesure) >= (LOG_INTERVAL * 60 * 1000 * 22))
{
// Condition GPS 1 fois sur 2
Serial.println(LOG_INTERVAL * 60 * 1000);
Creation();
// Enregistrement_SD();
TempsDerniereMesure = millis();
LEDMode();
}
}
/*
void Mode_config()
{
LEDMode();
TempsInactif = millis();
Serial.println(F("Mode Configuration. Tapez vos commandes de configuration."));
while ((millis() - TempsInactif) < (30000))
{
// Ce if pique un peu les yeux :sob:
// Nan en vrai tu connais l'index de ce que tu veux modifier, donc mieux vaut faire une
// fonction ou tu définis cette valeur plutot que de faire un write de toutes les valeurs
// dans l'EEPROM, surtout qu'elle a un cycle d'ecriture limité, demande moi quand t'arrivera ici si tu veux
// que je te t'explique ou si tu veux le faire par toi meme
if (Serial.available() > 0)
{
String commande = Serial.readStringUntil('\n');
* Ici, les startsWith prennent BEAUCOUP de ram ou de flash je sais plus, mais Ă la place, tu peux les remplacer
* par des ==, si tu divise le string Ă l'endroit ou est le '=', t'obtient le membre de gauche et tu le compares,
* si tu veux je t'explique ou alors si tu veux le faire toi mĂŞme
* parce que je pense que c'est ici que tu perds le plus (avec le ModificationConfig() en plus évidemment)
*
* De plus, tu isole le membre de droite et tu le transformes en int, comme ça pas besoin de faire des substrings qui
* prennent aussi pas mal de mémoire :)
*
if (commande.startsWith("LOG_INTERVAL="))
{
ParametresConfig[LOG_INTERVAL_INDEX] = commande.substring(13).toInt();
ModificationConfig();
}
else if (commande.startsWith("FILE_MAX_SIZE="))
{
ParametresConfig[FILE_MAX_SIZE_INDEX] = commande.substring(14).toInt();
ModificationConfig();
}
else if (commande.equals("RESET"))
{
for (int i = 0; i < TAILLE_TABLEAU; i++)
{
ParametresConfig[i] = ParametresDefault[i];
}
FaireEEPROM(ParametresConfig);
ModificationConfig();
}
else if (commande.equals("VERSION"))
{
Serial.println(F("Version du programme : 1.0"));
Serial.println(F("Numéro de lot : 1"));
}
else if (commande.startsWith("TIMEOUT="))
{
ParametresConfig[TIMEOUT_INDEX] = commande.substring(8).toInt();
ModificationConfig();
}
else if (commande.startsWith("LUMIN="))
{
ParametresConfig[LUMIN_INDEX] = commande.substring(6).toInt();
ModificationConfig();
}
else if (commande.startsWith("LUMIN_LOW="))
{
ParametresConfig[LUMIN_LOW_INDEX] = commande.substring(10).toInt();
ModificationConfig();
}
else if (commande.startsWith("LUMIN_HIGH="))
{
ParametresConfig[LUMIN_HIGH_INDEX] = commande.substring(11).toInt();
ModificationConfig();
}
else if (commande.startsWith("TEMP_AIR="))
{
ParametresConfig[TEMP_AIR_INDEX] = commande.substring(9).toInt();
ModificationConfig();
}
else if (commande.startsWith("MIN_TEMP_AIR="))
{
ParametresConfig[MIN_TEMP_AIR_INDEX] = commande.substring(9).toInt();
ModificationConfig();
}
else if (commande.startsWith("MAX_TEMP_AIR="))
{
ParametresConfig[MAX_TEMP_AIR_INDEX] = commande.substring(9).toInt();
ModificationConfig();
}
else if (commande.startsWith("HYGR="))
{
ParametresConfig[HYGR_INDEX] = commande.substring(5).toInt();
ModificationConfig();
}
else if (commande.startsWith("HYGR_MINT="))
{
ParametresConfig[HYGR_MINT_INDEX] = commande.substring(10).toInt();
ModificationConfig();
}
else if (commande.startsWith("HYGR_MAXT="))
{
ParametresConfig[HYGR_MAXT_INDEX] = commande.substring(10).toInt();
ModificationConfig();
}
else if (commande.startsWith("PRESSURE="))
{
ParametresConfig[PRESSURE_INDEX] = commande.substring(5).toInt();
ModificationConfig();
}
else if (commande.startsWith("PRESSURE_MIN="))
{
ParametresConfig[PRESSURE_MIN_INDEX] = commande.substring(13).toInt();
ModificationConfig();
}
else if (commande.startsWith("PRESSURE_MAX="))
{
ParametresConfig[PRESSURE_MAX_INDEX] = commande.substring(13).toInt();
ModificationConfig();
}
else if (commande.startsWith("CLOCK="))
{
String Horloge = commande.substring(6);
int annee = Horloge.substring(0, 4).toInt();
int mois = Horloge.substring(5, 7).toInt();
int jour = Horloge.substring(8, 10).toInt();
int heure = Horloge.substring(11, 13).toInt();
int minute = Horloge.substring(14, 16).toInt();
int seconde = Horloge.substring(17, 19).toInt();
ChangerHorloge(annee, mois, jour, heure, minute, seconde);
}
else
{
Serial.println(F("Commande inexistante."));
}
TempsInactif = millis();
}
}
Serial.println(F("Fin de la configuration. Retour au mode standard."));
mode_actu = MODE_STANDARD;
}
*/
/*
void Enregistrement_SD()
{
DateTime Maintenant = rtc.now();
String NomFichier;
NomFichier = String(Maintenant.year() % 100) + String(Maintenant.month()) + String(Maintenant.day()) + "_" + String(RevisionFichier) + ".LOG";
// snprintf(NomFichier, sizeof(NomFichier), "%02d%02d%02d_%c.LOG", Maintenant.year() % 100, Maintenant.month(), Maintenant.day(), RevisionFichier);
connexionSD();
Fichier = SD.open(NomFichier, FILE_WRITE);
// Verifier si carte SD pleine
if (Fichier)
{
// Mesures des capteurs
// ...
*
* Comme je t'avais dit, mieux vaut faire le print dans le fichier plutot que de faire un enorme string
* maintenant que tu as la fonction Affichage, t'as juste à appeler la fonction qui genere les données ici
*
// Écriture des données dans le fichier
Fichier.close();
// Vérifier la taille du fichier
if ((Fichier.size()) > (ParametresConfig[FILE_MAX_SIZE_INDEX]))
{
RevisionFichier++;
}
TempsDerniereMesure = millis();
}
else
{
Serial.println(F("Erreur d'écriture sur la carte SD."));
erreur_carte_SD_pleine();
TempsDerniereMesure = millis();
}
}
*/
void ChangerHorloge(int annee, int mois, int jour, int heure, int minute, int seconde)
{
DateTime NouvelleHorloge(annee, mois, jour, heure, minute, seconde); // Année, mois, jour, heure, minute, seconde
rtc.adjust(NouvelleHorloge);
Serial.println(F("Horloge changée avec succès."));
}
void LEDMode()
{
switch (mode_actu)
{
case MODE_STANDARD:
leds.setColorRGB(0, 0, 255, 0);
break;
case MODE_MAINTENANCE:
leds.setColorRGB(0, 255, 155, 0);
break;
case MODE_ECO:
leds.setColorRGB(0, 0, 0, 255);
break;
case MODE_CONFIGURATION:
leds.setColorRGB(0, 255, 0, 0);
break;
default:
break;
}
}
void erreur_acces_horloge()
{ // Si erreur d'accès à l'horloge
leds.setColorRGB(0, 255, 0, 0); // Allume la LED en rouge
delay(1000); // On attend 1 sec
leds.setColorRGB(0, 0, 0, 255); // Allume la LED en bleu
delay(1000); // On attend 1 sec
}
void erreur_acces_GPS()
{ // Si erreur d'accès au GPS
leds.setColorRGB(0, 255, 0, 0); // Allume la LED en rouge
delay(1000); // On attend 1 sec
leds.setColorRGB(0, 255, 255, 0); // Allume la LED en jaune
delay(1000); // On attend 1 sec
}
void erreur_acces_donnees_capteurs()
{ // Si erreur d'accès aux données d'un capteur
leds.setColorRGB(0, 255, 0, 0); // Allume la LED en rouge
delay(1000); // On attend 1 sec
leds.setColorRGB(0, 0, 255, 0); // Allume la LED en verte
delay(1000); // On attend 1 sec
}
void erreur_donnees_incoherentes()
{ // Si données incohérentes
leds.setColorRGB(0, 255, 0, 0); // Allume la LED en rouge
delay(1000); // On attend 1 sec
leds.setColorRGB(0, 0, 255, 0); // Allume la LED en vert
delay(2000); // On attend 2 sec
}
void erreur_carte_SD_pleine()
{ // Si erreur de carte SD pleine
leds.setColorRGB(0, 255, 0, 0); // Allume la LED en rouge
delay(1000); // On attend 1 sec
leds.setColorRGB(0, 255, 255, 255); // Allume la LED en blanc
delay(1000); // On attend 1 sec
}
void erreur_acces_ecriture()
{ // Si erreur d'accès et d'écriture sur la carte SD
leds.setColorRGB(0, 255, 0, 0); // On allume la LED en rouge
delay(1000); // On attend 1 sec
leds.setColorRGB(0, 255, 255, 255); // On allume la LED en blanc
delay(2000); // On attend 2 sec
}
void GenerationDonnees()
{
climateSensor.takeForcedMeasurement();
if (ParametresConfig[LUMIN_INDEX])
{
int Luminosite = analogRead(PIN_LUMIN);
Affichage(String(Luminosite) + " ; ", false);
}
else
{
Affichage("Capteur désactivé ; ", false);
}
float Temperature_Air = climateSensor.getTemperatureCelcius();
if (ParametresConfig[TEMP_AIR_INDEX])
{
if (Temperature_Air >= ParametresConfig[MIN_TEMP_AIR_INDEX] && Temperature_Air <= ParametresConfig[MAX_TEMP_AIR_INDEX])
{
Affichage(String(Temperature_Air) + " ; ", false);
}
else
{
erreur_donnees_incoherentes();
Affichage("Hors intervalle ; ", false);
}
}
else
{
Affichage("Capteur désactivé ; ", false);
}
if (ParametresConfig[HYGR_INDEX])
{
float Hygrometrie = climateSensor.getRelativeHumidity();
if (Temperature_Air >= ParametresConfig[MIN_TEMP_AIR_INDEX] && Temperature_Air <= ParametresConfig[MAX_TEMP_AIR_INDEX])
{
Affichage(String(Hygrometrie) + " ; ", false);
}
else
{
erreur_donnees_incoherentes();
Affichage("Hors intervalle ; ", false);
}
}
else
{
Affichage("Capteur désactivé ; ", false);
}
if (ParametresConfig[PRESSURE_INDEX])
{
float Pression = climateSensor.getPressure();
if (Pression >= ParametresConfig[PRESSURE_MIN_INDEX] && Pression <= ParametresConfig[PRESSURE_MAX_INDEX])
{
Affichage(String(Pression), true);
}
else
{
erreur_donnees_incoherentes();
Affichage("Hors intervalle", true);
}
}
else
{
Affichage("Capteur désactivé", true);
}
}
void connexionSD()
{
while (!SD.begin(PIN_SD))
{
Serial.println(F("Connexion Ă la carte SD impossible, veuillez verifier la connexion."));
erreur_acces_ecriture();
}
}
void ModificationConfig()
{
/*
* Comme dit au dessus, Changer ça :'(
* Tu sais quel paramètre tu changes dans le mode config donc ne modifie que cette valeur
* Par contre pour le setup tu peux le laisser :)
*/
Serial.println(F("Modification effectuée avec succès."));
FaireEEPROM(ParametresConfig);
}
void ClearMoniteurSerie()
{
for (int i = 0; i < 30; i++)
{
Serial.println();
}
}
void FaireEEPROM(int ParametresConfig[TAILLE_TABLEAU])
{
adresse = 0;
for (int i = 0; i < TAILLE_TABLEAU; i++)
{
EEPROM.put(adresse + i * sizeof(long), ParametresConfig[i]);
}
}
void LireEEPROM(int ParametresConfig[TAILLE_TABLEAU])
{
adresse = 0;
for (int i = 0; i < TAILLE_TABLEAU; i++)
{
EEPROM.get(adresse + i * sizeof(long), ParametresConfig[i]);
}
}
void DonneesGPS()
{
if (SoftSerial.available())
{
GPS = "";
unsigned long StartGPS = millis();
do
{
GPS = SoftSerial.readStringUntil('\n');
if ((millis() - StartGPS) > 5000)
{
erreur_acces_GPS();
Affichage("GPS Timeout", false);
PointVirgule();
StartGPS = millis();
break;
}
} while (!GPS.startsWith(F("$GPGGA")));
Affichage(GPS, false);
PointVirgule();
}
}
void Affichage(String Donnees, bool ligne)
{
if (mode_actu == MODE_MAINTENANCE)
{
if (ligne)
{
Serial.println(Donnees);
}
else
{
Serial.print(Donnees);
}
}
else
{
Fichier.print(Donnees);
}
}
void PointVirgule()
{
Affichage(" ; ", false);
}
void SeparateurHorloge()
{
Affichage(":", false);
}
void Creation()
{
DateTime Maintenant = rtc.now();
Affichage(Maintenant.hour() > 9 ? String(Maintenant.hour()) : '0' + String(Maintenant.hour()), false);
SeparateurHorloge();
Affichage(Maintenant.minute() > 9 ? String(Maintenant.minute()) : '0' + String(Maintenant.minute()), false);
SeparateurHorloge();
Affichage(Maintenant.second() > 9 ? String(Maintenant.second()) : '0' + String(Maintenant.second()), false);
PointVirgule();
delay(1000);
DonneesGPS();
GenerationDonnees();
}