Hallo liebe Coomunity. Eigentlich will ich niemanden mit meinen kleinen Problemen behelligen - und bisher hat es immer irgendwann irgendwie geklappt. Aber diesmal will es einfach nicht.
Es geht um LoRa via HC-12 Module. An einem Esp32(RX) und Nano(TX) hat es sogar schon funktioniert. Wollte/musste aber wieder auf einen ArduinoBoard für den Empfänger wechseln. Es ist ein MegaPro - der ist schön klein und hat genug Pins und Power um u.a. das angeschlossende E-Paper display zu steuern.
Ausgangslage:
Ein Sensor und ein HC12 Modul sind am guten alten NANO angeschlossen. Der Code hat sich seit dem es mal funktioniert hat nicht geändert und die TX-led leuchtet, wenn sie soll. Scheint beim Sender alles ok zu sein. Auch Serial gibt den richtigen debug Text aus.
Am MegaPro ist ebenfalls ein HC12 Modul mit der selber Chip-Typen-Nummer und natürlich auch ein 1000mf Kondensator verbaut. Bei beiden Boards ist RX-10 und TX-11 - wie empfohlen. Beide HC12 Module haben eine Ansteck-Antenne mit Spirale.
Verkabelung ist wie überall zu sehen: 5v,Grd,RX10, TX11 - nix auf SetPin.
Das Epaper am MegaPro ist auf den Pins: 7,8,9, 51, 52, 53 - und funktioniert.
Code:
Vom TX soll eine kleine Ineger übertragen werden, die beim RX etwas aufgeggliedert und interpretiert wird. Dann gibts dort ne menge Arrays, die dann fein auf dem Display mit full und partialUpdate angezeigt werden. Nix besonderes. Hat so grundsätzlich auf dem ESP32 schonmal funktioniert.
Was ich auch versuche - ich finde den Fehler einfach nicht. Seit Monaten versuche ich alles, was mir einfällt. Das Internet hatte bisher auch keine Lösung. Ich bin Profi oder Programmierer in jäglicher Form. Darum ist mein Code wohl auch sehr simpel.
Vielleicht könnt ihr helfen...
#define ENABLE_GxEPD2_GFX 1
// #include <Arduino.h>
// #include <SPI.h>
#include <GxEPD2_BW.h>
#include <Fonts/FreeSans9pt7b.h>
#include <Fonts/FreeMonoBold9pt7b.h>
#include <SoftwareSerial.h>
// #include "BitmapDisplay.h"
// #include "TextDisplay.h"
#include "GxEPD2_display_selection.h"
// #include "GxEPD2_display_selection_added.h"
// #include "GxEPD2_display_selection_new_style.h"
SoftwareSerial HC12(10, 11); // RX:Pin 10 - TX:Pin 11,
// BitmapDisplay bitmaps(display);
// Variablen: ### könnten die INTs auch Bytes sein?
const int vibrationPin = 2; // DataPin für Vibrator
int emeID = 0;
int emeStatus = 0;
int LastData = 0;
bool newData = false;
byte emeIDslot[20];
int timerArray[20];
int pingTimer[20];
byte startTimer[20];
byte minutes = 0;
byte seconds = 0;
byte emeStateArray[20];
byte acitiveEMEs = 0;
unsigned long nowTime = 0;
// char incomingByte;
// String receivedString;
// layout Variablen
int timerPosLeft = 82;
// Zeilenhöhe fehlt noch: (18)
void setup()
{
HC12.begin(9600); // Serielle Kommunikation zum HC-12-Modul (9600 ist im Modul eingestellt)
delay(1000);
Serial.begin(57200);
Serial.println("setup");
delay(1000);
display.init(115200, true, 2, false); // USE THIS for Waveshare boards with "clever" reset circuit, 2ms reset pulse
display.setRotation(2);
pinMode(vibrationPin, OUTPUT);
pinMode(10, INPUT); pinMode(11, OUTPUT);
delay(1000);
// beispiel EMEs (TESTDATA for Display)
emeIDslot[11]=11;
emeIDslot[12]=12;
emeIDslot[13]=13;timerArray[13]=25;startTimer[13] = 1;
vibration01();
countEMEs();
//
DisplayFullUpdate();
}
void loop() {
while (HC12.available()) { ///Empfangen von neuen Daten
String receivedString = HC12.readString();
Serial.println(receivedString);
if (receivedString.length() == 3) {
LastData = receivedString.toInt();
Serial.print("Empfangene Zahl: "); Serial.println(LastData);
Serial.print("Anzahl der EMEs: "); Serial.println(acitiveEMEs);
newData = true;
}
delay(1000);
}
// while (HC12.available()) { ///Empfangen von neuen Daten
// incomingByte = HC12.read();
// receivedString += char(incomingByte);
// }
// delay(100);
// if (receivedString.length() == 3) {
// LastData = receivedString.toInt(); // String wird zu einer integer Zahl umgewandelt -NICE
// Serial.print("Empfangene Zahl: "); Serial.println(LastData);
// Serial.print("Anzahl der EMEs: "); Serial.println(acitiveEMEs);
// newData = true;}
if(newData){ /// Datenpaket Empfangen !!!
emeStatus = LastData/100; emeID = LastData - (emeStatus*100); // Aufschlüsselung der Funk Daten
emeStateArray[emeID] = emeStatus;
// DisplayFullUpdate(); // TEST full update
if(emeIDslot[emeID] == 0){ // neues EME noch nicht erkannt --> full display Update
emeIDslot[emeID] = emeID;
countEMEs();
DisplayFullUpdate();
}
nowTime = millis()/1000;
if(emeStateArray[emeID]==2){ //bewegung erkannt
vibration01();
timerArray[emeID] = nowTime; // timer wir auf jetzte - also NULL gesetzt
startTimer[emeID] = 1; // timer wird aktiviert (bool)
}
if(emeStateArray[emeID]==1){ //status ok (Lebenszeichen)
pingTimer[emeID]=millis()/1000;
}
emeIDspeichern();
DisplayFullUpdate(); // in "new data"-if-Loop
}
// Abfrage ob irgendwelche Timer laufen - nur dann Partial Update
int AllTimers = 0;
for(int i=0;i<20;i++){
AllTimers = AllTimers + startTimer[i];
}
if (AllTimers > 0) {
DisplayPartUpdate();
}
newData = false;
emeStateArray[emeID] = 0; // eme Status wird zurückgesetzt für nächste Übertragung
emeID = 0;
//deadEME();
// delay(250);
}
void DisplayFullUpdate(){
//Serial.println("FullDisplayUpdate");
display.firstPage();
display.fillScreen(GxEPD_WHITE);
display.setFont(&FreeSans9pt7b);
display.setTextColor(GxEPD_BLACK);
// ab hier: dynamische chronologische EME Tabellierung ohne Timer Position
for(int x=0;x<acitiveEMEs;x){
for(int i=0;i<20;i++){ //durchlauf aller ID slots - Welche EMEs sind online (works)
if(emeIDslot[i]!=0){ // nicht null heißt online und wird angezeigt
display.setCursor(1, 20+x*18);display.print("e");
if(i<10){display.print("0");display.print(i);}
else{display.print(i);}
Serial.println(emeIDslot[i]);
x++;
}
}
}
//DEBUG on Display
display.setCursor(3,200); display.print(acitiveEMEs);
while(display.nextPage());
DisplayPartUpdate(); // immer am Edne von full update
}
void DisplayPartUpdate(){ // hier nur Timer updates !!! Alles andere zum static Full upadte
display.setFont(&FreeSans9pt7b);
display.setTextColor(GxEPD_BLACK);
display.setPartialWindow(timerPosLeft, 0, 128-timerPosLeft, acitiveEMEs*20); // 1 Updatewindow für alle erkannten EMEs
display.firstPage();
display.fillScreen(GxEPD_WHITE); // Reienfolge hier wichtig!
for(int x=0;x<acitiveEMEs;x){ // ### Bis jetzt nur Timer -> Mehr infos müssen ins UpdateWindow
for(int i=0;i<20;i++){
if(emeIDslot[i]!=0){
display.setCursor(timerPosLeft, 20+x*18);
if(startTimer[i]==0)
{display.print("-------");} // übersichtline lines wenn keine bewegung erkannt wurde
else{ // Umrechnung von Sekunden in MM:SS
minutes = (millis()/1000 - timerArray[i]) / 60;
seconds = (millis()/1000 - timerArray[i]) % 60;
if(minutes<10){display.print("0");}
display.print(minutes);
display.print(":");
if(seconds<10){display.print("0");}
display.print(seconds);
}
x++;
}
}
}
while(display.nextPage());
//delay(100);//display.clearDisplay();display.display();
}
void countEMEs(){
acitiveEMEs = 0;
for(int i=0;i<20;i++){
if(emeIDslot[i] != 0){
acitiveEMEs++;
}
}
}
void deadEME(){ // EMEs müssen ein Lebenszeichen senden - sonst werden sie als Tot merkiert (ToDo)
for(int i=0;i<20;i++){
if(millis()/1000 - pingTimer[i] > 720){ /// wenn 720sek nicht vom eme gekommen ist
emeIDslot[i] = 0; /// wird er aus der aktiven liste entfernt
}
}
}
void emeIDspeichern(){ /// hier wird die empfange emeID in das ID-Array geschrieben
for(int i=0;i<20;i++){
if(emeID==i){
emeIDslot[i]=emeID;
}
}
}
void vibration01(){ /// 30 sec /// neue Bewegung erkannt ab 30sek nach der letzten
if(millis()/1000 - timerArray[emeID] > 30 || timerArray[emeID] == 0){
digitalWrite(vibrationPin, HIGH);delay(300);digitalWrite(vibrationPin, LOW); /// dreifach Vibration wenn das letzte Siganal 30sek her ist
delay(100);
digitalWrite(vibrationPin, HIGH);delay(300);digitalWrite(vibrationPin, LOW);
delay(100);
digitalWrite(vibrationPin, HIGH);delay(300);digitalWrite(vibrationPin, LOW);
}
else{
digitalWrite(vibrationPin, HIGH);delay(300);digitalWrite(vibrationPin, LOW); // einfache Vibration wenn das Signal nicht neu ist.
}
}
TX - sender Code:
#include <SoftwareSerial.h>
const int pirPin = A2; // Pin für den PIR-Bewegungsmelder
const int hc12TxPin = 11; // Pin für HC-12 Lora TX
const int hc12RxPin = 10; // Pin für HC-12 Lora RX
const int batteryPin = A0; // Pin für den Batteriespannungssensor
const int ledPin = 13; // Onboard-LED Pin
SoftwareSerial HC12(10, 11); // RX, TX
int motionCounter = 0; // Zähler für erkannte Bewegungen
unsigned long lastMotionTime; // Zeitpunkt der letzten Bewegung
int pingTimer = 0;
const int unitID = 2; // Einheits-ID
int status = 1; // Status der Einheit (1 für Betriebsbereitschaft, 2 für erkannte Bewegung, 3 für eingeschränkte Betriebsbereitschaft)
void setup() {
pinMode(pirPin, INPUT);
pinMode(ledPin, OUTPUT);
HC12.begin(9600);
Serial.begin(57600);
// Batteriespannung überprüfen
float batteryVoltage = readBatteryVoltage();
if (batteryVoltage < 7.0) {
status = 3;
sendLoRaMessage(); // Schwache Batterie: Nachricht mit "3" für eingeschränkte Betriebsbereitschaft
} else {
status = 1;
sendLoRaMessage(); // Alles OK: Nachricht mit "1" für Betriebsbereitschaft
blinkLED(3); // LED blinkt 3-mal lang auf
}
//delay(10000); // 10 Sekunden Wartezeit
}
void loop() {
if (checkMotion()) {
// Bewegung erkannt, wechsle in den genauer-hingucken-Modus
if (waitForMoreMotion()) {
// Mehrere Bewegungen innerhalb des Zeitfensters erkannt, sende die Nachricht
status = 2;
sendLoRaMessage();
}
}
// Batteriespannung alle 10 Minuten überprüfen
if (millis() % (10 * 60 * 1000) == 0) {
float batteryVoltage = readBatteryVoltage();
if (batteryVoltage < 7.0) {
status = 3;
sendLoRaMessage(); // Schwache Batterie: Nachricht mit "3" für eingeschränkte Betriebsbereitschaft
}
else {
status = 1;
sendLoRaMessage();
}
}
delay(1000); // 2 Sekunden Wartezeit für die Bewegungsmelder-Abfrage
// Serial.println(analogRead(pirPin));
}
bool checkMotion() {
// Serial.println(analogRead(A2));
if (analogRead(pirPin) >= 500) {
// Bewegung erkannt
lastMotionTime = millis();
return true;
}
return false;
}
bool waitForMoreMotion() {
motionCounter = 1;
unsigned long startTime = millis();
while (millis() - startTime < 10000) {
if (checkMotion()) {
motionCounter++;
if (motionCounter >= 2 || (millis() - lastMotionTime >= 3000)) {
// Drei Bewegungen erkannt oder positive Bewegungserkennung für 3 Sekunden konstant
return true;
}
}
delay(500);
}
return false;
}
void sendLoRaMessage() {
if(unitID<10){ // wenn ID kleiner als 10 -> '0' hinzukopieren
String message = String(status) + String(0) + String(unitID);
Serial.println(message); // Ausgabe auf der Konsole zur Überprüfung
delay(1000);
HC12.print(message); // Sende den Inhalt der Nachricht als String
} else {
String message = String(status) + String(unitID);
Serial.println(message); // Ausgabe auf der Konsole zur Überprüfung
delay(1000);
HC12.print(message); // Sende den Inhalt der Nachricht als String
}
}
float readBatteryVoltage() {
int sensorValue = analogRead(batteryPin);
float voltage = sensorValue * (5.0 / 1023.0) * 2.0; // Faktor 2.0 für Spannungsteiler, falls erforderlich
return voltage;
}
void blinkLED(int count) {
for (int i = 0; i < count; i++) {
digitalWrite(ledPin, HIGH);
delay(300);
digitalWrite(ledPin, LOW);
delay(300);
}
}