dove ho sbagliato?

Salve a tutti, frequento questo forum da quando ho iniziato ad usare Arduino ma non riesco a risolvere un problema.
Sulla base di alcuni programmi trovati e di molte modifiche ho creato un termostato che mi indica temperatura, umidità,data e ora su un display lcd ma dopo un po' di tempo (sempre inferiore a 2 ore) mi cambiano tutte le scritte diventando tipo cinesi (senza un senso).
Credo che il problema sia per la memoria che usa il programma ma non saprei.
Sapete dirmi se avete qualche idea per sistemarlo?
Qui vi posto il codice:

#include <Arduino.h>
#include <Wire.h>
#include "DS1307.h"
#include "LiquidCrystal.h"
#include "idDHT11.h"

int relay = 4;
int pot_pin = 1;  
int led_rosso = 5;
int led_blu = 3;
int led_verde =12;
int lcd_luce = 13;
float act_temp = 0.0;
float set_temp = 15.0;
int hum = 0;
int last_time = 0;
int hys = 1;
int temperatura_notturna = 18;

//serve a settare il tempo in cui il termostato rimane spento
int time_STOPinizio = 2;
int time_STOPfine = 6;

int prev_temp = 0;
int prev_time = 0;
int delay_set = 5;
byte degree[8] = {
 B01000,
 B10100,
 B01000,
 B00011,
 B00100,
 B00100,
 B00011,
};
//inizializza
LiquidCrystal lcd(10, 11, 6, 7, 8, 9); //LCD inizializzazione
int idDHT11pin = 2;
//pin digitale per la comunicazione del DHT11
int idDHT11intNumber = 0;
//interrupt number (deve essere quello che utilizza il pin definito precedentemente (guarda la tabella) DHT11
void dht11_wrapper(); // deve essere dichiarata prima dell'inizializzazione della libreria
idDHT11 DHT11(idDHT11pin,idDHT11intNumber,dht11_wrapper);
DS1307 clock;
//definisce l'oggetto (DS1307)
void setup()
{
Serial.begin(9600);
pinMode(relay, OUTPUT);
pinMode(led_blu, OUTPUT);
pinMode(led_rosso, OUTPUT);
pinMode(led_verde, OUTPUT);
pinMode(lcd_luce, OUTPUT);
clock.begin();
lcd.createChar(0, degree);

/* **********serve ad impostare data e ora********* *\
clock.fillByYMD(2015,9,16); //16-9-2015              *
clock.fillByHMS(19,00,00);  //19:00 00"              *
clock.fillDayOfWeek(WED);   //mercoledì              *
clock.setTime();//scrivi ora e data sul ds1307       *
\* ************************************************ */

lcd.begin(16, 2); // inizializza LCD
lcd.setCursor(0,0); // mette il cursore a 0,0
}

void dht11_wrapper() //necessario per inizializzare la libreria idDHT11
{
DHT11.isrCallback();
}

void stop_pump() //spegne il relay e accende il LED rosso
{
digitalWrite(relay, 1);
digitalWrite(led_verde, 0);
digitalWrite(led_rosso, 1);
digitalWrite(led_blu, 0);
}

void start_pump() //spegne il relay e accende il led blu
{
digitalWrite(relay, 0);
digitalWrite(led_verde, 0);
digitalWrite(led_rosso, 0);
digitalWrite(led_blu, 1);
}

void stop_system() //spegne il relay e accende il led verde
{
digitalWrite(relay, 1);
digitalWrite(led_verde, 1);
digitalWrite(led_rosso, 0);
digitalWrite(led_blu, 0);
}
void print_LCD() //scrive lo stato sul display LCD (16x2)
{
//linea 0
lcd.setCursor(0,0);
lcd.print(act_temp, 0);
lcd.setCursor(2,0);
lcd.write(byte(0));
lcd.setCursor(4,0);
lcd.print("|");
lcd.setCursor(5,0);
if(clock.hour < 10) // scrivi 0 prima dell'ora se è minore di 10
{
lcd.print("0");
lcd.setCursor(6,0);
lcd.print(clock.hour, DEC);
}
else (lcd.print(clock.hour, DEC));
lcd.setCursor(7,0);
lcd.print(":");
lcd.setCursor(8,0);
if(clock.minute < 10) // scrivi 0 prima dei minuti se sono minori di 10
{
lcd.print("0");
lcd.setCursor(9,0);
lcd.print(clock.minute, DEC);
}
else (lcd.print(clock.minute, DEC));
lcd.setCursor(10,0);
lcd.print("|");
lcd.setCursor(12,0);
lcd.setCursor(12,1);
lcd.print(set_temp, 1);

//linea 1
lcd.setCursor(2,1);
lcd.print("%");
lcd.setCursor(0,1);
lcd.print(DHT11.getHumidity(), 0);
lcd.setCursor(4,1);
lcd.print("|");
lcd.setCursor(5,1);

if(clock.dayOfMonth < 10) // scrivi 0 del giorno se è minore di 10
{
lcd.print("0");
}
lcd.print(clock.dayOfMonth, DEC);

lcd.setCursor(7,1);
lcd.print("/");
lcd.setCursor(8,1);

if(clock.month < 10) // scrivi 0 del giorno se è minore di 10
{
lcd.print("0");
}
lcd.print(clock.month, DEC);

lcd.setCursor(10,1);
lcd.print("|");
lcd.setCursor(12,1);
lcd.print(set_temp, 1);
lcd.setCursor(4,0);
}

void DHT11_acquiring() // aquisisci le informazioni dal sensore DHT11
{
DHT11.acquire();
while (DHT11.acquiring());
int result = DHT11.getStatus();

switch (result)  //segnala se è tutto ok o che errore si verifica
{
 case IDDHTLIB_OK:
 Serial.println("OK");
 break;
 case IDDHTLIB_ERROR_CHECKSUM:
 Serial.println("Error\n\r\tChecksum error");
 break;
 case IDDHTLIB_ERROR_ISR_TIMEOUT:
 Serial.println("Error\n\r\tISR Time out error");
 break;
 case IDDHTLIB_ERROR_RESPONSE_TIMEOUT:
 Serial.println("Error\n\r\tResponse time out error");
 break;
 case IDDHTLIB_ERROR_DATA_TIMEOUT:
 Serial.println("Error\n\r\tData time out error");
 break;
 case IDDHTLIB_ERROR_ACQUIRING:
 Serial.println("Error\n\r\tAcquiring");
 break;
 case IDDHTLIB_ERROR_DELTA:
 Serial.println("Error\n\r\tDelta time to small");
 break;
 case IDDHTLIB_ERROR_NOTSTARTED:
 Serial.println("Error\n\r\tNot started");
 break;
 default:
 Serial.println("Unknown error");
 break;
}
}
int day_time() //imposta il tempo
{
int x = (clock.hour);
if(x > time_STOPinizio && x < time_STOPfine)
return 2; //se è notte setta 2
else
return 1; //se è giorno setta 1
}
int seconds_elapsed()
{
int elapsed_secs = 0;
if(prev_time > clock.second) //necessario per lavorare con un conto di base di 60
{
elapsed_secs = (60-prev_time)+clock.second;
}
else
{
elapsed_secs = clock.second - prev_time;
}
return elapsed_secs;
}
int minutes_elapsed()
{
int elapsed_mins = 0;
if(last_time > clock.minute) //necessario per lavorare con un conto di base di 60
{
elapsed_mins = (60-last_time)+clock.minute;
}
else
{
elapsed_mins = clock.minute - last_time;
}
return elapsed_mins;
}
void loop()
{

int x = 0;
bool change_temp = 0;

//ottieni temperatura, data e tempo
DHT11_acquiring();
act_temp = (DHT11.getCelsius());
clock.getTime();

//leggi il pot pin
x = analogRead(pot_pin);
x = map(x, 0, 1023, 15, 45);
//se la temperatura è al minimo disattiva i controlli, spegni la retroilluminazione e accendi il led verde
if (x == 15)
{
stop_system();
print_LCD();
lcd.setCursor(12,1);
set_temp = (((x+15)*10)/2)/10.00; //se non si inserisce la temp si blocca sull'ultimo ricalcolo
lcd.setCursor(11,0);
lcd.print("-OFF-");
if(seconds_elapsed() >= delay_set)
digitalWrite(lcd_luce, 0);
goto stop;
}
//5 secondi dopo l'ultimo cambiamento spegni la retroilluminazione del LCD
if(seconds_elapsed() >= delay_set)
digitalWrite(lcd_luce, 0);
//se il potenziometro cambia temperatura accendi la retroilluminazione del LCD
if(x != prev_temp)
{
digitalWrite(lcd_luce, 1);
prev_time = (clock.second);
change_temp = 1;
delay(100);

}
//se è giorno regola la temperatura con il potenziometro
if (day_time() == 1)
{
set_temp = (((x+15)*10)/2)/10.00; // cambia la temperatura con il potenzionetro di 0.5°C per volta
lcd.setCursor(11,0);
lcd.print(" set");
lcd.setCursor(15,0);
lcd.write(byte(0));
}
//se è notte imposta la temperatura notturna
else if (day_time() == 2)
{
set_temp = temperatura_notturna;
lcd.setCursor(11,0);
lcd.print("sleep");
}
//se il tempo di attesa è passato attiva i controlli
if (minutes_elapsed() >= delay_set || change_temp == 1)
{
if (act_temp < (set_temp - hys)) //se la stanza è fredda accendi il termosifone
{
start_pump();
last_time = (clock.minute);
}
else //altrimenti se la stanza è calda spegni il termosifone
{
stop_pump();
last_time = (clock.minute);
}
change_temp = 0;
}
// scrivi sul LCD,imposta il valore del prev_temp
print_LCD();
prev_temp = x;
delay(100);
stop:
delay(500);
}

Ciao,
ho visto che usi anche la analogRead. Hai anche un termometro analogico? Perche il DHT è digitale e con la analogRead non puoi leggerlo.
Inoltre prima di pubblicare il codice dovresti formattarla in modo da correggere l'indentazione. Usa il comando dell'IDE "formattazione automatica" nel menù "Strumenti".

... se è un problema di memoria SRAM esaurita fai presto a scoprirlo ... guarda QUI :wink: ... e potrai verificare, con il programma in esecuzione, quale è l'andamento dell'occupazione di memoria.

Guglielmo

gpb01:
... se è un problema di memoria SRAM esaurita fai presto a scoprirlo ... guarda QUI :wink: ... e potrai verificare, con il programma in esecuzione, quale è l'andamento dell'occupazione di memoria.

Guglielmo

l'url proposto da guglielmo mi viene bloccato dall'antivirus perché potenzialmente dannoso... è un problema solo mio? ovviamente sto usando windows...

Avast? ... è un falso positivo ... NOD32 (di cui mi fido infinitamente di più) non segnala alcun problema sulla pagina.

Guglielmo

Ciao,
ho visto che usi anche la analogRead. Hai anche un termometro analogico? Perche il DHT è digitale e con la analogRead non puoi leggerlo.

Innanzitutto grazie per l'interessamento.
Ho controllato per l'uso della digitalread e vedo che non funziona ma che funziona solo la analogread.
Ora provo a vedere per la ram e poi vi dico.
Preparo anche gli schemi del circuito cosi' si puo' vedere se dipende da quello l'errore anche se dubito.

Vedo che ci sono tanti sottomenu per la gestione del lcd con i sensori..beh prima cosa ti consiglio di mettere i controlli del sensore prima di tutti...sia di quello che della rtc se presente..inoltre dopo ogni sottomenu dovresti controllare se è' presente la funziona lcd.clear() poiché arduino in automatico non cancella ma gli va sopra..potrebbe essere questa la spiegazione..oppure più banalmente a me lo faceva quando scontravo qualche collegamento con il lcd e quindi va in panico xD...cmq confermo anche io che quel sensore lavora in digitale e non in analogico...quindi dovresti collegarlo a A5 e A4 e lavorare con la libreria wire e spi...quindi dovresti cercarti anche l'indirizzo della porta..c'è una libreria che si chiama scan i2c ch ti aiuterebbe molto...poi se metti anche nel void setup dei controlli per la verifica del funzionamento della rtc sarebbe perfetto! Controlla anche la funzione di stampa dell'ora..

paolo98:
Salve a tutti, frequento questo forum da quando ho iniziato ad usare Arduino ma non riesco a risolvere un problema.
Sulla base di alcuni programmi trovati e di molte modifiche ho creato un termostato che mi indica temperatura, umidità,data e ora su un display lcd ma dopo un po' di tempo (sempre inferiore a 2 ore) mi cambiano tutte le scritte diventando tipo cinesi (senza un senso).
Credo che il problema sia per la memoria che usa il programma ma non saprei.
Sapete dirmi se avete qualche idea per sistemarlo?
Qui vi posto il codice:

#include <Arduino.h>

#include <Wire.h>
#include "DS1307.h"
#include "LiquidCrystal.h"
#include "idDHT11.h"

int relay = 4;
int pot_pin = 1; 
int led_rosso = 5;
int led_blu = 3;
int led_verde =12;
int lcd_luce = 13;
float act_temp = 0.0;
float set_temp = 15.0;
int hum = 0;
int last_time = 0;
int hys = 1;
int temperatura_notturna = 18;

//serve a settare il tempo in cui il termostato rimane spento
int time_STOPinizio = 2;
int time_STOPfine = 6;

int prev_temp = 0;
int prev_time = 0;
int delay_set = 5;
byte degree[8] = {
B01000,
B10100,
B01000,
B00011,
B00100,
B00100,
B00011,
};
//inizializza
LiquidCrystal lcd(10, 11, 6, 7, 8, 9); //LCD inizializzazione
int idDHT11pin = 2;
//pin digitale per la comunicazione del DHT11
int idDHT11intNumber = 0;
//interrupt number (deve essere quello che utilizza il pin definito precedentemente (guarda la tabella) DHT11
void dht11_wrapper(); // deve essere dichiarata prima dell'inizializzazione della libreria
idDHT11 DHT11(idDHT11pin,idDHT11intNumber,dht11_wrapper);
DS1307 clock;
//definisce l'oggetto (DS1307)
void setup()
{
Serial.begin(9600);
pinMode(relay, OUTPUT);
pinMode(led_blu, OUTPUT);
pinMode(led_rosso, OUTPUT);
pinMode(led_verde, OUTPUT);
pinMode(lcd_luce, OUTPUT);
clock.begin();
lcd.createChar(0, degree);

/* *serve ad impostare data e ora *
clock.fillByYMD(2015,9,16); //16-9-2015              *
clock.fillByHMS(19,00,00);  //19:00 00"              *
clock.fillDayOfWeek(WED);  //mercoledì              *
clock.setTime();//scrivi ora e data sul ds1307      *
* ************************************************ */

lcd.begin(16, 2); // inizializza LCD
lcd.setCursor(0,0); // mette il cursore a 0,0
}

void dht11_wrapper() //necessario per inizializzare la libreria idDHT11
{
DHT11.isrCallback();
}

void stop_pump() //spegne il relay e accende il LED rosso
{
digitalWrite(relay, 1);
digitalWrite(led_verde, 0);
digitalWrite(led_rosso, 1);
digitalWrite(led_blu, 0);
}

void start_pump() //spegne il relay e accende il led blu
{
digitalWrite(relay, 0);
digitalWrite(led_verde, 0);
digitalWrite(led_rosso, 0);
digitalWrite(led_blu, 1);
}

void stop_system() //spegne il relay e accende il led verde
{
digitalWrite(relay, 1);
digitalWrite(led_verde, 1);
digitalWrite(led_rosso, 0);
digitalWrite(led_blu, 0);
}
void print_LCD() //scrive lo stato sul display LCD (16x2)
{
//linea 0
lcd.setCursor(0,0);
lcd.print(act_temp, 0);
lcd.setCursor(2,0);
lcd.write(byte(0));
lcd.setCursor(4,0);
lcd.print("|");
lcd.setCursor(5,0);
if(clock.hour < 10) // scrivi 0 prima dell'ora se è minore di 10
{
lcd.print("0");
lcd.setCursor(6,0);
lcd.print(clock.hour, DEC);
}
else (lcd.print(clock.hour, DEC));
lcd.setCursor(7,0);
lcd.print(":");
lcd.setCursor(8,0);
if(clock.minute < 10) // scrivi 0 prima dei minuti se sono minori di 10
{
lcd.print("0");
lcd.setCursor(9,0);
lcd.print(clock.minute, DEC);
}
else (lcd.print(clock.minute, DEC));
lcd.setCursor(10,0);
lcd.print("|");
lcd.setCursor(12,0);
lcd.setCursor(12,1);
lcd.print(set_temp, 1);

//linea 1
lcd.setCursor(2,1);
lcd.print("%");
lcd.setCursor(0,1);
lcd.print(DHT11.getHumidity(), 0);
lcd.setCursor(4,1);
lcd.print("|");
lcd.setCursor(5,1);

if(clock.dayOfMonth < 10) // scrivi 0 del giorno se è minore di 10
{
lcd.print("0");
}
lcd.print(clock.dayOfMonth, DEC);

lcd.setCursor(7,1);
lcd.print("/");
lcd.setCursor(8,1);

if(clock.month < 10) // scrivi 0 del giorno se è minore di 10
{
lcd.print("0");
}
lcd.print(clock.month, DEC);

lcd.setCursor(10,1);
lcd.print("|");
lcd.setCursor(12,1);
lcd.print(set_temp, 1);
lcd.setCursor(4,0);
}

void DHT11_acquiring() // aquisisci le informazioni dal sensore DHT11
{
DHT11.acquire();
while (DHT11.acquiring());
int result = DHT11.getStatus();

switch (result)  //segnala se è tutto ok o che errore si verifica
{
case IDDHTLIB_OK:
Serial.println("OK");
break;
case IDDHTLIB_ERROR_CHECKSUM:
Serial.println("Error\n\r\tChecksum error");
break;
case IDDHTLIB_ERROR_ISR_TIMEOUT:
Serial.println("Error\n\r\tISR Time out error");
break;
case IDDHTLIB_ERROR_RESPONSE_TIMEOUT:
Serial.println("Error\n\r\tResponse time out error");
break;
case IDDHTLIB_ERROR_DATA_TIMEOUT:
Serial.println("Error\n\r\tData time out error");
break;
case IDDHTLIB_ERROR_ACQUIRING:
Serial.println("Error\n\r\tAcquiring");
break;
case IDDHTLIB_ERROR_DELTA:
Serial.println("Error\n\r\tDelta time to small");
break;
case IDDHTLIB_ERROR_NOTSTARTED:
Serial.println("Error\n\r\tNot started");
break;
default:
Serial.println("Unknown error");
break;
}
}
int day_time() //imposta il tempo
{
int x = (clock.hour);
if(x > time_STOPinizio && x < time_STOPfine)
return 2; //se è notte setta 2
else
return 1; //se è giorno setta 1
}
int seconds_elapsed()
{
int elapsed_secs = 0;
if(prev_time > clock.second) //necessario per lavorare con un conto di base di 60
{
elapsed_secs = (60-prev_time)+clock.second;
}
else
{
elapsed_secs = clock.second - prev_time;
}
return elapsed_secs;
}
int minutes_elapsed()
{
int elapsed_mins = 0;
if(last_time > clock.minute) //necessario per lavorare con un conto di base di 60
{
elapsed_mins = (60-last_time)+clock.minute;
}
else
{
elapsed_mins = clock.minute - last_time;
}
return elapsed_mins;
}
void loop()
{

int x = 0;
bool change_temp = 0;

//ottieni temperatura, data e tempo
DHT11_acquiring();
act_temp = (DHT11.getCelsius());
clock.getTime();

//leggi il pot pin
x = analogRead(pot_pin);
x = map(x, 0, 1023, 15, 45);
//se la temperatura è al minimo disattiva i controlli, spegni la retroilluminazione e accendi il led verde
if (x == 15)
{
stop_system();
print_LCD();
lcd.setCursor(12,1);
set_temp = (((x+15)*10)/2)/10.00; //se non si inserisce la temp si blocca sull'ultimo ricalcolo
lcd.setCursor(11,0);
lcd.print("-OFF-");
if(seconds_elapsed() >= delay_set)
digitalWrite(lcd_luce, 0);
goto stop;
}
//5 secondi dopo l'ultimo cambiamento spegni la retroilluminazione del LCD
if(seconds_elapsed() >= delay_set)
digitalWrite(lcd_luce, 0);
//se il potenziometro cambia temperatura accendi la retroilluminazione del LCD
if(x != prev_temp)
{
digitalWrite(lcd_luce, 1);
prev_time = (clock.second);
change_temp = 1;
delay(100);

}
//se è giorno regola la temperatura con il potenziometro
if (day_time() == 1)
{
set_temp = (((x+15)*10)/2)/10.00; // cambia la temperatura con il potenzionetro di 0.5°C per volta
lcd.setCursor(11,0);
lcd.print(" set");
lcd.setCursor(15,0);
lcd.write(byte(0));
}
//se è notte imposta la temperatura notturna
else if (day_time() == 2)
{
set_temp = temperatura_notturna;
lcd.setCursor(11,0);
lcd.print("sleep");
}
//se il tempo di attesa è passato attiva i controlli
if (minutes_elapsed() >= delay_set || change_temp == 1)
{
if (act_temp < (set_temp - hys)) //se la stanza è fredda accendi il termosifone
{
start_pump();
last_time = (clock.minute);
}
else //altrimenti se la stanza è calda spegni il termosifone
{
stop_pump();
last_time = (clock.minute);
}
change_temp = 0;
}
// scrivi sul LCD,imposta il valore del prev_temp
print_LCD();
prev_temp = x;
delay(100);
stop:
delay(500);
}

scusate se rispondo tardi ma sono stato un po' preso :stuck_out_tongue: comunque qui potete trovare lo schema:schema

Vedo che ci sono tanti sottomenu per la gestione del lcd con i sensori..beh prima cosa ti consiglio di mettere i controlli del sensore prima di tutti...sia di quello che della rtc se presente..inoltre dopo ogni sottomenu dovresti controllare se è' presente la funziona lcd.clear() poiché arduino in automatico non cancella ma gli va sopra..potrebbe essere questa la spiegazione..oppure più banalmente a me lo faceva quando scontravo qualche collegamento con il lcd e quindi va in panico xD...cmq confermo anche io che quel sensore lavora in digitale e non in analogico...quindi dovresti collegarlo a A5 e A4 e lavorare con la libreria wire e spi...quindi dovresti cercarti anche l'indirizzo della porta..c'è una libreria che si chiama scan i2c ch ti aiuterebbe molto...poi se metti anche nel void setup dei controlli per la verifica del funzionamento della rtc sarebbe perfetto! Controlla anche la funzione di stampa dell'ora..

Appena ho tempo provo a vedere di sistemare il programma con la funzione clear, i contatti li ho già controllati per lcd e sembrano a posto.
per la funzione di lettura tramite il digitalread potete dirmi come sistemarla che appena provo a cambiarla il programma non parte neanche.
Vi allego anche le immagini del termostato:
termostato
tanti cavi
scritte cinesi

ok ho sistemato un paio di cose sul programma

#include <Arduino.h>
#include <Wire.h>
#include "DS1307.h"
#include "LiquidCrystal.h"
#include "idDHT11.h"

int relay = 4;
int pot_pin = A1;
int led_rosso = 5;
int led_blu = 3;
int led_verde = 12;
int lcd_luce = 13;
float act_temp = 0.0;
float set_temp = 15.0;
int hum = 0;
int last_time = 0;
int hys = 1;
int temperatura_notturna = 18;

//serve a settare il tempo in cui il termostato rimane spento
int time_STOPinizio = 2;
int time_STOPfine = 6;

int prev_temp = 0;
int prev_time = 0;
int delay_set = 5;
byte degree[8] = {
  B01000,
  B10100,
  B01000,
  B00011,
  B00100,
  B00100,
  B00011,
};
//inizializza
LiquidCrystal lcd(10, 11, 6, 7, 8, 9); //LCD inizializzazione
int idDHT11pin = 2;
//pin digitale per la comunicazione del DHT11
int idDHT11intNumber = 0;
//interrupt number (deve essere quello che utilizza il pin definito precedentemente (guarda la tabella) DHT11
void dht11_wrapper(); // deve essere dichiarata prima dell'inizializzazione della libreria
idDHT11 DHT11(idDHT11pin, idDHT11intNumber, dht11_wrapper);
DS1307 clock;
//definisce l'oggetto (DS1307)
void setup()
{
  Serial.begin(9600);
  pinMode(relay, OUTPUT);
  pinMode(led_blu, OUTPUT);
  pinMode(led_rosso, OUTPUT);
  pinMode(led_verde, OUTPUT);
  pinMode(lcd_luce, OUTPUT);
  clock.begin();
  lcd.createChar(0, degree);
  lcd.begin(16, 2); // inizializza LCD
  lcd.setCursor(0, 0); // mette il cursore a 0,0

  /* **********serve ad impostare data e ora********* *\
  clock.fillByYMD(2015,9,16); //16-9-2015              *
  clock.fillByHMS(19,00,00);  //19:00 00"              *
  clock.fillDayOfWeek(WED);   //mercoledì              *
  clock.setTime();//scrivi ora e data sul ds1307       *
  \* ************************************************ */
}

//funzione: inizializzare la libreria idDHT11
void dht11_wrapper()
{
  DHT11.isrCallback();
}

//funzione: ottengo i dati dal sensore
void DHT11_acquiring() // aquisisci le informazioni dal sensore DHT11
{
  DHT11.acquire();
  while (DHT11.acquiring());
  int result = DHT11.getStatus();

  switch (result)  //segnala se è tutto ok o che errore si verifica
  {
    case IDDHTLIB_OK:
      Serial.println("OK");
      break;
    case IDDHTLIB_ERROR_CHECKSUM:
      Serial.println("Error\n\r\tChecksum error");
      break;
    case IDDHTLIB_ERROR_ISR_TIMEOUT:
      Serial.println("Error\n\r\tISR Time out error");
      break;
    case IDDHTLIB_ERROR_RESPONSE_TIMEOUT:
      Serial.println("Error\n\r\tResponse time out error");
      break;
    case IDDHTLIB_ERROR_DATA_TIMEOUT:
      Serial.println("Error\n\r\tData time out error");
      break;
    case IDDHTLIB_ERROR_ACQUIRING:
      Serial.println("Error\n\r\tAcquiring");
      break;
    case IDDHTLIB_ERROR_DELTA:
      Serial.println("Error\n\r\tDelta time to small");
      break;
    case IDDHTLIB_ERROR_NOTSTARTED:
      Serial.println("Error\n\r\tNot started");
      break;
    default:
      Serial.println("Unknown error");
      break;
  }
}

//funzioni: stati del termostato
void stop_pump() //spegne il relay e accende il LED rosso
{
  digitalWrite(relay, 1);
  digitalWrite(led_verde, 0);
  digitalWrite(led_rosso, 1);
  digitalWrite(led_blu, 0);
}

void start_pump() //spegne il relay e accende il led blu
{
  digitalWrite(relay, 0);
  digitalWrite(led_verde, 0);
  digitalWrite(led_rosso, 0);
  digitalWrite(led_blu, 1);
}

void stop_system() //spegne il relay e accende il led verde
{
  digitalWrite(relay, 1);
  digitalWrite(led_verde, 1);
  digitalWrite(led_rosso, 0);
  digitalWrite(led_blu, 0);
}
 
//funzione: scrive i dati sul display LCD (16x2)
void print_LCD()
{
  //linea 0
  lcd.setCursor(0, 0);
  lcd.print(act_temp, 0);
  lcd.setCursor(2, 0);
  lcd.write(byte(0));
  lcd.setCursor(4, 0);
  lcd.print("|");
  lcd.setCursor(5, 0);
  if (clock.hour < 10) // scrivi 0 prima dell'ora se è minore di 10
  {
    lcd.print("0");
    lcd.setCursor(6, 0);
    lcd.print(clock.hour, DEC);
  }
  else (lcd.print(clock.hour, DEC));
  lcd.setCursor(7, 0);
  lcd.print(":");
  lcd.setCursor(8, 0);
  if (clock.minute < 10) // scrivi 0 prima dei minuti se sono minori di 10
  {
    lcd.print("0");
    lcd.setCursor(9, 0);
    lcd.print(clock.minute, DEC);
  }
  else (lcd.print(clock.minute, DEC));
  lcd.setCursor(10, 0);
  lcd.print("|");
  lcd.setCursor(12, 0);
  lcd.setCursor(12, 1);
  lcd.print(set_temp, 1);

  //linea 1
  lcd.setCursor(2, 1);
  lcd.print("%");
  lcd.setCursor(0, 1);
  lcd.print(DHT11.getHumidity(), 0);
  lcd.setCursor(4, 1);
  lcd.print("|");
  lcd.setCursor(5, 1);

  if (clock.dayOfMonth < 10) // scrivi 0 del giorno se è minore di 10
  {
    lcd.print("0");
  }
  lcd.print(clock.dayOfMonth, DEC);

  lcd.setCursor(7, 1);
  lcd.print("/");
  lcd.setCursor(8, 1);

  if (clock.month < 10) // scrivi 0 del giorno se è minore di 10
  {
    lcd.print("0");
  }
  lcd.print(clock.month, DEC);

  lcd.setCursor(10, 1);
  lcd.print("|");
  lcd.setCursor(12, 1);
  lcd.print(set_temp, 1);
  lcd.setCursor(4, 0);
}

//funzione: variabili per il tempo
int day_time()
{
  int x = (clock.hour);
  if (x > time_STOPinizio && x < time_STOPfine)
    return 2; //se è notte setta 2
  else
    return 1; //se è giorno setta 1
}
int seconds_elapsed()
{
  int elapsed_secs = 0;
  if (prev_time > clock.second) //necessario per lavorare con un conto di base di 60
  {
    elapsed_secs = (60 - prev_time) + clock.second;
  }
  else
  {
    elapsed_secs = clock.second - prev_time;
  }
  return elapsed_secs;
}
int minutes_elapsed()
{
  int elapsed_mins = 0;
  if (last_time > clock.minute) //necessario per lavorare con un conto di base di 60
  {
    elapsed_mins = (60 - last_time) + clock.minute;
  }
  else
  {
    elapsed_mins = clock.minute - last_time;
  }
  return elapsed_mins;
}

//programma
void loop()
{

  int x = 0;
  bool change_temp = 0;

  //ottieni temperatura, data e tempo
  DHT11_acquiring();
  act_temp = (DHT11.getCelsius());
  clock.getTime();

  //leggi il pot pin
  x = analogRead(pot_pin);
  x = map(x, 0, 1023, 15, 45);
  //se la temperatura è al minimo disattiva i controlli, spegni la retroilluminazione e accendi il led verde
  if (x == 15)
  {
    stop_system();
    print_LCD();
    lcd.setCursor(12, 1);
    set_temp = (((x + 15) * 10) / 2) / 10.00; //se non si inserisce la temperatura si blocca sull'ultimo ricalcolo
    lcd.setCursor(11, 0);
    lcd.print("-OFF-");
    if (seconds_elapsed() >= delay_set)
      digitalWrite(lcd_luce, 0);
    goto stop;
  }
  //5 secondi dopo l'ultimo cambiamento spegni la retroilluminazione del LCD
  if (seconds_elapsed() >= delay_set)
    digitalWrite(lcd_luce, 0);
  //se il potenziometro cambia temperatura accendi la retroilluminazione del LCD
  if (x != prev_temp)
  {
    digitalWrite(lcd_luce, 1);
    prev_time = (clock.second);
    change_temp = 1;
    delay(100);

  }
  //se è giorno regola la temperatura con il potenziometro
  if (day_time() == 1)
  {
    set_temp = (((x + 15) * 10) / 2) / 10.00; // cambia la temperatura con il potenziometro di 0.5°C per volta
    lcd.setCursor(11, 0);
    lcd.print(" set");
    lcd.setCursor(15, 0);
    lcd.write(byte(0));
  }
  //se è notte imposta la temperatura notturna
  else if (day_time() == 2)
  {
    set_temp = temperatura_notturna;
    lcd.setCursor(11, 0);
    lcd.print("sleep");
  }
  //se il tempo di attesa è passato attiva i controlli
  if (minutes_elapsed() >= delay_set || change_temp == 1)
  {
    if (act_temp < (set_temp - hys)) //se la stanza è fredda accendi il termosifone
    {
      start_pump();
      last_time = (clock.minute);
    }
    else //altrimenti se la stanza è calda spegni il termosifone
    {
      stop_pump();
      last_time = (clock.minute);
    }
    change_temp = 0;
  }
  // scrivi sul LCD,imposta il valore del prev_temp
  print_LCD();
  prev_temp = x;
  delay(100);
stop:
  delay(500);
}

ok ho finito di implementare la funzione di pulizia del display e domani vi dirò se ci sono ancora le scritte cinesi

Ciao,
Io userei la macro F() in tutte le parti dove hai una serial.println o un lcd.print di un testo fisso; in questo modo useresti meno ram per cui la ram stessa si dovrebbe frammentare di meno. Per la spiegazione della macro F() vedi qui:

Inoltre, con il programma a regime, se non ti interessano più i messaggi di informazione inviati via seriale, io li metterei in un blocco condizionale di compilazione del tipo

Appena dopo gli include

#define DEBUG 1

E poi nel blocco delle serial.println qualcosa del tipo

#ifdef DEBUG
   serial.println(..)
#endif

Così se commento il
#define DEBUG 1
Il compilatore evita di compilarmi il codice tra #if e #endif, e guadagno anche in dimensione del codice finale.

Ciao!
P.S. Sto scrivendo da un tablet, per cui ci possono essere dei refusi...

xilav:
Ciao,
Io userei la macro F() in tutte le parti dove hai una serial.println o un lcd.print di un testo fisso; in questo modo useresti meno ram per cui la ram stessa si dovrebbe frammentare di meno. Per la spiegazione della macro F() vedi qui:
Optimizing SRAM | Memories of an Arduino | Adafruit Learning System
Inoltre, con il programma a regime, se non ti interessano più i messaggi di informazione inviati via seriale, io li metterei in un blocco condizionale di compilazione del tipo

Appena dopo gli include

#define DEBUG 1

E poi nel blocco delle serial.println qualcosa del tipo

#ifdef DEBUG

serial.println(..)
#endif




Così se commento il
#define DEBUG 1
Il compilatore evita di compilarmi il codice tra #if e #endif, e guadagno anche in dimensione del codice finale.

Ciao!
P.S. Sto scrivendo da un tablet, per cui ci possono essere dei refusi...

Grazie mille XILAV per avermi consigliato queste modifiche, ho modificato il programma aggiungendo la macrof che mi ha liberato il 10% di memoria e ho aggiunto la funzione clearscreen nominata in un altro post.
domani provo ad aggiungere il #define con calma, per oggi vado a nanna XD.
Ho notato però che con la clear screen non mi appaiono piu' i caratteri cinesi ma che lo schermo diventa vuoto dopo un po' quindi credo che il problema sia proprio la ram.
qui vi posto il codice modificato e impaginato un po' meglio:
codice termostato (non ci stava tutto XD)

Ciao,
ho visto che però non hai usato la macro F() quando scrivi nel LCD; io la metterei anche li, anche perchè è il punto che viene richiamato più frequentemente e può creare frammentazione.
Logicamente userei la macro F() solo dove fai un lcd.print() di testi statici. Ho preso un pezzo del tuo codice e lo ho modificato giusto per esempio:

//--snip--

    switch (funzione)
    {
      case 1:
      lcd.setCursor(11,0);
      lcd.print(F(" set"));               //<- testo statico
      lcd.setCursor(15,0);
      lcd.write(byte(0));
      break;
      case 2:
      lcd.setCursor(11,0);
      lcd.print(F("sleep"));              //<- testo statico
      break;
      case 3:
      lcd.setCursor(11,0);
      lcd.print(F("-OFF-"));              //<- testo statico
      break;
 
    }

//--snip--

Logicamente dovrai applicare la modifica all'intero sketch... ma questo è un lavoro tuo :slight_smile:

Ciao!

xilav:
Ciao,
ho visto che però non hai usato la macro F() quando scrivi nel LCD; io la metterei anche li, anche perchè è il punto che viene richiamato più frequentemente e può creare frammentazione.
Logicamente userei la macro F() solo dove fai un lcd.print() di testi statici. Ho preso un pezzo del tuo codice e lo ho modificato giusto per esempio:

//--snip--

switch (funzione)
    {
      case 1:
      lcd.setCursor(11,0);
      lcd.print(F(" set"));              //<- testo statico
      lcd.setCursor(15,0);
      lcd.write(byte(0));
      break;
      case 2:
      lcd.setCursor(11,0);
      lcd.print(F("sleep"));              //<- testo statico
      break;
      case 3:
      lcd.setCursor(11,0);
      lcd.print(F("-OFF-"));              //<- testo statico
      break;

}

//--snip--



Logicamente dovrai applicare la modifica all'intero sketch... ma questo è un lavoro tuo :)

Ciao!

ok ho sistemato per la macro f e la ho messa in tutte le cose che rimangono statiche sul display LCD ma potresti spiegarmi la storia della #define visto che non la ho mai usata?
io ho capito solo di metterla tra le variabili

#define DEBUG 1
int funzione = 0;
int pulisciLCD = 0;
...

e di mettere tipo qui:

 switch (result)  //segnala se è tutto ok o che errore si verifica
  {
    case IDDHTLIB_OK:
    #ifdef DEBUG
      Serial.println(F("OK"));
    #endif
    break;

Questa funzione la si può usare anche solo per una linea di testo o lo fà per tutto lo schermo? (ho un lcd 16x2 in I2c)
Sbaglio o lcd ha di per sè una ram da 32byte? questa funzione lo memorizza li lasciando la ram di arduino più libera?

xilav:
Ciao,
Io userei la macro F() in tutte le parti dove hai una serial.println o un lcd.print di un testo fisso; in questo modo useresti meno ram per cui la ram stessa si dovrebbe frammentare di meno. Per la spiegazione della macro F() vedi qui:
Optimizing SRAM | Memories of an Arduino | Adafruit Learning System
Inoltre, con il programma a regime, se non ti interessano più i messaggi di informazione inviati via seriale, io li metterei in un blocco condizionale di compilazione del tipo

Appena dopo gli include

#define DEBUG 1

E poi nel blocco delle serial.println qualcosa del tipo

#ifdef DEBUG

serial.println(..)
#endif




Così se commento il
#define DEBUG 1
Il compilatore evita di compilarmi il codice tra #if e #endif, e guadagno anche in dimensione del codice finale.

Ciao!
P.S. Sto scrivendo da un tablet, per cui ci possono essere dei refusi...

paolo98:
ok ho sistemato per la macro f e la ho messa in tutte le cose che rimangono statiche sul display LCD ma potresti spiegarmi la storia della #define visto che non la ho mai usata?
io ho capito solo di metterla tra le variabili

#define DEBUG 1

int funzione = 0;
int pulisciLCD = 0;
...




e di mettere tipo qui:



switch (result)  //segnala se è tutto ok o che errore si verifica
  {
    case IDDHTLIB_OK:
    #ifdef DEBUG
      Serial.println(F("OK"));
    #endif
    break;

le condizioni #ifdef #define e #endif (oltre alle altre direttive con il #) vengono eseguite dal pre-processore del compilatore.
Prima della compilazione viene eseguito il preprocessore che fra l'altro, risolve tutte le direttive (in soldoni le keywords con #)
In questo caso il codice tra #ifdef DEBUG e #endif viene processato dal pre-processore solo se la direttiva DEBUG è stata definita a priori tramite #define
(#ifdef sta per if defined ).

Questo vuol dire che il tuo codice:

switch (result)  //segnala se è tutto ok o che errore si verifica
  {
    case IDDHTLIB_OK:
    #ifdef DEBUG
      Serial.println(F("OK"));
    #endif
    break;

con #define DEBUG 1 verrà dato in pasto al compilatore come

switch (result)  //segnala se è tutto ok o che errore si verifica
  {
    case IDDHTLIB_OK:
      Serial.println(F("OK"));
    break;

mentre con commentato il //#define DEBUG 1 verrà passato al compilatore come

switch (result)  //segnala se è tutto ok o che errore si verifica
  {
    case IDDHTLIB_OK:
    break;

praticamente è come se quel codice nella versione di release neanche lo avessi scritto, per cui la dimensione del compilato sarà minore Nel tuo caso potresti mettere tra #ifdef DEBUG e #endif tutto il blocco dello switch(), visto che è stato implementato imho solo per il debug seriale.

Questo era solo un suggerimento, perchè sicuramente queste parti non vanno ad inficiare la RAM, comunque possono aiutare a rendere più piccolo e più veloce il codice.

P.S. Fammi sapere se dopo questi trimmimg lo sketch si è messo a funzionare e non visualizza più caratteri strani nè schermo vuoto...

Ciao!

francescomi92:
Questa funzione la si può usare anche solo per una linea di testo o lo fà per tutto lo schermo? (ho un lcd 16x2 in I2c)
Sbaglio o lcd ha di per sè una ram da 32byte? questa funzione lo memorizza li lasciando la ram di arduino più libera?

Intendi la macro F()?
Se intendi la macro F(), praticamente istruisce il compilatore di caricare il dato direttamente dalla EEPROM (dove è scritto il codice), anzichè copiare il dato dalla EEPROM alla RAM per poi caricarlo dalla RAM. Questo causa un minor uso della RAM a runtime, per cui minor probabilità di finire la RAM a causa di frammentazione.

Ok, grazie mille XILAV per avermi spiegato il #define che ho inserito perchè troppo comodo XD, comunque ho modificato anche qualche variabile e la ho messa in byte per risparmiare altra memoria.
Qui il codice e spero che non mi dia piu' il problema.
Nel caso ho visto che esiste una funzione chiamata reserve() sapresti dirmi se puo' essermi utile?

Ciao,
non ho visto il tuo codice attuale perchè dovrei registrarmi al sito e non ne ho voglia :), ma se sostanzialmente hai usato gli stessi tipi del vecchio sketch non c'è nessuna variabile che derivi dalla classe String, per cui la reserve() non è necessaria nè utiizzabile visto che è un metodo di quella classe.

La reserve() indica ad una variabile di classe String di allocare staticamente dello spazio in RAM di quella variabile.
Questo perchè la classe String è sostanzialmente dinamica, per cui ad esempio si può inizializzare la variabile con una stringa di 4 caratteri per poi sommarla ad un'altra stringa di 6 caratteri ed ottenere quindi la stressa variabile di 10 caratteri.

Questo è comodo quando si programma con sistemi operativi dove la memoria non è un problema, ma dato che per ottenerre questa dinamicità la classe internamente usa funzioni di allocazione di memoria (quali ad esempio malloc(), realloc() e free() ), è soggetta a frammentare la RAM.

L'utilizzo della reseve() serve a mitigare la frammentazione in quanto la si utilizzerà per riservare a priori la massima lunghezza della variabile di tipo String. La conseguenza è che internamente non verranno chiamate le funzioni di riallocazione di memoria (sempre se chi ha programmato ha allocato a priori tramite reserve() una dimensione inferiore alla massima dimensione di stringa gestita nello sketch).

Comunque questo non è il tuo caso.

Ciao!