Semplice telesoccorso con Arduino
Tutti quanti molte volte abbiamo sentito parlare di quei dispositivi chiamati “telesoccorso” oppure “tele salvavita” i quali, nella loro forma più semplice, permettono di effettuare una chiamata verso un numero telefonico preimpostato dando così la possibilità di poter intervenire tempestivamente in tutte quelle situazioni di pericolo. Si pensi ad esempio ai numerosi casi in cui, per un motivo o per l’altro, molte persone anziane devono rimanere sole in casa e quanto sia importante per loro poter chiedere aiuto in caso di emergenza.
Il semplice telesoccorso descritto in questo articolo di certo non ha nessuna pretesa di competere con i numerosi tipi commercializzati, specialmente per le numerose opzioni aggiuntive che si possono trovare in svariati modelli, ma nella sua funzione di base svolge perfettamente il suo compito e partendo da questo potremo decidere di arricchirlo in futuro di ulteriori funzionalità.
Schema elettrico
Il principio di funzionamento di tutti i tipi di telesoccorso è molto semplice : la persona interessata porta con se un telecomando con un solo tasto, di solito appeso al collo, premendo il quale invia un segnale radio ad una centralina in grado di riconoscerlo e di effettuare, tramite la linea fissa, una chiamata verso il numero di telefono memorizzato. Quindi il sistema è formato da una coppia formata da trasmettitore e ricevitore che comunicano fra loro via radio. Detto questo partiamo dalla descrizione del ricevitore raffigurato nello schema elettrico qui in basso e in particolare dall’entrata della linea telefonica in alto a destra.
In condizioni normali il relè a doppio scambio risulta disattivato lasciando libera la linea in modo da permettere la ricezione di eventuali chiamate su telefoni collegati su altre prese. Premendo il pulsante sul trasmettitore si invia un segnale radio che verrà captato dal modulo ricevente a 433 Mhz, il quale sarà trasferito al pin 11 dell’Arduino UNO che lo elaborerà e commuterà l’uscita 3 a livello logico 1. In questo modo si provvederà a mandare in conduzione il transistor 2N3904 e a far chiudere i contatti del relè collegato sul suo collettore.
A questo punto la resistenza da 470 Ohm 1/2 W verrà a trovarsi in parallelo sulla linea telefonica e la tensione su di essa, che in condizioni normali è di circa 48 V, scenderà fino ad un valore intorno agli 8-10 V. Questa resistenza in pratica non fa altro che simulare lo sgancio della cornetta in modo da poter iniziare la procedura di composizione del numero. Ricevuto il segnale di allarme il buzzer collegato sul pin A1 suonerà per tre volte, contemporaneamente il led sul pin A5 si accenderà e dopo 3 secondi verrà effettuata la chiamata verso il numero telefonico memorizzato. Trascorso 1 minuto dall’invio della chiamata il circuito verrà disattivato in automatico e la linea telefonica tornerà libera ( questo lasso di tempo possiamo regolarlo cambiando la variabile corrispondente nello sketch ).
La composizione del numero avviene tramite la generazione di toni DTMF in uscita dai pin A3-A4 e immessi sulla linea telefonica attraverso il condensatore da 47 uF. Terminata questa fase, dopo circa 1 secondo, sulla linea verrà immesso un segnale di bassa frequenza che sarà udito dalla persona che riceverà la chiamata. In pratica, la persona che risponderà al telefono sentirà questo tono caratteristico e saprà che da quel numero è partita una richiesta di aiuto. Come accennato sopra, trascorso un minuto il relè verrà disattivato e il tutto si ripeterà ad ogni pressione del tasto posto sul trasmettitore o premendo il pulsante “test” collegato al pin 2.
Come memorizzare un numero telefonico
La registrazione di un numero telefonico viene effettua attraverso i quattro pulsanti collegati alle entrate 10-9-8-A0 le cui funzioni sono riepilogate nella seguente tabella
Pulsante | Descizione | Note |
---|---|---|
Set | Entra o esce dalla fase di memorizzazione del numero telefonico | Ogni volta che si preme questo pulsante il numero precedentemente memorizzato verrà cancellato |
Num | Incrementa da 0 a 9 le singole cifre | |
Succ | Aggiunge una cifra al numero | |
Memo | Effettua la registrazione del numero sulla EEPROM di Arduino | Durante il normale funzionamento, premendo questo pulsante si visualizza sul display il numero telefonico memorizzato. Se la memoria è vuota sul display verrà visualizzato "Nessun numero" |
In pratica si preme il pulsante “Set” e dopo aver visualizzato sul display “Imp. numero” si procede con i pulsanti “Num” e “Succ” che servono rispettivamente uno ad incrementare e l’altro ad aggiungere le cifre che andranno a formare il numero che abbiamo intenzione di memorizzare. Infine, basta premere il pulsante “Memo” e il numero sarà registrato sulla EEPROM dell’ATmega di Arduino. Il video seguente dovrebbe illustrare chiaramente la procedura appena descritta.
Nota : quando si entra nella fase di memorizzazione del numero, può succedere di sbagliare durante la composizione delle singole cifre e poiché non è possibile tornare indietro l’unica cosa che si può fare è uscire ed entrare dalla procedura premendo nuovamente il pulsante “Set”.
Quello seguente invece è lo schema del trasmettitore nel quale premendo il pulsante collegato al pin 7 invieremo un segnale codificato attraverso il modulo radio a 433 Mhz che raggiungerà lo stadio ricevente e farà partire la chiamata di soccorso. Anche se in questo schema viene raffigurata una scheda Arduino, nella realizzazione pratica l’intento è quello di poter rendere il telecomando il più compatto possibile e quindi si può pensare di realizzare un sistema stand-alone con un ATmega 328. Anche per quanto riguarda l’antenna, indispensabile per una corretta trasmissione, si potrebbe pensare di nasconderla nel contenitore che decideremo di usare.
Il video seguente mostra invece il funzionamento pratico del telesoccorso. Per inviare la chiamata viene usato il pulsante di Test.
Uno sguardo agli sketch
Qui in basso sono riportati gli sketch usati nel progetto. Partendo da quello più semplice del trasmettitore possiamo vedere come il programma non fa altro che trasmettere via radio una stringa che dovrà essere riconosciuta dal ricevitore attraverso la pressione del pulsante collegato al pin 7. Nello sketch la stringa in questione è “#SOS” e viene inviata per mezzo della funzione “Trasmetti()” che accetta come argomento una variabile di tipo *char. L’unica nota da aggiungere è che il codice fa uso della libreria “<RH_ASK.h> ( scaricabile a fondo pagina ) e che per il pulsante si possono usare tutti i pin tranne il numero 12 in quanto esso viene utilizzato per default dalla libreria che codifica il segnale.
/* * Programma radiocomando a 433 Mhz : TRASMETTITORE by Mario de Nichilo 13/10/2018 */ #include <RH_ASK.h> #include <SPI.h> int pulsante = 7; RH_ASK askTx; // Crea un oggetto ASK che permette la trasmissione di dati via radio sul pin 12 void setup() { pinMode(pulsante, INPUT); askTx.init(); // inizializza l'oggetto ASK } // Trasmette la stringa che dovrà essere riconosciuta dal ricevitore // void trasmetti(char *msg) { askTx.send((uint8_t *)msg, strlen(msg)); askTx.waitPacketSent(); delay(200); } void loop() { if (digitalRead(pulsante) == LOW ) { trasmetti("#SOS"); } }
Di seguito invece viene riportato lo sketch usato dallo stadio ricevitore
/* Programma Telesoccorso Arduino Stadio ricevente by Mario de Nichilo 18/10/2018 */ #include <avr/eeprom.h> #include <LiquidCrystal.h> #include <RH_ASK.h> #include <SPI.h> LiquidCrystal lcd(12, 13, 5, 4, 7, 6); // RS-E-D4-D5-D6-D7 #define hp A4 // Uscita segnale BF sulla linea e Tono DTMF1 #define hp2 A3 // Uscita Tono DTMF2 #define pulsante 2 // Entrata segnale allarme #define ledChiamata A5 // Indicazione allarme avvenuto #define rele 3 // pin uscita del relè commutatore #define set 10 // pulsante entra o esce dalla modalità imposta numero #define num 9 // pin pulsante selezione numero #define cifraSucc 8 // pin pulsante sposta cursore sul display #define memo A0 // pin pulsante memorizza #define dimMax 20 // numero massimo di cifre #define bz A1 // pin buzzer String EPt = ""; // Stringa usata per l'impostazione del numero telefonico char ArrayTemp[dimMax]; // Array usato per la scrittura e lettura dati dalla EEPROM char EEMEM ArrayEEPROM[dimMax]; // Array nella EEPROM int tOff = 60; int tOn = 30; boolean chiamata = false; int attesa = 0; boolean setNum; int n = 0; short pos = 0; boolean invioBF = false; RH_ASK ask; // Crea un oggetto ask per la ricezione dati int DTMF[13][2] = { {941, 1336}, // tono 0 {697, 1209}, // tono 1 {697, 1336}, // tono 2 {697, 1477}, // tono 3 {770, 1209}, // tono 4 {770, 1336}, // tono 5 {770, 1477}, // tono 6 {852, 1209}, // tono 7 {852, 1336}, // tono 8 {852, 1477}, // tono 9 {941, 1209}, // tono * {941, 1477}, // tono # {0, 0} // pausa }; void playDTMF(byte digit, byte duration) { boolean tone1state = false; boolean tone2state = false; int tone1delay = (500000 / DTMF[digit][0]) - 10; int tone2delay = (500000 / DTMF[digit][1]) - 10; unsigned long tone1timer = micros(); unsigned long tone2timer = micros(); unsigned long timer = millis(); if (digit == 12) { delay(1000); } else { while (millis() - timer < duration) { if (micros() - tone1timer > tone1delay) { tone1timer = micros(); tone1state = !tone1state; digitalWrite(hp, tone1state); } if (micros() - tone2timer > tone2delay) { tone2timer = micros(); tone2state = !tone2state; digitalWrite(hp2, tone2state); } } digitalWrite(hp, LOW); digitalWrite(hp2, LOW); } } void dialNumber(int number[], int len) { for (int i = 0; i < len; i++) { playDTMF(number[i], 100); delay(100); } } // // funzione che converte una stringa in *char // char* stringTochar(String stringa) { if (stringa.length() != 0) { char *c = const_cast<char*>(stringa.c_str()); return c; } } void displayDefault() { lcd.clear(); lcd.setCursor(0, 0); lcd.print("Telesoccorso"); lcd.setCursor(0, 1); lcd.print("in funzione..."); } void memorizza() { /* La variabile String EPt che contiene il numero telefonico viene convertita in Array char dalla funzione stringTochar e copiata in ArrayEEPROM, cioè nella EEPROM, attraverso il metodo eeprom_write_block. */ eeprom_write_block(stringTochar(EPt), ArrayEEPROM, dimMax); // Scrive nella EEPROM il numero di telefono delay(300); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Registr. OK"); delay(1000); displayDefault(); } void componiNumero() { /* L'arrayEEPROM che contiene il numero telefonico viene copiato in ArrayTemp attraverso il metodo eeprom_read_block */ eeprom_read_block(ArrayTemp, ArrayEEPROM, dimMax); // legge dalla EEPROM il numero di telefono delay(100); if (strlen(ArrayTemp) > 0 ) { // controlla se ArrayTemp non sia vuoto int numeroTelefonico[dimMax]; // Array usato per memorizzare il numero telefonico in formato integer int lung = strlen(ArrayTemp); // numero di cifre che compongono il numero int cifra; // variabile usata per la conversione delle cifre da char a int lcd.clear(); lcd.setCursor(0, 0); lcd.print("Sto chiamando:"); lcd.setCursor(0, 1); lcd.print(ArrayTemp); Serial.println(ArrayTemp); // scrive sulla seriale il numero recuperato sulla EEPROM delay(1000); // attende 1 sec. /* Ogni cifra del numero telefonico contenuta in ArrayTemp viene scansionata e convertita in formato intero e successivamente memorizzata nell'array numeroTelefonico */ for ( int i = 0; i < strlen(ArrayTemp); i++) { cifra = (int)ArrayTemp[i] - '0'; numeroTelefonico[i] = cifra; Serial.println(numeroTelefonico[i]); } digitalWrite(rele, HIGH); // Aziona il relè per stabilire la connessione con la linea telefonica delay(3000); dialNumber(numeroTelefonico, lung); delay(1000); invioBF = true; } else { /* Se la EEPROM non contiene nessun numero visualizza sul display la scritta "EEPRON vuota!" per tre secondi */ lcd.clear(); lcd.setCursor(0, 0); lcd.print("Errore:"); lcd.setCursor(0, 1); lcd.print("EEPROM vuota!"); delay(3000); displayDefault(); return; } while (chiamata == true ) { digitalWrite(ledChiamata, HIGH); // Visualizzazione chiamata in corso if (invioBF == true) { tone( hp, 754, 200 ); // Tono allarme immesso sulla linea telefonica delay(200); tone( hp, 390, 200 ); delay(500); } if (attesa > 60) // +- 1 min { chiamata = false; attesa = 0; digitalWrite(rele, LOW); digitalWrite(ledChiamata, LOW); delay(100); displayDefault(); invioBF = false; } attesa++; } } void setup() { ask.init(); Serial.begin(9600); pinMode(hp, OUTPUT); pinMode(hp2, OUTPUT); pinMode(rele, OUTPUT); pinMode(ledChiamata, OUTPUT); pinMode(pulsante, INPUT); pinMode(set, INPUT); pinMode(num, INPUT); pinMode(cifraSucc, INPUT); pinMode(memo, INPUT); pinMode(bz, OUTPUT); digitalWrite(ledChiamata, LOW); digitalWrite(rele, LOW); lcd.begin(16, 2); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Telesoccorso"); lcd.setCursor(0, 1); lcd.print("in funzione..."); setNum = false; } void loop() { /* Premendo il pulsante "set" inverto la variabile "setNum", in questo ad ogni pressione del pulsante si entra ed esce dalla funzione di impostazione del numero telefonico */ if (digitalRead(set) == LOW) { setNum = !setNum; delay(300); if ( setNum == true ) { // Cancello prima la EEPROM EPt = ""; eeprom_write_block(stringTochar(EPt), ArrayEEPROM, dimMax); delay(300); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Imp. numero"); } if ( setNum == false ) { n = 0; displayDefault(); } } switch (setNum) { /* Se "setNum" è true,attraverso la pressione del pulsante "num" incremento le cifre che dovranno formare il numero telefonico da memorizzare. */ case true: lcd.setCursor(pos, 1); lcd.print(n); if (digitalRead(num) == LOW) { n++; // parto da zero e incremento n if (n > 9) { n = 0; //azzero n se supera 9 } lcd.setCursor(pos, 1); lcd.print(n); // scrivo sul display il numero delay(300); } if ( digitalRead(cifraSucc) == LOW ) // passo alla cifra successiva con il pulsante "succ" { EPt.concat(String(n)); // memorizzo nella stringa EP l'ultima cifra scelta pos++; n = 0; if (pos > 15) { pos = 0; } lcd.setCursor(pos, 1); // faccio attenzione a considerare la lunghezza della riga del display lcd.print(n); delay(300); } if (digitalRead(memo) == LOW) // pulsante di memorizzazione del numero { EPt.concat(String(n)); memorizza(); // richiamo il codice che effettua la scrittura in memoria setNum = false; // esco dalla fase di settaggio del numero } break; case false: // visualizza,se c'è, il numero memorizzato nella EEPROM pos = 0; /* Se premo il pulsante "memo" al di fuori della procedura di memorizzazione, visualizza sul display il numero telefonico registrato in memoria oppure stampa "nessun numero" se quest'ultima è vuota. */ if (digitalRead(memo) == LOW) { delay(300); eeprom_read_block(ArrayTemp, ArrayEEPROM, dimMax); // legge dalla EEPROM il numero di telefono delay(100); if (strlen(ArrayTemp) > 0) { // verifica se l'array del numero è vuoto lcd.clear(); lcd.setCursor(0, 0); lcd.print(ArrayTemp); delay(2000); } else { lcd.clear(); lcd.setCursor(0, 0); lcd.print("nessun numero"); delay(2000); } displayDefault(); } break; } /* Ricezione del segnale radio */ uint8_t buf[RH_ASK_MAX_MESSAGE_LEN]; // Array in cui viene memorizzato il dato ricevuto uint8_t buflen = sizeof(buf); byte lung_datoRicevuto = 4; // Lunghezza dell stringa che ci si aspetta di avere char dato[lung_datoRicevuto]; if (ask.recv(buf, &buflen)) { // Prendo i primi quattro caratteri della variabile buf e li memorizzo nella variabile 'dato' // for (int j = 0; j < lung_datoRicevuto; j++) { dato[j] = buf[j]; } // converto la variabile char 'dato' in stringa if (String(dato).substring(0, 4) == "#SOS") { delay(500); for (int j = 0; j < 3; j++) { tone( bz, 390, 300 ); // Tono allarme immesso sulla linea telefonica delay(500); } chiamata = true; componiNumero(); } } /* alla pressione del pulsante "test" si avvia la chiamata al numero memorizzato un memoria */ if (digitalRead(pulsante) == LOW) { delay(500); for (int j = 0; j < 3; j++) { tone( bz, 390, 300 ); // Tono immesso sulla linea telefonica delay(500); } chiamata = true; componiNumero(); // esegue la chiamata } }
Logicamente esso risulta notevolmente più complesso rispetto a quello del trasmettitore, in quanto deve gestire diversi aspetti come ad esempio la fase di formazione del numero attraverso i pulsanti visti sopra e la memorizzazione dello stesso sulla EEPROM. Per tale scopo viene usata dapprima una variabile tipo String denominata “EPt” la quale, alla pressione del pulsante “Memo” e attraverso il richiamo della funzione “memorizza()“, viene convertita in char* e fisicamente memorizzata all’interno dell’array ArrayEEPROM grazie al metodo eeprom_write_block() della libreria <avr/eeprom.h>.
Nel momento in cui si va ad effettuare la chiamata viene eseguita la funzione componiNumero(), nella quale viene evocato il metodo eeprom_read_block() che copia il contenuto di ArrayEEPROM in ArrayTemp[]. Dopo aver controllato che questo array non sia vuoto, si effettua una conversione dei suoi elementi da char a Int e lo si copia in un altro array chiamato numeroTelefonico[], quest’ultimo a sua volta sarà passato come argomento in dialNumber() che infine, attraverso playDTMF(), genererà i toni DTMF corrispondenti al numero letto dalla memoria. Per quanto riguarda la ricezione del segnale radio, vediamo che esso è affidato alla libreria già menzionata e non fa altro che confrontare il dato in arrivo con quello che deve far scattare le operazioni appena viste. Per il resto penso che il codice sia stato sufficientemente commentato e quindi non dovrebbe risultare difficile.
Elenco componenti del ricevitore
Tipo | Quantità |
---|---|
Scheda Arduino UNO | 1 |
Display LCD 16 x 2 | 1 |
Modulo radio 433 Mhz XD-RF-5V | 1 |
Amplificatore 1 W basato su LM 386 | 1 |
Transistor NPN tipo 2N3904 oppure BC547 | 1 |
Relè 5V doppio scambio | 1 |
Connettore femmina RJ11 | 1 |
Diodo led | 2 |
Diodo 1N4007 | 1 |
Trimmer da 5K | 1 |
Condensatore elettrolitico da 47uF 400V | 1 |
Condensatore elettrolitico da 4,7uF 25V | 2 |
Buzzer preamplificato | 1 |
Resistenza da 470 Ohm 1/2 Watt | 1 |
Resistenza da 240 Ohm | 1 |
Resistenza da 270 Ohm | 1 |
Resistenza da 470 Ohm 1/4 W | 1 |
Resistenza d 1K 1/4 W | 1 |
Resistenza da 10K 1/4 W | 6 |
Altoparlante 8 Ohm | 1 |
Pulsante N.A. | 5 |
Elenco componenti del telecomando
Tipo | Quantità |
---|---|
Scheda Arduino UNO | 1 |
Modulo radio 433 Mhz tipo XD-SFT | 1 |
Resistenza da 10K 1/4 W | 1 |
Pulsante N.A. | 1 |
File del progetto
Considerazioni finali
Come già detto all’inizio, benché il circuito nella sua funzione di base svolge perfettamente il suo compito esso potrebbe essere migliorato in alcuni aspetti. Ad esempio, lo si potrebbe dotare della capacità di poter memorizzare più numeri di telefono anziché uno solo e far in modo che questi vengano chiamati ciclicamente e a distanza di tempo prestabiliti. Inoltre, lo si potrebbe dotare di un sistema di alimentazione autonomo in caso di mancanza di corrente elettrica, ecc. ma tutto questo logicamente avrebbe richiesto un codice e uno schema più complessi di quelli visti. Ciò nonostante esso potrebbe essere preso come base per poter realizzare progetti di altro tipo e più rispondenti alle nostre esigenze.