[SOLVED] Trying to implement buttons/servo over Nrf24l01

I’ve literally been tearing my hair out over this so any help is very much appreciated, believe me!
The basic setup I have is 2 nanos, 1 in my shed to monitor a battery bank and temperature and to control a servo. The other one in the house receives and displays the battery bank status and temperature with no problem. However, I wish to be able to use 2 buttons in the house to control that servo in the shed,(and 2 LEDs, red and green for off and on) which in turn controls the brake for a wind turbine.

At the moment, it works perfectly as the basic “monitor”.

I have a separate sketch that works the 2 buttons/1 servo on the same nano, again no problem. The problems start when I try to split the sketch and implement it into my other ones. I have tried for weeks but am getting nowhere fast.
I have returned my sketches to the basic “monitor” again and will include these and the separate servo sketch also (On next post!). I have read and studied the Nrf24l01 tutorials but am still a bit lost when it comes to the compiling and sending of the data.
I’ll also attach a Fritzing drawing i have made.

I am a bit of a noob (wish they had things like this when I was younger!) so please be patient!
Many thanks,
Andrew

House Nano -

//Buttons

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#include <Fonts/FreeSans9pt7b.h>


#define CE_PIN   7
#define CSN_PIN 8


// OLED display TWI address
#define OLED_ADDR   0x3C
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     0 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

const byte addresses[][6] = {"00001", "00002"};

RF24 radio(CE_PIN, CSN_PIN);

int but1 = 4;
int but2 = 5;

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

boolean buttonState = 0;

float val2;
float temperature;

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

void setup()
{
 // initialize and clear display
  display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);
  display.clearDisplay();

  pinMode(4, INPUT);
  pinMode(5, INPUT);

   Serial.begin(9600);
   

   Serial.println("Receiver starting");
   radio.begin();
   radio.setPALevel(RF24_PA_MIN);
   radio.setDataRate( RF24_2MBPS );
   radio.openWritingPipe(addresses[0]); // 00002
  radio.openReadingPipe(1, addresses[1]); // 00001
   radio.startListening();
}

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

void loop(){
  

   getData();
   showData();


}

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

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

void showData()
{
   if (newData == true)
   {
      Serial.print("Data received ");
      Serial.println(dataReceived);
      char * strtokIndx; // this is used by strtok() as an index

      strtokIndx = strtok(dataReceived, ",");     // get the first part - the string
     val2 = atoi(strtokIndx) / 100.00;

      strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
      temperature = atoi(strtokIndx) / 100.00;


      Serial.print("Battery Voltage  ");
      Serial.print(val2);
      Serial.print("V  ");
      Serial.print("   Temperature  ");
      Serial.print(temperature);
      Serial.println("deg C");

display.drawRect(0, 0, 128, 64, WHITE);
display.setFont(&FreeSans9pt7b);
display.setTextColor(WHITE, BLACK);
display.setCursor(70,25);
display.setTextSize(1);
display.println("Temp");


display.setFont(&FreeSans9pt7b);
display.setTextColor(WHITE, BLACK);
display.setCursor(10,25);
display.setTextSize(1);
display.println("Batts");

display.setFont(&FreeSans9pt7b);
display.setTextColor(WHITE, BLACK);
display.setCursor(70,49);
display.setTextSize(1);
display.println(temperature);

display.setFont(&FreeSans9pt7b);
display.setTextColor(WHITE, BLACK);
display.setCursor(10,49);
display.setTextSize(1);
display.println(val2);


display.display();
display.clearDisplay();  

  
      newData = false;

   }
   }

Shed Nano -

//Servo

#include <Arduino.h>
#include <Wire.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <BMP180MI.h>
#include <Servo.h>

Servo servo;  

int angle =90;    // initial angle  for servo
int angleStep =180;


#define CE_PIN   7
#define CSN_PIN 8
#define I2C_ADDRESS 0x77





BMP180I2C bmp180(I2C_ADDRESS);
const byte addresses[][6] = {"00001", "00002"};


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

char dataToSend[20];
char txNum = '0';


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

// test data *******************************
float val2;
float temperature;
boolean buttonState = 0;

int val11;

void setup() {
  
  pinMode(5, OUTPUT);
  
  Wire.begin();



servo.attach(4);  // attaches the servo on pin 4 to the servo object
servo.write(angle);// send servo to the middle at 90 degrees

    Serial.begin(9600);

    Serial.println("Sender Starting");

    radio.begin();
    radio.setPALevel(RF24_PA_MIN);
    radio.setDataRate( RF24_2MBPS );
    radio.openWritingPipe(addresses[1]); // 00001
  radio.openReadingPipe(1, addresses[0]); // 00002

//begin() initializes the interface, checks the sensor ID and reads the calibration parameters.  
  if (!bmp180.begin())
  {
    Serial.println("begin() failed. check your BMP180 Interface and I2C Address.");
    while (1);
  }

  //reset sensor to default parameters.
  bmp180.resetToDefaults();

  //enable ultra high resolution mode for pressure measurements
  bmp180.setSamplingMode(BMP180MI::MODE_UHR);
}

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

void loop() {

float temp ; //Float..
val11 = analogRead (1) ; //Sets analog pin 1 as input
temp = val11 / 3.930 ; //Val1 divided by 4.092
val11 = (int) temp ; //get float
val2 = ((val11 % 200) / 11.18 ); //Value divider line. I set to 200% to read from a 12 volt system with a divider value of 11.18

  delay (1000 ) ; //Every 1 second(s)
  
    currentMillis = millis();
    if (currentMillis - prevMillis >= txIntervalMillis) {
        makePacket(val2, temperature);
        send();
        prevMillis = millis();

        if (!bmp180.measureTemperature())
  {
    Serial.println("could not start temperature measurement, is a measurement already running?");
    return;
  }

  //wait for the measurement to finish. proceed as soon as hasValue() returned true. 
  do
  {
    delay(100);
  } while (!bmp180.hasValue());

Serial.print("Battery Voltage  ");
      Serial.print(val2);
      Serial.print("V  ");
      Serial.print("   Temperature  ");
      Serial.print(bmp180.getTemperature());
      Serial.println("deg C");

 
    }
}



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

void makePacket(float val2, float temp)
{
  // convert data to int for easier transmission
  int batteryInt = val2 * 100;
  int tempInt = bmp180.getTemperature() * 100;
  // make packet
  sprintf(dataToSend, "%d,%d", batteryInt, tempInt);
}

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

    Serial.print("Data Sent ");
    Serial.print(dataToSend);
    if (rslt) {
        Serial.println("  Acknowledge received");        
    }
    else {
        Serial.println("  Tx failed");


    
    
  
    

    }
    }

2 Buttons/1 Servo -

#include <Servo.h>

Servo myservo;  // create servo object to control a servo

int angle =90;    // initial angle  for servo
int angleStep =180;

#define LEFT 4   // pin 4 is connected to left button
#define RIGHT  5  // pin 5 is connected to right button

void setup() {
  
  Serial.begin(9600);          //  setup serial
  myservo.attach(3);  // attaches the servo on pin 8 to the servo object
  pinMode(LEFT,INPUT_PULLUP); // assign pin 12 ass input for Left button
  pinMode(RIGHT,INPUT_PULLUP);// assing pin 2 as input for right button
  myservo.write(angle);// send servo to the middle at 90 degrees
 Serial.println("Servo Buttons ");
}

void loop() {
 
  while(digitalRead(RIGHT) == LOW){

    if (angle > 0 && angle <= 180) {
      angle = angle - angleStep;
       if(angle < 0){
        angle = 180;
       }else{
      myservo.write(angle); // move the servo to desired angle
      Serial.print("Moved to: ");
      Serial.print(angle);   // print the angle
      Serial.println(" Brake On");
       }
    }
    
  delay(100); // waits for the servo to get there
  }// while
 

  while(digitalRead(LEFT) == LOW){

    if (angle >= 0 && angle <= 180) {
      angle = angle + angleStep;
      if(angle >180){
        angle =180;
       }else{
      myservo.write(angle); // move the servo to desired angle
      Serial.print("Moved to: ");
      Serial.print(angle);   // print the angle
      Serial.println("Brake Off");
       }
    }
    
  delay(100); // waits for the servo to get there
  }// 

  
}

Buttons are wired incorrectly, fix that first.

JCA79B:
Buttons are wired incorrectly, fix that first.

Oops, my mistake on the drawing. They are wired correctly to the negative! I'll try and update it in the morning.

Have a look at this Simple nRF24L01+ Tutorial.

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

…R

Robin2:
Have a look at this Simple nRF24L01+ Tutorial.

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

...R

Hi Robin, thanks for the reply.
It was your tutorial that I have used but I'm still a bit confused on configuring the data i need to send then sorting it out at the other end also :frowning:

As you seem to want to send two int values why not make it simple like this

int dataToSend[2];
dataToSend[0] = batteryInt;
dataToSend[1] = tempInt;

and do the same on the receiving side

int dataReceived[2];

Then there is no need for sprintf() or atoi() etc

...R

I would put the data to be sent in a struct like this as it gives more flexibility regarding data types if needed

// SimpleTx - the master or the transmitter

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

//not all #defines used but here for documentation
#define CE_PIN   9
#define CSN_PIN 10
#define MOSI_PIN 11
#define MISO_PIN 12
#define SCK_PIN 13

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

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

char txNum = '0';

struct data
{
  byte pinState;
  int temperature;
} sentData;

unsigned long currentMillis;
unsigned long prevMillis;
unsigned long txIntervalMillis = 1000;

void setup()
{
  Serial.begin(115200);
  Serial.println("SimpleTx Starting");
  radio.begin();
  radio.setDataRate( RF24_250KBPS );
  radio.setRetries(3, 5); // delay, count
  radio.openWritingPipe(slaveAddress);
}

void loop()
{
  currentMillis = millis();
  if (currentMillis - prevMillis >= txIntervalMillis)
  {
    sentData.pinState = !sentData.pinState;
    sentData.temperature = sentData.temperature + 1;
    send();
    prevMillis = millis();
  }
}

void send()
{
  bool rslt;
  rslt = radio.write( &sentData, sizeof(sentData) );
  if (rslt)
  {
    Serial.println("  Acknowledge received");
  }
  else
  {
    Serial.println("  Tx failed");
  }
}

and receive it like this

// SimpleRx - the slave or the receiver

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

//not all #defines used but here for documentation
#define CE_PIN   9
#define CSN_PIN 10
#define MOSI_PIN 11
#define MISO_PIN 12
#define SCK_PIN 13

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

RF24 radio(CE_PIN, CSN_PIN);

struct data
{
  byte pinState;
  int temperature;
} receivedData;

bool newData = false;

void setup()
{
  Serial.begin(115200);
  Serial.println("SimpleRx Starting");
  radio.begin();
  radio.setDataRate( RF24_250KBPS );
  radio.openReadingPipe(1, thisSlaveAddress);
  radio.startListening();
}

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

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

void showData()
{
  if (newData == true)
  {
    Serial.print("Data received\tpinState : ");
    Serial.print(receivedData.pinState);
    Serial.print("\t");
    Serial.print("temperature : ");
    Serial.println(receivedData.temperature);
    newData = false;
  }
}

The code is basically that written by Robin2

I have the voltage and temperature part already up and running fine. Just having a bit of trouble adding 2 buttons and a servo to the mix. How would I be able to send the data from the buttons in the house to the servo in the shed. :confused:

How would I be able to send the data from the buttons in the house to the servo in the shed

Put the values in a struct and send that. See my example

Thanks again for everyone’s advice!

However I still have a problem of some kind. I have gone back to basics and tried to work 2 leds with the buttons wirelessly but am still unable to receive the input.

I used your example UKHeliBob but it seems I am missing something somewhere. The wiring is exactly the same as before but i have wired in the 2 leds to d5 and d6 of the second nano.

Any chance you could have a look?
Really appreciate it!

Buttons -

// Buttons side

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

RF24 radio(7, 8); // CE, CSN
const byte addresses[][6] = {"00001", "00002"};

int button1 = 4;
int button2 = 5;


char txNum = '0';

struct data
{
  int button1;
  int button2;
} sentData;

unsigned long currentMillis;
unsigned long prevMillis;
unsigned long txIntervalMillis = 1000;


void setup() {
  
Serial.begin(9600);
Serial.println("SimpleTx Starting");

  pinMode(button1, INPUT);
  pinMode(button2, INPUT);

  radio.begin();
  radio.openWritingPipe(addresses[0]); // 00002
  radio.openReadingPipe(1, addresses[1]); // 00001
  radio.setPALevel(RF24_PA_MIN);
  radio.setDataRate( RF24_2MBPS );

}

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

void send()
{
  bool rslt;
  rslt = radio.write( &sentData, sizeof(sentData) );
  if (rslt)
  {
    Serial.println("  Acknowledge received");
  }
  else
  {
    Serial.println("  Tx failed");
  }
}

LEDs -

// LEDs side

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

int button1;
int button2;

int led1 = 5;
int led2 = 6;


RF24 radio(7, 8); // CE, CSN
const byte addresses[][6] = {"00001", "00002"};

struct data
{
  int button1;
  int button2;
} receivedData;

bool newData = false;

void setup() {

pinMode(5, OUTPUT);
pinMode(6, OUTPUT);

 Serial.begin(9600);
 Serial.println("Test Starting");

 radio.begin();
  radio.openWritingPipe(addresses[1]); // 00001
  radio.openReadingPipe(1, addresses[0]); // 00002
  radio.setPALevel(RF24_PA_MIN);
  radio.setDataRate( RF24_2MBPS );
  radio.startListening();
  
}
void loop()
{
  getData();
  showData();
}
void getData()
{
  if ( radio.available() )
  {
    radio.read( &receivedData, sizeof(receivedData) );

    newData = true;

    
  }
}

void showData()
{
  if (newData == true)
  {
if (button1 == HIGH) {
    // turn LED on:
    digitalWrite(led1, HIGH);
  } else {
    // turn LED off:
    digitalWrite(led1, LOW);
    if (button2 == HIGH) {
    // turn LED on:
    digitalWrite(led2, HIGH);
  } else {
    // turn LED off:
    digitalWrite(led2, LOW);
    
    Serial.print("Data received\tButton 1 : ");
    Serial.print(receivedData.button1);
    Serial.print("\t");
    Serial.print("Button 2 : ");
    Serial.println(receivedData.button2);
    newData = false;
  
  }
  }

  }
  }

These two lines do nothing:

    sentData.button1 = sentData.button1;
    sentData.button2 = sentData.button2;

There was so much wrong that it was easier to correct it rather than describe the problems

TX

// Buttons side

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

RF24 radio(9, 10); // CE, CSN
const byte addresses[][6] = {"00001", "00002"};

char txNum = '0';

int button1Pin = 4;
int button2Pin = 5;

struct data
{
  int button1State;
  int button2State;
} sentData;

unsigned long currentMillis;
unsigned long prevMillis;
unsigned long txIntervalMillis = 1000;


void setup()
{
  Serial.begin(115200);
  Serial.println("SimpleTx Starting");
  pinMode(button1Pin, INPUT_PULLUP);
  pinMode(button2Pin, INPUT_PULLUP);
  radio.begin();
  radio.openWritingPipe(addresses[0]); // 00002
  radio.openReadingPipe(1, addresses[1]); // 00001
  radio.setPALevel(RF24_PA_MIN);
  radio.setDataRate( RF24_2MBPS );
}

void loop()
{
  currentMillis = millis();
  if (currentMillis - prevMillis >= txIntervalMillis)
  {
    sentData.button1State = digitalRead(button1Pin);
    sentData.button2State = digitalRead(button2Pin);
    send();
    prevMillis = millis();
  }
}

void send()
{
  bool rslt;
  rslt = radio.write( &sentData, sizeof(sentData) );
  if (rslt)
  {
    Serial.println("  Acknowledge received");
  }
  else
  {
    Serial.println("  Tx failed");
  }
}

RX

// LEDs side

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

int button1;
int button2;

int led1 = 5;
int led2 = 6;


RF24 radio(9, 10); // CE, CSN
const byte addresses[][6] = {"00001", "00002"};

struct data
{
  int button1State;
  int button2State;
} receivedData;

bool newData = false;

void setup()
{
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  Serial.begin(115200);
  Serial.println("Test Starting");
  radio.begin();
  radio.openWritingPipe(addresses[1]); // 00001
  radio.openReadingPipe(1, addresses[0]); // 00002
  radio.setPALevel(RF24_PA_MIN);
  radio.setDataRate( RF24_2MBPS );
  radio.startListening();
}
void loop()
{
  getData();
  showData();
}
void getData()
{
  if ( radio.available() )
  {
    radio.read( &receivedData, sizeof(receivedData) );
    newData = true;
  }
}

void showData()
{
  if (newData == true)
  {
    if (receivedData.button1State == HIGH)
    {
      // turn LED on:
      digitalWrite(led1, HIGH);
    }
    else
    {
      // turn LED off:
      digitalWrite(led1, LOW);
    }
    if (receivedData.button2State == HIGH)
    {
      // turn LED on:
      digitalWrite(led2, HIGH);
    }
    else
    {
      // turn LED off:
      digitalWrite(led2, LOW);
    }
    Serial.print("Data received\tButton 1 : ");
    Serial.print(receivedData.button1State);
    Serial.print("\t");
    Serial.print("Button 2 : ");
    Serial.println(receivedData.button2State);
    newData = false;
  }
}

UKHeliBob, I can't thank you enough!

Looks simple once you see it....

Thanks again,
Andrew

Looks simple once you see it....

Sometimes even simple things like giving variables meaningful names can make things more obvious. For instance it is not uncommon to see confusion between pin number and pin states.

Note that as suggested by Robin2 you could have just as well used an array to hold to hold the pin states in this example.

UKHeliBob:
Sometimes even simple things like giving variables meaningful names can make things more obvious. For instance it is not uncommon to see confusion between pin number and pin states.

Note that as suggested by Robin2 you could have just as well used an array to hold to hold the pin states in this example.

Think I might have to study it a bit more when i get time!

You could even get clever and use 2 bits of a single byte to pass the on/off state of 2 pins.

UKHeliBob:
You could even get clever and use 2 bits of a single byte to pass the on/off state of 2 pins.

1 step at a time! :astonished: :astonished:

1 step at a time!

Yes, but remember that

the journey of a thousand miles begins with one step.

Nobody said it would be easy! :confused: