Multiple Arduinos with NRF24L01 Modules

End goal is to have multiple arduinos with analog sensors, sending their sensor data to the receiving arduino, and the receiver prints all of the data in one line in the serial monitor. Starting off simple, I got it to work, and print the way I like it, with one transmitter and one FSR. I’ve read through and looked at these two examples, but I’m still confused for how to make it work the way I described for multiple transmitters:

Here is the code that I started with, with one transmitter.

Transmitter

#include <SPI.h> 
#include <nRF24L01.h>
#include <RF24.h>
//#define button 6

RF24 radio(7, 8); // CE, CSN

const byte address[6] = "00001";
//boolean buttonState = 0;

void setup() {
  //pinMode(button, INPUT);
  radio.begin();
  radio.openWritingPipe(address);
  radio.setPALevel(RF24_PA_MAX);
  radio.stopListening();
}

void loop() {
delay(5);
    radio.stopListening();
    //buttonState = digitalRead(button);
    int sensorValue = analogRead(A0);
    float voltage = sensorValue;
    radio.write(&sensorValue, sizeof(unsigned long));
  }

Receiver:

#include  <SPI.h>
#include <nRF24L01.h>
#include<RF24.h>
//#define led 6

RF24 radio(7, 8); // CE, CSN
const byte address[6] = "00001";
//boolean buttonState = 0;

void setup() {
  //pinMode(6, OUTPUT);
  Serial.begin(9600);
  radio.begin();
  radio.openReadingPipe(0, address);
  radio.setPALevel(RF24_PA_MAX);
  radio.startListening();
}
void loop() {
 delay(5);
  radio.startListening();
  while (!radio.available());
  radio.read(&sensorValue, sizeof(unsigned long));
  Serial.println(); 
  /*if (buttonState == HIGH) {
    digitalWrite(led, HIGH);
  }
  else {
    digitalWrite(led, LOW); 
  } */
  }

Why are you not using the sample code that was given in your link?

Paul

I thought starting fresh from what I have already accomplished, then thinking of how to add to it, would be more productive.

The first link uses sensors and servos that I am unfamiliar with. It is also working as a contained unit with one sensor on one arduino controlling a servo on another arduino. I just need the data from each transmitter to print out on the receiver.

The second link has an example with a master arduino controlling two slaves, but I'm unsure of how to reverse engineer it, then get it to read my analog pins.

Worry about "reverse engineering" after you get it to work.

Paul

CLK: I thought starting fresh from what I have already accomplished, then thinking of how to add to it, would be more productive.

I would not call that unsensible 'stuff' an accomplishment.

void loop() {
delay(5);
    radio.stopListening();
    //buttonState = digitalRead(button);
    int sensorValue = analogRead(A0);
    float voltage = sensorValue;
    radio.write(&sensorValue, sizeof(unsigned long));
  }

For this test you want to send 200 packets a second? Why?

Why are you calling stopListening without ever having called startListening?

Why are you using delay in the receiver?

Why is that button code still in there? You know that you will need an external pulldown/pullup for the button with INPUT?

You are reading from the analog port into an 16 bit integer, then you copy that value to a float variable that is never used. (The compiler is smart enough to remove that code.) You are sending the integer from above and the two bytes behind it (whatever that may be).

There is nothing inside the packet that would allow the receiver to detect the source of the packet, that strategy will make it unnecessarily hard to communicate with many sources.

Have a look at this Simple nRF24L01+ Tutorial.

It includes an example for a master and 2 slaves that can easily be extended to a larger number of slaves.

Wireless problems can be very difficult to debug so get the wireless part working on its own before you start adding any other features.

The examples are as simple as I could make them and they have worked for other Forum members. If you get stuck it will be easier to help with code that I am familiar with. Start by getting the first example to work

There is also a connection test program to check that the Arduino can talk to the nRF24 it is connected to.

...R

Hope you all had good holidays! I took a break from this, had some wine, and started to look at it again with a clear head.

To recap, I was previously taking the route of:

  1. Test a NRF24l01 code that uses a simple button sensor. One transmitter to one receiver.
  2. Comment out the button code and adapt it for an FSR (because I have FSRs on hand and not buttons. Better to comment out rather than completely delete too in case if I do want to add a button later on)
  3. Adapt it for multiple transmitters and one receiver.

In my original post, I had gotten to step 2 before getting stuck. Apparently it was “unsensible stuff”, although at the time when I pressed the FSR of the transmitting Uno, I could see its data printing out in the receiving Uno. Maybe I’ll go back to this later to make it “sensible”.

Since starting again after Christmas, I decided to not look at my previous codes, and once again look at the tutorial in the forums. https://forum.arduino.cc/index.php?topic=421081

In my original post, I did say that it confused me, but here is where I am at:
A. Make sure the original code works before altering it. One trans to one receiver
B. Adapt the codes for 2 transmitters and one receiver
C. Adapt the codes again so the receiver is printing the data from the analog pins of both transmitter 1 and 2 (right now it’s just counting up)

I am at step B. In the serial monitor, I can see transmitter 1 and 2 both making their connections and printing their data. But for the receiver, in the serial monitor it only says “Data Received”. Is it supposed to be like, or should it print the numbers counting from 0-9 from each transmitter? Here are the codes:

Receiver:

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

#define CE_PIN   7
#define CSN_PIN 10

const byte thisSlaveAddress1[5] = {'R','x','A','A','A'};
const byte thisSlaveAddress2[5] = {'R','x','A','A','A'};

RF24 radio(CE_PIN, CSN_PIN);

char dataReceived[10]; // this must match dataToSend in the TX
bool newData = false;

//===========

void setup() {

    Serial.begin(9600);

    Serial.println("SimpleRx Starting");
    radio.begin();
    radio.setDataRate( RF24_250KBPS );
    radio.openReadingPipe(1, thisSlaveAddress1);
    radio.openReadingPipe(2, thisSlaveAddress2);
    radio.startListening();
}

//=============

void loop() {
    getData();
    showData();
}

//==============

void getData() {
    if ( radio.available() ) {
        radio.read( &dataReceived, sizeof(unsigned long) );
        newData = true;
    }
}

void showData() {
    if (newData == true) {
        Serial.print("Data received ");
        Serial.println(dataReceived);
        newData = false;
    }
}

Trans 1

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>


#define CE_PIN   7
#define CSN_PIN 8

const byte slaveAddress1[5] = {'R','x','A','A','A'};

RF24 radio(CE_PIN, CSN_PIN); // Create a Radio

char dataToSend[10] = "Message 0";
char txNum = '0';


unsigned long currentMillis;
unsigned long prevMillis;
unsigned long txIntervalMillis = 1000; // send once per second


void setup() {

    Serial.begin(9600);

    Serial.println("SimpleTx1 Starting");
    radio.begin();
    radio.setDataRate( RF24_250KBPS );
    radio.setRetries(3,5); // delay, count
    radio.openWritingPipe(slaveAddress1);
}

//====================

void loop() {
    currentMillis = millis();
    if (currentMillis - prevMillis >= txIntervalMillis) {
        send();
        prevMillis = millis();
    }
}

//====================

void send() {

    /*bool rslt;
    rslt = radio.write( &dataToSend, sizeof(dataToSend) );
        // Always use sizeof() as it gives the size as the number of bytes.
        // For example if dataToSend was an int sizeof() would correctly return 2
*/ 
int dataReceived = analogRead(A0);
    float voltage = dataReceived;
    radio.write(&dataReceived, sizeof(unsigned long));
    
    Serial.print("Data Sent ");
    Serial.print(dataToSend);
    //if (rslt) {
    if (dataReceived) {
        Serial.println("  Acknowledge received1");
        updateMessage();
    }
    else {
        Serial.println("  Tx1 failed");
    }
}

//================

void updateMessage() {
        // so you can see that new data is being sent
    txNum += 1;
    if (txNum > '9') {
        txNum = '0';
    }
    dataToSend[8] = txNum;
}

Trans 2

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>


#define CE_PIN   7
#define CSN_PIN 8

const byte slaveAddress2[5] = {'R','x','A','A','A'};

RF24 radio(CE_PIN, CSN_PIN); // Create a Radio

char dataToSend[10] = "Message 1";
char txNum = '1';


unsigned long currentMillis;
unsigned long prevMillis;
unsigned long txIntervalMillis = 1000; // send once per second


void setup() {

    Serial.begin(9600);

    Serial.println("SimpleTx2 Starting");
    radio.begin();
    radio.setDataRate( RF24_250KBPS );
    radio.setRetries(3,5); // delay, count
    radio.openWritingPipe(slaveAddress2);
}

//====================

void loop() {
    currentMillis = millis();
    if (currentMillis - prevMillis >= txIntervalMillis) {
        send();
        prevMillis = millis();
    }
}

//====================

void send() {

    /*bool rslt;
    rslt = radio.write( &dataToSend, sizeof(dataToSend) );
        // Always use sizeof() as it gives the size as the number of bytes.
        // For example if dataToSend was an int sizeof() would correctly return 2
*/ 
int dataReceived = analogRead(A1);
    float voltage = dataReceived;
    radio.write(&dataReceived, sizeof(unsigned long));
    
    Serial.print("Data Sent ");
    Serial.print(dataToSend);
    //if (rslt) {
    if (dataReceived) {
        Serial.println("  Acknowledge received2");
        updateMessage();
    }
    else {
        Serial.println("  Tx2 failed");
    }
}

//================

void updateMessage() {
        // so you can see that new data is being sent
    txNum += 1;
    if (txNum > '9') {
        txNum = '0';
    }
    dataToSend[8] = txNum;
}

You seem to be hopelessly confused about the sizes of the data you are sending and receiving

In one of the Tx programs you have

int dataReceived = analogRead(A0);
    float voltage = dataReceived;
    radio.write(&dataReceived, sizeof(unsigned long));

Why are you trying to send the size of an unsigned long (4 bytes) when the data is in an int (2 bytes).

And, to make things worse, I see this in the Receive program

char dataReceived[10];

That should also be an int to match exactly what is in the Tx program.

If you look at the examples in my tutorial you will see that the code is the equivalent of

radio.write(&dataReceived, sizeof(datareceived));

so that the size is automatically correct.

Separately, while the compiler won't care, it seems unhelpful to call the data produced by analogRead() "receivedData". Why not call it fsrValue or something like that that describes what it really is. Program development and debugging is much easier when you use meaningful names for variables and functions.

...R