Ciao a tutti,
ho realizzato un piccolo codice per rilevare fulmini utilizzando il sensore AS3935 ed Arduino tramite comunicazione SPI, prendendo spunto da esempi trovati in rete.
Il tutto funziona correttamente.
Volendo trasmettere i dati via wifi, ho deciso di trasferire il tutto da Arduino a una scheda Esp8266 12-E.
Non riesco però a capire come e dove sbaglio a collegare e a utilizzare la comunicazione SPI nella scheda esp8266.
Intanto riporto il codice funzionante che utilizzo con Arduino:
#include <SPI.h>
#include <AS3935.h>
void printAS3935Registers(); //rileva e stampa i parametri del sensore (rumore di fondo, spike rejection, soglia di controllo)
byte SPItransfer(byte sendByte); //funzione che si occupa del traferimento dei dati via SPI
int valore_calibrazione;
void AS3935Irq(); //funzione che verifica se ci sono disturbi o fulmini e causa l'interrupt
AS3935 AS3935(SPItransfer,3,2); //primo parametro: funzione per il trasferimento dei dati via SPI
//secondo parametro: pin CS collegato ad Arduino
//terzo parametro:pin IRQ collegato ad Arduino
void setup()
{
Serial.begin(9600);
SPI.begin();
SPI.setDataMode(SPI_MODE1);
SPI.setClockDivider(SPI_CLOCK_DIV16);
SPI.setBitOrder(MSBFIRST);
AS3935.reset(); //ripristina tutti i valori di registro interni ai valori predefiniti
delay(10);
AS3935.setOutdoors(); //setta il sensore per il funzionamento all'esterno
AS3935.registerWrite(AS3935_NF_LEV,2); //scrive 2 nel Noise Level register
//se il sensore non riesce a stare nel range di tolleranza la calibrazione non andrà a buon fine e restituirà false
if(!AS3935.calibrate()) {
Serial.println("La calibrazione non è andata a buon fine, controllare il cablaggio");
}
valore_calibrazione=AS3935.registerRead(AS3935_TUN_CAP); //il range è compreso tra 0 e 15
Serial.print("La calibrazione rilevata è (range concesso tra 0 e 15): ");
Serial.println(valore_calibrazione);
AS3935.enableDisturbers(); //turn on indication of distrubers, once you have AS3935 all tuned, you can turn those off with disableDisturbers()
printAS3935Registers(); //rileva e stampa i parametri del sensore (rumore di fondo, spike rejection, soglia di controllo)
//usare interrupt significa che non serve controllare lo stato del pin continuamente, lo fa il chip da solo
attachInterrupt(0,AS3935Irq,RISING);
}
void loop()
{
}
void printAS3935Registers()
{
int noiseFloor = AS3935.getNoiseFloor();
int spikeRejection = AS3935.getSpikeRejection();
int watchdogThreshold = AS3935.getWatchdogThreshold();
Serial.print("Il rumore di fondo è: ");
Serial.println(noiseFloor,DEC);
Serial.print("Lo spike rejection è: ");
Serial.println(spikeRejection,DEC);
Serial.print("La soglia di controllo è: ");
Serial.println(watchdogThreshold,DEC);
}
byte SPItransfer(byte sendByte)
{
return SPI.transfer(sendByte);
}
void AS3935Irq()
{
//verifica cosa ha causato l'interrupt
//appena leggiamo l'interrupt, il pin IRQ diventa LOW
int irqSource = AS3935.interruptSource(); //restituisce bit 0: livello rumore troppo alto
// bit 2: rilevato disturbo
// bit 3: rilevato fulmine
if (irqSource & 0b0001){
Serial.println("Livello rumore troppo alto");
}
if (irqSource & 0b0100){
Serial.println("Disturbo rilevato");
}
if (irqSource & 0b1000){
int strokeDistance = AS3935.lightningDistanceKm(); //determina la distanza del fulmine in km
if (strokeDistance < 41 && strokeDistance > 0) //40 km è la distanza di rilevamento massima
{
Serial.print("Lightning detected ");
Serial.print(strokeDistance,DEC);
Serial.println(" kilometers away.");
}
}
}
Chiedo se qualcuno sa aiutarmi su come devo collegare il sensore a una scheda Esp8266 e come devo variare il codice.
Mmmm ... se il modulo che hai funziona con Arduino è un modulino progettato per lavorare con segnali a 5V ... i livelli invece di ESP8266 sono tutti a 3.3V ... hai verificato con il produttore se il modulo è in grado di lavorare con tali livelli di tensione?
Comunque, i pin del ESP8266 che si possono usare sono:
Innanzitutto ringrazio per avermi risposto e chiarito qualche passaggio.
Confermo che sto usando i 3 pin corretti D5, D6 e D7 per il collegamento.
In merito alla tensione, il modulo va alimentato a 5V, infatti lo alimento a 5V tramite un alimentatore per breadboard. Va bene questo o è comunque errato utilizzare una scheda esp8266 che lavora a 3V?
Inoltre avrei un chiarimento in merito al codice che ho utilizzato per Arduino in modalità Spi: nella parte di codice attachInterrupt(0,AS3935Irq,RISING); si fa riferimento al pin 0, che però non ho utilizzato. Vorrei provare a mettere una foto del collegamento hardware ma non capisco come si fa qui nel forum.
Un conto è l'alimentazione (la scheda potrebbe avere un regolatore a bordo) ed un conto sono i livelli dei segnali che arrivano sui pin del sensore (il bus SPI degli Arduino classici, AVR, lavora a 5V) ...
... dacci un link esatto al modulo che hai acquistato e vediamo se danno delle specifiche tecniche.
Guglielmo
P.S.: Ti faccio un esempio, i classici moduli bluetooth HC-05 si alimentano a 5V, ma i segnali TX ed RX devono essere a 3.3V pena il possibile danneggiamento ...
Nel caso quindi fosse proprio questa la causa del problema, come posso risolvere la mancanza di WiFi di Arduino Uno? Che scheda mi consigliate o come mi consigliate di fare?
... il pdf di documentazione scaricabile non da molte informazioni, ma una cosa la dice ... che è alimentabile sia a 3.3 che a 5V, quindi, teoricamente, se i pin utilizzati sono quelli corretti, alimentandolo a 3.3V dal ESP8266 dovrebbe funzionare ...
Guglielmo
P.S.: per il momento prova a non usare interrupt ...
Ok è già qualcosa in più di quello che sapevo!
Per non utilizzare interrupt, quale pin devo monitorare e come per capire quando il segnale cambia?
Non ho mai avuto a che fare con interrupt e mi sono limitato a semplificare un codice esempio per adattarlo alle mie esigenze.
Non so, tocca studiarsi il datasheet e vedere se c'è un sistema ... quello che è certo è che se lo alimenti a 5V poi il bus si aspetta segnali di quel livello, quindi, se lo colleghi a ESP, alimentalo a 3.3V.
Sono andato a guardare un vecchio programma che ho scritto molti anni fa (2017) in cui usavo quel sensore ... intanto lo usavo su bus I2C e non SPI, ma, si, usavo l'interrupt ...
Tramite I2C potrebbe cambiare qualcosa?
Come cambiano i collegamenti ed eventualmente il mio codice?
La cosa che più mi lascia perplesso è che con arduino funziona, quindi facendo gli stessi collegamenti è variando i due pin diversi mi aspettavo funzionasse senza difficoltà anche sulla scheda esp8266.
... e perché mai? Sono due MCU totalmente diverse, una a 8 bit una a 32 bit, una con una tecnologia, una con un'altra ... non è assolutammete detto che una cosa che funziona su un Arduino classico funzioni su altre MCU.
Comunque se lo facevi funzionare con SPI, prosegui come facevi, verifica solo che i pin che usi siano utilizzabili su ESP (secondo la tabella che ti ho messo) ed alimentalo a 3.3V ... poi si vede.
Una cosa piuttosto, tu sai che su ESP i pin vanno indicati con il numero di GPIO o con il prefisso Dx?
Ovvero, se su Arduino classico identifichi, ad esempio il pin D2 solo con 2, su ESP DEVI o mettere D2 oppure indicare 4, ovvero il GPIO 4 ... mi raccomando, altrimenti non funzionerà mai.
Grazie mille Guglielmo, stasera provo come da tue indicazioni, posterò sia la foto dei collegamenti che il nuovo codice modificato per la scheda esp8266 in modo che possiamo capire quale potrebbe essere il problema.
Ho provato a seguire i consigli che mi son stati dati: ho quindi collegato il sensore alla scheda esp8266, compresa l'alimentazione a 3V, e ho cambiato i pin nel codice.
Riporto quindi di seguito le foto dei collegamenti e il nuovo codice.
#include <SPI.h>
#include <AS3935.h>
void printAS3935Registers(); //rileva e stampa i parametri del sensore (rumore di fondo, spike rejection, soglia di controllo)
byte SPItransfer(byte sendByte); //funzione che si occupa del traferimento dei dati via SPI
int valore_calibrazione;
void ICACHE_RAM_ATTR AS3935Irq(); //funzione che verifica se ci sono disturbi o fulmini e causa l'interrupt
//ICACHE_RAM_ATTR serve per caricare nella ram altrimenti con esp non funzionano gli interrupt
AS3935 AS3935(SPItransfer,D4,D3); //primo parametro: funzione per il trasferimento dei dati via SPI
//secondo parametro: pin CS collegato ad Arduino
//terzo parametro:pin IRQ collegato ad Arduino
void setup()
{
Serial.begin(9600);
SPI.begin();
SPI.setDataMode(SPI_MODE1);
SPI.setClockDivider(SPI_CLOCK_DIV16);
SPI.setBitOrder(MSBFIRST);
AS3935.reset(); //ripristina tutti i valori di registro interni ai valori predefiniti
delay(10);
AS3935.setOutdoors(); //setta il sensore per il funzionamento all'esterno
AS3935.registerWrite(AS3935_NF_LEV,2); //scrive 2 nel Noise Level register
//se il sensore non riesce a stare nel range di tolleranza la calibrazione non andrà a buon fine e restituirà false
if(!AS3935.calibrate()) {
Serial.println("La calibrazione non è andata a buon fine, controllare il cablaggio");
}
valore_calibrazione=AS3935.registerRead(AS3935_TUN_CAP); //il range è compreso tra 0 e 15
Serial.print("La calibrazione rilevata è (range concesso tra 0 e 15): ");
Serial.println(valore_calibrazione);
AS3935.enableDisturbers(); //turn on indication of distrubers, once you have AS3935 all tuned, you can turn those off with disableDisturbers()
printAS3935Registers(); //rileva e stampa i parametri del sensore (rumore di fondo, spike rejection, soglia di controllo)
//usare interrupt significa che non serve controllare lo stato del pin continuamente, lo fa il chip da solo
attachInterrupt(0,AS3935Irq,RISING);
}
void loop()
{
}
void printAS3935Registers()
{
int noiseFloor = AS3935.getNoiseFloor();
int spikeRejection = AS3935.getSpikeRejection();
int watchdogThreshold = AS3935.getWatchdogThreshold();
Serial.print("Il rumore di fondo è: ");
Serial.println(noiseFloor,DEC);
Serial.print("Lo spike rejection è: ");
Serial.println(spikeRejection,DEC);
Serial.print("La soglia di controllo è: ");
Serial.println(watchdogThreshold,DEC);
}
byte SPItransfer(byte sendByte)
{
return SPI.transfer(sendByte);
}
void AS3935Irq()
{
//verifica cosa ha causato l'interrupt
//appena leggiamo l'interrupt, il pin IRQ diventa LOW
int irqSource = AS3935.interruptSource(); //restituisce bit 0: livello rumore troppo alto
// bit 2: rilevato disturbo
// bit 3: rilevato fulmine
if (irqSource & 0b0001){
Serial.println("Livello rumore troppo alto");
}
if (irqSource & 0b0100){
Serial.println("Disturbo rilevato");
}
if (irqSource & 0b1000){
int strokeDistance = AS3935.lightningDistanceKm(); //determina la distanza del fulmine in km
if (strokeDistance < 41 && strokeDistance > 0) //40 km è la distanza di rilevamento massima
{
Serial.print("Lightning detected ");
Serial.print(strokeDistance,DEC);
Serial.println(" kilometers away.");
}
}
}
Il sensore sembra rilevare qualcosa, ma la calibrazione non mi sembra andare a buon fine, mi da un valore 15.
Riporto infatti di seguito quanto viene visualizzato nel serial monitor:
19:16:15.243 -> La calibrazione rilevata è (range concesso tra 0 e 15): 15
19:16:16.985 -> Il rumore di fondo è: 2
19:16:17.032 -> Lo spike rejection è: 2
19:16:17.079 -> La soglia di controllo è: 2
19:16:19.511 -> Livello rumore troppo alto
19:18:48.194 -> Lightning detected 8 kilometers away.
19:18:54.032 -> Disturbo rilevato
19:18:54.348 -> Lightning detected 8 kilometers away.
19:18:59.293 -> Disturbo rilevato
19:19:01.992 -> Lightning detected 8 kilometers away.
19:19:04.387 -> Disturbo rilevato
19:19:37.542 -> Disturbo rilevato
19:19:40.289 -> Disturbo rilevato
19:19:41.947 -> Lightning detected 8 kilometers away.
19:19:43.995 -> Disturbo rilevato
19:19:44.820 -> Disturbo rilevato
19:19:45.522 -> Disturbo rilevato
19:19:46.225 -> Disturbo rilevato
19:19:46.873 -> Lightning detected 8 kilometers away.
Quesi sensori sono molto sensibili hai disturbi, ricordo che dovetti lavorare parecchio con i vari parametri che si possonio configurare (vd. datasheet) per avere qualche cosa di "utilizzabile" praticamente.
Sicuramente NO, è sempre molto sconsigliato mettere direttamente il numero di un pin nella attachInterrupt(), come è ampiamente spiegato nel reference (che andrebbe studiato).
Quale pin hai usato per l'interrupt? D3? allora dovresti scrivere, come dice il reference:
Buonasera Guglielmo,
ho provveduto a seguire i consigli e sembra che ora il tutto funzioni, almeno per quel che ne capisco dai primi test.
Ho voluto proseguire col progetto, e volevo far si che quando viene rilevato un fulmine la funzione AS3935Irq richiamata dall'interrupt non si limitasse a scrivere nel serial monitor ma che inviasse i dati ad un host per salvarli col metodo get in un database.
Il codice che utilizzo, e che ho provveduto ad inserire nella funzione, se lo utilizzo al di fuori della funzione AS3935Irq funziona correttamente.
Se invece lo metto all'interno della funzione, la connessione non va mai a buon fine, come mai?
Di seguito il codice che ho inserito:
//collegamento all'host
WiFiClientSecure client;
client.setInsecure(); //non si utilizzano certificati di sicurezza
//verifica se il collegamento non è andato a buon fine
if (!client.connect(host, port)) {
delay(5000);
return;
}
Serial.println("VERIFICA OK");
//se la connessione all'host è avvenuta
if (client.connected()) {
String var="distanza_fulmine=" + String(distanza_fulmine);
String url = "GET /aggiungi_fulmini.php?" + var + " HTTP/1.1";
Serial.println(url);
//invio url all'host per il salvataggio dei dati sul database mysql
client.println(url);
client.println("Host: www.xyz.it");
client.println("Access-Control-Allow-Origin: *");
client.println("Connection: close");
client.println();
client.stop();
}
}
client.connect(host, port) non va mai a buon fine e quindi la connessione non avviene.