• Hallo Zusammen, Aufgrund der aktuellen Situation setzten wir die Möglichkeit aus, sich mit Gmail zu registrieren. Wir bitten um Verständnis Das RCMP Team

Praxisbericht WEMOS D1 mini mit NRF24l01

BAXL

Admin
Mitarbeiter
Mein Ziel war es, einem WEMOS D1 mini ein Datentelegram von einem Arduino Nano per 2,4 GHz NRF24l01 Modul zu übertragen.
Das hat mich wieder zwei Wochenende gekostet. Als Basis dienten zwei bereits funktionierende Programme, die auf zwei Nanos fehlerfrei funktionierten.

Einziger Unterschied, so dachte ich, war die Deklaration der Anschlusspins CE und CSN für den NRF24l01 beim WEMOS D1 mini. Trotz aller Bemühungen hat es nicht geklappt.
Zuerst dachte ich, es läge daran, welche Pins des D1 mini ich verwendet hatte. Aber alle Versuche schlugen fehl.
Nach langem Suchen, fummeln und Probieren habe ich einen kompletten Schnitt gemacht und zwei Beispielprogramme von einer Internetseite genommen.
Was soll ich sagen, es funktionierte auf Anhieb. Allerdings war dort die Kommunikation anders herum. Der D1 mini hat gesendet und der Nano empfangen.
Kurz die relevanten Programmteile untereinander getauscht und siehe da, es ging auch vom Nano zum D1 mini :).

Nun gilt es noch herauszufinden, welche Programmteile der alten Programme für die Nanos, das Scheitern verursachte.
Signifikante Unterschiede sind zwei Einstellungen des NRF24, nämlich die Übertragungsgeschwindigkeit und die Signalstärke.
Im alten Programm ist die Übertragungsgeschwindigkeit 250kb/s und Übertragungsleistung auf Maximum.

In den neuen Programmen habe ich die Einstellung auf Default gelassen.

Zuerst möchte ich ein paar grundsätzliche Dinge zum Anschluß klären.

Das NRF24l01 wird über eine so genannte SPI-Schnittstelle angesteuert. Für einen SPI-Anschluß benötigt man mindestens die Signale MISO, MOSI, SCK und CS.
Das bedeutet MOSI (Master in Slave Out) und heißt, auf dieser Leitung sendet das Mastermodul an den Slave. MISO ist (Master in Slave Out) und bedeutet, dass auf dieser leitung der Slave Informationen an den Master sendet.
SCK ist die Taktleitung, die vom Master angesteuert wird, damit der Slave weiß, wann jeweils ein Informationsbit ankommt. Weil der SPI-Bus ein Bus ist, können mehrere Slaves an diesen Bus angeschlossen werden, dabei teilen sie sich alle die MOSI, MISO und SCK Leitung. Damit der jeweilige Slave auch weiß, dass er gemeint ist, gibt es noch den CS (Chip Select) Kanal. Dafür benötigt der master in der Regel soviele Ausgänge, wie Slaves angeschlossen sind.

Bei den unterschiedlichen Modulplattformen sind diverse Ports bereits für die erforderlichen Anschlüsse der SPI-Kommunikation vorgesehen und stellen damit so eine Art Standard dar.
Lediglich bei der CS (Chip Select) Leitung können unterschiedliche Ports gewählt werden. Leider kochen die Hersteller von Sensoren beim SPI-Bus teilweise eigene Süppchen. Bestes Beispeil ist der NRF24, der zusätzlich noch einen IRQ und CSN-Anschluß besitzt. Auf den IRQ-Anschluß kann man ggf. verzichten, nicht aber auf den CSN-Anschluß.

Kommen wir wieder zum konkreten Beispiel. Der WEMOS D1 mini sieht für die SPI-Schnittstelle die Ports D5, D6 und D7 vor. D5 - SCK, D6 - MISO und D7 - MOSI.
CE / CS habe ich in meinem Beispiel auf D1 liegen. Es funktionieren aber auch D2 und D4 (ausprobiert). Für CSN verwende ich D2, es geht aber auch D8 (ausprobiert)

Für den Nano sind die Anschlüsse D10, D11, D12 und D13 üblich. D10 - SS / CS (Chip Select), D11 MOSI, D12 - MISO und D13 - SCK (Clock).
CE und CSN werden gerne auf D8 und D9 gelegt. Es kommen durchaus auch die Ports D3 und D4 vor.

Meine spezielle Belegung für CS und CSN beim WEMOS D1 mini hat einen besonderen Grund. ich möchte später noch ein TFT-Display dazu anschließen, wie im Bericht WEMOS D1 mini mit 240x320 2,4" TFT Display RGB beschrieben. Da wird ein Portausgang für CS (TFT-Display) beim D1 mini bereits mit D2 belegt, weshalb ich den für den NRF24 für CS wahrscheinlich D8 oder D0 verwenden werde.



Eine kurze Anmerkung, warum ich unbedingt jetzt den D1 mini ans Laufen bringen möchte:
Das später noch anzuschließendes TFT-Display arbeitet leider nur mit 3,3V, weshalb ich bei einem Nano Spannungsteiler oder einen zusätzlichen Pegelwandler einsetzen müsste. Das liefert der D1 mini bereits "ab Werk" und es sind keine weiteren Hardwareanpassungen nötig. Außerdem habe ich die D1 minis hier schon nutzlos liegen. Die D1 minis sind zudem schneller und haben einen größeren Speicher. Die geringere Portzahl ist nicht so schlimm, weil ich damit sowieso nicht mehrere Sensoren betreiben, oder analoge Signale messen möchte. Trotzdem wird es mit dem NRF24 und dem geplaten TFT-Display langsam eng.
 
Zuletzt bearbeitet:

BAXL

Admin
Mitarbeiter
Software zur Ansteuerung

Es sollen also zwei Module, ein Nano und ein D1 mini, Daten austauschen. Die Programme werde ich unbereinigt hier einstellen, d.h. das die Programme die Codezeilen jeweils für die Funktion als Sender und als Empfänger enthalten. In meinem Beispiel ist der Nano der Sender und der D1 mini der Empfänger. Die Codezeilen für die jeweils andere Datenrichtung habe ich nur mit // oder /* */ auskommentiert. Man kann diese also nach eigenem Gusto wieder aktivieren und dafür die anderen Zeilen deaktivieren. Eine kleine Besonderheit gibt es noch. Die ursprünglichen Beispielprogramme haben lediglich ein "Hallo Welt" in gewissen Zeitabständen gesendet. Weil mein endgültiges Ziel aber die Darstellung von Messwerten mehrerer Sender sein soll, habe ich bereits beim Nano die Abfrage eines Ports eingebaut, dessen Status am Empfänger, dem D1 mini, im seriellen Fenster am PC angezeigt werden soll.

Zuerst der Code für den Nano (als Sender):

C++:
//Include Libraries
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

//create an RF24 object
RF24 radio(8, 9);  // CE, CSN

//address through which two modules communicate.
const byte address[6] = "00001";

int button_pin = 7;               // Signalpin zum Einlesen des Schaltsignals (Taster, Bewegungsmelder etc.)
byte button_state = 0;
void setup()
{
/*
// daten empfangen
  Serial.begin(9600);
  delay(2000);

  radio.begin();

  //set the address
  radio.openReadingPipe(0, address);

  //Set module as receiver
  radio.startListening();

  Serial.println("inizio ad ascoltare");
  Serial.println(radio.isChipConnected());
  */
// Daten senden
  Serial.begin(9600);
  pinMode(button_pin, INPUT);     // Port zum Einlesen des Schalterzustandes konfigurieren
  delay(500);

  radio.begin();

  //set the address
  radio.openWritingPipe(address);

  //Set module as transmitter
  radio.stopListening();

  Serial.println("inizio ad trasmettere");
  Serial.println(radio.isChipConnected());

}

void loop()
{


// Daten senden 
  button_state = digitalRead(button_pin); // Einlesen des Schalterzustandes
  Serial.println(button_state);           // Kontrollausgabe des Schalterzustandes am PC-Monitor

  Serial.println("Start");
  radio.write(&button_state, sizeof(button_state));  //Senden des Schalterstatus zum Empfänger
  //const char text[] = "Hello World";
  //bool ret = radio.write(&text, sizeof(text));
  bool ret =  radio.write(&button_state, sizeof(button_state));  //Senden des Schalterstatus zum Empfänger
  Serial.print("Sendeergebnis: ");
  Serial.println(ret);
  delay(500);
  /*
  //Read the data if available in buffer
  if (radio.available())
  {
    char text[32] = {0};
    radio.read(&text, sizeof(text));
    Serial.println(text);
  }
*/


}
Und der Code für den D1 mini als Empfänger:

C++:
//Include Libraries
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

//create an RF24 object
//RF24 radio(D4, D8);  // CE, CSN geht
// RF24 radio(D2, D8);  // CE, CSN geht
RF24 radio(D1, D2);  // CE, CSN geht
//address through which two modules communicate.
const byte address[6] = "00001";
byte button_state = 0;        // Überprüfung des eingehenden Schaltsignals
void setup()
{
/*
// Daten senden
  Serial.begin(9600);
  delay(2000);

  radio.begin();

  //set the address
  radio.openWritingPipe(address);

  //Set module as transmitter
  radio.stopListening();

  Serial.println("inizio ad trasmettere");
  Serial.println(radio.isChipConnected());
  */
// Daten empfangen
  Serial.begin(9600);
  delay(2000);

  radio.begin();

  //set the address
  radio.openReadingPipe(0, address);

  //Set module as receiver
  radio.startListening();

  Serial.println("Lausche auf Signal");
  Serial.println(radio.isChipConnected());
}
void loop()
{
  /*
// Daten senden 
  Serial.println("qui");
  const char text[] = "Hello World";
  bool ret = radio.write(&text, sizeof(text));
  Serial.print("Write ret: ");
  Serial.println(ret);
  delay(1000);
  */

  //Read the data if available in buffer
  if (radio.available())
  {
//    char text[32] = {0};
//    radio.read(&text, sizeof(text));
    radio.read(&button_state, sizeof(button_state));    //Einlesen des Schalterstatus vom Sender
    Serial.print("Schalter: "); Serial.println(button_state);
  }
  delay(500);
}
 
Zuletzt bearbeitet:

BAXL

Admin
Mitarbeiter
Heute habe ich nach einer bewegten Woche ;) wieder Zeit mich dem in Post 1 genannten Problem zu widmen.

Ich hatte bereits bei mir vorhandenen, auf Nanos funktionierenden Code, auf den WEMOS übertragen, um Daten per NRF24 auszutauschen. Das schlug Anfangs leider fehl. Der in Post 2 genannte Code konnte dann eine Datenverbindung herstellen. Ich mußte herausfinden, warum es ganz am Anfang nicht klappte. Heute das AHA-Erlebnis.

Wenn man parallel zwei Programme bearbeitet, muß man immer genau hinschauen. Beim Hin- und Herkopieren hatte ich wohl einen Fehler gemacht, der erst nicht ganz offensichtlich war. Der Fehler lag auf der Empfängerseite beim WEMOS. Dort muß das NRF24 Modul initialisiert und als Empfänger deklariert werden. Dazu muß man einmal die "2,4GHz-Adresse" angeben und die interne Pipe-Nummer. Und da lag der Fehler. Ich hatte zwar die 2,4 GHz-Adresse richtig gesetzt, aber vergessen für die Pipenummer eine entsprechende Variable zu deklarieren, bzw. den Wert richtig zu setzen. Einfache Ursache, große Wirkung. Jetzt geht es.

Und das ist der Übeltäter, bzw. die korrigierte, funktionierende Zeile aus der Setuproutine:

radio.openReadingPipe(pipeNr, pipe[pipeNr]); // Adresse, auf dem die Empfangsdaten erwartet werden sollen

Hier sind die Zeilen aus dem Deklarationsteil des Programms :

static const uint64_t pipe[6] = {0xF0F0F0F0C1LL, 0xF0F0F0F0D2LL, 0xF0F0F0F0C3LL, 0xF0F0F0F0B4LL, 0xF0F0F0F0A5LL, 0xF0F0F0F096LL};
byte pipeNr = 0;

Am Rande sei noch bemerkt, dass meine ursprüngliche Vermutung, dass es evtl. an der Übertragungsgeschwindigkeit oder Übertragungsleistung liegen könne, sich damit nicht bestätigt hat.

Im nächsten Schritt soll der WEMOS nun Daten aus dem bestehenden Projekt der Hausdatenüberwachung (Alarmanlage/Smart Home mit Arduino - vorbereitende Experimente ) empfangen können. Dazu sind umfangreichere Anpassungen des Programms erforderlich. Zum einen müssen pro Messstelle mehrere Daten empfangen werden und das dann der Reihe nach für mehrere Messstellen.

Dafür wechsele ich aber wieder in das Hauptprojekt, weil ich hier nur das eine spezifische Problem mit dem NRF24l01 herausarbeiten wollte. Deshalb öffne ich das Thema hier jetzt auch. Es können nun gerne Fragen oder andere sachdienliche Hinweise dazu gepostet werden.
 
Zuletzt bearbeitet:
Top Bottom