LoRa mit der EByte E220-, E22- und E32-Serie nutzen

Über den Beitrag

In diesem Beitrag geht es mal wieder um Funk, und zwar um die LoRa Technologie am Beispiel der Ebyte E220-, E22- und E32-Modul-Serien. Die Beispielsketche sind für die E220-Module geschrieben, lassen sich aber relativ leicht übertragen, zumal ich die wesentlichen anzupassenden Punkte aufführe. Ich bitte mir nachzusehen, dass ich nicht jeden Sketch in drei Versionen verfasst habe.

Hier ein Überblick über den Beitrag:

Rechtliches – bitte beachten!

Wichtig zu wissen:

  • Funk ist in fast allen Ländern dieser Welt rechtlich geregelt, z.B. hinsichtlich erlaubter Frequenzen, der Sendeleistung oder dem Duty-Cycle (prozentualer Anteil tatsächlicher Sendezeit).
  • Nicht alles, was man kaufen kann, darf man auch ohne Einschränkungen betreiben – manches auch gar nicht!

In Deutschland werden die Regeln für den Funk durch die Bundesnetzagentur festgelegt. Die relevanten Details findet ihr hier im Abschnitt „Funkanlagen mit geringer Reichweite“. Von Hobbyisten werden vor allem die Frequenzen um 433 MHz, 868 MHz und 2.4 GHz genutzt – aber nicht frei von Einschränkungen. Ihr seid selbst dafür verantwortlich, die gültigen Vorschriften in eurem Land einzuhalten.

Was ist LoRa, LoRaWAN und LPWAN?

Wenn ihr euch mit LoRa beschäftigt, dann trefft ihr auch auf die Begriffe LoRaWAN und LPWAN. LoRa steht für Long Range, d. h. es handelt sich eine Funktechnologie für vergleichsweise große Strecken. LoRa (wie auch Sigfox) gehört zu der Gruppe der LPWAN-Funktechnologien, was wiederum die Abkürzung für Low Power Wide Area Network ist. In dieser Bezeichnung steckt damit ein zweites Charakteristikum dieser Technik, nämlich der niedrige Energiebedarf. Während sich LoRa auf die spezielle Funktechnologie bezieht, ist LoRaWAN ein darauf basierendes Kommunikationsprotokoll.

Ich bin weder Physiker noch Funktechniker. Deshalb halte ich mich mit Erklärungen, wie LoRa genau funktioniert, lieber zurück. Nur so viel: Es handelt sich um eine spezielle Modulationstechnik, mit der die große Reichweite und der niedrige Energieverbrauch erreicht wird. Die Datenübertragungsraten sind vergleichsweise gering.

LoRa Module

In den gängigen Online-Shops wie Amazon oder AliExpress werden viele verschiedene LoRa Module angeboten. Darunter befinden sich auch fertige Lösungen, z. B. auf ESP32 basierende Boards mit OLED Display. Ursprünglich hatte ich geplant, einen breiteren Überblick über gängige Module und Bibliotheken zu geben. Dann musste ich allerdings feststellen, dass das Thema schlicht zu umfangreich ist, um alles in einem Beitrag zu behandeln. Ich beschränke mich deshalb zunächst auf die E220-, E22- und die E32-Reihen von Ebyte. Sie sind nahe Verwandte, die fast gleich zu programmieren sind. Weitere Module werde ich evtl. in einem späteren Beitrag betrachten.

Ebyte LoRa Module

Übersicht

Die Firma Ebyte, genau gesagt Chengdu Ebyte Electronic Technology Co. Ltd., bietet eine Vielzahl verschiedener LoRa Module an. Wenn ihr nach bestimmten Modellen sucht, dann schaut hier. Die wichtigsten Unterschiede der Modulreihen habe ich hier zusammengefasst:

Übersicht E220-, E22- und E32-Reihe
Übersicht E220-, E22- und E32-Reihe

Die Module besitzen alle dasselbe Pinout und sind in der Bedienung sehr ähnlich.

Eine Übersicht über die Chips SX1262, SX1276 und SX1278 findet ihr hier. Alle Chips bzw. Module haben ihre Vor- und Nachteile.

Namensgebung

Die Namensgebung der Module erfolgt nach dem Schema EaaabbbTccd, z.B. E220-900T22D. Dabei ist: 

  • aaa: der „Familienname“,
  • bbb: kodiert die Funkfrequenz,
  • cc: kodiert die Signalstärke in dBm,
  • d: kodiert die Bauform (DIP o. SMD).

Hier, als Beispiel, eine Übersicht über einige Vertreter der E220-Reihe:

Modellübersicht der LoRa E220-Serie
Modellübersicht der LoRa E220-Serie (Quelle: E220-900T22D Datenblatt)

Technische Daten am Beispiel E220-900T22D

Datenblätter bzw. Manuals findet ihr beispielsweise auf den Seiten von Chengdu Ebyte. Als Beispiel habe ich hier für euch die technischen Daten des Modells E220-900T22D:

Technische Daten E220-900T22D LoRa Modul
Technische Daten E220-900T22D LoRa Modul (Quelle: E220-900T22D Datenblatt)

An anderer Stelle habe ich ein Datenblatt für dasselbe Modul gefunden, aber mit etwas unterschiedlichen Angaben zur optimalen Spannungsversorgung:

Version 2 des E220-900T22D LoRa-Moduls.
Version 2 des E220-900T22D LoRa-Moduls.

Probiert im Zweifelsfall aus, ob ihr mit 5 Volt bessere Ergebnisse erzielt. Wichtig ist aber, dass nicht alle Pins 5 Volt vertragen. Bei 5 Volt MCUs solltet ihr also Levelshifter oder Spannungsteiler nutzen.

Pinout LoRa E220-, E22-, E32-Serie

Pinout LoRa E220 (identisch mit E22 und E32)
Pinout LoRa E220, E22 und E32
  • GND / VCC: Spannungsversorgung
  • AUX: Zeigt den Status der Datenpuffer zum Senden und Empfangen an und wird für den Selbstcheck genutzt.
  • RX / TX: Serielle Kommunikation
  • M0 / M1 (E220): Steuerung der vier Betriebsmodi:
    1. M0 = LOW,  M1 = LOW: Normaler Modus
    2. M0 = HIGH, M1 = LOW: WOR Transmitter
    3. M0 = LOW,  M1 = HIGH: WOR Receiver
    4. M0 = HIGH, M1 = HIGH: Deep Sleep
  • M0 /M1 (E22): Steuerung  der vier Betriebsmodi:
    1. M0 = LOW,  M1 = LOW: Normaler Modus
    2. M0 = HIGH, M1 = LOW: WOR Mode (Transmitter/Receiver)
    3. M0 = LOW,  M1 = HIGH: Configuration Mode
    4. M0 = HIGH, M1 = HIGH: Deep Sleep
  • M0 / M1 (E32): Steuerung der vier Betriebsmodi:
    1. M0 = LOW,  M1 = LOW: Normaler Modus
    2. M0 = HIGH, M1 = LOW: Wake-Up Modus (Transmitter)
    3. M0 = LOW,  M1 = HIGH: Power-Saving
    4. M0 = HIGH, M1 = HIGH: Sleep

Bibliotheken für die Ebyte E220-, E22- und E32-Serie

Für die Ansteuerung der Module habe ich die Bibliotheken von Renzo Mischianti ausgewählt. Ihr könnt sie hier von GitHub herunterladen:

… oder über den Bibliotheksmanager der Arduino IDE installieren.

Zusätzlich hat der fleißige Renzo Mischianti zu jeder der Modulreihen noch ein mehrteiliges Tutorial erstellt. Hier die Links zum jeweiligen ersten Teil: E220-Tutorial, E22-Tutorial, E32-Tutorial.

Meine Motivation einen eigenen Beitrag zu schreiben war es, die Dinge etwas kompakter zusammenzufassen und die Modulserien gegenüberzustellen. Es lohnt sich aber auf jeden Fall, auch in die Tutorials schauen. Sie bieten viele zusätzliche Informationen, so z. B. Beispielsketche und Schaltpläne für andere Boards.

Die Tutorials und die Bibliotheken für die verschiedenen Reihen sind nach demselben Schema aufgebaut. So findet ihr euch schnell zurecht, wenn ihr mal die Modulreihe wechselt.

Schaltung für den Arduino Nano

Ich verwende in diesem Beitrag den klassischen Arduino Nano als steuerndes Board. Folgendermaßen habe ich ihn mit dem E220-Modul verbunden (identisch für E22 und E32):

Pin Connection LoRa E220 Modul am Arduino Nano
Pin Connection LoRa E220 Modul am Arduino Nano

Ein paar Anmerkungen dazu:

  • Wenn ihr die WOR- (Wake On Radio) oder Power-Down-Modi nicht verwenden wollt, dann könnt ihr M0 und M1 mit GND verbinden.
  • Auch AUX könnt ihr im Prinzip unverbunden lassen. Dann weiß der steuernde Mikrocontroller zwar nicht, wann die Datenübertragung abgeschlossen ist, aber die Bibliothek fügt eine ausreichende Wartezeit ein.
  • Bei Verwendung eines 5 Volt Boards müsst ihr zwischen M0, M1, RX und den Board-Pins einen Levelshifter oder einen Spannungsteiler (z.B. 2 kΩ / 1 kΩ) setzen.
  • AUX, RX und TX benötigen einen Pull-up-Widerstand.
  • Beispielschaltungen für andere MCU-Boards findet ihr in den Tutorials von Renzo Mischianti.
  • Als Antenne für die von mir getesteten Module E220-900T22D und E32-433T30D kamen Standantennen für 868 MHz bzw. 433 MHz zum Einsatz. Diese gibt es für < 10 € in Online-Shops.

So sah mein Aufbau auf dem Breadboard aus:

LoRa E220-Modul am Arduino Nano auf dem Breadboard
LoRa E220-Modul am Arduino Nano auf dem Breadboard

Einstellungen

Einstellungssketch am Beispiel der E220-Modulreihe

Die Bibliotheken sind mit separaten Beispielsketchen für die Einstellung und den Betrieb der Module ausgestattet. Mit setConfiguration.ino nehmt ihr die Einstellungen vor und mit getConfiguration.ino fragt ihr sie ab. Diese Einstellungen bleiben auch bei Trennung von der Stromversorgung erhalten, sofern ihr beim Speichern der Konfiguration den Parameter WRITE_CFG_PWR_DWN_SAVE wählt (Zeile 62 im nächsten Sketch).

Wenn ihr setConfiguration.ino öffnet, dann seid ihr vielleicht von seinem Umfang erschlagen. Der größte Teil ist aber auskommentiert und die viele Dinge wiederholen sich. So finden sich im oberen Teil verschiedene Beispiele zur Objekterstellung für verschiedene Boards. Im mittleren Teil gibt es vorgefertigte Konfigurationsbeispiele, die ihr bequem entkommentieren könnt. Am Ende finden sich die Funktionen zum Ausgeben der Einstellungen. 

Ich habe setConfiguration.ino (E220-Modul) auf das Wesentliche für die Verwendung auf einem Arduino Nano reduziert. Einige Zeilen habe ich aber auch zugefügt:

  • Die Zeilen 1 bis 5 dienen der Ausgabe der richtigen Frequenz. Entkommentiert die Zeile mit dem richtigen Frequenzbereich.
  • Die Zeilen 6 und 7 sind für die Auswahl der Signalstärke relevant.
  • Zeile 8 sorgt dafür, dass die Einstellungen detailliert ausgegeben werden.
  • Die Zeilen 57 und 58 erlauben es euch, eure Nachrichten individuell zu verschlüsseln.
// #define FREQUENCY_433 // default value without set 
// #define FREQUENCY_170
// #define FREQUENCY_470
#define FREQUENCY_868
// #define FREQUENCY_915
// #define E220_22 // default value without set 
// #define E220_30 // uncomment in case you use an E220...T30D or E220...T30S
#define LoRa_E220_DEBUG  // for printing the settings
#include "LoRa_E220.h"

SoftwareSerial mySerial(4, 5); // Arduino RX <-- e220 TX, Arduino TX --> e220 RX
LoRa_E220 e220ttl(&mySerial, 3, 7, 6); // AUX M0 M1
// LoRa_E220 e220ttl(4, 5, 3, 7, 6); // alternative function to create the LoRa_E220 object

void printParameters(struct Configuration configuration);
void printModuleInformation(struct ModuleInformation moduleInformation);

void setup() {
  Serial.begin(9600);
  while(!Serial){};
  delay(500);

  Serial.println();


  // Startup all pins and UART
  e220ttl.begin();

  ResponseStructContainer c;
  c = e220ttl.getConfiguration();
  // It's important get configuration pointer before all other operation
  Configuration configuration = *(Configuration*) c.data;
  Serial.println(c.status.getResponseDescription());
  Serial.println(c.status.code);

  printParameters(configuration);

//	----------------------- DEFAULT TRANSPARENT ----------------------- 
  configuration.ADDL = 0x02;  // Low byte of address
  configuration.ADDH = 0x00; // High byte of address

  configuration.CHAN = 18; // 868 MHz for Exxx-900 modules, choose 23 for Exxx-400 to set 433 MHz 

  configuration.SPED.uartBaudRate = UART_BPS_9600; // Serial baud rate
  configuration.SPED.airDataRate = AIR_DATA_RATE_010_24; // Air baud rate
  configuration.SPED.uartParity = MODE_00_8N1; // Parity bit

  configuration.OPTION.subPacketSetting = SPS_200_00; // Packet size
  configuration.OPTION.RSSIAmbientNoise = RSSI_AMBIENT_NOISE_DISABLED; // Need to send special command
  configuration.OPTION.transmissionPower = POWER_22; // Device power

  configuration.TRANSMISSION_MODE.enableRSSI = RSSI_DISABLED; // Enable RSSI info
  configuration.TRANSMISSION_MODE.fixedTransmission = FT_TRANSPARENT_TRANSMISSION; // Transmission mode
  configuration.TRANSMISSION_MODE.enableLBT = LBT_DISABLED; // Check interference
  configuration.TRANSMISSION_MODE.WORPeriod = WOR_2000_011; // WOR timing

  configuration.CRYPT.CRYPT_H = 0x00;  // encryption high byte, default: 0x00
  configuration.CRYPT.CRYPT_L = 0x00;  // encryption low byte, default: 0x00

  /* Set configuration changed and set to hold the configuration; chose 
WRITE_CFG_PWR_DWN_LOSE to not save the configuration permanently */
  ResponseStatus rs = e220ttl.setConfiguration(configuration, WRITE_CFG_PWR_DWN_SAVE);
  Serial.println(rs.getResponseDescription());
  Serial.println(rs.code);

  c = e220ttl.getConfiguration();
  // It's important get configuration pointer before all other operation
  configuration = *(Configuration*) c.data;
  Serial.println(c.status.getResponseDescription());
  Serial.println(c.status.code);

  printParameters(configuration);
  c.close();
}

void loop() {

}
void printParameters(struct Configuration configuration) {
  DEBUG_PRINTLN("----------------------------------------");

  DEBUG_PRINT(F("HEAD : "));  DEBUG_PRINT(configuration.COMMAND, HEX);DEBUG_PRINT(" ");DEBUG_PRINT(configuration.STARTING_ADDRESS, HEX);DEBUG_PRINT(" ");DEBUG_PRINTLN(configuration.LENGHT, HEX);
  DEBUG_PRINTLN(F(" "));
  DEBUG_PRINT(F("AddH : "));  DEBUG_PRINTLN(configuration.ADDH, HEX);
  DEBUG_PRINT(F("AddL : "));  DEBUG_PRINTLN(configuration.ADDL, HEX);
  DEBUG_PRINTLN(F(" "));
  DEBUG_PRINT(F("Chan : "));  DEBUG_PRINT(configuration.CHAN, DEC); DEBUG_PRINT(" -> "); DEBUG_PRINTLN(configuration.getChannelDescription());
  DEBUG_PRINTLN(F(" "));
  DEBUG_PRINT(F("SpeedParityBit     : "));  DEBUG_PRINT(configuration.SPED.uartParity, BIN);DEBUG_PRINT(" -> "); DEBUG_PRINTLN(configuration.SPED.getUARTParityDescription());
  DEBUG_PRINT(F("SpeedUARTDatte     : "));  DEBUG_PRINT(configuration.SPED.uartBaudRate, BIN);DEBUG_PRINT(" -> "); DEBUG_PRINTLN(configuration.SPED.getUARTBaudRateDescription());
  DEBUG_PRINT(F("SpeedAirDataRate   : "));  DEBUG_PRINT(configuration.SPED.airDataRate, BIN);DEBUG_PRINT(" -> "); DEBUG_PRINTLN(configuration.SPED.getAirDataRateDescription());
  DEBUG_PRINTLN(F(" "));
  DEBUG_PRINT(F("OptionSubPacketSett: "));  DEBUG_PRINT(configuration.OPTION.subPacketSetting, BIN);DEBUG_PRINT(" -> "); DEBUG_PRINTLN(configuration.OPTION.getSubPacketSetting());
  DEBUG_PRINT(F("OptionTranPower    : "));  DEBUG_PRINT(configuration.OPTION.transmissionPower, BIN);DEBUG_PRINT(" -> "); DEBUG_PRINTLN(configuration.OPTION.getTransmissionPowerDescription());
  DEBUG_PRINT(F("OptionRSSIAmbientNo: "));  DEBUG_PRINT(configuration.OPTION.RSSIAmbientNoise, BIN);DEBUG_PRINT(" -> "); DEBUG_PRINTLN(configuration.OPTION.getRSSIAmbientNoiseEnable());
  DEBUG_PRINTLN(F(" "));
  DEBUG_PRINT(F("TransModeWORPeriod : "));  DEBUG_PRINT(configuration.TRANSMISSION_MODE.WORPeriod, BIN);DEBUG_PRINT(" -> "); DEBUG_PRINTLN(configuration.TRANSMISSION_MODE.getWORPeriodByParamsDescription());
  DEBUG_PRINT(F("TransModeEnableLBT : "));  DEBUG_PRINT(configuration.TRANSMISSION_MODE.enableLBT, BIN);DEBUG_PRINT(" -> "); DEBUG_PRINTLN(configuration.TRANSMISSION_MODE.getLBTEnableByteDescription());
  DEBUG_PRINT(F("TransModeEnableRSSI: "));  DEBUG_PRINT(configuration.TRANSMISSION_MODE.enableRSSI, BIN);DEBUG_PRINT(" -> "); DEBUG_PRINTLN(configuration.TRANSMISSION_MODE.getRSSIEnableByteDescription());
  DEBUG_PRINT(F("TransModeFixedTrans: "));  DEBUG_PRINT(configuration.TRANSMISSION_MODE.fixedTransmission, BIN);DEBUG_PRINT(" -> "); DEBUG_PRINTLN(configuration.TRANSMISSION_MODE.getFixedTransmissionDescription());


  DEBUG_PRINTLN("----------------------------------------");
}
void printModuleInformation(struct ModuleInformation moduleInformation) {
  Serial.println("----------------------------------------");
  DEBUG_PRINT(F("HEAD: "));  DEBUG_PRINT(moduleInformation.COMMAND, HEX);DEBUG_PRINT(" ");DEBUG_PRINT(moduleInformation.STARTING_ADDRESS, HEX);DEBUG_PRINT(" ");DEBUG_PRINTLN(moduleInformation.LENGHT, DEC);

  Serial.print(F("Model no.: "));  Serial.println(moduleInformation.model, HEX);
  Serial.print(F("Version  : "));  Serial.println(moduleInformation.version, HEX);
  Serial.print(F("Features : "));  Serial.println(moduleInformation.features, HEX);
  Serial.println("----------------------------------------");
}

 

Beim Herumprobieren kann es etwas nerven, die Einstellungen über einen separaten Sketch einzustellen, auch wenn das ressourcensparend ist. Vielleicht möchtet ihr die Einstellungen lieber direkt in den Sketchen vornehmen, die ihr auch zur Ansteuerung benutzt? Und vielleicht möchtet ihr den Überblick über alle Einstellungsoptionen haben? Dann schaut für die E220-Reihe in den Anhang 1.

Einstellungssketche für die E22- und die E32-Reihe

Im Anhang 2 und Anhang 3 findet ihr die Pendants zum Anhang 1 für die E22- bzw. E32-Reihe.  Die Sketche geben auch einen guten Überblick über die Unterschiede der verschiedenen Modulreihen.

Einstellungen im Detail

Adresse und Kanal (configuration)

Jedes LoRa Modul hat eine Adresse, die sich aus dem höheren Byte ADDH und dem niedrigeren Byte ADDL zusammensetzt. Damit könnt ihr 65536 Adressen einstellen. Die Zuweisung der Adresse erfolgt über configuration.ADDL = ... bzw. configuration.ADDH = ....

Die von mir getesteten Module decken die Frequenzen 850 – 930 MHz bzw. 410 bis 493 MHz ab. Die Feineinstellung erfolgt über den Kanal. Die Formel für die Frequenz ν lautet:

    \[ \nu_{Exxx-900}\; \text{[MHz]} = 850.125\ + \text{\it{CHANNEL}} \]

    \[ \nu_{Exxx-400}\; \text{[MHz]} = 410.125 + \text{\it{CHANNEL}} \]

Bei den Exxx-900 Modulen stellt ihr also mit configuration.CHAN = 18 die Frequenz 868.125 MHz ein. Bei den Exxx-400 Modellen bekommt ihr 433.125 MHz mit configuration.CHAN = 23.

Hier besteht die Gefahr, dass ihr durch die falsche Auswahl auf einer in eurem Land unzulässigen Frequenz sendet. Ich sag’s ja nur.

Eine Überprüfung mit einem tinySA Spectrum Analyzer ergab, im Rahmen der Genauigkeit dieses Gerätes, eine gute Übereinstimmung mit der Zielfrequenz. Hier das Ergebnis für Kanal 0, 18 und 80 eines E220-900T22D Moduls:

Überprüfung der Sendefrequenz E220-900T22D für Kanal 0, 18 und 80
Überprüfung der Sendefrequenz für Kanal 0, 18 und 80 -> 850.13 / 868.20 / 930.12 MHz

Das Prinzip der Kanaleinstellung ist für alle Module identisch.

Übertragungsrate und -modalitäten (configuration.SPED)

Folgende Parameter könnt ihr für die UART Kommunikation und die Datenübertragung über die Luft einstellen (Beispiel E220):

  • uartBaudRate: Baudrate UART_BPS_xxx
    • xxx = 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200
  • airDataRate: Datenrate bei Funkübertragung AIR_DATA_RATE_xxx
    • AIR_DATA_RATE_010_24: 2.4 kbit/s (default)
    • AIR_DATA_RATE_011_48: 4.8 kbit/s
    • AIR_DATA_RATE_100_96: 9.6 kbit/s
    • AIR_DATA_RATE_101_192: 19.2 kbit/s
    • AIR_DATA_RATE_110_384: 38.4 kbit/s
    • AIR_DATA_RATE_111_625: 62.5 kbit/s
  • uartParity: Parität MODE_xxx;
    • MODE_00_8N1: none (default)
    • MODE_01_8O1: odd
    • MODE_10_8E1: even

Für die E22- und 32-Reihe weichen die Optionen für die airDataRate ab. Siehe Anhang 2 und 3.

Zur Datenrate über Funk ist noch zu sagen: je kleiner die Datenrate, desto höher die maximale Reichweite.

Weitere Übertragungsoptionen (configuration.OPTION)

Weitere Optionen (Beispiel E220):

  • subPacketSetting: Maximale Datenpaketgröße, d. h. die maximale Länge eurer Nachricht, die ihr in einem Stück ununterbrochen versenden könnt.
    • SPS_200_00: 200 Byte
    • SPS_128_01: 128 Byte
    • SPS_064_10: 64 Byte
    • SPS_032_11: 32 Byte
  • RSSIAmbientNoise: RSSI (Received Signal Strength Indicator) Ambient Noise enable
    • RSSI_AMBIENT_NOISE_DISABLED: Funktion ist abgeschaltet
    • RSSI_AMBIENT_NOISE_ENABLED: Funktion ist angeschaltet
  • transmissionPower: Sendeleistung POWER_xx mit xx = Leistung in dbm. Die zulässigen Einstellungen sind modellabhängig.
    • xx für E220….22D: 22, 17, 13, 10
    • xx für E220….30D: 30, 27, 24, 21

Die Einstellungen subPacketSetting und transmissionPower weichen bei der E22- und E32-Reihe ab (siehe Anhang 2 und 3). RSSIAmbientNoise ist auf dem E32-Modul nicht verfügbar.

Modus-Einstellungen (configuration.TRANSMISSION_MODE)

Auf einige dieser Einstellungen komme ich später zurück. Hier die Optionen für die E220-Reihe:

  • enableRSSI: Signalstärkeninformation (Received Signal Strength Indication)
    • RSSI_DISABLED: deaktiviert
    • RSSI_ENABLED: aktiviert
  • fixedTransmission: Übertragungsmodus
    • FT_FIXED_TRANSMISSION: Senden an eine bestimmte Adresse / Kanal.
    • FT_TRANSPARENT_TRANSMISSION: Senden an alle Module mit identischer Adresse und Kanal.
  • enableLBT: LBT (Listen Before Talk) ist eine Funktion, die bewirkt, dass das Modul mit dem Senden bis zu zwei Sekunden abwartet, dass ein günstiger Moment (mit geringen Interferenzen) gekommen ist.
    • LBT_DISABLED: Funktion deaktiviert
    • LBT_ENABLED: Funktion aktiviert
  • WORPeriod: WOR (Wake On Radio) Periode WOR_xxx_yyy mit xxx = Aufwachperiode in Millisekunden
    • xxx_yyy = 500_000, 1000_001, 1500_010, 2000_011, 2500_100, 3000_101, 3500_110, 4000_111

Der Parameter WORPeriod braucht noch ein wenig Erklärung. Es handelt sich dabei um die Periode, nach der der Receiver jeweils aufwacht, um zu prüfen, ob eine Nachricht kommt. Der Sender weiß natürlich nicht, wann der Empfänger wach ist und sendet deshalb eine „Präambel“ mit der Länge der Aufwachperiode. Der WOR Receiver bleibt dann so lange wach, bis die eigentliche Nachricht kommt. Aus diesem Grund müssen der WOR Receiver und der WOR Transmitter dieselbe WORPeriod eingestellt haben.

Die WORPeriod heißt bei der E32-Serie wirelessWakeUpTime. Auch die auswählbaren Zeiten sind abweichend. Die Einstellungen enableRSSI und enableLBT stehen auf den E32-Modulen gar nicht zur Verfügung.

Verschlüsselung (configuration.CRYPT)

Alle Module verschlüsseln die Nachrichten. Allerdings lassen nur die Module der Reihen E22 und E220 eine individuelle Verschlüsselung zu. Dazu legt ihr Werte für die beiden Bytes CRYPT_H und CRYPT_L fest. Die Einstellung muss beim Transmitter und beim Empfänger natürlich identisch sein. Auf dem E32 wird mit einer fest eingestellten Verschlüsselung gearbeitet.

Response Container und Response Status

Bevor es endlich losgeht, muss ich noch zwei in der Bibliothek definierte Strukturen erklären, und zwar ResponseContainer und ResponseStatus. Sie beinhalten Informationen über die ein- und ausgehenden Nachrichten.

Der ResponseContainer enthält die eigentliche Nachricht data, den Signalstärkenwert rssi, und den ResponseStatus status.

struct ResponseContainer {
  String data;
  byte rssi; // only E22 and E220 series!
  ResponseStatus status;
};

Der ResponseStatus ist auch wieder eine Struktur. Sie beinhaltet den Fehlercode code und die Funktion getResponseDescription(), die einen String zurückgibt, der den Code verständlich übersetzt. Der Fehlercode 1 (E220_SUCCESS) bedeutet beispielsweise „Success“, also Erfolg.

struct ResponseStatus {
  Status code;
  String getResponseDescription() {
    return getResponseDescriptionByParams(this->code);
  }
};

Transparent Transmission Mode

Nun aber zum ersten Sketch. Dabei lassen wir mehrere (mind. zwei) Module im „Transparent Transmission Modus“ miteinander kommunizieren. In diesem Modus könnt ihr alle LoRa Module erreichen, die dieselbe Adresse und denselben Kanal eingestellt haben:

Schema für Transparent Transmission Mode
Schema für Transparent Transmission Mode

Um den transparenten Modus auszuprobieren, solltet ihr an den Einstellungen normalerweise keine Änderungen vornehmen müssen. Falls ihr aber Probleme haben solltet, dann bringt die Module mit setConfiguration_modified.ino in den richtigen Zustand.

Dann ladet den Sketch lora_transparent.ino auf die Mikrocontrollerboards. Ggf. müsst ihr für eure Boards die Zeilen 3 und 4 anpassen. Schaut in die Originalbeispielsketche der Bibliothek – da gibt es viele vorgefertigte Einstellungen für verschiedene Boards. 

Bei den meisten Beispielen brauchen wir für jedes Board einen eigenen seriellen Monitor. Mit der alten Arduino IDE 1.x war das recht simpel, indem man die IDE einfach mehrfach aufrief, also mehrere Instanzen schuf und für jede Instanz einen eigenen seriellen Port auswählte. Die IDE 2.x macht das nicht so ohne Weiteres. Hier könnt ihr euch behelfen, indem ihr den Sketch unter verschiedenen Namen speichert, die Versionen öffnet und dann für jeden Sketch einen eigenen Port einstellt. 

#include "LoRa_E220.h"
 
SoftwareSerial mySerial(4,5);
LoRa_E220 e220ttl(&mySerial, 3, 7, 6); // AUX M0 M1
 
void setup() {
  Serial.begin(9600);
  delay(500);
 
  Serial.println("Hi, I'm going to send message!");
 
  // Startup all pins and UARTD
  e220ttl.begin();
 
  // Send message
  ResponseStatus rs = e220ttl.sendMessage("Hello, world?");
  // Check if there is some problem of successfully send
  Serial.println(rs.getResponseDescription());
}
 
void loop() {
    // If something available
  if (e220ttl.available()>1) {
      // read the String message
    ResponseContainer rc = e220ttl.receiveMessage();
    // Is something goes wrong print error
    if (rc.status.code!=1){
        Serial.println(rc.status.getResponseDescription());
    }else{
        // Print the data received
        Serial.println(rc.data);
    }
  }
  if (Serial.available()) {
      String input = Serial.readString();
      e220ttl.sendMessage(input);
  }
}

 

Abgesehen von der einzubindenden Bibliothek und der Objekterstellung (Zeile 4) funktioniert der Sketch genauso mit den E22- und E32-Boards.

Erläuterungen zu lora_transparent.ino

Zunächst erzeugt ihr das Objekt e220ttl und initialisiert euer Modul mit e220ttl.begin().

Ihr versendet Nachrichten mit der Funktion sendMessage(). Wie ihr seht, gebt ihr im transparenten Modus keine Adresse und keinen Kanal an. Das Modul sendet automatisch an die Module mit denselben Einstellungen. Der Rückgabewert der Funktion sendMessage() ist eine Struktur vom Typ ResponseStatus, die ich weiter oben erläutert habe. Mittels getResponseDescription() bekommt ihr eine lesbare Übersetzung des Status Codes. Im Idealfall ist das „Success“. „Success“ bedeutet aber nur, dass die Nachricht erfolgreich rausging und nicht, dass sie auch empfangen wurde.

Ob eine Nachricht eingegangen ist, prüft ihr auf der Receiverseite mit e220ttl.available(). Ihr lest die Nachricht mit receiveMessage(). Genauer gesagt gibt receiveMessage() eine Struktur vom Typ ResponseContainer zurück, die die eigentliche Nachricht im Element data enthält.

Der ResponseContainer „rc“ enthält wiederum den ResponseStatus „rc.status“. Ihr prüft mit

if (rc.status.code != 1) {....

ob ein Fehler aufgetreten ist. Vielleicht wäre die Variante

if (rc.status.getResponseDescription() = "Success") {... 

etwas verständlicher, aber ich wollte nah an den Originalsketchen der Bibliotheken bleiben.

Wenn alles OK ist, wird die Nachricht ausgegeben, falls nicht, erscheint die entsprechende Fehlermeldung.

Mit if (Serial.available(){... prüft ihr, ob eine Eingabe über den seriellen Monitor erfolgt ist. Ist das der Fall, wird die Eingabe gelesen und versendet.

Ausgabe lora_transparent.ino

Ich habe drei Module verwendet. Unten seht ihr die Ausgabe des zuerst aktivierten Moduls. Die zwei „Hello, world?“ Nachrichten wurden über das Setup der anderen Module versendet. Die zwei anderen Nachrichten habe ich „manuell“ von den anderen Modulen mittels Eingabe im seriellen Monitor versendet.

Ausgabe lora_transparent. ino
Ausgabe lora_transparent. ino

Strukturen senden und empfangen

In den meisten Fällen wollt ihr wahrscheinlich keine Zeichenketten übermitteln, sondern Daten, wie z. B. die einer Wetterstation. Im folgenden Beispiel senden wir alle fünf Sekunden die Luftfeuchte (integer), die Temperatur (float) den Regenstatus (bool). Um diese Daten als „Paket“ zu versenden, definieren wir die Struktur weatherData.

Für dieses Beispiel bleiben wir noch im transparenten Modus. Die beiden Sketche für den Transmitter und Receiver müssen für die E22- und E32-Module nur hinsichtlich der einzubindenden Bibliothek und der Objekterstellung geändert werden.

Transmitter

Der Sketch für den Transmitter sollte weitgehend selbsterklärend sein:

#include "LoRa_E220.h"
 
SoftwareSerial mySerial(4,5);
LoRa_E220 e220ttl(&mySerial, 3, 7, 6); // AUX M0 M1

struct weatherData {
  int humidity;
  float temperature;
  bool rain;
};

weatherData currentWeather = {50, 20.0, false};
 
void setup() {
  Serial.begin(9600);
  delay(500);
 
  Serial.println("Hi, I'm going to send message!");
 
  // Startup all pins and UARTD
  e220ttl.begin();
 
  // Send message
  ResponseStatus rs = e220ttl.sendMessage("Hello, world?");
  // Check if there is some problem of successfully send
  Serial.println(rs.getResponseDescription());
}
 
void loop() {
  static unsigned long lastSend = millis(); 
  if(millis() - lastSend > 5000){
      currentWeather.humidity = 30;
      currentWeather.temperature = 23.7;
      currentWeather.rain = false; 
      e220ttl.sendMessage(&currentWeather, sizeof(currentWeather));
      lastSend = millis();
  }
}

 

In Bezug auf den Sendevorgang ist der einzige Unterschied zum vorherigen Sketch, dass wir sendMessage() keinen String, sondern eine Struktur (als Referenz mit „&“) und die Größe der Struktur übergeben.

Receiver

Um die zu empfangende Struktur verarbeiten zu können, verwenden wir anstelle des ResponseContainer die Struktur ResponseStructContainer, die folgendermaßen definiert ist:

struct ResponseStructContainer {
  void *data;
  byte rssi;
  ResponseStatus status;
  void close() {
    free(this->data);
  }
};

Der Datentyp void* ist ein untypisierter Zeiger, der vielen vielleicht nicht geläufig ist. Im Gegensatz zu den gewohnten Zeigern wie etwa int* muss ihm seine Bedeutung, also der Datentyp, erst zugewiesen werden.

Hier erst einmal der Sketch:

#include "LoRa_E220.h"
 
SoftwareSerial mySerial(4,5);
LoRa_E220 e220ttl(&mySerial, 3, 7, 6); // AUX M0 M1

struct weatherData {
  int humidity;
  float temperature;
  bool rain;
};
 
void setup() {
  Serial.begin(9600);
  delay(500);
 
  Serial.println("Hi, waiting for weather data...");
  // Startup all pins and UARTD
  e220ttl.begin();
}
 
void loop() {
  if (e220ttl.available()>1) {
      // read the String message
    ResponseStructContainer rsc = e220ttl.receiveMessage(sizeof(weatherData));
    weatherData currentWeather = *(weatherData*) rsc.data;
    Serial.print("Humidity     [%]: ");
    Serial.println(currentWeather.humidity);
    Serial.print("Temperature [°C]: ");
    Serial.println(currentWeather.temperature);
    Serial.print("Rain            : ");
    if(currentWeather.rain){
      Serial.println("yes");
    }
    else{
      Serial.println("no");
    }
    Serial.println();
  }
}

 

Die Zeile:

ResponseStructContainer rsc = e220ttl.receiveMessage(sizeof(weatherData));

liest die empfangene Nachricht und speichert sie im ResponseStructContainer „rsc“. Zu beachten ist, dass wir receiveMessage() die Größe des erwarteten Datenpaketes übergeben müssen.

Die eigentlichen Daten sind als Datentyp void* in rsc.data abgelegt. Um damit etwas anfangen zu können, wandeln wir den Datentyp void* mit (weatherData*) in einen Zeiger um, der auf die Struktur vom Typ weatherData zeigt. Um die Daten in der Struktur currentWeather zu speichern, müssen wir den Zeiger mit einem weiteren * dereferenzieren. Also:

weatherData currentWeather = *(weatherData*) rsc.data;

Fehlt noch die Ausgabe. Sie ist natürlich etwas langweilig, weil wir immer dieselben Daten senden. Aber es geht ja hier nur um das Prinzip.

Ausgabe lora_struct_receiver.ino

Fixed Transmission Mode

Ihr stellt den Fixed Transmission Mode ein, indem ihr im Sketch setConfiguration_modified.ino die Zeile

configuration.TRANSMISSION_MODE.fixedTransmission = FT_TRANSPARENT_TRANSMISSION;

abändert in:

configuration.TRANSMISSION_MODE.fixedTransmission = FT_FIXED_TRANSMISSION;

Im Fixed Transmission Mode gibt es zwei Optionen für das Versenden von Nachrichten:

  1. Exklusives Senden an die Module mit einer bestimmten Adresse auf einem bestimmten Kanal:
    • Funktion: sendFixedMessage(ADDH, ADDL, channel, message);
    • Das sendende Modul selbst darf eine abweichende Adresse und einen anderen Kanal eingestellt haben.
  2. Senden an alle Module auf einem bestimmten Kanal, unabhängig von ihrer Adresse („Broadcasting“):
    • Funktion: sendBroadcastFixedMessage(channel, message)
      • das entspricht: sendFixedMessage(0xFF, 0xFF, channel, message), da 0xFFFF die Broadcasting-Adresse ist.
    • Auch hier darf das sendende Modul einen abweichenden Kanal eingestellt haben.

Zu Verdeutlichung habe ich zwei Schemata dazu. Hier zunächst für das Senden an eine bestimmte Adresse:

LoRa E220: Schema für Fixed Transmission Mode
Schema für Fixed Transmission Mode

Und hier das Schema für das Broadcasting im Fixed Transmission Mode:

LoRa E220: Schema für Broadcast Nachricht im Fixed Transmission Mode
Schema für Broadcasting im Fixed Transmission Mode

Beispielsketch Fixed Transmission Mode

Um den Fixed Transmission Mode auszuprobieren, habe ich drei Module mit den folgenden Einstellungen verwendet:

  1. ADDH = 0x00, ADDL = 0x01, Channel = 18
  2. ADDH = 0x00, ADDL = 0x02, Channel = 18
  3. ADDH = 0x00, ADDL = 0x03, Channel = 18

Auf die drei steuernden Arduinos habe ich den folgenden Sketch hochgeladen, wobei ich lediglich die Begrüßungsformel in Zeile 16 und die Switch-Konstruktion ab Zeile 38 angepasst habe.

Der Sketch erlaubt es, über den seriellen Monitor eingegebene Nachrichten an bestimmte Adressen zu versenden (Eingabe: „x,Nachricht“ mit x = 1,2,3) oder per Broadcasting an alle Module (Eingabe: „18,Nachricht“). 

Der Sketch muss für die Verwendung auf E22- und E32-Modulen nur hinsichtlich der Bibliothek und der Objekterstellung angepasst werden. 

#include "LoRa_E220.h"

SoftwareSerial mySerial(4, 5); // Arduino RX <-- e220 TX, Arduino TX --> e220 RX
LoRa_E220 e220ttl(&mySerial, 3, 7, 6); // AUX M0 M1
 
void setup() {
  Serial.begin(9600);
  delay(500);
 
  Serial.println("Hi, I'm going to send message!");
 
  // Startup all pins and UART
  e220ttl.begin();
 
  // Send message
  ResponseStatus rs = e220ttl.sendBroadcastFixedMessage(18,"Hi to all receivers! This is no. 1"); // adjust
  // Check If there is some problem of successfully send
  Serial.println(rs.getResponseDescription());
}
 
void loop() {
    // If something available
  if (e220ttl.available()>1) {
      // read the String message
    ResponseContainer rc = e220ttl.receiveMessage();
    // Is something goes wrong print error
    if (rc.status.code!=1){
        Serial.println(rc.status.getResponseDescription());
    }else{
        // Print the data received
        Serial.println(rc.data);
    }
  }
  if (Serial.available()) {
    int addr = Serial.parseInt();
    String input = Serial.readString();
    input = input.substring(input.indexOf(",")+1);
    switch(addr){
      case 2:
        e220ttl.sendFixedMessage(0,2,18,input);
        break;
      case 3:
        e220ttl.sendFixedMessage(0,3,18,input);
        break;
      case 18:
        e220ttl.sendBroadcastFixedMessage(18,input);
        break;
      default:
        e220ttl.sendBroadcastFixedMessage(18,input);
    }
  }
}

 

Hier die Ausgabe von Modul 3 (ADDL = 3). Um die Begrüßungen („Hi to all Receivers! …“) der anderen Module zu erhalten, musste es vor ihnen initialisiert werden.

Ausgabe

Natürlich lassen sich auch im Fixed Transmission Mode Strukturen versenden. Ich versuche aber meine Beispiele einfach zu halten und auf das gerade relevante Thema zu beschränken.

RSSI Received Signal Strength Indicator

Da die RSSI Funktion auf den E32-Modulen nicht zur Verfügung steht, gilt dieser Abschnitt nur für die E22- und E220-Module. 

Der RSSI ist eine dimensionslose Zahl vom Typ byte, die euch mitteilt, wie stark das empfangene Signal war. Die Zahl lässt sich nicht direkt in eine Signalstärke in dBm übersetzen. Um den RSSI auslesen zu können, müsst ihr lediglich auf der Receiverseite receiveMessage() durch ReceiveMessageRSSI() ersetzen, also beispielsweise:

ResponseContainer rc = e220ttl.receiveMessageRSSI();

Hier ein Beispielsketch:

#include "LoRa_E220.h"
 
SoftwareSerial mySerial(4,5);
LoRa_E220 e220ttl(&mySerial, 3, 7, 6); // AUX M0 M1
 
void setup() {
  Serial.begin(9600);
  delay(500);
 
  Serial.println("Hi, I'm going to send message!");
 
  // Startup all pins and UART
  e220ttl.begin();
 
  // Send message
  ResponseStatus rs = e220ttl.sendFixedMessage(0,2,18,"Hello, world?");
  // Check If there is some problem of successfully send
  Serial.println(rs.getResponseDescription());
}
 
void loop() {
    // If something available
  if (e220ttl.available()>1) {
      // read the String message
    ResponseContainer rc = e220ttl.receiveMessageRSSI();
    // Is something goes wrong print error
    if (rc.status.code!=1){
        Serial.println(rc.status.getResponseDescription());
    }else{
        // Print the data received
        String output = rc.data;
        byte rssiVal =  rc.rssi;
        Serial.println(rc.data);
        Serial.print("RSSI: ");
        Serial.println(rc.rssi);
    }
  }
  if (Serial.available()) {
      String input = Serial.readString();
      e220ttl.sendFixedMessage(0,2,18,input);
  }
}

 

Für die folgende Receiver-Ausgabe habe ich zwei Module auf meinem Schreibtisch platziert und zwei Nachrichten versendet. Bei der ersten Nachricht habe ich bei beiden Modulen eine kleine Standantenne verwendet. Vor dem Versenden der zweiten Nachricht habe ich die Antenne auf der Receiverseite entfernt. Wie man sieht, ist die empfangene Signalstärke entsprechend heruntergegangen. Wie ihr auch seht, hat der RSSI nur bedingt etwas mit der eigentlichen Signalstärke zu tun, denn die ist ja in beiden Fällen gleich.

Ausgabe lora_fixed_rssi.ino
Ausgabe lora_fixed_rssi.ino

Wake On Radio (WOR) nutzen

Der Stromverbrauch der LoRa Modulserien E220, E22 und E32 kann erheblich reduziert werden, wenn man sie im WOR-Modus („Wake On Radio“) betreibt. Wie zuvor erwähnt müssen Transmitter und Receiver dieselbe WOR Periode eingestellt haben. 

WOR-Transmitter

Das Einzige, was ihr auf der Transmitterseite zusätzlich einstellen müsst, ist der WOR-Transmitter Modus:

e220ttl.setMode(MODE_1_WOR_TRANSMITTER);

Das macht ihr direkt in eurem Anwendungssketch, d. h. nicht über den Einstellungssketch. Trotz seiner Rolle als WOR-Transmitter kann das Modul auch Nachrichten empfangen.

Hier der Sketch für den WOR-Transmitter:

#include "LoRa_E220.h"

SoftwareSerial mySerial(4, 5); // Arduino RX <-- e220 TX, Arduino TX --> e220 RX
LoRa_E220 e220ttl(&mySerial, 3, 7, 6); // AUX M0 M1

void setup() {
  Serial.begin(9600);
  delay(500);
 
  Serial.println("Hi, I'm going to send a WOR message!");
 
  e220ttl.begin();
  e220ttl.setMode(MODE_1_WOR_TRANSMITTER);
 
  // Send message
  ResponseStatus rs = e220ttl.sendFixedMessage(0,2,18,"Hello, world? WOR!");
  // Check If there is some problem of successfully send
  Serial.println(rs.getResponseDescription());
}
 
void loop() {
    // If something available
  if (e220ttl.available()>1) {
      // read the String message
    ResponseContainer rc = e220ttl.receiveMessage();
    // Is something goes wrong print error
    if (rc.status.code!=1){
       Serial.println(rc.status.getResponseDescription());
    }else{
        // Print the data received
        Serial.println(rc.data);
    }
  }
  if (Serial.available()) {
      String input = Serial.readString();
      e220ttl.sendFixedMessage(0,2,18,input);
  }
}

 

Fehlt noch die Ausgabe. Wie ihr unten seht, bekommt der Transmitter eine Empfangsbestätigung. Das ist keine Eigenschaft des WOR-Modus, sondern ein Feature des Receiversketches, zu dem wir gleich kommen.

Ausgabe lora_wor_transmitter.ino
Ausgabe lora_wor_transmitter.ino

Anstelle von setMode(MODE_1_WOR_TRANSMITTER) verwendet ihr bei den E32-Modulen setMode(MODE_1_WAKE_UP). Bei den E22-Modulen stellt ihr den Modus MODE_1_WOR im Sketch ein und legt die Rolle als WOR Transmitter über den Einstellungssketch fest. 

WOR-Receiver

Den WOR-Receivermodus stellt ihr folgendermaßen ein:

e220ttl.setMode(MODE_2_WOR_RECEIVER);

Um die schon erwähnte Empfangsbestätigung zurückschicken zu können, müsst ihr den Receiver zwischenzeitlich mit e220ttl.setMode(MODE_0_NORMAL); in den normalen Modus bringen.

Den hier eingefügten Interrupt, der durch die fallende Flanke des AUX-Pins ausgelöst wird, braucht ihr nicht unbedingt. Er wird lediglich genutzt, um die Ausgabe der eingegangenen Nachricht über den TX-Pin anzukündigen. Hier das Schema für das Verhalten von AUX-Pin und TX-Pin:

AUX-Pin vs. TX-Pin bei der Ausgabe einer Nachricht über TX
AUX-Pin vs. TX-Pin bei der Ausgabe einer Nachricht über TX
#include "LoRa_E220.h"
#define AUX_PIN 3
volatile bool interruptExecuted = false;
 
SoftwareSerial mySerial(4, 5); // Arduino RX <-- e220 TX, Arduino TX --> e220 RX
LoRa_E220 e220ttl(&mySerial, AUX_PIN, 7, 6); // AUX M0 M1


void wakeUp() {
  interruptExecuted = true;
  //detachInterrupt(digitalPinToInterrupt(AUX_PIN));
}

void setup() {
  Serial.begin(9600);
  delay(500);
 
  e220ttl.begin();
  e220ttl.setMode(MODE_2_WOR_RECEIVER);

  Serial.println("Start sleep!");
  delay(100);
  attachInterrupt(digitalPinToInterrupt(AUX_PIN), wakeUp, FALLING);
}
 
void loop() {
  //  If something available
  if (e220ttl.available()>1) {
    Serial.println("Message arrived");
      // read the String message
    ResponseContainer rc = e220ttl.receiveMessage();

    String message = rc.data;
    //Serial.println(rc.status.getResponseDescription());
    Serial.println(message);

    e220ttl.setMode(MODE_0_NORMAL); // change to normal mode
    delay(1000);

    e220ttl.sendFixedMessage(0, 1, 18, "We have received the message!");
    e220ttl.setMode(MODE_2_WOR_RECEIVER); // change back to WOR receiver mode
    interruptExecuted = false;
  }
 
  if(interruptExecuted) {
    Serial.println("WakeUp Callback, AUX pin go LOW and start receive message!");
    Serial.flush();
    //attachInterrupt(digitalPinToInterrupt(AUX_PIN), wakeUp, FALLING);
    interruptExecuted = false;
  }
}

 

Und hier die Ausgabe:

Ausgabe lora_wor_receiver.ino
Ausgabe lora_wor_receiver.ino

Anstelle von setMode(MODE_2_WOR_RECEIVER) verwendet ihr bei den E32-Modulen setMode(MODE_2_POWER_SAVING). Bei den E22-Modulen stellt ihr den Modus MODE_1_WOR im Sketch ein und legt die Rolle als WOR Receiver als permanente Einstellung über setConfiguration.ino fest. 

Mit WOR die MCU wecken

Da der AUX-Pin nach Empfang der Nachricht und vor der Ausgabe an den Mikrocontroller auf LOW geht, kann man dieses Signal nutzen, um nicht nur das LoRa Modul, sondern auch einen schlafenden Mikrocontroller über einen externen Interrupt zu wecken.

Leider ist die Vorlaufzeit zwischen fallender Flanke des AUX-Pin und Beginn der Übertragung über den TX-Pin nicht einstellbar (jedenfalls habe ich keine Möglichkeit gefunden). Zwei bis drei Millisekunden sind eventuell zu wenig Zeit, etwa um einen ESP32 aus dem Deep Sleep zurückzuholen. Auf dem Arduino Nano habe ich festgestellt, dass mindestens das erste Zeichen der übertragenen Nachricht verschluckt wurde. Eine pragmatische Lösung wäre, zumindest für meine Arduino Nano Konfiguration, der Nachricht ein paar Dummy-Zeichen voranzustellen.

Ich habe in meinem Beispiel eine andere Lösung gewählt, und zwar senden wir zunächst einen „Wake-Up-Call“. Bevor dann die eigentliche Nachricht hinausgeht, lassen wir dem Transmitter noch eine Bestätigung zukommen, dass der Receiver wach ist.

Hier der Transmittersketch:

Transmitterseite

#include "LoRa_E220.h"

SoftwareSerial mySerial(4, 5); // Arduino RX <-- e220 TX, Arduino TX --> e220 RX
LoRa_E220 e220ttl(&mySerial, 3, 7, 6); // AUX M0 M1
 
void setup() {
  Serial.begin(9600);
  delay(500);
  Serial.println("Hello, starting now. Type in a message.");

  e220ttl.begin();
  e220ttl.setMode(MODE_1_WOR_TRANSMITTER);
}
 
void loop() {
  if (Serial.available()) {
    String input = Serial.readString();
    e220ttl.sendFixedMessage(0,2,18,"......wake up!!"); // wake up call
    e220ttl.setMode(MODE_0_NORMAL); // change to normal mode
    delay(100); // give time for the receiver to wake up
    
    while(e220ttl.available()<= 1); // wait for confirmation
    ResponseContainer rc = e220ttl.receiveMessage(); // receive message
    rc.status.getResponseDescription(); 
    Serial.println(rc.data);
    
    e220ttl.sendFixedMessage(0,2,18,input); // send the actual message
    e220ttl.setMode(MODE_1_WOR_TRANSMITTER); // change back to WOR transmitter mode
  }
}

 

Und hier die wenig überraschende Ausgabe:

Auch hier müsst ihr – abgesehen von den allgemeinen Anpassungen – für die E32-Module anstelle von setMode(MODE_1_WOR_TRANSMITTER) die Einstellung setMode(MODE_1_WAKE_UP) vornehmen. Bei den E22-Modulen stellt ihr den Modus MODE_1_WOR im Sketch ein und legt die Rolle als WOR Transmitter als permanente Einstellung fest.  

Receiverseite

Die „Schlafgewohnheiten“ der Mikrocontroller sind hardwarespezifisch. Über die Schlafmodi der AVR-Mikrocontroller habe ich hier etwas geschrieben. Wenn ihr keinen AVR-basiertes Mikrocontrollerboard verwendet, müsst ihr den Sketch entsprechend anpassen.

#include "LoRa_E220.h"
#include <avr/sleep.h>

#define AUX_PIN 3

SoftwareSerial mySerial(4, 5); // Arduino RX <-- e220 TX, Arduino TX --> e220 RX
LoRa_E220 e220ttl(&mySerial, AUX_PIN, 7, 6); // AUX M0 M1

void wakeUp() {
  delay(0); // add code if you want
}


void setup() {
  Serial.begin(9600);
  delay(500);

  // Startup all pins and UART
  e220ttl.begin();

  e220ttl.setMode(MODE_2_WOR_RECEIVER);

  Serial.println("Start sleep!");
  delay(100);
  attachInterrupt(digitalPinToInterrupt(AUX_PIN), wakeUp, FALLING);
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // define sleep mode
}
 
 
void loop() {
  sleep_mode(); // set MCU (Arduino Nano) to sleep
  delay(10);
  if (e220ttl.available()>1) {  // wait for wake up
    ResponseContainer rc = e220ttl.receiveMessage();
    String message = rc.data;
    Serial.println(message);

    e220ttl.setMode(MODE_0_NORMAL);
    delay(200);
    e220ttl.sendFixedMessage(0, 1, 18, "Receiver woke up!");
    delay(100);
    
    while(e220ttl.available()<= 1); // wait for second message
    rc = e220ttl.receiveMessage();
    message = rc.data;
    Serial.println(message);
    Serial.flush();
    e220ttl.setMode(MODE_2_WOR_RECEIVER);
  }
}

 

Hier die Ausgabe:

Ausgabe lora_wor_wake_up_mcu_receiver.ino
Ausgabe lora_wor_wake_up_mcu_receiver.ino

Wenn ihr die WORPeriod ändert, dann müsst ihr die Delays in den Sketchen ändern, damit das Wechselspiel funktioniert.

Für E32-Module ist, unter anderem, setMode(MODE_2_WOR_RECEIVER) durch setMode(MODE_2_POWER_SAVING) zu ersetzen. Bei den E22-Modulen stellt ihr den Modus MODE_1_WOR im Sketch ein und legt die Rolle als WOR Receiver als permanente Einstellung fest. 

Reichweitentest

Dann habe ich mit dem E220-900T22D Modul noch einen Reichweitentest durchgeführt. Die Reichweite beträgt laut Datenblatt bis zu 5 km, allerdings gilt das für eine hindernislose Funkstrecke, die man bei dieser Entfernung ja eher selten hat.

Ich habe mit 22 dBm die höchste Sendeleistung gewählt und die niedrigste Datenrate, weil das die höchste Reichweite liefern sollte. Als Antenne kam eine 868 MHz Standantenne zum Einsatz. Der Arduino wurde über einen 9 V Lithium-Akku mit Strom versorgt. Maßnahmen zur Spannungsstabilisierung wie zusätzliche Kondensatoren kamen nicht zu Einsatz.

Hier die Receivereinheit:

Versuchsaufbau LoRa E220 Range Test (Receiver)
Versuchsaufbau LoRa E220 Range Test (Receiver)

Der Transmitter hat alle 5 Sekunden eine Nachricht gesendet:

#include "LoRa_E220.h"

SoftwareSerial mySerial(4, 5); // Arduino RX <-- e220 TX, Arduino TX --> e220 RX
LoRa_E220 e220ttl(&mySerial, 3, 7, 6); // AUX M0 M1
 
void setup() {
  Serial.begin(9600);
  delay(500);
 
  Serial.println("Hi, I'm going to send message!");
 
  // Startup all pins and UART
  e220ttl.begin();
 
  // Send message
  ResponseStatus rs = e220ttl.sendFixedMessage(0,2,18,"Hi to receiver!"); // adjust
  // Check If there is some problem of successfully send
  Serial.println(rs.getResponseDescription());
  delay(2000);
}
 
void loop() {
  // If something available
  static unsigned long lastSend = 0;
  if (millis() - lastSend > 5000) {
    e220ttl.sendFixedMessage(0,2,18, "Hi Receiver, did you get this message?");
    lastSend = millis();
  }
}

 

Der Receiver hat die Nachricht entgegengenommen, den Inhalt überprüft und bei Richtigkeit eine LED an Pin 8 fünfmal kurz leuchten lassen.

#include "LoRa_E220.h"
#define LED_PIN 8

SoftwareSerial mySerial(4, 5); // Arduino RX <-- e220 TX, Arduino TX --> e220 RX
LoRa_E220 e220ttl(&mySerial, 3, 7, 6); // AUX M0 M1
 
void setup() {
  pinMode(LED_PIN, OUTPUT);
  Serial.begin(9600);
  delay(500);
 
  Serial.println("Hi, waiting for messages!");
 
  // Startup all pins and UART
  e220ttl.begin();
  delay(2000);
}
 
void loop() {
  // If something available
  if (e220ttl.available()>1) {
    ResponseContainer rc = e220ttl.receiveMessage();
    //Serial.println(rc.data);
    if(rc.data = "Hi Receiver, did you get this message?"){
      for(int i=0; i<5; i++){
        digitalWrite(LED_PIN, HIGH);
        delay(100);
        digitalWrite(LED_PIN, LOW);
        delay(100);
      }
    }
  }
}

 

Der Transmitter stand bei mir zu Hause auf dem Schreibtisch. Ich bin mit der Receivereinheit auf die Felder gegangen und habe geprüft, bis zu welcher Entfernung ich Nachrichten empfangen konnte. Das Funksignal musste erst einmal meine eigene Hauswand durchdringen, dann einen schmalen Waldstreifen und drei bis vier Wohnhäuser, bis es dann über das freie Feld ging. Das Gelände war flach. Damit kam ich immerhin auf 1.34 km Reichweite.

Ergebnis des Range-Tests
Ergebnis des Reichweitentests (ausgemessen mit Google Maps).

Anhänge – Transceiversketche mit Einstellungen für E220, E22, E32

Anhang 1 – E220 Transceiver Sketch mit Einstellungen

Sketch mit eingebetteter Konfiguration für E220-Module. Ihr könnt die Funktion setConfiguration() herauskopieren und in anderen Sketchen verwenden. Der Sketch wurde mit zwei E220-900T22D Modulen getestet.

// #define FREQUENCY_433 // default value without set 
// #define FREQUENCY_170
// #define FREQUENCY_470
#define FREQUENCY_868
// #define FREQUENCY_915
// #define E220_22 // default value without set 
// #define E220_30 // uncomment in case you use an E220...T30D or E220...T30S
#include "LoRa_E220.h"
 
SoftwareSerial mySerial(4,5);
LoRa_E220 e220ttl(&mySerial, 3, 7, 6); // AUX M0 M1
 
void setup() {
  Serial.begin(9600);
  delay(500);
  
  Serial.println("Beginning configuration...");
  e220ttl.begin();
  setConfiguration();
  Serial.println("Hi, I'm going to send message!");
 
  ResponseStatus rs = e220ttl.sendBroadcastFixedMessage(18, "Hello, world?");
  Serial.println(rs.getResponseDescription());
}
 
void loop() {
    // If something available
  if (e220ttl.available()>1) {
      // read the String message
    ResponseContainer rc = e220ttl.receiveMessage();
    // Is something goes wrong print error
    if (rc.status.code!=1){
        Serial.println(rc.status.getResponseDescription());
    }else{
        // Print the data received
        Serial.println(rc.data);
    }
  }
  if (Serial.available()) {
      String input = Serial.readString();
      e220ttl.sendFixedMessage(0, 2, 18, input);
  }
}

void setConfiguration(){
  ResponseStructContainer c;
  c = e220ttl.getConfiguration();
  // It's important get configuration pointer before all other operation
  Configuration configuration = *(Configuration*) c.data;
  Serial.println(c.status.getResponseDescription());
  Serial.println(c.status.code);

  configuration.ADDL = 0x03;  // Low byte of address
  configuration.ADDH = 0x00; // High byte of address

  configuration.CHAN = 18; // Communication channel --> 868 MHz

  /*
  UART_BPS_xxx with xxx = Baudrate
  xxx = 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200
  */
  configuration.SPED.uartBaudRate = UART_BPS_9600; // Serial baud rate

  /*
  AIR_DATA_RATE_000_24     2.4 kb/s
  AIR_DATA_RATE_001_24     2.4 kb/s
  AIR_DATA_RATE_010_24     2.4 kb/s
  AIR_DATA_RATE_011_48     4.8 kb/s
  AIR_DATA_RATE_100_96     9.6 kb/s
  AIR_DATA_RATE_101_192   19.2 kb/s
  AIR_DATA_RATE_110_384   38.4 kb/s
  AIR_DATA_RATE_111_625   62.5 kb/s 
  */
  configuration.SPED.airDataRate = AIR_DATA_RATE_010_24; // Air baud rate
  
  /* 
  MODE_00_8N1  none
  MODE_01_8O1  odd
  MODE_10_8E1  even
  MODE_11_8N1  none
  */
  configuration.SPED.uartParity = MODE_00_8N1; // Parity bit

  /*
  SPS_200_00  200
  SPS_128_01  128
  SPS_064_10   64
  SPS_032_11   32
  */
  configuration.OPTION.subPacketSetting = SPS_200_00; // Packet size

  /*
  RSSI_AMBIENT_NOISE_DISABLED
  RSSI_AMBIENT_NOISE_ENABLED
  */
  configuration.OPTION.RSSIAmbientNoise = RSSI_AMBIENT_NOISE_DISABLED; // Need to send special command

  /*
  POWER_xxx with xxx = power in dBm
  E220...T22D/S: xxx = 22, 17, 13, 10
  E220...T30D/S: xxx = 30, 27, 24, 21
  */
  configuration.OPTION.transmissionPower = POWER_22; // Device power

  /*
  RSSI_DISABLED
  RSSI_DISABLED
  */
  configuration.TRANSMISSION_MODE.enableRSSI = RSSI_DISABLED; // Enable RSSI info

  /*
  FT_FIXED_TRANSMISSION
  FT_TRANSPARENT_RANSMISSION
  */
  configuration.TRANSMISSION_MODE.fixedTransmission = FT_FIXED_TRANSMISSION; // Transmission mode

  /*
  LBT_DISABLED
  LBT_ENABLED
  */
  configuration.TRANSMISSION_MODE.enableLBT = LBT_DISABLED; // Check interference

  /*
  WOR_xxx_yyy with xxx = WOR Period
  xxx_yyy = 500_000, 1000_001, 1500_010, 2000_011, 2500_100, 3000_101, 3500_110, 4000_111
  */
  configuration.TRANSMISSION_MODE.WORPeriod = WOR_2000_011; // WOR timing

  configuration.CRYPT.CRYPT_H = 0x00;  // encryption high byte, default: 0x00
  configuration.CRYPT.CRYPT_L = 0x00;  // encryption low byte, default: 0x00

  // Set configuration changed and set to hold the configuration
  ResponseStatus rs = e220ttl.setConfiguration(configuration, WRITE_CFG_PWR_DWN_SAVE); // WRITE_CFG_PWR_DWN_LOSE to not permanently save

  Serial.println(rs.getResponseDescription());
  Serial.println(rs.code);
  c.close();
}

 

Anhang 2 – E22 Transceiver Sketch mit Einstellungen

Sketch mit eingebetteter Konfiguration für E22-Module. Ihr könnt die Funktion setConfiguration() herauskopieren und in anderen Sketchen verwenden. Der Sketch wurde mit zwei E22-400T22D Modulen getestet.

// #define FREQUENCY_433 // default value without set 
// #define FREQUENCY_170
// #define FREQUENCY_470
// #define FREQUENCY_868
// #define FREQUENCY_915
// #define E22_22 // default value without set 
// #define E22_30 // uncomment in case you use an E22...T30D or E22...T30S
#include "LoRa_E22.h"
 
SoftwareSerial mySerial(4,5);
LoRa_E22 e22ttl(&mySerial, 3, 7, 6); // AUX M0 M1
 
void setup() {
  Serial.begin(9600);
  delay(500);
  
  Serial.println("Beginning configuration...");
  e22ttl.begin();
  setConfiguration();
  Serial.println("Hi, I'm going to send message!");
 
  ResponseStatus rs = e22ttl.sendBroadcastFixedMessage(23, "Hello, world?");
  Serial.println(rs.getResponseDescription());
}
 
void loop() {
    // If something available
  if (e22ttl.available()>1) {
      // read the String message
    ResponseContainer rc = e22ttl.receiveMessage();
    // Is something goes wrong print error
    if (rc.status.code!=1){
        Serial.println(rc.status.getResponseDescription());
    }else{
        // Print the data received
        Serial.println(rc.data);
    }
  }
  if (Serial.available()) {
      String input = Serial.readString();
      e22ttl.sendFixedMessage(0, 2, 23, input);
  }
}

void setConfiguration(){
  ResponseStructContainer c;
  c = e22ttl.getConfiguration();
  // It's important get configuration pointer before all other operation
  Configuration configuration = *(Configuration*) c.data;
  Serial.println(c.status.getResponseDescription());
  Serial.println(c.status.code);

  configuration.ADDL = 0x03;  // Low byte of address
  configuration.ADDH = 0x00; // High byte of address
  configuration.NETID = 0x00; // used for repeater function

  configuration.CHAN = 23; // Communication channel --> 433 MHz

  /*
  UART_BPS_xxx with xxx = Baudrate
  xxx = 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200
  */
  configuration.SPED.uartBaudRate = UART_BPS_9600; // Serial baud rate

  /*
  AIR_DATA_RATE_000_03     0.3 kb/s
  AIR_DATA_RATE_001_12     1.2 kb/s
  AIR_DATA_RATE_010_24     2.4 kb/s
  AIR_DATA_RATE_011_48     4.8 kb/s
  AIR_DATA_RATE_100_96     9.6 kb/s
  AIR_DATA_RATE_101_192   19.2 kb/s
  AIR_DATA_RATE_110_384   38.4 kb/s
  AIR_DATA_RATE_111_625   62.5 kb/s 
  */
  configuration.SPED.airDataRate = AIR_DATA_RATE_010_24; // Air baud rate
  
  /* 
  MODE_00_8N1  none
  MODE_01_8O1  odd
  MODE_10_8E1  even
  MODE_11_8N1  none
  */
  configuration.SPED.uartParity = MODE_00_8N1; // Parity bit

  /*
  SPS_240_00  200
  SPS_128_01  128
  SPS_064_10   64
  SPS_032_11   32
  */
  configuration.OPTION.subPacketSetting = SPS_240_00; // Packet size

  /*
  RSSI_AMBIENT_NOISE_DISABLED
  RSSI_AMBIENT_NOISE_ENABLED
  */
  configuration.OPTION.RSSIAmbientNoise = RSSI_AMBIENT_NOISE_DISABLED; // Need to send special command

  /*
  POWER_xxx with xxx = power in dBm
  E22...T22D/S: xxx = 22, 17, 13, 10
  E22...T30D/S: xxx = 30, 27, 24, 21
  */
  configuration.OPTION.transmissionPower = POWER_22; // Device power

  /*
  RSSI_DISABLED
  RSSI_DISABLED
  */
  configuration.TRANSMISSION_MODE.enableRSSI = RSSI_DISABLED; // Enable RSSI info

  /*
  FT_FIXED_TRANSMISSION
  FT_TRANSPARENT_RANSMISSION
  */
  configuration.TRANSMISSION_MODE.fixedTransmission = FT_FIXED_TRANSMISSION; // Transmission mode

  /*  In the repeater mode, ADDH/ADDL is no longer used as the module address, it is used as a NETID 
  to pair and forwarding. If the reperater receive the data from a network, then it will forward the 
  data to the other network. The network ID of the repeater itself is invalid in this case.
  The repeater module cannot transmit and receive data, and cannot perform low-power operation.
  REPEATER_ENABLED 
  REPEATER_DISABLED
  */
  configuration.TRANSMISSION_MODE.enableRepeater = REPEATER_DISABLED;

  /*
  LBT_DISABLED
  LBT_ENABLED
  */
  configuration.TRANSMISSION_MODE.enableLBT = LBT_DISABLED; // Check interference

  /*
  WOR_TRANSMITTER
  WOR_RECEIVER
  */
  configuration.TRANSMISSION_MODE.WORTransceiverControl = WOR_RECEIVER;

  /*
  WOR_xxx_yyy with xxx = WOR Period in ms
  xxx_yyy = 500_000, 1000_001, 1500_010, 2000_011, 2500_100, 3000_101, 3500_110, 4000_111
  */
  configuration.TRANSMISSION_MODE.WORPeriod = WOR_2000_011; // WOR timing

  configuration.CRYPT.CRYPT_H = 0x00;  // encryption high byte, default: 0x00
  configuration.CRYPT.CRYPT_L = 0x00;  // encryption low byte, default: 0x00

  // Set configuration changed and set to not hold the configuration
  ResponseStatus rs = e22ttl.setConfiguration(configuration, WRITE_CFG_PWR_DWN_SAVE); // WRITE_CFG_PWR_DWN_LOSE to not permanently save

  Serial.println(rs.getResponseDescription());
  Serial.println(rs.code);
  c.close();
}

 

Anhang 3 – E32 Transceiver Sketch mit Einstellungen

Sketch mit eingebetteter Konfiguration für E32-Module. Ihr könnt die Funktion setConfiguration() herauskopieren und in anderen Sketchen verwenden. Der Sketch wurde mit zwei E32-433T30D Modulen getestet.

// #define FREQUENCY_433 // default value without set 
// #define FREQUENCY_170
// #define FREQUENCY_470
// #define FREQUENCY_868
// #define FREQUENCY_915/* Choose your module */
// #define E32_TTL_100 
// #define E32_TTL_500 
#define E32_TTL_1W // E32-TTL-1W, E32-433T30S/D, E32-868T30S/D, E32-915T30S/D
// #define E32_TTL_2W
#include "LoRa_E32.h"
 
SoftwareSerial mySerial(4,5);
LoRa_E32 e32ttl(&mySerial, 3, 7, 6); // AUX M0 M1
 
void setup() {
  Serial.begin(9600);
  delay(500);
  
  Serial.println("Beginning configuration...");
  e32ttl.begin();
  setConfiguration();
  Serial.println("Hi, I'm going to send message!");
 
  ResponseStatus rs = e32ttl.sendBroadcastFixedMessage(23, "Hello, world?");
  Serial.println(rs.getResponseDescription());
}
 
void loop() {
    // If something available
  if (e32ttl.available()>1) {
      // read the String message
    ResponseContainer rc = e32ttl.receiveMessage();
    // Is something goes wrong print error
    if (rc.status.code!=1){
        Serial.println(rc.status.getResponseDescription());
    }else{
        // Print the data received
        Serial.println(rc.data);
    }
  }
  if (Serial.available()) {
      String input = Serial.readString();
      e32ttl.sendFixedMessage(0, 2, 23, input);
  }
}

void setConfiguration(){
  ResponseStructContainer c;
  c = e32ttl.getConfiguration();
  // It's important get configuration pointer before all other operation
  Configuration configuration = *(Configuration*) c.data;
  Serial.println(c.status.getResponseDescription());
  Serial.println(c.status.code);

  configuration.ADDL = 0x03;  // Low byte of address
  configuration.ADDH = 0x00; // High byte of address

  configuration.CHAN = 23; // Communication channel --> 433 MHz

  /* After turning off FEC, the actual data transmission rate increases 
  while anti-interference ability decreases. Also, the transmission distance is relatively short, and both communication parties must keep on the same pages about turn-on or turn-off FEC.
  FEC_0_OFF
  FEC_1_ON
  */
  configuration.OPTION.fec = FEC_1_ON;

  /*
  FT_FIXED_TRANSMISSION
  FT_TRANSPARENT_RANSMISSION
  */
  configuration.OPTION.fixedTransmission = FT_FIXED_TRANSMISSION; // Transmission mode
  
  /* Using internal pull-up resistors may make external redundant 
  IO_D_MODE_OPEN_COLLECTOR
  IO_D_MODE_PUSH_PULLS_PULL_UPS
  */
  configuration.OPTION.ioDriveMode = IO_D_MODE_PUSH_PULLS_PULL_UPS;

  /* for E32_TTL_1W
  POWER_xxx with xxx = power in dBm
  E32_TTL_100: xxx = 20, 17, 14, 10
  E32_TTL_500: xxx = 27, 24, 21, 18
  E32_TTL_1W : xxx = 30, 27, 24, 21
  E32_TTL_2W : xxx = 33, 30, 27, 24
  */
  configuration.OPTION.transmissionPower = POWER_30; // Device power

  /* WOR period is called WAKE_UP time here
  WAKE_UP_xxx with xxx = Wake-Up Period
  xxx = 250, 500. 750, 1000, 1250, 1500, 1750, 2000
  */
  configuration.OPTION.wirelessWakeupTime = WAKE_UP_1250; 

  /*
  AIR_DATA_RATE_000_03     0.3 kb/s
  AIR_DATA_RATE_001_12     1.2 kb/s
  AIR_DATA_RATE_010_24     2.4 kb/s
  AIR_DATA_RATE_011_48     4.8 kb/s
  AIR_DATA_RATE_100_96     9.6 kb/s
  AIR_DATA_RATE_101_192   19.2 kb/s
  AIR_DATA_RATE_110_192   19.2 kb/s
  AIR_DATA_RATE_111_192   19.2 kb/s 
  */
  configuration.SPED.airDataRate = AIR_DATA_RATE_010_24; // Air baud rate

  /*
  UART_BPS_RATE_xxx with xxx = Baudrate
  xxx = 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200
  */
  configuration.SPED.uartBaudRate = UART_BPS_9600; // Serial baud rate

  // Set configuration changed and set to hold the configuration
  ResponseStatus rs = e32ttl.setConfiguration(configuration, WRITE_CFG_PWR_DWN_SAVE); // WRITE_CFG_PWR_DWN_LOSE to not save permanently

  Serial.println(rs.getResponseDescription());
  Serial.println(rs.code);
  c.close();
}

 

Danksagung

Renzo Mischianti möchte ich für die wunderbaren Bibliotheken und die ausführlichen Tutorials danken.

12 thoughts on “LoRa mit der EByte E220-, E22- und E32-Serie nutzen

  1. Hallo Wolfgang,
    vielen Dank für deinen tollen Beitrag.

    Das ist hier fast die Bibel für IoT Selbstbau geworden … 😉

    Ich hätte da mal eine Frage….
    Die Module gibt es ja mit seriellen Interface und auch mit SPI Interface.
    Mir ist nicht ganz klar wo die Vor- und Nachteile bei den Interfacetypen liegen.
    Vielleicht kannst du da Licht in die Sache bringen…

    Herzliche Grüße aus Dessau
    Alain

    1. Hi Alain,

      die Module von EByte haben alle ein serielles Interface. Ich denke, mit den SPI-Modulen meinst du die Teile, die als LoRa SX126x oder LoRA SX127x angeboten werden? Die EByte-Module basieren auf denselben SX12xy Chips der Fa. SemTech. Insofern sind die technischen Eigenschaften (z.B. Übertragungsraten / Reichweiten) vergleichbar. Als ich über LoRa Module berichten wollte, stand ich genau vor der Frage, welche Teile ich nehmen sollte. Nachdem ich ein paar Bibliotheken angeschaut hatte, fand ich die von Renzo Mischianti am besten verständlich und am besten dokumentiert. Die anderen Teile habe ich bisher schlicht nicht ausprobiert. Werde ich irgendwann mal tun. SPI ist schneller als seriell, aber bei den langsamen Übertragungsraten der LoRa Technologie ist das nicht der Flaschenhals.

      VG, Wolfgang

  2. Moin, sag mal, ist der „Transparent Transmission Modus“ eigentlich ein propritäres Protokoll von EByte? Bzw das jeder Hersteller irgendwie implementiert? Ich habe nämlich einen Ai-Thinker RA-08 Board, für welches es auch eine „LoRaWAN Transparent Transmission Firmware Application“ https://www.youtube.com/watch?v=UulXDdYWaSk gibt. Allerdings bekomme ich das RA-08 Board (noch) nicht mit meinem E22-900T22U USB-Dongle zum Laufen.

    1. EByte ist nur der Modulhersteller. Die zugrundeliegenden LoRa Chips wie etwa der SX1262 oder SX1268 wurden von der Semtech Corporation entwickelt. Was jetzt spezifisch von EByte, Semtech oder anderen ist und inwiefern das alles in den LoRa-/LoRaWan Standards festgelegt ist, kann ich dir leider nicht sagen. Mit dem Ai-Thinker RA-08 Board habe ich keine Erfahrung.

      1. Ja, die Basics versuche ich auch gerade zu verstehen. Mittlerweile spricht wenigstens mein RA-08 im Transparent Mode mit einem Lora OpenMQTTGateway auf einem ttgo-Lora Board.
        Allerdings ist mir nicht klar, ob es möglich ist die EByte Module in diesem propritären Transparent Modus mit ADDRL/H und Air Rate/airDataRate auch mit normalen Lora Modulen sprechen zu lassen. Schaut man sich Arduino Beispiel Code der gängigen Module an, findet man folgende Kommunikations-Parameter:

        LORA_BANDWIDTH 0: 125 kHz, 1: 250 kHz,2: 500 kHz
        LORA_SPREADING_FACTOR 7 // [SF7..SF12]
        LORA_CODINGRATE [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
        LORA_PREAMBLE_LENGTH 8
        LORA_SYMBOL_TIMEOUT 0
        LORA_FIX_LENGTH_PAYLOAD_ON
        LORA_IQ_INVERSION_ON false

  3. Hallo Wolfgang,
    Danke für den Beitrag. Wieder einmal hast Du komplexe Materie in verständliche Form gebracht.
    @Stefan Kluge: es gibt bereits ein Fernsteuer-Protokoll, das LoRa nutzt: ELRS. Es ist open-source und da kann man auch Sender und Empfänger selber bauen. Wobei die gekauften extrem leicht sind. Habe hier einen Rx, der 0,47 Gramm wiegt und den man per WLAN konfigurieren kann. Weiterer Vorteil: Es gibt Sendemodule mit bis zu 1 Watt Leistung. Damit werden Reichweiten von 30 km erreicht.

  4. Ganz großes Kino, wie immer verständlich erklärt. Mal schauen ob man damit nicht eine einfache Fernsteuerung realisieren kann. THX

    1. Herzlichen Dank. Für eine Fernsteuerung würde ich LoRa-Module aber nur nehmen, wenn es die Entfernung wirklich erfordert. Viel Spaß und Erfolg!

  5. Hallo Wolfgang,
    seit Monaten will ich einen Kommentar unter Deinen Beiträgen verfassen und habe es immer wieder auf die lange Bank geschoben. Jetzt ist es soweit. Auch, wenn ich noch keine Projekte von Dir nachgebaut habe, sind sie immer eine Bereicherung für mich und lassen meine Liste mit Ideen und Experimenten immer weiter anwachsen. Ich möchte mich an dieser Stelle für Dein Engagement und Deinen zeitlichen Invest bedanken, den du in diesen Blog und die Projekte steckst. Immer verständlich aufgebaut, gut erklärt… 1.000 Dank… Mach bitte weiter so… Irgendwann im Herbst lege ich los und habe bestimmt zum einen oder anderen Projekt eine Detailfrage oder schicke Dir meinen Spagetticode zur Fehleranalyse… 😉
    Grüße aus Niedersachsen
    Ulf

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert