NRF24L01+ Communications errors

High, I have a very basic knowledge of code, and I am trying to transfer the press of a button press from an Arduino Uno to an Arduino Mega.

When I have only one button set up the code works perfectly, but as soon as I add a second button into the mix the code outputs randomly the first or second button.

Here is the transmitter code

//transmitter

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#define btn1 3 //btn1
#define btn2 5 //btn2
RF24 radio(7, 8 ); // CE, CSN
const byte addresses[][6] = {"00002"};
boolean btn1State = 0;
boolean btn2State = 0;
void setup() {
pinMode(btn1, INPUT);
pinMode(btn2, INPUT);
radio.begin();
radio.openWritingPipe(addresses[0]); // 00002
radio.setPALevel(RF24_PA_MIN);
radio.stopListening();

}
void loop() {
btn1State = digitalRead(btn1);
radio.write(&btn1State, sizeof(btn1State));
btn2State = digitalRead(btn2);
radio.write(&btn2State, sizeof(btn2State));
}

Here is the receiver code

//reciever

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
RF24 radio(7, 8 ); // CE, CSN
const byte addresses[][6] = {"00002"};
boolean btn1State = 0;
boolean btn2State = 0;
void setup() {
Serial.begin(9600);
radio.begin();
radio.openReadingPipe(1, addresses[0]); // 00002
radio.setPALevel(RF24_PA_MIN);
radio.startListening();

}
void loop() {
while (!radio.available());
radio.read(&btn1State, sizeof(btn1State));
if (btn1State == HIGH) {
Serial.println("btn1");
}
else {}
radio.read(&btn2State, sizeof(btn2State));
if (btn1State == HIGH) {
Serial.println("btn2");
}
else {}
}

Any help to change the code to make each button output its desired value would be greatly appreciated

The code may be OK.
Those radios fancy a very stable 3.3V to work properly.
They are more reliable with a capacitor soldered onto the modules power pins. 10uF is mentioned in many posts. I had luck with this 'fix'

One obvious mistake

radio.read(&btn2State, sizeof(btn2State));
  if (btn1State == HIGH) {           //which button ?
    Serial.println("btn2");
  }

All you are sending is the state of the buttons, one after the other after the other after the other after the other, you get the idea.

There is nothing that says which is which. You need a bigger packet - the transmissions do not catch a clue from your variable names.

Looks like now if both buttons are high, you get both listed. If both are low you get nothing. (You could put something in your emprty "else" clauses whilst testing).

If one button is down and the other up, you get continuous message about one of them, a missed packet will start telling you the other one is the one that's pressed.

Add an identifier to the packet. Check it to see which button's state is in the other part of your message. Send a little array of chars, not just one (anonymous!) byte.

a7

Or just send one packet consisting of both button states whenever at least one of them changes.

TX

#include <RF24.h>

struct Pack {
  boolean btn1State;
  boolean btn2State;
} packet;

const byte btn1 = 3;
const byte btn2 = 5;
const byte address[6] = {"20000"};

RF24 radio(7, 8 );

void setup() {
  pinMode(btn1, INPUT_PULLUP);
  pinMode(btn2, INPUT_PULLUP);
  radio.begin();
  radio.openWritingPipe(address);
  radio.setPALevel(RF24_PA_MIN);
  radio.enableDynamicPayloads();
}

void loop() {
  boolean sendPacket = false;
  boolean btn1State = digitalRead(btn1);
  boolean btn2State = digitalRead(btn2);
  if (btn1State != packet.btn1State) {
    packet.btn1State = btn1State;
    sendPacket = true;
  }
  if (btn2State != packet.btn2State) {
    packet.btn2State = btn2State;
    sendPacket = true;
  }
  if (sendPacket) {
    radio.write(&packet, sizeof(packet));
  }
}

RX

#include <RF24.h>

struct Pack {
  boolean btn1State;
  boolean btn2State;
} packet;

RF24 radio(7, 8 );

const byte address[] = {"20000"};

void setup() {
  Serial.begin(9600);
  radio.begin();
  radio.openReadingPipe(1, address);
  radio.enableDynamicPayloads();
  radio.setPALevel(RF24_PA_MIN);
  radio.startListening();
}

void loop() {
  if (radio.available()) {
    radio.read(&packet, sizeof(packet));
    Serial.print(F("btn1 is O"));
    Serial.print(packet.btn1State ? F("FF") : F("N"));
    Serial.print(F(", btn2 is O"));
    Serial.println(packet.btn2State ? F("FF") : F("N"));
  }
}

Whandall:
Or just send one packet consisting of both button states whenever at least one of them changes.

Yes. In some circumstances you might want to send such a message occasionally even if there is no button change.

a7

alto777:
In some circumstances you might want to send such a message occasionally even if there is no button change.

You could force at least one packet a second like this:

#include <RF24.h>

struct Pack {
  boolean btn1State;
  boolean btn2State;
} packet = { true, true };

const byte btn1 = 3;
const byte btn2 = 5;
const byte address[6] = {"20000"};

unsigned long lastSend;

RF24 radio(7, 8 );

void setup() {
  pinMode(btn1, INPUT_PULLUP);
  pinMode(btn2, INPUT_PULLUP);
  radio.begin();
  radio.openWritingPipe(address);
  radio.setPALevel(RF24_PA_MIN);
  radio.enableDynamicPayloads();
}

void loop() {
  unsigned long topLoop = millis();
  boolean sendPacket = false;
  boolean btn1State = digitalRead(btn1);
  boolean btn2State = digitalRead(btn2);
  if (btn1State != packet.btn1State) {
    packet.btn1State = btn1State;
    sendPacket = true;
  }
  if (btn2State != packet.btn2State) {
    packet.btn2State = btn2State;
    sendPacket = true;
  }
  if (!sendPacket && topLoop - lastSend >= 1000) {
    sendPacket = true;
  }
  if (sendPacket) {
    radio.write(&packet, sizeof(packet));
    lastSend = topLoop;
  }
}

Have a look at this Simple nRF24L01+ Tutorial.

If this was my project I would always send all the data in a single message and send messages at regular intervals (perhaps 5 per second) even if the data does not change. That way if the messages fail to arrive the receiving device can know that there is a communication failure.

...R

Add an identifier to the packet. Check it to see which button's state is in the other part of your message. Send a little array of chars, not just one (anonymous!) byte.

a7

[/quote]

How would I do that?

Thanks for all the help

Thesadclown:
How would I do that?

Have you studied the examples in my tutorial and tried them?

...R

Robin2:
Have you studied the examples in my tutorial and tried them?

...R

I have read through your examples, but am confused.

Robin2:
Have you studied the examples in my tutorial and tried them?

...R

I have read through your examples, but am confused.
In my situation, I want a series of buttons to transmit from the RX and influence a series of IF statements on the TX. In your code I can see that it will Serial print a message, but I am unsure as to where I would place the IF statements for the two buttons and where I would place the IF statements to make the RX do the desired effect.

Sorry about the previous post, I posted before I meant to

Whandall:
You could force at least one packet a second like this:

#include <RF24.h>

struct Pack {
  boolean btn1State;
  boolean btn2State;
} packet = { true, true };

const byte btn1 = 3;
const byte btn2 = 5;
const byte address[6] = {"20000"};

unsigned long lastSend;

RF24 radio(7, 8 );

void setup() {
  pinMode(btn1, INPUT_PULLUP);
  pinMode(btn2, INPUT_PULLUP);
  radio.begin();
  radio.openWritingPipe(address);
  radio.setPALevel(RF24_PA_MIN);
  radio.enableDynamicPayloads();
}

void loop() {
  unsigned long topLoop = millis();
  boolean sendPacket = false;
  boolean btn1State = digitalRead(btn1);
  boolean btn2State = digitalRead(btn2);
  if (btn1State != packet.btn1State) {
    packet.btn1State = btn1State;
    sendPacket = true;
  }
  if (btn2State != packet.btn2State) {
    packet.btn2State = btn2State;
    sendPacket = true;
  }
  if (!sendPacket && topLoop - lastSend >= 1000) {
    sendPacket = true;
  }
  if (sendPacket) {
    radio.write(&packet, sizeof(packet));
    lastSend = topLoop;
  }
}

I have been messing around with this and it has gotten me the farthest so far
Do you have any Ideas on how I could transfer the serial print so that me pressing a btn1 would light one LED and pressing btn2 would light a second LED?

Thanks a ton for all the help

LED Rx

#include <RF24.h>

struct Pack {
  boolean btn1State;
  boolean btn2State;
} packet;

RF24 radio(7, 8 );

const byte address[] = {"20000"};
const byte led1Pin = 4;
const byte led2Pin = 5;

void setup() {
  pinMode(led1Pin, OUTPUT);
  pinMode(led2Pin, OUTPUT);
  Serial.begin(9600);
  radio.begin();
  radio.openReadingPipe(1, address);
  radio.enableDynamicPayloads();
  radio.setPALevel(RF24_PA_MIN);
  radio.startListening();
}

void loop() {
  if (radio.available()) {
    radio.read(&packet, sizeof(packet));
    digitalWrite(led1Pin, !packet.btn1State);
    digitalWrite(led2Pin, !packet.btn2State);
  }
}

I want to thank all of you so much, I spent 4 weeks trying to teach myself how to do this, and you helped me make a working code in 2 days.

Thanks again for all the help

Hi,
How have you got your buttons wired to the controller.

If when you press the button, the controller input gets pulled HIGH, have you got a 10k resistor between the controller input and ground to pull the input LOW when the button is open circuit?

Thanks.. Tom.. :slight_smile:

Basically there is 5 volts to one side of the switch while the other has a wire running to the arduino and on that side of the switch there is also a 10k pull down resistor to keep the arduino reading nothing when the button is not pressed

Attached is a drawing of the button schematic