Tutorial: nrf24l01+

Introduction

The nrf24l01+ is often the best solution for close range communication between arduino based devices. They are extraordinarily cheap, do not require a wireless network, and any number of them can talk to eachother at once. However, there are limitations that should be considered when using them. They have a range of around 300 feet and should always be under that to ensure good use. They can send more complex signals, but there is no api for using them, so anything more than just sending numbers between them will take more time. If these limitations fit your project, however, the nrf24l01+ is a great option.
For more information about this component, here is a datasheet

Set Up

To connect the nrf24l01+ to an arduino, there are very specific pins that are required. This is due to the serial communications that are required. Fortunately, most of the serial is abstracted away during code, but the following pins must be hooked up to the same pins on your arduino; MOSI, SCK and MISO. Vcc and Gnd are connected to 3.3v and ground, CE and CSN can be attached to any pin (we will default to 9 and 10 respectively) and IRQ is not used when communicating with arduinos. For this tutorial we will be using an arduino uno, so the pins we connect will be based on that, but remember you will need to look at your specific arduino’s pinout if you wish to use a different arduino

Gnd-Gnd

Vcc-3.3v

CE-d9

CS-d10

SCK-d13

MOSI-d11

MISO-d12

You will also need to download and install the following library https://github.com/jscrane/RF24

 

 

Test it out

To test this project, simply set up two different arduino’s with nrf24l01+s and run the pingpair code found in the github repository. You will need two different computers to read the different serial lines, and if done right one should be pinging and one should be ponging. (One of the arduinos should have their 7th pin ground to set it to a different mode than the other one).

Go further

Included is more sample code, created for a final project for Physical Computing. This code is easier to edit, and involves two different sections. The servoin code waits for a number between 0 and 180 and sets a servo to that value, and also waits for a number between 1000 and 1180 and sets a second servo to that value. The servoout code waits for a number to be written to its serial and sends that number to the other arduino. This allows for remote access of an arduino from a computer (which can be expanded to include python code controlling a remote arduino, for example.)

Note: This code also requires printf.h, found in the pingpong example used earlier

ServoIn

#include <SPI.h>
#include <RF24.h>
#include "printf.h"
#include <Servo.h>
#define CE 9
#define CS 10
#define ROLE 7
#define BAUD 57600
RF24 radio(CE, CS);
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
Servo myServo1;
Servo myServo2;
unsigned int leftLight=0;
unsigned int rightLight=0;
void setup(void)
{
  myServo1.attach(2);
  myServo1.write(0);
  myServo2.attach(3);
  myServo2.write(0);
  Serial.begin(BAUD);
  printf_begin();
  printf("ServoIn\n\r");
  radio.begin();
  radio.openWritingPipe(pipes[1]);
  radio.openReadingPipe(1,pipes[0]);
  radio.enableDynamicPayloads() ;
  radio.setAutoAck( true ) ;
  radio.powerUp() ;
  radio.startListening();
  radio.printDetails();
}
void loop(void)
{
  if ( radio.available() )
  {
    unsigned long got_time;
    bool done = false;
    while (!done)
    {
      done = radio.read( &got_time, sizeof(unsigned long) );
    }
    Serial.println(got_time,DEC);
    radio.stopListening();
    if(got_time<181)
    {
      if(got_time==0)
        myServo1.write(1);
      if(got_time==180)
        myServo1.write(179);
      else
        myServo1.write(got_time);
      analogWrite(5,(got_time*255)/180);
    }
    if(got_time>999 && got_time<1181)
    {
      if(got_time==1000)
        myServo1.write(1);
      if(got_time==1180)
        myServo1.write(179);
      else
        myServo2.write(got_time-1000);
      analogWrite(6,((got_time-1000)*255)/180);
    }
  radio.startListening();
  }
}
// vim:cin:ai:sts=2 sw=2 ft=cpp

ServoOut

#include <SPI.h>
#include <RF24.h>
#include "printf.h"
#define CE	9
#define CS	10
#define ROLE	7
#define BAUD	57600
RF24 radio(CE, CS);
unsigned long integerValue;
unsigned long incomingByte;
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
void setup(void)
{
  Serial.begin(BAUD);
  printf_begin();
  radio.begin();
  radio.openWritingPipe(pipes[0]);
  radio.openReadingPipe(1,pipes[1]);
  radio.enableDynamicPayloads() ;
  radio.setAutoAck( true ) ;
  radio.powerUp() ;
  radio.startListening();
  radio.printDetails();
}
void loop(void)
{ 
    radio.stopListening();
    if (Serial.available() > 0) {   
    integerValue = 0;         
    while(1) {            
      incomingByte = Serial.read();
      if (incomingByte == '\n') break;   
      if (incomingByte == -1) continue;  
      integerValue *= 10;  
      integerValue = ((incomingByte - 48) + integerValue);
    }
    }
   radio.write( &integerValue, sizeof(unsigned long) );
}
// vim:cin:ai:sts=2 sw=2 ft=cpp