Ottimizzazione algoritmo

Buonasera ragazzi, oggi vi chiedo una mano ad ottimizzare il mio codice, premetto che alcune cose non sono state testata (sd card) e quindi chiedo perdono per eventuali errori. Il problema sta nel fatto che le variabili G occupano 89% di memoria, lasciando cosi una situazione ambigua. Le possibilità sono 3 a mio avviso :
1---->eliminare la libreria sd card ed usare la eeprom (ha lo svantaggio che a causa dell'eccessivo accesso la memoria si "consuma")
2---->ottimizzare il codice in termini di variabili/algoritmi ( sarebbe necessaria una spiegazione più avanzata di quello che voglio fare )
3----->idea folle... mettere in comunicazione 2 Arduini con una software serial e con uno eseguire l'algoritmo e con l'altro leggere/scrivere i file sulla sd.

ciò che non si capisce dal codice è la seguente cosa:
io voglio mettere in high la "valvola" ogni tot tempo, ma a causa di una serie di cose Arduino potrebbe bloccarsi e qui entra in gioco il WD che riavvia tutto, ora se Arduino si dovesse bloccare almeno una volta prima di questo tot tempo... succede che la "valvola" non andrà in high, o meglio andrà in high (se non si blocca) dopo tot.tempo+t_v con t_v il tempo passato prima del primo blocco. Allora ho pensato che se salvassi il t_v anche dopo il riavvio della scheda (dovuta a WD) usare dopo per ripristinare i tempi e mettere il high la "valvola" dopo esattamente quel tot.tempo, come se non fosse successo nulla... spero di essere stato chiaro. :slightly_frowning_face: :neutral_face: :neutral_face:

// Arduino con pid+sht31+dimmer+lcd+ricezione seraile

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <RBDdimmer.h>
#include <Arduino.h>
#include "Adafruit_SHT31.h"
#include <avr/wdt.h>
#include <PID_v1.h>
#include <SD.h>

#define dimmerPin 3
#define ventola 7
#define vapore 8
#define valvola 9
#define ONE_WIRE_BUS 4
#define CS_pin 10

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sonda(&oneWire);
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
dimmerLamp dimmer(dimmerPin);


Adafruit_SHT31 sht3x_s = Adafruit_SHT31();
Adafruit_SHT31 sht3x_i = Adafruit_SHT31();

double  Setpoint = 37.7, Output, t1, t2, h_s, h_i, Sp_s = 80;;
PID cont_t(&t2, &Output, &Setpoint, 1000, 0, 0, DIRECT);

float conv_t;
unsigned long tmr,t, s, c;
 boolean frist = true; 

File myFile;

void setup() {
  wdt_disable();
  
  Serial.begin(9600);
  
  sonda.begin();
  sonda.setResolution(12);
  delay(500);
  
  sht3x_s.begin(0x44);
  sht3x_i.begin(0x45);
  delay(500);
  
  lcd.begin(20, 4);
  delay(500);
  
  dimmer.begin(NORMAL_MODE, ON);
 
  cont_t.SetMode(AUTOMATIC);
  delay(500);
  
  pinMode(ventola,  OUTPUT);
  pinMode(valvola,  OUTPUT);
  pinMode(vapore,  OUTPUT);
  pinMode(CS_pin, OUTPUT);

  delay(500); 
  
  tmr = millis();
  
  SD.begin(CS_pin);
   
  
  wdt_enable(WDTO_8S);
  delay(1000);
  
  myFile = SD.open("test.txt", FILE_READ);
  if (myFile) {
   while (myFile.available()) {
     c = myFile.read();
   }
   
   myFile.close();
 }

}


void loop() {
if (frist == true){
  s= millis() - t + c ; 
  frist = false;
  }else{
   s= millis() - t ;
 } 


  h_s = sht3x_s.readHumidity();
  h_i = sht3x_i.readHumidity();
  
  sonda.requestTemperatures();
  t1 = sonda.getTempCByIndex(0);
  t2 = sonda.getTempCByIndex(1);
  
  cont_t.Compute();
  conv_t = map(Output, 0, 255, 13, 90 );
  
  myFile = SD.open("test.txt", FILE_WRITE);
   if (myFile) {
      myFile.println(s);
      myFile.close();
    }
   
 

      if (h_s >= Sp_s &&  conv_t == 13 ) {
      
      digitalWrite(valvola, LOW);
      digitalWrite(ventola, LOW);  
      digitalWrite(vapore, LOW);
      dimmer.setState(OFF);
      
    }
   
    if (h_s < Sp_s && conv_t == 13) {
     
      
      digitalWrite(valvola, LOW);
      digitalWrite(ventola, HIGH); 
      digitalWrite(vapore, HIGH);
      dimmer.setState(OFF);

      if( s > 1800000){
           t = millis();
           digitalWrite(valvola, HIGH);
           digitalWrite(ventola, LOW); 
           digitalWrite(vapore, LOW);
           dimmer.setState(OFF);
           delay(5000);
          
        }   
   
         
    }
    
   wdt_reset();   
    
  
     if (h_s >= Sp_s && conv_t != 13 ) {
      
  
      digitalWrite(valvola, LOW);
      digitalWrite(vapore, LOW);
      digitalWrite(ventola, HIGH); 
      dimmer.setState(ON);
      dimmer.setPower(conv_t);
       
     }
   wdt_reset(); 
   
    if (h_s < Sp_s && conv_t != 13) {
  
      digitalWrite(valvola, LOW);
      digitalWrite(ventola, HIGH);
      digitalWrite(vapore, HIGH);
      dimmer.setState(ON);
      dimmer.setPower(conv_t);
      
      if( s > 1800000){
           t = millis();
           digitalWrite(valvola, HIGH);
           digitalWrite(ventola, LOW); 
           digitalWrite(vapore, LOW);
           dimmer.setState(OFF);
           delay(5000);
        }  
    }
    

  
  wdt_reset(); 


 if (millis() - tmr > 2000) {

   // Serial.print(h_s);
  //   Serial.print("  ");
    // Serial.print(t2);
   //  Serial.print("  ");
  //   Serial.print(h_i);
    // Serial.print("  ");
    // Serial.println(80);
    // Serial.print("  ");
     //Serial.print(37.7);
    // Serial.print("  ");
   //  Serial.print(50);
    // Serial.print("  ");
    // Serial.print(t1);
    // Serial.print("  ");
    
    tmr = millis();
    
    lcd.setCursor(0,0);      lcd.print("Arduino ON ");lcd.print("T_i:");   lcd.print(t1);
    lcd.setCursor(0, 1);     lcd.print("T_s:");       lcd.print(t2);
    lcd.setCursor(9, 1);     lcd.print(" P_c: ");     lcd.print(conv_t);
    lcd.setCursor(0, 2);     lcd.print("U_s:");       lcd.print(h_s);
    lcd.setCursor(9, 2);     lcd.print(" Sp: ");     lcd.print(Sp_s);
    lcd.setCursor(0, 3);     lcd.print("U_i:");       lcd.print(h_i);
    lcd.setCursor(9, 3);     lcd.print("   ");   
  }
    wdt_reset();
}

Non credo siano le variabili a occupare memoria, quanto piuttosto le numerose librerie usate.
Hai parlato di usare due arduino, ma non specifichi che scheda stai utilizzando, una mega ha molta più Ram di una uno, usare una mega si ha più memoria che usare due uno.

Si probabilmente sono le librerie, ma purtroppo non ho un mega...come potrei fare ?? se tolgo la sd card e tutto ciò che è connesso, la cosa va .... soluzioni alternative per memorizzare il dato (tempo) prima dello spegnimento e poi recuperarlo?

La "soluzione" sarebbe analizzare e minimazzare le possibilitá di "impallamento" di arduino.

Alto tasso di potenziale caso x-y! :grinning:

Be visto che le schede clone della mega si trovano a 10 euro su ebay, invece di sforzarmi a trovare soluzioni alternative comprerei un clone della mega.

Sì effettivamente non hai tutti i torti, ma quello che vorrei è trovare una soluzione alternativa al problema per 2 ordini di ragione

  1. vorrei far funzionare tutto come sta e non aspettare 1 mese per un mega, ma non per il costo che è irrisorio ma piuttosto non mi andrebbe di cambiare tutto il cablaggio a causa delle dimensioni più grosse dell’hardware
  2. penso che la soluzione che ho proposto non sia intelligente... chiedo a voi come poter fare...la domanda è come posso far memorizzare una valore, e dopo il riavvio, recuperarlo, con la mia situazione di codice /memoria?

Letto il codice al volo dal telefono...
Ma mi pare di vedere che scrivi su sd ad ogni giro di loop()... Sicuro che sia necessario?
A seconda della precisione che ti serve potresti scrivere anche solo ogni minuto.
Per carità, la eeprom si esaurirebbe comunque in fretta, ma molto meno di adesso.
Una soluzione potrebbe essere l'utilizzo "circolare" della eeprom. Ne hanno parlato qualche giorno fa in un'altra discussione Guglielmo e Claudio. Se la cerchi trovi anche degli esempi di codice.

Edit: la discussione è questa
https://forum.arduino.cc/index.php?topic=725590.0

Si assolutamente, mi sembra una buona idea per testare il codice, potrei anche semplicemente scrivere ogni 5min, ma comunque dopo un certo tempo avrei esaurito i 100k di sovra scrizioni... magari sistemo il codice e ci provo. Una domanda, l'sd si potrebbe utilizzare come una eeprom ? ovvero potrebbe farne le veci giusto?

Se salvi ogni 5 minuti la "bruci" in circa un anno. Se però la usi in modo circolare come suggerito nella discussione che ho linkato aumenti notevolmente il numero di anni.
Poi non ho capito cosa vuol dire che la sd potrebbe fare le veci della eeprom...

La risposta "breve" per la sd é no. La si puó usare solo con le librerie apposite.

Senza assolutamente voler fare pubblicità (... fortunatamente non ce ne è bisogno), ma solo per segnalare la possibile soluzione, su un prossimo numero della rivista "Elettronica In" uscirà un mio articolo relativo all'utilizzo di memorie NVSRAM di Microchip™ con una piccola shield dedicata adatta ad Arduino UNO/MEGA/Leonardo.

Il vantaggio di tali memorie è che sono praticamente veloci come delle SRAM, hanno un numero di cicli di scrittura/lettura quasi illimitato, utilizzano per tenere memorizzate le informazioni una piccola batteria a bottone (una CR2032 garantisce il mantenimento dei dati per oltre 4 anni), colloquiano con la MCU via bus SPI (alta velocità) ed ... ho scritto una libreria per utilizzarle che permette di usare praticamente le stesse chiamate della libreria EEPROM con qualche banale cambiamento :grin: . Sono disponibili in capacità di 64KBytes e 128 KBytes (costano attorno ai 2 US$)

NVSRAM.jpg
Guglielmo

P.S.: In allegato anche il datasheet del chip da 128KBytes. Quello da 64KBytes è identico, cambia solo la memoria disponibile.

NVSRAM.jpg

23lcv1024.pdf (680 KB)

A parte tutto quello che ti hanno già detto, chi concorquoto...

Il programma è sbagliato, nella parte di lettura da sd

Comunque io pure sospetto un problema x-y

Spiega cosa vuoi fare, non come vuoi farlo,

Ah...

E poi non mi trovo con la liquidcrystal..

Quale hai usato? Che piedini hai usato per collegarti?

Scusate se rispondo solo ora..
gpb01, sicuramente proverò la scheda prossimamente, grazie per il consiglio.
Allora quello che voglio fare penso sia chiaro: vorrei credere un timer che vada "avanti" anche se Arduino si riavvia.
Ovvero devo memorizzare un valore, che se nel caso vada tutto bene non utilizzo, ma se se si verificano riavvi di Arduino il valore mi fa capire dove il ciclo precedente mi "aveva lascito". Penso che adesso dovrebbe essere chiaro..e comunque non si tratta di errore x-y ;D ;D :smiley: 8)

E non puoi salvare solo allo spegnimento? C'era un post su questo argomento ultimamente

salvare a spegnimento è un po complicato per via dell'hardware...
piuttosto qualcuno sa come ottimizzare il codice per la EEPROM??
stavo provando ad usare il sistema ciclico ed ho fatto cosi...ma penso che si possa fare meglio

#include <avr/wdt.h> 
#include <EEPROM.h>
byte A[8];
byte ultimo_scritto;
boolean frist=true;

void setup() {

  wdt_disable();
  Serial.begin(9600);



   
 ultimo_scritto= EEPROM.read(EEPROM.read(0));
  
 Serial.println("Il valore ultimo registrato sulla EEPROM è: ");
 Serial.println(ultimo_scritto);

 wdt_enable(WDTO_4S);
}

int a = 1 ;
int b = 0;

void loop(void) {
  
  if(ultimo_scritto != 255 && frist==true){
    b = ultimo_scritto;
    frist=false;
    }
  
  
  
  if(a==9){
    a=1;
  }
   wdt_reset();
  Serial.println("");

   
  b=b+2;
  if(b>=22){
    b=0;
    }
  wdt_reset();
  
EEPROM[a] = b ;
EEPROM[0] = a ;

 a++;
 Serial.println("B: ");
  Serial.println(b);

  delay(1000);
    wdt_reset();
}

Ma hai letto i post da QUI in poi? ? ? Perché sono ben descritte varie soluzioni con tanto di esempi !

Guglielmo

ho seguito con un certo interesse la discussione, come avevo seguito la sua "genitrice" un paio di anni fa

ma temo che non se ne uscirà, non in maniera facile almeno

perché dico questo?

perché se dopo circa due anni ci si trova ancora con un Arduino che si blocca significa che la strada intrapresa non porta da nessuna parte

era stato consigliato di cambiare i relè, usare cavi schermati, cambiare lo LCD, ma non so se sia stato fatto

per lo LCD forse si, ma la sua inizializzazione è strana, e lo OP non ha risposto alla relativa domanda

era stato consigliato di mettere un led lampeggiante, per capire se e quando si blocca Arduino

questo sì, siamo sicuri: non è stato fatto

era stato consigliato di usare un watch-dog; anche questo è stato fatto, e sembra che in effetti intevenga, anche se non sappiamo perché
e quindi siamo ancora qui: relè optoisolati, cavi schermati cambiare LCD, queste sono le cose che si consigliano di solito e queste sono state fatte? non si sa

intanto sono state aggiunte funzioni "accessorie" che aumentano la confusione ma non vanno nella direzione di "chiarire" la situazione
per esempio
gestione PID
uso di riscaldatori PWM

e avviate "strade" collaterali, che anche loro aumentano la confusione:
EEprom
Scheda SD
tempi di intervento (di cose non definite) che devono essere rispettati anche in caso di crash del sistema

inoltre lo OP continua a dirci "come vuole fare" e non "cosa voglia fare"
e non entriamo in questa questione che qui tutto scritto è

quindi io che cosa ne ipotizzo:

  1. lo OP non si esprime chiaramente, quindi non sapremo mai se "ci abbiamo pigliato"
  2. non segue i consigli datigli, o almeno segue solo quelli che vuole
  3. non tiene "aggiornata" la situazione

e quindi?

e quindi secondo me in questa situazione non si arriverà da nessuna parte, come non ci si è arrivati negli ultimi due anni (in effetti la mia è una facile previsione, basata sul passato recente)

mi sembra solo di poter dire che per un'incubatrice tutto questo tempo e tutti questi problemi sono "eccessivi"
vale veramente la pena di ripensare (in questo ordine) a:
cosa si vuole fare
cosa serve per ottenerlo
come possiamo fare per farlo a mano
come possiamo "farlo fare ad Arduino"
mettere insieme il tutto

Mi fa davvero piacere sapere che ci sono persone che ricordano di post di circa 1/2 anni, mi fa capire la potenza e la grandezza di questa community. Ma ti devo (almeno su qualche punto) contraddire.

  1. si stanno utilizzando cavi schermati, relè non optoisolati (quelli avevo) (che presto cambierò con degli ssr), lcd sostituito (i pin dovrebbero essere A4 A5, dico dovrebbero perché non ricordo con precisione) funziona abbastanza bene, quasi perfetto.

Il led lampeggiante non è stato messo...per un semplice motivo: non sto sempre li ad osservare, e comunque c'è il WD a riavviare la scheda in caso di blocco.

  1. per quanto riguarda l'aggiunta di "confusione" (riscaldatori pwn e pid) sono cose che ho inserito per 2 ordini di ragione..

facendo io il codice non ho, almeno teoricamente, limiti di inventiva e quindi mi sono chiesto... cosa può rendere il sistema migliore e più stabile ? e mi sono risposto da solo.

Poi per quanto riguarda la parte sd e eeprom, lo ammeto è stato un azzardo, ma poiché non sono giunto ad una conclusione reale e funzionate...ho fatto da me, con i vostri suggerimenti e consigli

(ad ora sto utilizzando la EEprom con un codice sulla falsa riga di quello in cima alla pagina, che però va migliorato e modificato come consigliava Guglielmo).

molto probabilmente non mi esprimo chiaramente, è un mio difetto. Infatti sono arrivato qui e non ho descritto cosa vorrei realmente fare. Ma ora lo faccio

partendo dall'idea che arduino ogni tanto si blocca (cause non ben comprese) quello che dovrei fare è la temporizzazione dell'accensione di un relè, e bloccare il codice per circa 1-2 minuti ogni mezzora con il relè in HIGH ovviamente se si verificano certe condizioni di umidità. Dopo questi 2 minuti, la situazione di ripropone dopo mezz'ora.
esempio:
(h=umidità, 50 valore di setPoint)
-il codice fa il suo lavoro
-passano 30 minuti -->h<50
-il codice fa il suo lavoro (h =50)--->tutte le operazioni vengono bloccate e si mette in HIGH il relè (dall'accensione possono essere passati minimo 30 minuti- oppure un tempo infinito)
-si ripete da capo

spero di essermi spigato e di aver centrato il punto.
io non direi che tutto questo tempo è "eccesivo" per una incubatrice, perché magari si i problemi sono stati molti (sia in ambito sw che per tutta la macchina in se) ma di sicuro ci sono state soddisfazioni e anche tante competenze acquisite in ambito Arduino e controlli automatici.

Per la parte di "blocco" del sistema credo che @Standardoil abbia ragione, tutto quello che è stato creato di contorno è una pezza per tentare di far funzionare la cosa nonostante il problema e, questo, è errato nella maggior parte dei casi.
Come sempre detto il WD serve a risolvere blocchi imprevisti ed imprevedibili, qui invece siamo di fronte a blocchi che sicuramente avvengono anche se non in modo regolare o comunque chiaro sul motivo per cui avvengono.
Capisco che possano esserci motivazioni dietro non discutibili, ma intervenendo con relé optoisolati, alimentazioni separate per la parte MCU/sensori/ecc. e attuatori i blocchi molto probabilmente sparirebbero.
In ogni caso invece di stare a fare speculazioni, SD, EEPROM ecc. potresti pensare di usare un RTC, memorizzare l'EPOCH solo quando ti serve e andare per differenza, anche in caso di blocco sapresti sempre con accuratezza il tempo trascorso dall'accensione al momnto in cui andrai ad analizzare il tempo trascorso eliminando anche la libreria SD e magari otterrai anche una riduzione della memoria usata