#include #line 1 "C:\\Users\\Antani\\Documents\\PortableApps\\arduino-1.8.5\\portable\\sketchbook\\ricette\\ricette.ino" #line 1 "C:\\Users\\Antani\\Documents\\PortableApps\\arduino-1.8.5\\portable\\sketchbook\\ricette\\ricette.ino" /* TAFFY v1.3 Termo Affumicatore Termostato multiuso per affumicare, misurare temperatura con sonda DS18B20 e termocoppia MAX6675. Affumicamitutto segue l'acensione e lo spegnimento di una ventola per ravvivare braciere affumicatore. Il warmup iniziale accende correttamente il bracere. pausa tiene spenta la ventola per non surriscaldare e consumare eccessivamente la brace. funzion da il colpetto di ventola di pochi secondi per ravvivare la brace che non si spenga. time_max è la durata del programma quindi del processo di affumicatura. Termostato controlla l'alimentazione elettrica di un forno usando un SSR (solid state relay) utilizza l'uscita fanPin 9 (la stessa che alimenta la ventola) per accendere e spegnere l'alimentazione al forno e mantenere la temperatura nel range impostato a seconda del programma. Creato nel 2018 da Gianluca Frare V1.0 relase iniziale V1.1 richiede pressione tasto verde per iniziare il programma dopo il riscaldamento V1.2 aggiunta la risposta alla pressione del tasto 1 per tornare inditro dai menù (restano fuori il menù affumicatura e termostato manuale) V1.2.1 Aggiornato affumicamitutto() con i while per funzionare senza il bisogno di loop. Aggiunte anche la ridefinizione di temp_max, min_max e stato. V1.2.2 ottimizzate dimensioni variabili e rimosse quelle non usate. v1.2.2.2 introdotto un PID approssimato per la gestione più precisa della temperatura in cottura() V1.3 introdotto il programma reverse searing con l'uso della sonda DS18B20 */ #include #include #include "max6675.h" #include #include #include #define ONE_WIRE_BUS 12 // pin sensore temperatura su millefori #include #include #define fanPin 9 // pin ventola #define MIN 0 #define MAX 255 #define MAXLED 0.16 // coefficiente per ridurre luminosità led. #define warmup 90 // secondi avvio della brace 90 #define pausa 40 // secondi di pausa 40 #define funzion 20 // secondi di funzionamento per ravvivare brace byte #define buffertemp 5 // array di valori di temperatura usato per calcolare la media byte ktcSO = 6; byte ktcCS = 7; byte ktcCLK = 8; MAX6675 ktc(ktcCLK, ktcCS, ktcSO); byte programma = 0; // variabile per controllare se far partire la semplice misurazione della temperatura (2) o l'affumicatura (1) unsigned int time_max; // tempo di durata del ciclo di affumicatura in secondi scelto dall'utente (settato da min_max*60) unsigned int t_trascorso; // attenzione non superare 65000sec (18 ore) unsigned int tempo_ins_dati = 0; // tiene traccia del tempo passato ad inserire i dati per calcolare il reale tempo impiegato da affumicatura() unsigned int t_stato_prec = 0; // variabile per il controllo del tempo trascorso int temp_max = 37; // temperatura massima di default modificabile da utente byte min_max = 30; // durata del programma di default 30 minuti sufficienti per 1 cucchiaio di segatura modificabile da utente bool stato = 0; // stato del programma <0 immissione parametri> <1 esecuzione affumicatura> float temperatura; // variabile 32 bit per la temperatura con virgola sensore DS18B20 float temperaturaT; // variabile temperatura termocoppia MAX6675 //Define Variables we'll be connecting to double Setpoint, Input, Output; //Specify the links and initial tuning parameters PID myPID(&Input, &Output, &Setpoint, 300, 300, 75, DIRECT); int WindowSize = 5000; unsigned long windowStartTime; float temp_media[buffertemp]; byte cont_array_temp = 0; byte riga = 0; // numero della riga del display byte byte rigadisplay = 0; // numero della riga del display byte led_rosso = 3; // pin del led rosso byte led_verde = 5; // pin del led verde byte fase = 0; //fase 0 warmup, fase 1 pausa, fase 2 ravvivamento, fase 3 STOP, fase 4 TEMPERATURA ALTA //int resetta = 0; //variabile che memeorizza la pressione prolungata del pulsate per il reset del programma //int ultimoresetta = 0; //unsigned int triggertempo = 0; LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display OneWire oneWire(ONE_WIRE_BUS); // Setup a oneWire instance to communicate with any OneWire devices DallasTemperature sensors(&oneWire); // Pass our oneWire reference to Dallas Temperature sensor class ricetta { public: String nome; int temperatura[5]; int durata[5]; }; ricetta ricettario[] { // NOME RICETTA , TEMPERATURE, TEMPI (minuti) {"Pane ", {230, 180}, {15, 30}}, {"Brioches ", {180}, {20}}, {"Baguettes ", {240, 180}, {15, 5}}, {"Rotolo Maiale ", {240, 160}, {15, 45}}, {"TEST ", {70}, {10}}, }; //definizione del simbolo di selezione riga byte pallino[8] = { 0b00000, 0b00000, 0b00100, 0b01110, 0b01110, 0b00100, 0b00000, 0b00000 }; //se aggiungi elementi modifica numero 4 in selectprog(menu_principale, 4); String menu_principale[] = { "AFFUMICATURA ", "MISURA ", "TERMOSTATO ", "REVERSE SEARING" }; //se aggiungi elementi modifica numero 2 in selectprog(menu_termostato, 2); String menu_termostato[] = { "MANUALE ", // 0 "PROGRAMMA ", // 1 }; #line 139 "C:\\Users\\Antani\\Documents\\PortableApps\\arduino-1.8.5\\portable\\sketchbook\\ricette\\ricette.ino" void setup(); #line 168 "C:\\Users\\Antani\\Documents\\PortableApps\\arduino-1.8.5\\portable\\sketchbook\\ricette\\ricette.ino" void loop(); #line 195 "C:\\Users\\Antani\\Documents\\PortableApps\\arduino-1.8.5\\portable\\sketchbook\\ricette\\ricette.ino" int selectprog(String menu[], int elementi); #line 256 "C:\\Users\\Antani\\Documents\\PortableApps\\arduino-1.8.5\\portable\\sketchbook\\ricette\\ricette.ino" int lettura_pulsante(); #line 266 "C:\\Users\\Antani\\Documents\\PortableApps\\arduino-1.8.5\\portable\\sketchbook\\ricette\\ricette.ino" void affumicamitutto(); #line 314 "C:\\Users\\Antani\\Documents\\PortableApps\\arduino-1.8.5\\portable\\sketchbook\\ricette\\ricette.ino" void affumicatura(); #line 386 "C:\\Users\\Antani\\Documents\\PortableApps\\arduino-1.8.5\\portable\\sketchbook\\ricette\\ricette.ino" void sondetemp(); #line 433 "C:\\Users\\Antani\\Documents\\PortableApps\\arduino-1.8.5\\portable\\sketchbook\\ricette\\ricette.ino" void restart(int res_var); #line 471 "C:\\Users\\Antani\\Documents\\PortableApps\\arduino-1.8.5\\portable\\sketchbook\\ricette\\ricette.ino" void inserimento_dati(int tmin, int tmax, int tstep); #line 517 "C:\\Users\\Antani\\Documents\\PortableApps\\arduino-1.8.5\\portable\\sketchbook\\ricette\\ricette.ino" void scrittura_dati(float wtemp, int wtime); #line 544 "C:\\Users\\Antani\\Documents\\PortableApps\\arduino-1.8.5\\portable\\sketchbook\\ricette\\ricette.ino" void scrittura_display(); #line 555 "C:\\Users\\Antani\\Documents\\PortableApps\\arduino-1.8.5\\portable\\sketchbook\\ricette\\ricette.ino" void termostato(); #line 629 "C:\\Users\\Antani\\Documents\\PortableApps\\arduino-1.8.5\\portable\\sketchbook\\ricette\\ricette.ino" void reversesearing(); #line 643 "C:\\Users\\Antani\\Documents\\PortableApps\\arduino-1.8.5\\portable\\sketchbook\\ricette\\ricette.ino" int selectricetta(ricetta ric[]); #line 706 "C:\\Users\\Antani\\Documents\\PortableApps\\arduino-1.8.5\\portable\\sketchbook\\ricette\\ricette.ino" void cottura(bool sonda, int gradi, int minuti); #line 790 "C:\\Users\\Antani\\Documents\\PortableApps\\arduino-1.8.5\\portable\\sketchbook\\ricette\\ricette.ino" void cotturapid(bool sonda, int gradi, int minuti); #line 852 "C:\\Users\\Antani\\Documents\\PortableApps\\arduino-1.8.5\\portable\\sketchbook\\ricette\\ricette.ino" float misuratemperatura(); #line 139 "C:\\Users\\Antani\\Documents\\PortableApps\\arduino-1.8.5\\portable\\sketchbook\\ricette\\ricette.ino" void setup() { pinMode(fanPin, OUTPUT); pinMode(led_rosso, OUTPUT); pinMode(led_verde, OUTPUT); Serial.begin(9600); sensors.begin(); //inizializza sensore temperatura analogWrite(led_rosso, (70 * MAXLED)); analogWrite(led_verde, (40 * MAXLED)); lcd.begin(); lcd.backlight(); //inizializza LCD lcd.clear(); //pulisce display da eventuali caratteri residui lcd.setCursor(5, 0); lcd.print("TAFFY"); lcd.setCursor(0, 1); lcd.print(" v1.3"); delay(1500); lcd.clear(); analogWrite(led_rosso, 0); analogWrite(led_verde, 0); lcd.createChar(1, pallino); //crea il simbolo di selezione riga } void loop() { if (programma == 0) { programma = selectprog(menu_principale, 4); programma++; //allinea la numerazione e se ritorna -1 (pulsante 1) riporta a 0 la selezione } if (programma == 1) { affumicamitutto(); } if (programma == 2) { sondetemp(); } if (programma == 3) { termostato(); } if (programma == 4) { reversesearing(); } } /* funzione che legge il pulsante premuto, sposta la freccia di selezione e avvia il programma selezionato*/ int selectprog(String menu[], int elementi) { lcd.clear(); riga = 0; int finestra = 0; bool esci = 0; elementi--; // numero elementi all'array (elementi-1) while (esci == 0) { int pulsante = lettura_pulsante(); lcd.setCursor(13, riga); // posiziona il cursore sulla riga selezionata if (riga > 0 && riga < elementi && pulsante == 3) finestra++; if (riga < elementi && riga > 0 && pulsante == 2) finestra--; switch (pulsante) { case 0: break; case 1: // se premo pulsante 1 ritorno -1 e mi fa uscire return -1; break; case 2: // se premo pulsante 2 (su) if (riga >= 1) riga--; break; case 3: if (riga < elementi) riga++; // se premo pulsante 3 (giù) break; case 4: // se premo pulsante 4 (start/stop) lcd.clear(); esci = 1; break; } rigadisplay = riga - finestra; lcd.setCursor(0, 0); lcd.print(menu[finestra]); lcd.setCursor(0, 1); lcd.print(menu[(finestra + 1)]); lcd.setCursor(15, rigadisplay); lcd.write(1); //scrive il pallino che indica la riga selezionata if (rigadisplay == 0) lcd.setCursor(15, 1); if (rigadisplay == 1) lcd.setCursor(15, 0); lcd.print(" "); delay(10); } lcd.clear(); return (riga); // ritorna il programma selezionato } /* lettura_pulsante() ritorna il numero del pulsante settaggio con R = 4700 + 1000 + 1000 + 1000 ohm */ int lettura_pulsante() { int Value = analogRead(A0); if (Value > 1000) return 0; //se non viene premuto nessun pulsante ritorna 0 Value = map(Value, 0, 377, 1, 4); //assegna a Value il numero pulsante proporzionando il valore analogico delay(100); //ritardo che evita di far variare i valori troppo velocemente se si tiene premuto return Value; } /* programma dell'affumicatura, tutto ciò che era precedentemente in loop() */ void affumicamitutto() { temp_max = 37; // temperatura massima di default modificabile da utente min_max = 30; // durata del programma di default 30 minuti sufficienti per 1 cucchiaio di segatura modificabile da utente stato = 0; // stato del programma <0 immissione parametri> <1 esecuzione affumicatura> while (stato == 0) { scrittura_display(); inserimento_dati(15 , 50, 1); scrittura_dati(temp_max, min_max); // lcd.setCursor(11, !riga); // ripulisce dal carattere -> l'altra riga // lcd.print(" "); // sovrascrivendo con uno spazio // lcd.setCursor(11, riga); // // lcd.print((char)126); // carattere -> per indicare posizione cursore time_max = min_max * 60; // assegna a time_max il numero di secondi di durata del ciclo, valore inserito da utente convertito in secondi if (stato == 1) lcd.clear(); // prima di passare al ciclo di affumicatura ripulisce lo schermo tempo_ins_dati = millis() / 1000; // memorizza i secondi impiegati per inserire i dati } while (stato == 1) { scrittura_display(); affumicatura(); scrittura_dati(temperatura, (time_max - t_trascorso)); if (fase == 3) { // se ciclo affumicatura è finito lcd.clear(); lcd.print(" AFFUMICATURA"); lcd.setCursor(0, 1); lcd.print(" COMPLETATA"); delay(10000); // attendi 10 secondi nella fase 3 poi resetta //resetta display, spegne led, resetta stato, fase e contatore tempo e ritorna a chiedere i dati lcd.clear(); stato = 0; fase = 0; analogWrite(led_rosso, 0); analogWrite(led_verde, 0); t_stato_prec = 0; scrittura_display(); } delay(100); } } /* ciclo di affumicatura che attiva la ventola e i led */ void affumicatura() { t_trascorso = (millis() / 1000) - tempo_ins_dati; // tempo trascorso in secondi dall'inizio del programma if (temperatura < temp_max) { // se la temperatura è bassa e if (t_trascorso > warmup && fase == 0) { // se il tempo di warmup è passato e non è scaduto il tempo massimo fase = 1; // passa al mantenimento (fase 1) } if (t_trascorso >= time_max) { // se il tempo di affumicatura è passato fase = 3; // conclusione programma (fase 3) } } else // se la temperatura è alta fase = 4; // spegni ventola per raffreddare (fase 4) sensors.requestTemperatures(); // Call sensors.requestTemperatures() to issue a global temperature and Requests to all devices on the bus temperatura = sensors.getTempCByIndex(0); switch (fase) { case 0: analogWrite(fanPin, MAX); // acensione iniziale: avvio per il tempo di warmup analogWrite(led_verde, (70 * MAXLED)); // led verde acceso molto forte if (t_trascorso - t_stato_prec >= warmup) { t_stato_prec += warmup; fase = 1; } else { fase = 0; } break; case 1: analogWrite(fanPin, MIN); // mantenimento, spegne ventola per il tempo della pausa analogWrite(led_verde, 1.5); // led verde acceso tenue if (t_trascorso - t_stato_prec >= pausa) { // senza usare delay() aspetto che trascorra il tempo della pausa t_stato_prec += pausa; // quando è trascorso resetto t_trascorso fase = 2; // e passo alla fase successiva } else { fase = 1; // altrimenti continuo ad aspettare } break; case 2: analogWrite(fanPin, MAX); // mantenimento, accende ventola per il tempo di funzion (ravviva leggermente la fiamma) analogWrite(led_verde, (70 * MAXLED)); // led verde acceso molto forte if (t_trascorso - t_stato_prec >= funzion) { t_stato_prec += funzion; fase = 1; } else { fase = 2; } break; case 3: analogWrite(fanPin, MIN); // programma concluso, spegne definitivamente ventola analogWrite(led_rosso, (70 * MAXLED)); // led rosso acceso fisso analogWrite(led_verde, 0); // led verde spento break; case 4: analogWrite(fanPin, MIN); // spegne ventola per raffreddare analogWrite(led_rosso, (70 * MAXLED)); analogWrite(led_verde, (40 * MAXLED)); delay(150); // fa lampeggiare entrambi i led per segnalare temperatura troppo alta analogWrite(led_rosso, 0); analogWrite(led_verde, 0); fase = 1; // resetta la fase per non rimanere bloccato in caso la temperatura torni a valori normali break; } } /* funzione che legge le temperature dalle due sonde e ne scrive i valori in tempo reale */ void sondetemp() { if (lettura_pulsante() == 1) { //se premo il pulsante 1 esce dal programma sondetemp e torna al menù principale programma = 0; lcd.clear(); return; } char buf[5]; String tempString; sensors.requestTemperatures(); // Call sensors.requestTemperatures() to issue a global temperature and Requests to all devices on the bus temperatura = sensors.getTempCByIndex(0); delay(250); lcd.setCursor(0, 0); lcd.print("DS"); lcd.setCursor(8, 0); lcd.print((char)223); //carattere ° di grado centigrado lcd.print("C"); lcd.setCursor(11, 0); // posziono il cursore sulla prima riga al 13° carattere if (temperatura == -127) lcd.print("-----"); //se la sonda è scollegata e ritorna il valore -127 oppure di inf scrive a display "----" else { // dtostrf(FLOAT,WIDTH,PRECSISION,BUFFER); assegna alla stringa tempString la rappresentazione ASCII del numero float con lunghezza totale 5 e una cifra dopo la virgola tempString = dtostrf(temperatura, 5, 1, buf); lcd.print(tempString); } temperaturaT = ktc.readCelsius(); lcd.setCursor(0, 1); //posiziono il cursore sulla seconda riga al 13° carattere lcd.print("MAX "); lcd.setCursor(8, 1); lcd.print((char)223); //carattere ° di grado centigrado lcd.print("C"); lcd.setCursor(11, 1); // posziono il cursore sulla seconda riga al 13° carattere tempString = dtostrf(temperaturaT, 5, 1, buf); // dtostrf(FLOAT,WIDTH,PRECSISION,BUFFER); lcd.print(tempString); } /* funzione che resetta arduino. attenzione che potrebbe non ripulire correttamente i registri */ void(* Riavvia)(void) = 0; /* funzione che resetta arduino alla pressione del pulsante 1 o riavvia il programma alla pressione del pulsante 4 */ void restart(int res_var) { if (res_var == 4) { // se il pulsante premuto era 2 (verde) lcd.clear(); lcd.print(" RESET"); delay(1000); Riavvia(); } if (res_var == 1) { // se il pulsante premuto era 1 (rosso) if (programma == 2) programma = 0; { // se il programma era lettura temperature torna alla richiesta programma } if (programma == 1 && stato == 0) { programma = 0; } if (programma == 1 && stato == 1) { stato = 0; // ripristina lo stato in caso di stop deciso dall'utente t_stato_prec = 0; // resetta la variabile per il controllo del tempo trascorso fase = 0; lcd.clear(); lcd.print(" STOP"); delay(1000); lcd.clear(); analogWrite(fanPin, MIN); // spegne la ventola analogWrite(led_rosso, 0); // spegne eventuali led accesi analogWrite(led_verde, 0); //scrittura_display(); } lcd.clear(); } } /* inserimento_dati(int tmin, int tmax, int tstep) sposta il cursore e cambia le variabili di settaggio temp_max e min_max alla pressione del pulsante corrispondente- parametri temperatura minima , massima e step di aumento/diminuzione*/ void inserimento_dati(int tmin, int tmax, int tstep) { int pulsante = lettura_pulsante(); lcd.setCursor(12, riga); //posiziona il cursore sul dato da modificare selezionato switch (pulsante) { case 0: break; case 1: //se premo pulsante 1 cambia la riga da modificare riga = !riga; break; case 2: //se premo pulsante 2 (su) if (riga == 0 && temp_max < tmax) { //se sono su riga 0 e temperatura settata minore di 50°C if (temp_max >= 50) temp_max += tstep; //aumenta dello step di temperatura tstep if (temp_max < 50) temp_max++; } if (riga == 1 && min_max < 180) //se sono su riga 1 e tempo minore di 100 minuti min_max += 5; //aumenta di 5 minuti break; case 3: //se premo pulsante 3 (giù) if (riga == 0 && temp_max > tmin) { //se sono su riga 0 e temperatura settata maggiore di 15°C if (temp_max <= 50) temp_max--; if (temp_max > 50) temp_max -= tstep; //diminuisce dello step di temperatura tstep } if (riga == 1 && min_max > 5) //se sono su riga 1 e tempo maggiore di 5 minuti min_max -= 5; //diminuisce di 5 minuti break; case 4: //se premo pulsante 4 (start/stop) stato = 1; //fa partire il ciclo di affumicatura break; } lcd.setCursor(11, riga); lcd.write(1); if (riga == 0) lcd.setCursor(11, 1); if (riga == 1) lcd.setCursor(11, 0); lcd.print(" "); } /* scrittura_dati(temp, time) viene usata per scrivere i dati temperatura e tempo sia durate il setup che durante il funzionamento. Vanno passati i due valori interi */ void scrittura_dati(float wtemp, int wtime) { if (stato == 0) { lcd.setCursor(12, 0); // posziono il cursore sulla prima riga al 13° carattere lcd.print(int(wtemp)); // se sono nell'inserimento dati converto in int senza decimali lcd.print(" "); // aggiungo spazi fino a fine display per sovrascrivere eventuali carattteri residui lcd.setCursor(12, 1); // posziono il cursore sulla seconda riga al 13° carattere lcd.print(wtime); lcd.print(" "); // aggiungo spazi fino a fine display per sovrascrivere eventuali carattteri residui } else { lcd.setCursor(11, 0); // posziono il cursore sulla prima riga al 13° carattere if (wtemp < -100) lcd.print("----"); //se la sonda è scollegata e ritorna il valore -127 oppure di inf scrive a display "----" else lcd.print(wtemp, 1); lcd.print(" "); //aggiungo spazi fino a fine display per sovrascrivere eventuali carattteri residui lcd.setCursor(11, 1); //posiziono il cursore sulla seconda riga al 11° carattere if ((wtime / 60) < 10) lcd.print(" "); lcd.print(wtime / 60); lcd.print(":"); if (((wtime % 3600) % 60) < 10) lcd.print("0"); lcd.print((wtime % 3600) % 60); if (wtime < 10) lcd.print(" "); //aggiungo spazi fino a fine display per sovrascrivere eventuali carattteri residui } } /* scrittura_display() scrive la richiesta di dati iniziale */ void scrittura_display() { lcd.setCursor(0, 0); lcd.print("temp <"); lcd.print((char)223); //carattere ° di grado centigrado lcd.print("C>"); lcd.setCursor(0, 1); lcd.print("time "); } /* termostato controlla l'acensione di un SSR in base alla temperatura della sonda selezionata */ void termostato() { bool esci = 0; int prog_termo = selectprog(menu_termostato, 2); if (prog_termo == -1) { programma = 0; return; //se ho premuto il tasto 1 quindi è tornato -1 esco al menù principale } temp_max = 200; min_max = 45; /*programa termostato 0, MANUALE, inserire tempo e temperatura esegue il riscaldamento del forno e poi scatta il conto alla rovescia. finito ritorna al menù*/ if (prog_termo == 0) { while (stato == 0) { scrittura_display(); inserimento_dati(30, 400, 5); scrittura_dati(temp_max, min_max); } time_max = min_max * 60; // assegna a time_max il numero di secondi di durata del ciclo, valore inserito da utente convertito in secondi //aspetta che il forno vada in temperatura while (lettura_pulsante() != 4) { // quando ha raggiunto la temperatura aspetta la pressione del tasto verde per partire con il conto alla rovescia cottura(1, (temp_max + 10), 0); scrittura_dati(temperaturaT, time_max); delay(250); } cottura(1, temp_max, min_max); // esegue la funzione di cottura passando i dati inseriti analogWrite(fanPin, MIN); // spegne forno analogWrite(led_verde, MIN); // spegne led stato = 0; } /*programa termostato 1, PROGRAMMI, selezionare un programma preregistrato tempo e temperatura esegue il riscaldamento del forno e poi scatta il conto alla rovescia. finito ritorna al menù*/ if (prog_termo == 1) { int i = 0; int scelto = selectricetta(ricettario); scrittura_display(); time_max = ricettario[scelto].durata[0] * 60; if (scelto == -1) return; //aspetta che il forno vada in temperatura while (lettura_pulsante() != 4) { // quando ha raggiunto la temperatura aspetta la pressione del tasto verde per partire con il conto alla rovescia // finchè la temperatura non è raggiunta pre-riscalda il forno cottura(1, (ricettario[scelto].temperatura[0] + 10), 0); scrittura_dati(temperaturaT, ricettario[scelto].durata[0] * 60); // delay(250); } while (ricettario[scelto].temperatura[i] != 0) { //finchè ci sono dati validi di temperatura li legge e li passa alla procedura cottura per eseguire il ciclo per ogni elemento dell'array lcd.setCursor(4, 0); lcd.print(i + 1); //aggiunge il numero dello step nelle righe per capire circa dove siamo lcd.setCursor(4, 1); lcd.print(i + 1); cottura(1, ricettario[scelto].temperatura[i], ricettario[scelto].durata[i]); // chiama cottura per ogni step passando la temperatura e il tempo inseriti in ogni step della ricetta i++; } analogWrite(fanPin, MIN); // spegne forno analogWrite(led_verde, MIN); // spegne led } } /* funzione di riscaldamento a bassa temperatura (inferiore a 60°C che usa la sonda DS per il controllo della temperatura */ void reversesearing() { temp_max = 52; // temperatura standar per reverse searing del manzo min_max = 60; // tempo minimo 1 ora per un ottimo reverse searing riga = 0; while (stato == 0) { scrittura_display(); inserimento_dati(30, 70, 1); scrittura_dati(temp_max, min_max); } cottura(0, temp_max, min_max); } /* funzione che passato un array di ricette (struct) permette di selezionarle e ritorna il numero progressivo della ricetta*/ int selectricetta(ricetta ric[]) { lcd.clear(); riga = 0; int elementi = sizeof(ricettario) / sizeof(ricetta); int finestra = 0; // finestra permette di visualizzare 2 righe alla volta bool esci = 0; elementi--; // indice numero elementi all'array (elementi-1) while (esci == 0) { int pulsante = lettura_pulsante(); lcd.setCursor(13, riga); // posiziona il cursore sulla riga selezionata if (riga > 0 && riga < elementi && pulsante == 3) finestra++; if (riga < elementi && riga > 0 && pulsante == 2) finestra--; switch (pulsante) { case 0: break; case 1: // se premo pulsante 1 ... to do! return -1; break; case 2: // se premo pulsante 2 (su) if (riga >= 1) riga--; break; case 3: if (riga < elementi) riga++; // se premo pulsante 3 (giù) break; case 4: // se premo pulsante 4 (start/stop) lcd.clear(); esci = 1; stato = 1; break; } rigadisplay = riga - finestra; lcd.setCursor(0, 0); lcd.print(ric[finestra].nome); lcd.setCursor(0, 1); lcd.print(ric[(finestra + 1)].nome); lcd.setCursor(15, rigadisplay); lcd.write(1); //scrive il pallino che indica la riga selezionata //cancella il pallino nell'altra riga if (rigadisplay == 0) lcd.setCursor(15, 1); if (rigadisplay == 1) lcd.setCursor(15, 0); lcd.print(" "); delay(10); } lcd.clear(); return (riga); // ritorna il programma selezionato } /* funzione che fa da preriscaldamento (se minuti = 0) e da cottura (se minuti è maggiore di 0) sonda = 0 usa DS18B20, sonda = 1 usa termocoppia */ void cottura(bool sonda, int gradi, int minuti) { analogWrite(fanPin, MAX); // accende forno analogWrite(led_verde, (70 * MAXLED)); // led verde acceso molto forte bool trig = true; long debounce = millis(); long tempo[2]; float temperature[2]; float gradisecondo; int tempoaltarget; int debounceDelay = 5000; // finestra di funzionamento e spegnimento byte stato = 0; // variabile per saltare da una posizione el 'altra dell'array delle temeprature unsigned int sec_max = minuti * 60; tempo_ins_dati = millis() / 1000; // memorizza i secondi impiegati per inserire i dati e per andare in temperatura t_trascorso = (millis() / 1000) - tempo_ins_dati; // tempo trascorso in secondi dall'inizio del programma while (trig) { // finchè il tempo non è finito t_trascorso = (millis() / 1000) - tempo_ins_dati; // tempo trascorso in secondi dall'inizio del programma if (sonda == 1) temperaturaT = misuratemperatura(); if (sonda == 0) { sensors.requestTemperatures(); // Call sensors.requestTemperatures() to issue a global temperature and Requests to all devices on the bus temperaturaT = sensors.getTempCByIndex(0); } if ((millis() - debounce) > debounceDelay) { // ogni debounceDelay usa la temperatura campionata per calcolare la velocità if (stato == 0) { temperature[0] = temperaturaT; tempo[0] = millis(); stato = 1; } else { temperature[1] = temperaturaT; tempo[1] = millis(); stato = 0; if (temperature[1] - temperature[0] != 0) { gradisecondo = (temperature[1] - temperature[0]) / (tempo[1] - tempo[0]) * 1000; //gradisencondo contiene la velocità di aumento di temperatura, positiva o negativa °C/secondo } } debounce = millis(); tempoaltarget = abs((gradi - temperaturaT) / gradisecondo); } Serial.print("secondi al target "); Serial.print(tempoaltarget); if (tempoaltarget < 90) { // se sono in una delle finestre da 90 sec dal target if (gradisecondo > 0) { // se la temperatura sale analogWrite(fanPin, MIN); // spegne forno analogWrite(led_rosso, (70 * MAXLED)); // led rosso acceso fisso analogWrite(led_verde, 0); // led verde spento } if (gradisecondo < 0) { // se la temperatura scende analogWrite(fanPin, MAX); // accende forno analogWrite(led_verde, (40 * MAXLED)); // led verde acceso molto forte analogWrite(led_rosso, 0); // led rosso spento } } else if (temperaturaT < gradi) { //se la temperatura misurata è sotto il target analogWrite(fanPin, MAX); // accende forno analogWrite(led_verde, (40 * MAXLED)); // led verde acceso molto forte analogWrite(led_rosso, 0); // led rosso spento } Serial.print(" - °C al sec "); Serial.print(gradisecondo); Serial.print(" - trig "); Serial.println(trig); scrittura_dati(temperaturaT, (sec_max - t_trascorso)); if (minuti == 0) { trig = true; if (temperaturaT > gradi) return; } else { trig = (sec_max - t_trascorso) > 0; } } } void cotturapid(bool sonda, int gradi, int minuti) { bool trig = true; unsigned int sec_max = minuti * 60; tempo_ins_dati = millis() / 1000; // memorizza i secondi impiegati per inserire i dati e per andare in temperatura t_trascorso = (millis() / 1000) - tempo_ins_dati; // tempo trascorso in secondi dall'inizio del programma windowStartTime = millis(); //initialize the variables we're linked to Setpoint = gradi; //tell the PID to range between 0 and the full window size myPID.SetOutputLimits(0, WindowSize); //turn the PID on myPID.SetMode(AUTOMATIC); while (trig) { // finchè il tempo non è finito t_trascorso = (millis() / 1000) - tempo_ins_dati; // tempo trascorso in secondi dall'inizio del programma if (sonda == 1) temperaturaT = misuratemperatura(); if (sonda == 0) { sensors.requestTemperatures(); // Call sensors.requestTemperatures() to issue a global temperature and Requests to all devices on the bus temperaturaT = sensors.getTempCByIndex(0); } scrittura_dati(temperaturaT, (sec_max - t_trascorso)); Input = temperaturaT; myPID.Compute(); /************************************************ turn the output pin on/off based on pid output ************************************************/ unsigned long now = millis(); if (now - windowStartTime > WindowSize) { //time to shift the Relay Window windowStartTime += WindowSize; } if (Output > now - windowStartTime) { digitalWrite(fanPin, HIGH); analogWrite(led_verde, (40 * MAXLED)); // led verde acceso molto forte analogWrite(led_rosso, 0); // led rosso spento } else { digitalWrite(fanPin, LOW); analogWrite(led_rosso, (70 * MAXLED)); // led rosso acceso fisso analogWrite(led_verde, 0); // led verde spento } if (minuti == 0) { trig = true; if (temperaturaT > gradi) return; } else { trig = (sec_max - t_trascorso) > 0; } } } /* funzione che interroga i sensori temperatura, memorizza gli ultimi [buffertemp] valori in un array e ne fa una media ad ogni ciclo sovrascrivendo il più vecchio */ float misuratemperatura() { float t_med = 0; byte conta = 0; temp_media[cont_array_temp] = ktc.readCelsius(); // scrive ciclicamente su ogni posizione dell'array le temperature delay(200); cont_array_temp++; if (cont_array_temp > (buffertemp - 1)) cont_array_temp = 0; // se arrivo alla fine dell'array ricomincio for (byte i = 0; i < (buffertemp - 1); i++) { // scorre l'array di temperature t_med = t_med + temp_media[i]; // e calcola la somma if (temp_media[i] > 0) conta++; // conta il numero di misure fatte (misure maggiori di 0) } return (t_med / conta); // e poi la media dei valori reali memorizzati }