Für mich ist WLAN erst einmal nicht so interessant, ich möchte selber testen wie weit die Module reichen - mit DIY Antennen oder auf anderen Frequenzen. Dafür gab es fertige Skripte wie "LoRa Sender & LoRa Empfänger". Ich habe sehr viele aus dem Netz ausprobiert, es funktionieren nur sehr wenige, die funktionieren, da bleibt das eingebaute OLED aber dunkel - die Anschlüsse wurden in V3 auch geändert.
Heltec selber hat ein Demo veröffentlicht, dieses habe ich sehr stark gekürzt und auch ein wenig verbessert (LED Kontrolle). Dieses läuft nun als Reichweitentester auf Version 3 einwandfrei.
Ich habe das Skript "PingPong" genannt, es funktioniert auch so. Wird der Baustein mit Spannung versorgt, horcht er 2 Sekunden auf der Frequenz nach einem Sender, hört er etwas, nimmt er die Botschaft auf und legt einen Zähler dazu. Hört er in den 2 Sekunden nix, wird er selber ein Sender und startet seine Botschaft mit dem Zählerstand 1.
Damit kann ein Baustein zu Hause bleiben, den anderen nimmt man(n) z.B. mit in das Auto und fährt los. Ich habe dafür noch ein LED-Flash einprogrammiert, jedes mal wenn eine Botschaft eintrifft und Fehlerfrei gelesen konnte, blitzt eine LED weiß hell auf, für 0,1 Sekunden. Da jede Sekunde eine Botschaft gesendet wird, blitzt logischerweise im Auto immer eine LED im Sekundentakt. blitzt nix mehr, bin ich ausser der Reichweite! So braucht man noch nicht einmal das OLED abzulesen.
Das OLED zeigt außerdem die Empfangsstärke des Gegenempfänger an, sowie seine eigene Empfangsqualität. Das war es eigentlich auch schon. Hat alles was ich mir im Moment vorstelle.
Im Skript habe ich noch alles wichtige als Kommentar hinterlegt. Zum Beispiel die Nachricht die versendet wird, ich habe ein Baustein mit "Hallo", den anderen mit "Ahoi" versehen. So lassen sich die Module leicht unterscheiden. Wichtig wenn verschiedene Sendeleistung programmiert wurde.
Hier mein Skript das nur mit V3 funzt:
Code: Alles auswählen
/*
* LoRa_32 PingPong Test
* c2023 Ruesseltechnik
*/
#include "Arduino.h"
#include "LoRaWan_APP.h"
#include <Wire.h>
#include "HT_SSD1306Wire.h"
/********************************* lora *********************************************/
#define RF_FREQUENCY 868000000 // Hz - auf angepasster Antenne achten!! Zerstörungsgefahr!!!
#define TX_OUTPUT_POWER 5 // dBm max.21!! Erlaubt max. in DE - 14
#define LORA_BANDWIDTH 0 // [0: 125 kHz, - größte Reichweite, langsamste Übertragung.
// 1: 250 kHz,
// 2: 500 kHz,
// 3: Reserved]
#define LORA_SPREADING_FACTOR 7 // [SF7..SF12]Pegel, die durch das SNR (Signal Noise Ratio)noch identifiziert werden. SF7: -123 dBm, SF12: -137 dBm
#define LORA_CODINGRATE 1 // [1: 4/5, Je kleiner die Codierungsrate ist (die kleinste ist 4/8), desto höher ist die On-Air-Zeit bei einer Übertragung, damit deutlicher.
// 2: 4/6,
// 3: 4/7,
// 4: 4/8]
#define LORA_PREAMBLE_LENGTH 8 // Es bedeutet, dass alle 4 Nutzbits je nach Wert durch 5, 6, 7 oder 8 Ãœbertragungsbits codiert werden.
#define LORA_SYMBOL_TIMEOUT 0 // Bei Empangsabbruch die Zeit den Empfänger schlafen zu legen
#define LORA_FIX_LENGTH_PAYLOAD_ON false
#define LORA_IQ_INVERSION_ON false
#define RX_TIMEOUT_VALUE 1000
#define BUFFER_SIZE 30 // Definiere die zu übertragende Datengröße
char txpacket[BUFFER_SIZE];
char rxpacket[BUFFER_SIZE];
static RadioEvents_t RadioEvents;
void OnTxDone( void );
void OnTxTimeout( void );
void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr );
typedef enum
{
LOWPOWER,
STATE_RX,
STATE_TX
}States_t;
int16_t txNumber;
int16_t rxNumber;
States_t state;
bool sleepMode = false;
int16_t Rssi,rxSize;
String rssi = "RSSI --";
String packSize = "--";
String packet;
String send_num;
String show_lora = "Empfange Daten:";
unsigned int counter = 0;
bool receiveflag = false; // Software Flag für LoRa Empfänger, empfangene Daten machen es "wahr"
long lastSendTime = 0; // Letzte Sendezeit
int interval = 1000; // Interval zwischen zwei Sendungen
uint64_t chipid;
int16_t RssiDetection = 0;
void OnTxDone( void )
{
Serial.print("TX done......");
state=STATE_RX;
}
void OnTxTimeout( void )
{
Radio.Sleep( );
Serial.print("TX Timeout......");
state=STATE_TX;
}
void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
{
rxNumber++;
Rssi=rssi;
rxSize=size;
memcpy(rxpacket, payload, size );
rxpacket[size]='\0';
Radio.Sleep( );
Serial.printf("\r\nreceived packet \"%s\" with Rssi %d , length %d\r\n",rxpacket,Rssi,rxSize);
Serial.println("Warte um naestes Paket zu senden");
receiveflag = true;
state=STATE_TX;
}
void lora_init(void)
{
Mcu.begin();
txNumber=0;
Rssi=0;
rxNumber = 0;
RadioEvents.TxDone = OnTxDone;
RadioEvents.TxTimeout = OnTxTimeout;
RadioEvents.RxDone = OnRxDone;
Radio.Init( &RadioEvents );
Radio.SetChannel( RF_FREQUENCY );
Radio.SetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH,
LORA_SPREADING_FACTOR, LORA_CODINGRATE,
LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON,
true, 0, 0, LORA_IQ_INVERSION_ON, 3000 );
Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR,
LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH,
LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON,
0, true, 0, 0, LORA_IQ_INVERSION_ON, true );
state=STATE_TX;
}
/********************************* lora *********************************************/
SSD1306Wire factory_display(0x3c, 500000, SDA_OLED, SCL_OLED, GEOMETRY_128_64, RST_OLED); // addr , freq , i2c group , resolution , rst
bool resendflag=false;
bool deepsleepflag=false;
bool interrupt_flag = false;
void interrupt_GPIO0()
{
interrupt_flag = true;
}
void interrupt_handle(void)
{
if(interrupt_flag)
{
interrupt_flag = false;
if(digitalRead(0)==0)
{
if(rxNumber <=2)
{
resendflag=true;
}
else
{
deepsleepflag=true;
}
}
}
}
void VextON(void)
{
pinMode(Vext,OUTPUT);
digitalWrite(Vext, LOW);
}
void VextOFF(void) //Vext default OFF
{
pinMode(Vext,OUTPUT);
digitalWrite(Vext, HIGH);
}
void setup()
{
Serial.begin(115200);
VextON();
delay(100);
factory_display.init();
factory_display.clear();
chipid=ESP.getEfuseMac();//Die Chip-ID ist im Wesentlichen seine MAC-Adresse (Länge: 6 Bytes).
Serial.printf("ESP32ChipID=%04X",(uint16_t)(chipid>>32));//print High 2 bytes
Serial.printf("%08X\n",(uint32_t)chipid);//print Low 4bytes.
attachInterrupt(0,interrupt_GPIO0,FALLING);
lora_init();
packet ="Warte auf Datenempfang!";
factory_display.drawString(0, 10, packet);
factory_display.display();
delay(100);
factory_display.clear();
pinMode(LED ,OUTPUT);
digitalWrite(LED, LOW);
}
void loop()
{
interrupt_handle();
if(deepsleepflag)
{
VextOFF();
Radio.Sleep();
SPI.end();
pinMode(RADIO_DIO_1,ANALOG);
pinMode(RADIO_NSS,ANALOG);
pinMode(RADIO_RESET,ANALOG);
pinMode(RADIO_BUSY,ANALOG);
pinMode(LORA_CLK,ANALOG);
pinMode(LORA_MISO,ANALOG);
pinMode(LORA_MOSI,ANALOG);
esp_sleep_enable_timer_wakeup(600*1000*(uint64_t)1000);
esp_deep_sleep_start();
}
if(resendflag)
{
state = STATE_TX;
resendflag = false;
}
if(receiveflag && (state==LOWPOWER) )
{
receiveflag = false;
packet ="Inhalt:";
int i = 0;
while(i < rxSize)
{
packet += rxpacket[i];
i++;
}
packSize = "R_Size: ";
packSize += String(rxSize,DEC);
packSize += " R_rssi: ";
packSize += String(Rssi,DEC);
send_num = "Sende Nummer: ";
send_num += String(txNumber,DEC);
factory_display.drawString(0, 0, show_lora);
factory_display.drawString(0, 10, packet);
factory_display.drawString(0, 20, packSize);
factory_display.drawString(0, 50, send_num);
factory_display.display();
delay(10);
factory_display.clear();
}
switch(state)
{
case STATE_TX:
delay(1000);
txNumber++;
sprintf(txpacket,"Ahoi %d,Rssi:%d",txNumber,Rssi); // Sendenachricht die verschickt wird, hier ein freundliches Ahoi!
Serial.printf("\r\nsending packet \"%s\" , length %d\r\n",txpacket, strlen(txpacket));
Radio.Send( (uint8_t *)txpacket, strlen(txpacket) );
state=LOWPOWER;
break;
case STATE_RX:
Serial.println("into RX mode");
Radio.Rx( 0 );
digitalWrite(LED, HIGH);
delay(100);
digitalWrite(LED, LOW);
state=LOWPOWER;
break;
case LOWPOWER:
Radio.IrqProcess( );
break;
default:
break;
}
}
Ziel könnte auch sein über lange Distanzen Kameras zu steuern.