Problema con il data logging

Ciao a tutti,

sto realizzando un controllo automatico per una mini serra.
vi elenco i componenti che sto usando al momento:

  1. Arduino Uno
  2. schield data logging SD con ds1307
  3. Display lcd 2X16
  4. Sensore AM2315 (temperatura e umidità)

In fondo vi posto lo sketch, intanto vi dico che attualmente grazie agli esempi e il materiale recuperato sul web sono riuscito a far visualizzare sullo schermo data, ora, temperatura e umidità.
Fino qui tutto bene.

Il problema:
In pratica la funzione loop si ripete ogni secondo per via della pausa alla fine.
Vorrei far scrivere le stesse informazioni sulla sd, non ogni secondo, ma ogni 30 minuti almeno, in modo da non avere file txt da megabyte in un giorno.

Possibile soluzione:
potrei dire di leggere i minuti e i secondi, e se sono (30 min) e (00 sec) fare scrivere i dati sulla SD.

Dubbio:
è già difficile refreshare i dati sul display ogni secondo, cioè ho dovuto abbassare il valore della pausa perchè ogni loop impiega piu' di 1000 ms per essere eseguito, quindi ogni tanto "manca" un secondo.
Ovvero compare per esempio 12:33:01 poi 12:33:02 poi 12:33:04 ecc... Questo non è un vero è proprio problema ma potrebbe accadere che il ritardo che ha arduino nell' eseguire il loop faccia saltare il log dei dati.
Detto questo non saprei neanche bene come fare ad inserire questi controlli sull'orario. Help.

Secondo me è da ripensare tutto lo sketch, anche perchè in futuro dovrà far avviare ventole e lampade.
Suggerimenti?

Grazie per l'attenzione

#include <Wire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <Adafruit_AM2315.h>
Adafruit_AM2315 am2315;
#define TEMP am2315.readTemperature()
#define UR am2315.readHumidity()
#include <SPI.h> // libreria sd
#include <SD.h>  // libreria sd
File dataFile; 
#include <utility/Adafruit_MCP23017.h>
#include <Adafruit_RGBLCDShield.h>
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
// These #defines make it easy to set the backlight color
#define RED 0x1
#define YELLOW 0x3
#define GREEN 0x2
#define TEAL 0x6
#define BLUE 0x4
#define VIOLET 0x5
#define WHITE 0x7


  
#include "RTClib.h"
RTC_DS1307 rtc;
char daysOfTheWeek[7][4] = {"Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab"};


void setup() {
  Serial.begin(115200);

lcd.begin(16, 2);
lcd.setBacklight(GREEN);
lcd.clear();

       if (!am2315.begin()) {
     Serial.println("Sensor not found, check wiring & pullups!");
     while (1);
  }
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }

  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
    // rtc.adjust(DateTime(__DATE__, __TIME__));
  }
   
}


void loop() { 
   DateTime now = rtc.now();
  lcd.setCursor(0,0);
  lcd.print("T=");
  lcd.print(am2315.readTemperature());
  lcd.print(" ");
  lcd.print("Ur=");
  lcd.print(am2315.readHumidity());
  
 tmElements_t tm;
  if (RTC.read(tm)) {
      
    lcd.setCursor(0,1); 
    lcd.print(daysOfTheWeek[now.dayOfTheWeek()]);
    lcd.print(' ');
    lcd.print(tm.Day);
    lcd.setCursor(0,1); 
    lcd.setCursor(8,1); 
    print2digits(tm.Hour);
    lcd.print(':');
    print2digits(tm.Minute);
    lcd.print(':');
    print2digits(tm.Second);
       
  } 
  delay(875);
}
void print2digits(int number) {
  if (number >= 0 && number < 10)
    lcd.write('0');
  lcd.print(number);
}

paracel:
Secondo me è da ripensare tutto lo sketch, anche perchè in futuro dovrà far avviare ventole e lampade.
Suggerimenti?

è probabile, un microcontrollore non dovrebbe mai andare in pausa forzata, è potenza di calcolo che stai buttando via, il controllo per salvataggio delle informazioni lo puoi attribuire a millis()
leggo millis() e la salvo, ad ogni ciclo sottraggo alnuovo valore di millis quello nuovo e verifico se sono passati (10006030)ms in quel caso salvo i dati sulla SD e aggiorno il vecchio valore di millis con quello attuale.

Per la gestione temporale a lungo termine sarebbe bene che tu ti affidassi ad un RTC.

Essendo il tuo primo post Ti invitiamo a presentarti QUI
(dicci quali conoscenze hai di elettronica e di programmazione) e a leggere il regolamento QUI
se non lo hai già fatto.

Comunque benvenuto sul forum.

Attilio

potrei dire di leggere i minuti e i secondi, e se sono (30 min) e (00 sec) fare scrivere i dati sulla SD.

se il tuo ciclo loop salta il secondo ... ovvero dura poco di più il tuo controllo 30:00 salta, è normale che succeda per questo si usa il "> di"

se tu vai a scrivere sulla SD quando il minuto è > di min30:sec00 ti scriverebbe una marea di roba, se però metti un flag booleano che quando il minuto scatta a 30 scrive su SD, al termine della scrittura il flag va a TRUE al 31 esimo minuto lo stesso flag va FALSE, deve passare un altra mezzora ... questo ti permette di avere un minuto di tempo per scrivere sulla SD e non il secondo spaccato .. per farla breve, lavora con i minuti non con i secondi.

variabile pubblica ... flag bool false
minuto==30 && !flag scrivo su SD
termine scrittura in file.close flag=true (ho già scritto)

if minuto==31 flag=false (in attesa del min==30 ... pronto per scrivere nuovamente)

non so se mi sono capito :slight_smile: .. anche se dubito che tornerai a riscrivere sul forum

Ciao ragazzi,
grazie a voi, ho fatto un grande passo in avanti. Ho capito una grande difficoltà di Arduino, ovvero quello di renderlo multitasking.

Aggiornamenti:
ho riscritto lo sketch, adesso gira senza bisogno della pausa. Adesso riesco a stampare solo data e ora. Ho studiato un po' per riuscire a inserire una flag booleiana, come dice pablos, ma nonostante il codice sia verificato e uppato, non funziona come dovrebbe. La soluzione di inserire queste flag, ho scoperto essere molti utili anche quando si effettuano delle ricerce, e per il mio caso sempbra essere una soluzione elegante.

Il codice:

#include <Wire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include "RTClib.h"
#include <Adafruit_AM2315.h>
Adafruit_AM2315 am2315;
#define TEMP am2315.readTemperature()
#define UR am2315.readHumidity()
#include <SPI.h> 
#include <SD.h>  
#include <utility/Adafruit_MCP23017.h>
#include <Adafruit_RGBLCDShield.h>

// These #defines make it easy to set the backlight color
#define RED 0x1
#define YELLOW 0x3
#define GREEN 0x2
#define TEAL 0x6
#define BLUE 0x4
#define VIOLET 0x5
#define WHITE 0x7

Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
File myFile; 
const int chipSelect = 10;
RTC_DS1307 rtc;
char daysOfTheWeek[7][4] = {"Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab"};

tmElements_t tm;
int tempoOre = (tm.Hour);
int tempoMinuti = (tm.Minute);
int tempoSecondi =(tm.Second);

boolean logSD = false;

void setup() {
Serial.begin(115200);
lcd.begin(16, 2);
lcd.setBacklight(GREEN);
lcd.clear();
pinMode(SS, OUTPUT);
SD.begin(chipSelect);
}


void loop() { 
 
  DateTime now = rtc.now();
  tmElements_t tm;
  RTC.read(tm);

if (tempoSecondi != (tm.Second))   {

  int tempoOre = (tm.Hour);
  int tempoMinuti = (tm.Minute);
  int tempoSecondi =(tm.Second);
  
    lcd.setCursor(0,1); 
    lcd.print(daysOfTheWeek[now.dayOfTheWeek()]);
    lcd.print(' ');  lcd.print(tm.Day);
    lcd.setCursor(0,1);  lcd.setCursor(8,1); 
    print2digits(tm.Hour);    lcd.print(':');
    print2digits(tm.Minute);    lcd.print(':');
    print2digits(tm.Second);
    }
if (tm.Second == 30) {
  logSD = !logSD;
  myFile = SD.open("log.txt", FILE_WRITE);
  // myFile.print (now.day()); myFile.print ('/'); myFile.print (now.month()); myFile.print ('/'); myFile.print(now.year());myFile.print("\t");
  // myFile.print(now.hour(), DEC);myFile.print(':');myFile.print(now.minute(), DEC);myFile.print(':');myFile.println(now.second(), DEC);
  myFile.print (am2315.readTemperature(), logSD); myFile.print (am2315.readHumidity(), logSD);
  myFile.close();
  logSD = !logSD;
  }  
}
void print2digits(int number) {
  if (number >= 0 && number < 10)
    lcd.write('0');
  lcd.print(number);
}

Problema:
se riuscissi a capire bene come funzionano queste flag, ovvero dovrei inserire la variabile booleiana all'interno del comando myFile.print ? Oppure c'è un errore, come sospetto, molto piu' grossolano?

Una volta risolto questo sarei riuscito a farli fare 2 cose contemporanemante.

Domande per il futuro (ma questo dovrebbe essere un altro topic):

1)Rimarrebbero comunque da aggiungere allo sketch l'interrogazione dei sensori, che praticamente non può essere minore di un secondo. Inserire un if che controlli se i secondi sono pari o dispari?

2)Aggiungere l'accensione di una lampada. Questo dovrebbe essere facile in apparenza. A meno che non si disponga di librerie ad hoc...
esempio: la lampada si acceende dalle 16 fino alle 20. In caso di blackout, Arduino dovrebbe controllare se si trova all'interno di quell'orario.

E' tutto per ora, a presto.

if (tm.Second == 30) {
  logSD = !logSD;

qui mi sembra sbagliato, in questo modo scrive per un minuto, il tuo orologio sarà hh:30:ss per 60 secondi, il programma incontra i minuti 30 durante il ciclo tantissime volte

per questo ti ho scritto minuto==30 && !flag scrivo su SD
probabilmente non mi sono spiegato bene e a rileggerlo in effetti non è chiaro.

dovevi mettere if (tm.Second == 30 && !logSD) {

che tradotto sarebbe
se minuti sono == a 30 e flag logSD è falso allora scrivi
una volta che ho scritto sulla SD chiudo il file e metto il flagSD a TRUE (è una bandierina che mi indica TRUE ha gia scritto ... FALSE puoi scrivere)

al prossimo ciclo loop (questione di pochi millisecondi) i minuti sono ancora a 30 no? se non avessi anche il controllo flagSD a TRUE questo mi scrive di nuovo sulla SD, ma io voglio che scriva una volta sola.

ora questo flag logSD essendo TRUE non mi farà mai più scrivere sulla sd se non la metto a FALSE giusto?
quindi quando la metto a false? quando second è = a 31

quando i minuti sono 31,32,33 ... 59 ecc ecc questo controllo
se minuti sono == a 30 e flag logSD è falso allora scrivi
non sarà più soddisfatto perchè minuti è == a 31 anche se logSD è FALSO

&& significa AND ... entrambe le condizioni devono essere soddisfatte per eseguire le istruzioni

ora è più chiaro?

te lo rispiego:

Perfetto pablos, ho capito. Non dovrei avere problemi a farlo funzionare.
Sono tornato subito a scrivere perchè volevo editare il post, in quanto mi sono ricordato che durante le prove stavo usando i secondi e non i minuti. Ovviamente l'ho fatto solo per ridurre i tempi di attesa tra una prova e l'altra.
Appena modifico lo sketch, lo pubblico. Puo' essere usato come sketch di esempio.
Grazie ancora e a presto.