Breve riepilogo delle puntate precedenti

Do per scontato che abbiate letto (e capito) la parte 1 relativa all’hardware del progetto. Se non lo avete fatto, fatelo: https://www.officinasottocasa.it/low-batt-gsm-alarm-hw/

Sorvolerò su alcuni dettagli relativi alla connessione e alla programmazione del SIM800L perché ho scritto tutto nella mia mini guida sul modulo. Se non l’avete ancora letta, leggetela: https://www.officinasottocasa.it/gsm-sim800l/

Riepilogo dello schema elettrico e della PCB in questa piccola galleria di immagini:

Ovviamente, prima di passare all’applicazione definitiva, ho realizzato un piccolo prototipo su breadboard per testare collegamenti e software. Come vedete ho utilizzato una Elegoo Uno R3 al posto di una Nano. Il software non cambia: hanno entrambe la CPU ATMEGA328 anche se in due configurazioni hardware diverse.

prototipo allarme GSM batteria scarica
prototipo allarme GSM batteria scarica

A questo punto possiamo dedicarci all’analisi di dettaglio del software, in attesa che arrivi la nostra PCB e che il dispositivo possa essere collocato nella sua posizione definitiva.

Programmazione software

Diagramma

Iniziamo con il diagramma di flusso che riepiloga le funzioni e soprattutto la sequenza in cui vengono eseguite con i vari IF

Flow chart del funzionamento del software
Flow chart del funzionamento del software
Librerie

Iniziamo con l’inserimento delle librerie che ci permettono di dialogare con i due componenti utilizzati in questo progetto

#include <U8x8lib.h> //libreria per gestione schermo OLED
#include "SoftwareSerial.h" //libreria per seriale con modulo SIM800L

Le librerie sono disponibili on-line oppure nel Library Manager dell’IDE di Arduino.

La lettura del voltaggio non ha bisogno di libreria, sarà il risultato di un calcolo effettuato da programma.

Attribuzione dei pin

Come molti, io preferisco definire all’inizio i pin assegnando nomi “parlanti” che richiamerò poi in tutto il codice. Qualora avessi fatto un errore di connessione potrò fare una piccola modifica in questa parte iniziale che avrà effetto in tutti i punti dove viene richiamato lo specifico pin.

In questo progetto utilizziamo tre pin digitali per il SIM800L e uno analogico per la lettura del voltaggio della batteria.

NB: ricordatevi i partitori altrimenti bruciate tutto prima di iniziare.

#define VoltTestPin A0 //Il pin analogico a cui sarà collegato il partitore per la misurazione del voltaggio
#define DTR_PIN 5 //Il pin DTR del Sim800L è collegato al pin D5 dell' Arduino
#define SIM_TX_PIN 6 //Il pin TX del Sim800L è collegato al pin D6 dell' Arduino
#define SIM_RX_PIN 7 //Il pin RD del Sim800L è collegato al pin D7 dell' Arduino

Non avevo molti vincoli nella scelta dei piedini da utilizzare. Non utilizziamo funzioni PWM quindi i digitali sono tutti ugualmente validi. Per gli analogici abbiamo solo A4 e A5 occupati dal collegamento con lo schermo I2C OLED perché, oltre ad essere due pin analogici sono anche i pin SDA e SCL per la comunicazione I2C, appunto.

Inizializzazione degli oggetti

Iniziamo a creare gli oggetti che sono definiti nelle librerie per la comunicazione con SIM800L e OLED I2C

SoftwareSerial serialSIM800(SIM_TX_PIN, SIM_RX_PIN); //Creiamo un oggetto seriale software sui pin digitali RX e TX del SIM800L
U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(/* reset=*/U8X8_PIN_NONE); //Creiamo oggetto lcd per comunicare con lo schermo OLED

Qui vengono solo creati, saranno inizializzati (attivati) più avanti.

Definizione delle variabili

Anche in questo definisco una volta e all’inizio tutte le variabili numeriche che mi servono per i calcoli del partitore necessari per interpretare la tensione della batteria.

Ho definito anche una variabile “function” che viene inizializzata a 0 e passa a 1 in caso di invio dell’allarme. Vedremo dopo perchè.

int read_value = 0; //numero intero che verrà usato per memorizzare valore letto sul Pin A0
float ref_voltage = 5.0; //si tratta del voltaggio massimo da usare come riferimento per il calcolo del voltaggio reale della batteria
float read_voltage = 0.0; //è la variabile in cui memorizziamo la tensione letta dal Pin A0
float batt_voltage = 0.0; //la tensione della batteria calcolata partendo dalla lettura del Pin A0 applicando la formula inversa del partitore
float R1 = 100000.0;//il valore di R1 del partitore
float R2 = 10000.0;//il valore di R2 del partitore
int v_dummy = 0;//variabile in cui memorizziamo il valore dummy per interrompere invio SMS dopo il primo e fino al reset

La variabile “read_value” è definita come intero perché è la lettura del pin A0 che può assumere solo 1024 valori (da 0 a 1023). Non ha senso definirla come floating perché allocheremmo memoria inutile.

Void setup()

Entriamo nel vivo del programma effettuando le operazioni preliminari. Inzializziamo la seriale con il SIM800L, mettiamo il pin DTR in stato HIGH (per rendere possibile la funzione di sleep e wake-up), avviamo lo schermo e mettiamo a dormire il SIM800L perché ci servirà attivo solo quando dovrà inviarci l’avviso di batteria scarica. In caso contrario è meglio che non consumi molta energia.

L’avvio dello schermo e la disattivazione del SIM800L, in questa parte di codice, sono richiami a funzioni definite dopo.

void setup() {
 serialSIM800.begin(57600);//inizializzo la seriale con il modulo gsm
 delay(50);
 digitalWrite(DTR_PIN,HIGH);
 delay(50);
 Screeninit();//richiamo la funzione per avviare lo schermo oled
 delay(50);
 sim800sleep();//mando in sleep mode il modulo gsm
}
Void loop()

Questa è la parte di programma che viene eseguita, appunto, in loop. Personalmente mi piace avere un loop sintetico, pulito e chiaro. Le operazioni di routine sono inserite tramite richiamo a funzioni definite separatamente. Questo mi permette anche di testare separatamente le funzioni e di isolare eventuali problematiche. In questa sequenza non facciamo altro che richiamare la funzione di test del livello batteria e, nel caso sia inferiore al valore soglia, di attivare la funzione di wake-up del modulo GSM e di invio del messaggio di allarme.

Perché testo anche la variabile “v_function” e in caso positivo gli cambio lo stato da 0 a 1? Per evitare che il dispositivo mi invii SMS in loop continuo. Una volta rilevato il superamento della soglia della tensione e inviato l’allarme, deve mettersi in modalità stand-by in attesa che qualcuno faccia qualcosa: nello specifico io, dovrei attaccare la batteria al caricatore/mantenitore e riavviare la scheda.

void loop(){
  Readvoltage();
  if(batt_voltage < 12.0 && v_dummy = 0){
    sim800wakeup();
    Sendsmsalarm();
    v_dummy = 1//modifico il valore della variabile dummy per impedire l'invio di sms in loop
  }
}
Void Screeninit()

Questa funzione la inserisco, oltre che per inizializzare la comunicazione con lo schermo OLED (u8x8.begin), anche perché mi piace leggere la scritta “Initializing” sullo schermo quando si avvia la scheda. La funzione viene eseguita in fase di setup, quando viene richiamata.

void Screeninit(){
 u8x8.begin();
 u8x8.setPowerSave(0);
 u8x8.setFont(u8x8_font_chroma48medium8_r);
 u8x8.clear();
 u8x8.drawString(0, 0, "Initializing...");
 delay(2000);
 u8x8.clear();
}
Void readvoltage()

Questa funzione viene richiamata, e quindi eseguita, ad ogni ciclo di esecuzione (loop). Merita un approfondimento specifico oltre a quanto si può leggere nei commenti.

Partiamo dalla batteria della moto che fornisce una tensione intorno ai 12V. Il partitore di tensione (con R1 e R2 rispettivamente da 100K e 10K) la abbassa a circa 1.09V (tensione ai due capi di R2), valore compreso tra i 0 e 5V che la scheda è in grado di gestire. Avremmo potuto anche demoltiplicare in modo diverso, a patto che con la batteria al valore massimo di tensione, la DDP ai capi di R2 non superi i 5V. La tensione di 1.09V viene interpretata dalla porta analogica A0 come valore tra 0 e 1023 (totale 1024 valori) in proporzione al valore di riferimento massimo (5V : 1023 = 1.09V : X). Siccome conosco l’operazione di demoltiplicazione del partitore di tensione (in quanto l’ho definita io stesso), tramite funzione inversa, posso ricalcolarmi il voltaggio reale corrispondente al voltaggio demoltiplicato del partitore. Ora posso testare il voltaggio della batteria senza averlo in ingresso sulla scheda.

void Readvoltage(){
  read_value = analogRead(VoltTestPin);//leggo il valore sul Pin A0 e lo memorizzo
  read_voltage  = (read_value * ref_voltage) / 1024.0;//trasformò il valore letto in ingresso sul Pin A0 in una tensione
  batt_voltage = read_voltage / (R2/(R1+R2));//con la formula inversa del partito re calcolo la tensione reale della batteria
}
Void sim800sleepmode()

Questa funzione è richiamata ed eseguito all’avvio della scheda perché, come dicevamo, il modulo GSM è sempre in modalità sleep, tranne nel caso in cui venga svegliato per inviare l’allarme. I dettagli sono nella guida sul modulo SIM800L.

void sim800sleepmode(){
  serialSIM800.println("AT+CSCLK=2");
}
Void sim800wakeup()

Questa funzione è richiamata ed eseguito all’avvio della scheda perché, come dicevamo, il modulo GSM è sempre in modalità sleep, tranne nel caso in cui venga svegliato per inviare l’allarme. I dettagli sono nella guida sul modulo SIM800L.

Questa funzione viene richiamata ed eseguita nel loop solo quando il test della tensione (e della variabile binaria di stand-by) rileva il sotto-soglia. Viene eseguita immediatamente prima di inviare il messaggio SMS. Anche qui rimando alle specifiche definite nella guida.

void sim800wakeup(){
  digitalWrite(DTR_PIN,LOW);
  delay(200);
  digitalWrite(DTR_PIN,HIGH);
  serialSIM800.println("AT");
  serialSIM800.println("AT+CSCLK=0");
}
Void sendsmsalarm()

Non ci rimane che inviare il messaggio SMS e attendere che qualcuno (sempre io in questo caso) abbia la bontà di attaccare la batteria al caricatore ed evitare di danneggiare un’altra batteria, che poi è l’origine e il fine ultimo di tutto il progetto.

void sendsmsalarm(){
  serialSIM800.println("AT+CMGF=1");
  serialSIM800.println("AT+CMGS=\"+39xxxxxxxxxx\"");
  serialSIM800.print("testo del messaggio");
  serialSIM800.write(26);
}

Conclusioni

Spero che tutta questa dissertazione dilazionata sostanzialmente in tre articoli sia stata di vostro interesse. Mi auguro che possa essere stata di ispirazione (non solo intellettuale ma anche applicativa) per altri vostri progetti e vi invito a condividere idee e considerazioni nei commenti.

Vi lascio come sempre i riferimenti di altri articoli da cui ho tratto ispirazione e materiale.

E per chi avesse bisogno o desiderio di condividere altre questioni in materia può usare il form dei contatti o scriverci direttamente sui social (siamo su facebook e instagram).

Sitografia

Categorie: Elettronica

2 commenti

Paolo Antonucci · 05/01/2023 alle 22:53

La Befana vien di notte ::: e ci ha lasciato un bel regalo -)))
Bravissimi !!!

Allarme GSM per batteria scarica - Parte 1: Hardware - officinasottocasa · 19/11/2023 alle 00:00

[…] Il modulo GSM colloquierà col Nano tramite comandi seriali AT, ma lo vedremo nello specifico nell’articolo dedicato al software: https://www.officinasottocasa.it/low-batt-gsm-alarm-sw/. […]

Se questo contenuto è stato di tuo interesse lascia un commento per farcelo sapere