Buona sera,
Ho sviluppato questo semplice termostato su richiesta di un amico che ne aveva la necessità.
Premetto che non sono ne elettronico ne programmatore, conosco molto bene PLC e elettromeccanica industriale(il mio lavoro), ma mi sono appassionato a questo mondo che trovo molto interessante e divertente allo stesso tempo, pertanto vorrei condividere con voi questa piccola esperienza, soprattutto per avere un vostro parere sulla mia esecuzione cosi da poter capire se sto andando nella direzione giusta dato che sono agli inizi, magari ricevere consigli da chi è piu esperto e a chi potesse servire un termostato magari dare qualche spunto!
Provo ad allegare schema e codice, abbiate pazienza ma è il mio primo post
/* TERMOSTATO PER GIGI COSI PUO' STARE AL CALDO SENZA SUDARE TROPPO */
#include <Wire.h> // libreria i2c
#include <SHT21.h> // libreria sensore temperatura/umidità
SHT21 sht; // definisco sensore
#include <Adafruit_GFX.h> // libreria fx display
#include <Adafruit_SH1106.h> // libreria display
Adafruit_SH1106 display(-1); // definisco display
#define Ppiu 9 // definisco pulsante +
#define Pmeno 7 // definisco pulsante meno-
#define rc 10 // definisco relè
int gradi = 22; // variabile valore iniziale set-point temperatura
int LSPpiu; // ultimo stato pulsante +(se voglio premere solo una volta)
int set_up; // stato pulsante +
int LSPmeno; // ultimo stato pulsante -(se voglio premere solo una volta)
int set_down; // stato pulsante -
void setup()
{
Wire.begin(); // inizializzo protocollo I2C
display.begin(SH1106_SWITCHCAPVCC, 0x3C); // inizializzo il display
display.setTextColor(WHITE); // e configuro colore
display.setTextSize(1); // e dimensione del testo
pinMode (Ppiu, INPUT); // pulsante piu ingresso
pinMode (Pmeno, INPUT); // pulsante meno ingresso
pinMode (rc, OUTPUT); // relè caldaia uscita
}
void loop()
{
set_up = digitalRead(Ppiu); // scrivo lo stato dell'ingresso del pulsante + sulla variabile set up
LSPpiu = set_up; /* da attivare se voglio */
if (LSPpiu == LOW && set_up == HIGH) /* premere solo una volta */
//if (set_up == HIGH) /* da attivare se voglio tenere premuto */
{ gradi++; } // premo il pulsante +, aumento di un grado il set point
set_down = digitalRead(Pmeno); // scrivo lo stato dell'ingresso del pulsante - sulla variabile set down
LSPmeno = set_down; /* da attivare se voglio */
if (LSPmeno == LOW && set_down == HIGH) /* premere solo una volta */
//if (set_down == HIGH) /* da attivare se voglio tenere premuto */
{ gradi--; } // premo il pulsante -, diminuisco di un grado il set point
if (gradi>30) // se imposto temperature oltre 30 gradi
{gradi=10;} // riporto il valore a 10 gradi
if (gradi<10) // se imposto temperature inferiori a 10 gradi
{gradi=30;} // riporto il valore a 30 gradi
int isteresi = (gradi-1); // isteresi utilizzata per la riattivazione del relè
int temp = sht.getTemperature(); // lettura temperatura da sensore SHT e scrittura su variabile con numero intero
if (temp >= gradi) // se la temperatura è maggiore/uguale al setpoint
{
digitalWrite(rc,LOW); // disattivo il relè
}
if (temp < isteresi) // se la temperatura è minore del setpoint meno i gradi di isteresi
{
digitalWrite(rc,HIGH); // attivo il relè
}
int rcstato = digitalRead(rc); // leggo lo stato dele relè
display.clearDisplay (); // pulisco il buffer del display
//scrivo sul display
display.setCursor(0,0);
display.print(" -> GIGI STATION <-");
display.setCursor(0,15);
display.print("Temperatura: ");
display.setCursor(115,15);
display.print("C");
display.setCursor(10,34);
display.print("Set Temp: ");
display.setCursor(90,34);
display.print("C");
display.setCursor(0,52);
display.print("Riscaldamento: ");
float seetemp = sht.getTemperature(); // lettura temperatura da sensore SHT e scrittura su variabile con 2 cifre dopo la virgola
display.setCursor(77,15);
display.print(seetemp); // lettura temperatura con 2 cifre dopo la virgola
display.setCursor(70,34);
display.print(gradi); // temperatura impostata
if (rcstato == LOW) // se lo stato del relè è disattivo
{
display.setCursor(85,52);
display.print("Spento"); // e scrivo sul display
}
else // altrimenti se è attivo
{
display.setCursor(85,52);
display.print("Attivo"); // e scrivo sul display
}
display.display(); // visualizzo il display
//attendo per ripetere il loop
delay(100); /* da attivare se voglio premere solo una volta */
//delay(666); /* da attivare se voglio tenere premuto */
}
Ti segnalo che, nella sezione in lingua Inglese, si può scrivere SOLO in Inglese ... quindi, per favore, la prossima volta presta più attenzione in quale sezione metti i tuoi post; questa volta esso è stato spostato, da un moderatore della sezione di lingua Inglese, nella sezione di lingua Italiana ... la prossima volta potrebbe venire direttamente eliminato. Grazie.
Chiedo scusa! non avevo fatto caso alla lingua!! Grazie per aver messo a posto l'errore, cercherò di fare piu attenzione la prossima volta, chiedo ancora scusa!
dunque, nelle righe dei comandi set_up legge lo stato dell'ingresso,
la variabile LSPpiu prende il valore dallo stato di set_up,
e se la variabile LSPpiu è uguale a 0 (perchè l'ingresso è 0) e lo stato della variabile set_up risulta uguale a 1 (ingresso a 1) incremento/decremento la variabile del setpoint
l'evento si verifica nel momento in cui inizia il loop successivo con l'ingresso a 1 e fintanto che resta ad 1 la variabile LSPpiu diventa uguale a 1, quindi nel loop dove riporto a 0 set_up torna tutto come in partenza finchè non si ripete l'evento nei loop successivi e via dicendo...
in poche parole devo premere ogni volta per incrementare/decrementare il valore di "gradi".
Mentre, se hai visto ho messo solo da condizione di set_up a 1 per modificare "gradi" tenendo premuto il tasto prolungatamente modificando il delay a fine loop.
arduino è una macchina e come tutte le macchine svolge un'azione alla volta, per quanto veloce la possa svolgere , set_up passerà ad 1 sempre prima di LSPpiu in quanto ne emula la posizione, in quel momento si verifica l'evento per cui sopra!
Mi spiace ma NON funziona così ... credo che tu NON sappia bene come funziona l'assegnazione e la lettura dei pin sulla MCU (... e poco ha a che vedere con quanto sapevi sui PLC e sul loro linguaggio di programmazione).
Quanto hai scritto NON può funzionare, cerca di capirlo ...
Semplificando tu fai:
A = qualche cosa
B = A
ed a questo punto pretendi che B possa essere diverso da A ...
Guglielmo
P.S.: NON ci sono eventi e l'assegnazione di A avviene SOLO nol momento in cui la fai, poi, anche se il pin cambia, A NON cambia.
Non fare l'errore di pensare che il software sia eseguito su una MCU come Arduino in modo analogo a quanto avviene su un PLC.
Con un microcontrollore non hai "di default" il classico flusso Acquisizione degli ingressi -> Esecuzione programma -> Aggiornamento uscite
Di certo lo puoi implementare (se vuoi) usando un algoritmo orientato in tal senso, ma di base su un microcontrollore leggi e scrivi dei registri di memoria (cosa che in fondo in fondo accade anche su un PLC ovviamente).
Tornando al tuo pezzo di codice, immagino tu volessi fare qualcosa di simile ad un fronte di salita (??), ma nel momento in cui scrivi
1. set_up = digitalRead(Ppiu); // scrivo lo stato dell'ingresso del pulsante + sulla variabile set up
2. LSPpiu = set_up; /* da attivare se voglio */
l'assegnazione del valore alle variabili è immediata e quindi le due variabili sono uguali e l'if successivo non sarà mai vero come ha già evidenziato Guglielmo.
Un ulteriore consiglio se posso: cura di più l'indentazione del codice perché è molto confuso ed il "naming" delle variabili che dovrebbe essere più auto-esplicativo e seguire sempre lo stesso stile (ci sono interi scaffali di libri su quali sono le "best practice" in C/C++ a tal riguardo).
A tale proposito, su questo forum ho più volte suggerito il libro del Barr Group, Embedded C Coding Standard, scaricabile gratuitamente come pdf dal loro sito andando su QUESTA pagina
Intanto ringrazio infinitamente per la vostra considerazione sul mio programmino, era quello che speravo di trovare da voi!! Vorrei però sottolineare che [quote="gpb01, post:8, topic:1081370"]
Mi spiace ma NON funziona così ... credo che tu NON sappia bene come funziona l'assegnazione e la lettura dei pin sulla MCU
[/quote] io NON so come funziona esattamente l'assegnazione e la lettura ma ho intuito da alcuni scritti pubblicati da scuole su manuali di programmazione di arduino la sintassi per identificare e nominare i pin, assegnarli come ingressi analogici/digitali o uscite anologiche/digitali, e come leggerne o scriverne gli stati durante il loop su variabili per utilizzarle nei vari scopi, detto questo non sto dicendo sicuramente di averne capito perfettamente il funzionamento e ringrazio ancora per le guide che mi avete consigliato perchè avrò sicuramente modo di poter comprendere meglio il linguaggio di programmazione, che, ripeto, non conosco assolutamente.
Nel mio programma ho usato la logica che uso solitamente utilizzando righe di comando che nella mia testa ho reputato funzionare, e vi posso assicurare che se avete il tempo per poter emulare il mio circuitino e caricare il mio programma , constaterete anche voi che funziona.
Accetto volentierissimo il consiglio di dare nomi che identifichino le variabili molto semplicemente, è una cosa che nella programmazione di un PLC è fondamentale per il riconoscimento durante una lettura o modifica di un programma, non sapevo ci fosse una modalità per nominare le variabili che si utilizzano ma vorrei spiegare che il nome LSPpiu ha un significato, LS sarebbe un acronimo utilizzato per identificare Last State o ultimo stato e Ppiu sarebbe Pulsante piu, come da abitudine lascio sempre commenti nei programmi che ho riportato anche qui su Arduino in modo che tutto sia sempre spiegato anche se ci si dovesse rimettere mano dopo anni...
detto questo non voglio parlare di PLC ma voglio capire meglio il funzionamento di questa magica schedina, quindi apprezzerei molto eventuali soluzioni diverse dal mio modo di ragionare per capire come svolgere il programma senza rimanere "intasato" di schematiche non proprie del tipo di linguaggio della scheda.
... ecco, però il fatto che un pin sia di input NON implica alcun evento e nessun aggiornamento di variabile.
Il fatto è che quando tu scrivi:
set_up = digitalRead(Ppiu);
semplicemente dici al compilatore di chiamare una funzione (digitalRead()), scritta anche essa in C/C++, che va a leggere, in quel momento, lo stato del pin e lo restituisce, quindi il valore restituito viene assegnato alla variabile ... STOP ... quella variabile, anche se il pin un istante dopo cambia stato, NON viene più aggiornata, tu hai letto in un certo istante come è il pin e basta.
Se ti è chiaro questo capisci che una volta che una variabile ha assunto un valore, NON cambia più per nessun evento, ma cambia SOLO se gli assegni TU un nuovo valore (es. vai a fare di nuovo la digitalRead()) e quindi ... il tuo discorso non funziona più
Piccolo consiglio, per gestire bene i bottoni ci sono ottime librerie, come, ad esempio, la Button2 che fanno, BENE, anche molto di più di quello che ti serve ... specie all'inizio, usale che ti trovi tutta una parte fatta senza dove stare ad impazzire
Guglielmo
P.S.: QUI trovi un elenco, diviso per categorie, delle centianai di librerie che esistono, gia pronte, per Arduino .... dacci sempre un occhio prima di reinventare l'acqua calda
Chiarissimo!!!
Vorrei farti una domanda se posso, nel loop che usa arduino, lui svolge tutte le righe di comando che gli sono state scritte è corretto?
il loop() è anch'esso una funzione che, dal main() (sempre presente, ma che tu non vedi perché, per semplificare, all'utente viene nascosto), viene chiamata in continuazione (la sua chiamata e dentro un ciclo "for" infinito).
Essendo una normalle funzione il compilatore compila una dopo l'altra tutte le righe e produce un codice che, così come le hai scritte, le esegue ... nulla di più, nulla di meno
Guglielmo
P.S. ... magari "di meno" SI, dato che il compilatore è altamente ottimizzato e se si accorge che stai facendo cose "inutili" le elimina direttamente
Ok... quindi sgridami se dico castronerie!
in questo ciclo che si ripete all'infinito inserendo un "attesa", lui memorizza lo stato delle variabili (in questo caso) e le mantiene per l'attesa stabilita all'interno di questo ciclo. Nel momento che si ripresenta il ciclo successivo le variabili assumeranno un nuovo valore se è avvenuto qualche cambiamento, viceversa manterranno il valore del ciclo precedente se nulla è cambiato per l'attesa che abbiamo stabilito in precedenza. Se ho un cambiamento di stato durante l'attesa, viene scritto sulle variabili terminata l'attesa e quindi nel loop successivo, è corretto?
P.S. perdona le mie spiegazioni ma non sono mai stato bravo a spiegare, sono piu manuale
Comunque ora vado a vedere quella libreria button2 che mi hai consigliato perche sono davvero curioso di capire come lo avrei dovuto fare!!!
se le variabili sono "locali", quindi dichiarate nel loop() tra un giro ed un altro ... vengono distrutte e quindi non resta nessun valore.
se le variabili sono "globali" (quindi dichiarate fuori dal loop()) mantengono il valore, ma ... NULLA le aggiorna da sole, devi SEMPRE aggiornare TU il loro valore o, l'ultima assegnazione fatta è quella che resta
Insomma ... tutto è in carico del programmatore, NON ci sono eventi che aggiornano nulla, devi essere sempre TU a leggere, quando ti interessa, quello che ti interessa ed aggiornare le eventuali variabili associate
Io quando leggo una descrizione del genere di solito inizio a storcere il naso fin da subito perché con questo "incipit" si trovano soprattutto delle gran "porcherie" (passatemi il termine poco elegante).
I manuali da consultare (in forma cartacea o in versione online) per imparare a programmare sono quelli del C/C++, magari orientati al mondo embedded se proprio ci si vuole specializzare un po' di più.
Arduino non è altro che un framework, ovvero una raccolta di funzioni e macro che in qualche modo vorrebbero semplificare l'approccio alla programmazione dei microcontrollori usando il C++ come compilatore.
La variabile rimane nello stesso stato fino alla successiva istruzione di assegnazione di un nuovo valore a prescindere da quello che fai nel mezzo. Se hai un cambiamento di stato, il valore della variabile verrà assegnato solo nel momento in cui l'esecuzione del programma elabora la riga var iabile = quelloCheTiPare;
Ciò detto, io ad esempio non uso praticamente mai l'approccio "didattico" di usare delle variabili per memorizzare lo stato di un GPIO perché ritengo che sia inutilmente ridondante (a meno che non serva ovviamente).
L'istruzione digitalRead(pin); infatti restituisce già da se il valore di un registro di memoria del microcontrollore che è legato via hardware allo stato del pin (e quello si che segue lo stato del segnale).
hehehe erano pdf di circa 15 pagine, spiegavano molto brevemente cosa facevano le stringhe più comuni, non erano certamente manuali di programmazione professionali!! Poi, parliamoci chiaro, io faccio funzionare delle righe di relè e teleruttori uniti assieme da una miriade di fili numerati.... puoi immaginare da te ,al di fuori di uno schema elettrico, cosa posso capire io leggendo un manuale professionale di c++..... quello che mi sta incuriosendo è questa modalità di svolgere le operazioni da parte di arduino! il fatto di far funzionare questi "marchingegni elettronici" con delle parole invece che con delle connessioni di fili immaginari!! Io non ho obiettivi di diventare un professionista di programmazione di Arduino, ma mi piacerebbe migliorare nella scrittura dei programmi cercando di capire dove sto facendo errori, come trovare delle soluzioni, e capire se sto andando nella direzione giusta...
E' diventato il mio hobby nel tempo libero mi ci sono appassionato e vorrei approfondire un po di piu....
Il fatto che le righe che mi avete detto non siano corrette mi ha fatto venire un sacco di dubbi sul funzionamento della schedina, perche vi posso assicurare che funzionano!
Il fatto che abbia usato tante variabili è probabilmente un errore di "abitudini", io per lavoro devo racchiudere ogni stato in una variabile ho appena scoperto, a quanto pare, che non è necessario farlo con Arduino.