Sommario:

Comunicazione wireless LoRa da 3Km a 8Km con dispositivo E32 (sx1278/sx1276) a basso costo per Arduino, Esp8266 o Esp32: 15 passaggi
Comunicazione wireless LoRa da 3Km a 8Km con dispositivo E32 (sx1278/sx1276) a basso costo per Arduino, Esp8266 o Esp32: 15 passaggi

Video: Comunicazione wireless LoRa da 3Km a 8Km con dispositivo E32 (sx1278/sx1276) a basso costo per Arduino, Esp8266 o Esp32: 15 passaggi

Video: Comunicazione wireless LoRa da 3Km a 8Km con dispositivo E32 (sx1278/sx1276) a basso costo per Arduino, Esp8266 o Esp32: 15 passaggi
Video: ✅ Módulo Lora Reyax RYLR896 Configuración Por Comandos AT 2024, Dicembre
Anonim
Comunicazione wireless LoRa da 3Km a 8Km con dispositivo E32 (sx1278/sx1276) a basso costo per Arduino, Esp8266 o Esp32
Comunicazione wireless LoRa da 3Km a 8Km con dispositivo E32 (sx1278/sx1276) a basso costo per Arduino, Esp8266 o Esp32

Creo una libreria per gestire EBYTE E32 basata sulla serie Semtech del dispositivo LoRa, dispositivo molto potente, semplice ed economico.

Puoi trovare la versione 3Km qui, la versione 8Km qui

Possono lavorare su una distanza da 3000 m a 8000 m e hanno molte caratteristiche e parametri. Quindi creo questa libreria per semplificare l'utilizzo.

E' una soluzione per recuperare dati da sensori metropolitani o per comandare droni.

Forniture

Arduino UNO

Wemos D1 mini

LoRa E32 TTL 100 versione 3Km

Versione LoRa E32 TTL 1W 8Km

Passaggio 1: libreria

Biblioteca
Biblioteca

Puoi trovare la mia libreria qui.

Scaricare.

Fare clic sul pulsante DOWNLOAD nell'angolo in alto a destra, rinominare la cartella non compressa LoRa_E32.

Verificare che la cartella LoRa_E32 contenga LoRa_E32.cpp e LoRa_E32.h.

Posiziona la cartella della libreria LoRa_E32 nella tua cartella /libraries/. Potrebbe essere necessario creare la sottocartella delle librerie se è la tua prima libreria.

Riavvia l'IDE.

Passaggio 2: piedinatura

pinout
pinout
pinout
pinout
pinout
pinout

Come puoi vedere puoi impostare varie modalità tramite i pin M0 e M1.

Ci sono alcuni pin che possono essere utilizzati in modo statico, ma se lo colleghi al microcontrollore e li configuri nella libreria guadagni in prestazioni e puoi controllare tutte le modalità via software, ma spiegheremo meglio in seguito.

Passaggio 3: pin AUX

Pin AUX
Pin AUX
Pin AUX
Pin AUX
Pin AUX
Pin AUX

Come ho già detto Non è importante collegare tutti i pin all'uscita del microcontrollore, puoi mettere i pin M0 e M1 su HIGH o LOW per ottenere la configurazione desiderata e se non colleghi AUX la libreria imposta un ritardo ragionevole per essere sicuro che l'operazione è conclusa.

Pin AUX

Durante la trasmissione dei dati può essere utilizzato per riattivare l'MCU esterno e restituire HIGH al termine del trasferimento dati.

Quando si riceve l'AUX va BASSO e ritorna ALTO quando il buffer è vuoto.

Viene anche utilizzato per l'autoverifica per ripristinare il normale funzionamento (all'accensione e in modalità sospensione/programma).

Passaggio 4: Schema completamente connesso Esp8266

Schema completamente connesso Esp8266
Schema completamente connesso Esp8266
Schema completamente connesso Esp8266
Schema completamente connesso Esp8266

Lo schema di connessione esp8266 è più semplice perché funziona alla stessa tensione delle comunicazioni logiche (3.3v).

È importante aggiungere una resistenza di pull-up (4, 7Kohm) per ottenere una buona stabilità.

Passaggio 5: Schema Arduino completamente connesso

Schema completamente connesso Arduino
Schema completamente connesso Arduino
Schema completamente connesso Arduino
Schema completamente connesso Arduino

La tensione di lavoro di Arduino è 5v, quindi dobbiamo aggiungere un divisore di tensione sui pin RX M0 e M1 del modulo LoRa per evitare danni, puoi ottenere maggiori informazioni qui. Divisore di tensione: calcolatrice e applicazione.

È possibile utilizzare un resistore da 2Kohm su GND e 1Kohm dal segnale che mettere insieme su RX.

Passaggio 6: Libreria: Costruttore

Ho creato un insieme di costruttori abbastanza numerosi, perché possiamo avere più opzioni e situazioni da gestire.

LoRa_E32(byte rxPin, byte txPin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600);

LoRa_E32(byte rxPin, byte txPin, byte auxPin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600); LoRa_E32(byte rxPin, byte txPin, byte auxPin, byte m0Pin, byte m1Pin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600);

Vengono creati i primi set di costruttori per delegare la gestione di Serial e altri pin alla libreria.

rxPin e txPin è il pin per connettersi a UART e sono obbligatori.

auxPin è un pin che controlla lo stato di funzionamento, trasmissione e ricezione (di seguito spiegheremo meglio), quel pin Non è obbligatorio, se non lo imposti applico un ritardo per permettere che l'operazione si completi (con latenza).

m0pin e m1Pin sono i pin per cambiare MODALITÀ di funzionamento (vedi tabella in alto), penso che questi pin in "produzione" andranno a collegarsi direttamente HIGH o LOW, ma per i test sono utili per essere gestiti dalla libreria.

bpsRate è il boudrate di SoftwareSerial normalmente è 9600 (l'unico baud rate in modalità programmazione/sleep)

Un semplice esempio è

#include "LoRa_E32.h"LoRa_E32 e32ttl100(2, 3); // RX, TX // LoRa_E32 e32ttl100(2, 3, 5, 6, 7); // RX, TX

Possiamo usare direttamente un SoftwareSerial con un altro costruttore

LoRa_E32(HardwareSerial* seriale, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600);

LoRa_E32(HardwareSerial* seriale, byte auxPin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600);

LoRa_E32(HardwareSerial* seriale, byte auxPin, byte m0Pin, byte m1Pin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600);

L'esempio superiore con questo costruttore può essere fatto in questo modo.

#include #include "LoRa_E32.h"

SoftwareSerial mySerial(2, 3); // RX, TX

LoRa_E32 e32ttl100(&mySerial);

// LoRa_E32 e32ttl100(&mySerial, 5, 7, 6);

L'ultimo set di costruttori è quello di consentire l'utilizzo di un HardwareSerial invece di SoftwareSerial.

LoRa_E32(SoftwareSerial* seriale, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600);

LoRa_E32(SoftwareSerial* seriale, byte auxPin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600);

LoRa_E32(SoftwareSerial* seriale, byte auxPin, byte m0Pin, byte m1Pin, UART_BPS_RATE bpsRate = UART_BPS_RATE_9600);

Passaggio 7: iniziare

Il comando begin viene utilizzato per avviare Serial e pin in modalità input e output.

void inizia();

in esecuzione è

// Avvia tutti i pin e UART

e32ttl100.begin();

Passaggio 8: metodo di configurazione e informazione

Esiste una serie di metodi per gestire la configurazione e ottenere informazioni sul dispositivo.

ResponseStructContainer getConfiguration();

ResponseStatus setConfiguration(Configuration configuration, PROGRAM_COMMAND saveType = WRITE_CFG_PWR_DWN_LOSE);

ResponseStructContainer getModuleInformation();

void printParameters (configurazione della configurazione della struttura);

ResponseStatus resetModule();

Passaggio 9: contenitore della risposta

Per semplificare la gestione della risposta creo un set di container, per me molto utile per gestire gli errori e restituire dati generici.

Stato risposta

Questo è un contenitore di stato e ha 2 semplici punti di ingresso, con questo puoi ottenere il codice di stato e la descrizione del codice di stato

Serial.println(c.getResponseDescription()); // Descrizione del codice

Serial.println(c.code); // 1 in caso di successo

Il codice è

SUCCESSO = 1, ERR_SCONOSCIUTO, ERR_NOT_SUPPORT, ERR_NOT_IMPLEMENT, ERR_NOT_INITIAL, ERR_INVALID_PARAM, ERR_DATA_SIZE_NOT_MATCH, ERR_BUF_TOO_SMALL, ERR_TIMEOUT, ERR_HARDWARE, ERR_HEAD_NOT_RECOGNIZED

Contenitore di risposta

Questo contenitore è stato creato per gestire la risposta String e avere 2 punti di ingresso.

data con la stringa restituita da message e status di un'istanza di RepsonseStatus.

ResponseContainer rs = e32ttl.receiveMessage();

Messaggio stringa = rs.data;

Serial.println(rs.status.getResponseDescription());

Serial.println(messaggio);

ResponseStructContainer

Questo è il contenitore più "complesso", lo uso per gestire la struttura, ha lo stesso punto di ingresso di ResponseContainer ma i dati sono un puntatore vuoto per gestire la struttura complessa.

ResponseStructContainer c;

c = e32ttl100.getConfiguration();// È importante ottenere il puntatore di configurazione prima di tutte le altre operazioni

Configurazione configurazione = *(Configuration*) c.data;

Serial.println(c.status.getResponseDescription());

Serial.println(c.status.code);

getConfiguration e setConfiguration

Il primo metodo è getConfiguration, puoi usarlo per recuperare tutti i dati memorizzati sul dispositivo.

ResponseStructContainer getConfiguration();

Qui un esempio di utilizzo.

ResponseStructContainer c;

c = e32ttl100.getConfiguration();// È importante ottenere il puntatore di configurazione prima di tutte le altre operazioni

Configurazione configurazione = *(Configuration*) c.data;

Serial.println(c.status.getResponseDescription());

Serial.println(c.status.code);

Serial.println(configuration. SPED.getUARTBaudRate());

La struttura della configurazione ha tutti i dati delle impostazioni e aggiungo una serie di funzioni per ottenere tutte le descrizioni dei singoli dati.

configurazione. ADDL = 0x0; // Prima parte di addressconfiguration. ADDH = 0x1; // Seconda parte della configurazione dell'indirizzo. CHAN = 0x19;// Configurazione del canale. OPTION.fec = FEC_0_OFF; // Interruttore di correzione degli errori in avanti configuration. OPTION.fixedTransmission = FT_TRANSPARENT_TRANSMISSION; // Configurazione della modalità di trasmissione. OPTION.ioDriveMode = IO_D_MODE_PUSH_PULLS_PULL_UPS; // Configurazione gestione pull-up. OPTION.transmissionPower = POWER_17; // Configurazione della potenza di trasmissione dBm. OPTION.wirelessWakeupTime = WAKE_UP_1250; // Tempo di attesa per la sveglia configuration. SPED.airDataRate = AIR_DATA_RATE_011_48; // Configurazione velocità dati aerei. SPED.uartBaudRate = UART_BPS_115200; // Configurazione baud rate di comunicazione. SPED.uartParity = MODE_00_8N1; // Bit di parità

Hai la funzione equivalente per tutti gli attributi per ottenere tutte le descrizioni:

Serial.print(F("Chan: ")); Serial.print(configuration. CHAN, DEC); Serial.print(" -> "); Serial.println(configuration.getChannelDescription());Serial.println(F(" ")); Serial.print(F("SpeedParityBit: ")); Serial.print(configuration. SPED.uartParity, BIN);Serial.print(" -> "); Serial.println(configuration. SPED.getUARTParityDescription()); Serial.print(F("SpeedUARTDatte: ")); Serial.print(configuration. SPED.uartBaudRate, BIN);Serial.print(" -> "); Serial.println(configuration. SPED.getUARTBaudRate()); Serial.print(F("SpeedAirDataRate: ")); Serial.print(configuration. SPED.airDataRate, BIN);Serial.print(" -> "); Serial.println(configuration. SPED.getAirDataRate()); Serial.print(F("OptionTrans: ")); Serial.print(configuration. OPTION.fixedTransmission, BIN);Serial.print(" -> "); Serial.println(configuration. OPTION.getFixedTransmissionDescription()); Serial.print(F("OptionPullup: ")); Serial.print(configuration. OPTION.ioDriveMode, BIN);Serial.print(" -> "); Serial.println(configuration. OPTION.getIODroveModeDescription()); Serial.print(F("OptionWakeup: ")); Serial.print(configuration. OPTION.wirelessWakeupTime, BIN);Serial.print(" -> "); Serial.println(configuration. OPTION.getWirelessWakeUPTimeDescription()); Serial.print(F("OptionFEC: ")); Serial.print(configuration. OPTION.fec, BIN);Serial.print(" -> "); Serial.println(configuration. OPTION.getFECDescription()); Serial.print(F("OptionPower: ")); Serial.print(configuration. OPTION.transmissionPower, BIN);Serial.print(" -> "); Serial.println(configuration. OPTION.getTransmissionPowerDescription());

Allo stesso modo setConfiguration vuole una struttura di configurazione, quindi penso che il modo migliore per gestire la configurazione sia recuperare quella corrente, applicare l'unica modifica necessaria e impostarla di nuovo.

ResponseStatus setConfiguration(Configuration configuration, PROGRAM_COMMAND saveType = WRITE_CFG_PWR_DWN_LOSE);

configurazione è la struttura precedentemente mostrata, saveType ti permette di scegliere se la modifica diventa permanentemente di solo per la sessione corrente.

ResponseStructContainer c;c = e32ttl100.getConfiguration(); // È importante ottenere il puntatore di configurazione prima di tutte le altre operazioni Configuration configuration = *(Configuration*) c.data; Serial.println(c.status.getResponseDescription()); Serial.println(c.status.code); printParameters(configurazione); configurazione. ADDL = 0x0; configurazione. ADDH = 0x1; configurazione. CHAN = 0x19; configurazione. OPTION.fec = FEC_0_OFF; configurazione. OPTION.fixedTransmission = FT_TRANSPARENT_TRANSMISSION; configurazione. OPTION.ioDriveMode = IO_D_MODE_PUSH_PULLS_PULL_UPS; configurazione. OPTION.transmissionPower = POWER_17; configurazione. OPTION.wirelessWakeupTime = WAKE_UP_1250; configurazione. SPED.airDataRate = AIR_DATA_RATE_011_48; configurazione. SPED.uartBaudRate = UART_BPS_115200; configurazione. SPED.uartParity = MODE_00_8N1; // Imposta la configurazione modificata e imposta per non mantenere la configurazione ResponseStatus rs = e32ttl100.setConfiguration(configuration, WRITE_CFG_PWR_DWN_LOSE); Serial.println(rs.getResponseDescription()); Serial.println(rs.code); printParameters(configurazione);

I parametri sono tutti gestiti come costanti:

Passaggio 10: opzione di configurazione di base

Opzione di configurazione di base
Opzione di configurazione di base

Passaggio 11: inviare un messaggio di ricezione

Per prima cosa dobbiamo introdurre un metodo semplice ma utile per verificare se c'è qualcosa nel buffer di ricezione

int disponibile();

È semplicemente restituire quanti byte hai nel flusso corrente.

Passaggio 12: modalità di trasmissione normale

Modalità di trasmissione normale
Modalità di trasmissione normale

La modalità di trasmissione normale/trasparente viene utilizzata per inviare messaggi a tutti i dispositivi con lo stesso indirizzo e canale.

Ci sono molti metodi per inviare/ricevere un messaggio, spiegheremo in dettaglio:

ResponseStatus sendMessage(const String messaggio);

ResponseContainer riceveMessage();

Il primo metodo è sendMessage e viene utilizzato per inviare una stringa a un dispositivo in modalità normale.

ResponseStatus rs = e32ttl.sendMessage("Prova");Serial.println(rs.getResponseDescription());

L'altro dispositivo lo fa semplicemente in loop

if (e32ttl.available() > 1){ResponseContainer rs = e32ttl.receiveMessage(); Stringa messaggio = rs.data; // Per prima cosa ottengo i dati Serial.println(rs.status.getResponseDescription()); Serial.println(messaggio); }

Passaggio 13: gestire la struttura

Se vuoi inviare una struttura complessa puoi usare questo metodo

ResponseStatus sendMessage(const void *message, const uint8_t size);ResponseStructContainer riceveMessage(const uint8_t size);

Viene utilizzato per inviare strutture, ad esempio:

struct Messaggione {tipo di carattere[5]; messaggio di carattere[8]; bool mitico; }; struct Messaggione messaggione = {"TEMP", "Peple", true}; ResponseStatus rs = e32ttl.sendMessage(&messaggione, sizeof(Messaggione)); Serial.println(rs.getResponseDescription());

e dall'altra parte puoi ricevere il messaggio così

ResponseStructContainer rsc = e32ttl.receiveMessage(sizeof(Messaggione));struct Messaggione messaggione = *(Messaggione*) rsc.data; Serial.println(messaggione.messaggio); Serial.println(messaggione.mitico);

Leggi struttura parziale

Se vuoi leggere la prima parte del messaggio per gestire più tipi di struttura puoi usare questo metodo.

ResponseContainer riceveInitialMessage(const uint8_t size);

Lo creo per ricevere una stringa con tipo o altro per identificare la struttura da caricare.

struct Messaggione { // Struttura parziale senza typechar message[8]; bool mitico; }; tipo di carattere[5]; // prima parte della struttura ResponseContainer rs = e32ttl.receiveInitialMessage(sizeof(type)); // Inserisci la stringa in un array di caratteri (non necessario) memcpy (type, rs.data.c_str(), sizeof(type)); Serial.println("LEGGI TIPO: "); Serial.println(rs.status.getResponseDescription()); Serial.println(tipo); // Legge il resto della struttura ResponseStructContainer rsc = e32ttl.receiveMessage(sizeof(Messaggione)); struct Messaggione messaggione = *(Messaggione*) rsc.data;

Passaggio 14: modalità fissa invece della modalità normale

Allo stesso modo creo un insieme di metodi da utilizzare con la trasmissione fissa

Trasmissione fissa

È necessario modificare solo la modalità di invio, perché il dispositivo di destinazione non riceve il preambolo con Indirizzo e Canale quando impostato il modo fisso.

Quindi per il messaggio String hai

ResponseStatus sendFixedMessage(byte ADDL, byte ADDH, byte CHAN, const String messaggio);ResponseStatus sendBroadcastFixedMessage(byte CHAN, const String messaggio);

e per struttura hai

ResponseStatus sendFixedMessage(byte ADDL, byte ADDH, byte CHAN, const void *message, const uint8_t size);ResponseStatus sendBroadcastFixedMessage(byte CHAN, const void *message, const uint8_t size);

Ecco un semplice esempio

ResponseStatus rs = e32ttl.sendFixedMessage(0, 0, 0x17, &messaggione, sizeof(Messaggione));// ResponseStatus rs = e32ttl.sendFixedMessage(0, 0, 0x17, "Ciao");

La trasmissione fissa ha più scenari

Se invii ad un dispositivo specifico (secondi scenari Trasmissione fissa) devi aggiungere ADDL, ADDH e CHAN per identificarlo direttamente.

ResponseStatus rs = e32ttl.sendFixedMessage(2, 2, 0x17, "Messaggio a un dispositivo");

Se vuoi inviare un messaggio a tutti i dispositivi in un canale specificato puoi utilizzare questo metodo.

ResponseStatus rs = e32ttl.sendBroadcastFixedMessage(0x17, "Messaggio a dispositivi di un canale");

Se vuoi ricevere tutti i messaggi trasmessi nella rete devi impostare il tuo ADDH e ADDL con BROADCAST_ADDRESS.

ResponseStructContainer c;c = e32ttl100.getConfiguration(); // È importante ottenere il puntatore di configurazione prima di tutte le altre operazioni Configuration configuration = *(Configuration*) c.data; Serial.println(c.status.getResponseDescription()); Serial.println(c.status.code); printParameters(configurazione); configurazione. ADDL = BROADCAST_ADDRESS; configurazione. ADDH = BROADCAST_ADDRESS; // Imposta la configurazione modificata e imposta per non mantenere la configurazione ResponseStatus rs = e32ttl100.setConfiguration(configuration, WRITE_CFG_PWR_DWN_LOSE); Serial.println(rs.getResponseDescription()); Serial.println(rs.code); printParameters(configurazione);

Passaggio 15: grazie

Ora hai tutte le informazioni per fare il tuo lavoro, ma penso che sia importante mostrare alcuni esempi realistici per capire meglio tutte le possibilità.

  1. Dispositivo LoRa E32 per Arduino, esp32 o esp8266: impostazioni e utilizzo di base
  2. Dispositivo LoRa E32 per Arduino, esp32 o esp8266: libreria
  3. Dispositivo LoRa E32 per Arduino, esp32 o esp8266: configurazione
  4. Dispositivo LoRa E32 per Arduino, esp32 o esp8266: trasmissione fissa
  5. Dispositivo LoRa E32 per Arduino, esp32 o esp8266: risparmio energetico e invio di dati strutturati

Consigliato: