Site icon Flowduino

Arduino Nano R3 + nRF24L01 = RF-Nano

RF-Nano Feature Image

RF-Nano Feature Image

Review-Tutorials?

Before we begin, we want to briefly explain the format of this Review article.

Where most publications produce Reviews as strictly-informational articles covering a particular product or service; Flowduino is all about education!

For this reason, we present every Review with at least one Tutorial element.

After all, how better to review a Microcontroller, Sensor, IO device, or Development Board than to walk through a project using them?

So, please enjoy this Review-Tutorial (“Reviewtorial?”)

The Problem…

We here at Flowduino build a lot of wirelessly interconnected devices. No, seriously! More than half of all of the projects we develop require multiple devices to communicate without wires, sometimes over vast distances.

We have, at times, gone so far as to build line-of-sight optical laser communications into our devices, sometimes even with optical repeater devices necessary to span distances of multiple kilometres, where low-latency is a concern.

Readers with more experience working with Arduino and other MCUs will very likely have experienced adding radio modules to their devices. There is certainly no shortage of choice in this area, either!

From the most simple modules, such as the 433MHz HC-12 UART radio, to the slightly more complex nRF24L01 SPI, or Bluetooth (JDY-33, DW-CT14, AT-09 etc), or WiFi, or LoRa, or even GPRS/LTE… the options are practically limitless.

Arduino Nano 33 IoT

These days, Arduino manufacture their IoT range of development boards, which feature WiFi and/or Bluetooth on-chip. However, these come at a higher price point, and – as with all things – have their own disadvantages.

So, what if you need radio communication between multiple devices, but want to use a simple, low-profile development board without having to attach a separate radio to it? What if Bluetooth and WiFi aren’t suitable?

The RF-Nano (a Solution)

Introducing the RF-Nano V3.0, from eMakefun!

The RF-Nano combines the simplicity and compatibility of the Arduino Nano R3’s ATmega328 with the usefulness of the nRF24L01+ 2.4GHz radio transceiver.

No more multi-wire SPI connection required!

RF-Nano – Profile 2 – © Flowduino.com
RF-Nano – Profile 3 – © Flowduino.com

Working our way down the board from the top of this photograph:

  • A Micro-USB socket… an improvement over the official Arduino Nano R3’s Mini-USB socket.
  • Beneath that in the middle we have the ATmega328 chip
  • You can then see the Reset button
  • Followed by some SMD components and the LEDs for power, TX, RX etc.
  • Beneath that is the nRF24L01+ chip. This is what gives the RF-Nano the integrated 2.4GHz radio functionality.
  • At the bottom, in the centre, we see a PCB Antenna for the nRF24L01+
  • Bottom-right, we have a socket for connecting an SMA or RP-SMA antenna pigtail. This allows us to use an External Antenna, increasing (considerably) the communication range.

Down the left- and right-hand sides, we have the GPIO pins, which are verbatim identical to those from the Arduino Nano R3.

Packaging

The RF-Nano comes in a very small cardboard box.

The printing on the box is nice, albeit bearing an illustration of the Arduino Nano R3 rather than the RF-Nano.

Inside, it contains the RF-Nano board itself, embedded into a piece of foam to offer some protection from physical impacts.

Just be aware that there is no form of static-proof packaging, or even plastic coverings on either the board or the box.

This means that damage could occur in storage or transit, depending on the conditions under which your chosen supplier looks after its stock.

Fortunately for me, my preferred supplier takes impeccable care of their stock, ensures that all outbound packages are suitably packed and protected, and I have had no problems with the 7 RF-Nano boards I have ordered for testing.

Specifications

FeatureValue
MicrocontrollerATmega328P
Clock16MHz
Flash32KB
GASH2KB
EEPROM1KB
USB-Serial BridgeCH340G
Digital I/O Pins14
PWM Pins6
Analog Input Pins8
DC Current-per-Pin40mA
Input Voltage6-20V recommended (5V works fine)
5V Max Current800mA
3.3V Max Current180mA
Weight15g
Addressable Registers3 (PORTB, PORTC, PORTD)
Radios-on-boardYes: nRF24L01+
AntennasYes: 1x PCB + 1x U.FL 1.15mm Pigtail Socket
Persistent StorageNo
Solder PinsYes, Pre-soldered
PackagingFoam insert in Cardboard. No Static-Proof Bag!
USB InterfaceMicro-USB Socket (Female)
Buttons on-boardYes: Reset
LEDs on-boardYes: Power, Flash, RX, TX
Closeup of the NRF24L01+ Chip

As you can see, the Microcontroller specifications are identical to the Arduino Nano R3 development board. This means you can do a direct MCU swap on existing projects or prototypes using the Arduino Nano R3 dev board, for Nano-RF dev boards.

Unavailable Pins!

It must be noted that the nRF24L01+ chip is connected to the ATmega328P chip directly on the board. This means that there are SPI pins on the GPIO that you can no longer use for other purposes.

I shall list these pins, and what they’re connected to, now:

GPIO Pin NumbernRF24L01+ SPI
D9CE (Chip Enable)
D10CS/CSN (Chip Select)
D11MOSI
D12MISO
D13SCK

Important Note: The RF-Nano official documentation has CE and CS listed in the wrong order! Our table here has the correct Pin assignments. This matters because, if you reverse CE and CS, the radio will initialise just fine, but you won’t be able to transmit or receive anything with it. We wasted an awful lot of time trying to figure this one out! Hopefully, we just saved yours.

So, just be aware that you cannot use these listed SPI pins on the GPIO pin header for anything else. This isn’t a problem, mind you, as you would have to use these same pins on an Arduino Nano R3 if you wanted to connect an external SPI radio module.

Let’s build something with two RF-Nanos!

Okay, so we’ve taken a look at the specifications, and acknowledged the handy advantages that a board integrating a 2.4GHz radio can have for our projects.

Now, let’s actually test these boards and see how quickly and easily we can make two devices talk to each other!

We’re going to make a simple RGB light unit, with a Radio Remote Controller!

Ingredients…

This recipe requires two breadboards, and two RF-Nano development boards.

Per-board, you will need:

One of the two boards will also require:

Wiring…

There are two similar wiring diagrams for this project.

The RGB Display (Receiver) Board

RF-Nano Demo – Receiver [Fritzing]

I’ve chosen to illustrate this wiring diagram using separate LEDs for Red, Green, and Blue (respectively) simply because it is easier to visualise. You can, of course, just as easily connect the resistors to the R, G, and B legs of a single RGB LED.

I ask that you forgive that the dev board shown in the illustration is the Arduino Nano R3 rather than the RF-Nano… I was unable to find the RF-Nano part available for Fritzing.

GPIO Pin wiring:

GPIO PinDirectionConnects to…
D2OutputRed LED via 330Ohm resistor
D3OutputGreen LED via 330Ohm resistor
D4OutputBlue LED via 330Ohm resistor

The Remote (Transmitter/Controller) Board

The Remote (Transmitter/Controller) Board is wired identically with LEDs and resistors, to the same pins of the RF-Nano.

However, we add 3 components to this board: push buttons.

RF-Nano Demo – Transmitter [Fritzing]

So, for the Remote (Transmitter/Controller) Board, the GPIO Pin Wiring looks like this:

GPIO PinDirectionConnects to…
D2OutputRed LED via 330Ohm resistor
D3OutputGreen LED via 330Ohm resistor
D4OutputBlue LED via 330Ohm resistor
D5InputButton to control Red LED
D6InputButton to control Green LED
D7InputButton to control Red LED

The Code

Let’s quickly put together the code for this project, but – before we do – we are going to begin with an obligatory reminder about coding standards and principles.

Examples are NOT the way you should write your code!

Please note that, for the sake of keeping this article concise, these code examples will follow the common “Arduino IDE” approach of putting all of our code into a single source file (a Sketch in the context of the Arduino IDE).

I want to preface this by stating that I do not condone developing code in this manner for real-world projects. Real-world code should always be written with the SOLID principles of development at its core.

On to the code!

For this project, we will be using the RF24 library. This Library is available in both the Arduino IDE, as well as PlatformIO.

We develop and maintain our projects using PlatformIO.

RGB Remote (Transmitter) Code

#include <Arduino.h>

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

#define PIN_LED_RED     2   // D2
#define PIN_LED_GREEN   3   // D3
#define PIN_LED_BLUE    4   // D4
#define PIN_BTN_RED     5   // D5
#define PIN_BTN_GREEN   6   // D6
#define PIN_BTN_BLUE    7   // D7

#define PIN_RF_CE       9   // D9 = Chip Enable (CE) for nRF24L01+
#define PIN_RF_CS       10  // D10 = Chip Select (CS) for nRF24L01+

#define CHANNEL_READ    987654321
#define CHANNEL_WRITE   123456789

/*
  RGBState
  We will Transmit and Receive this State data.
*/
struct RGBState {
  bool Red;   // True if the Red button is Down
  bool Green; // True if the Green button is Down
  bool Blue;  // True if the Blue button is Down
};

RGBState currentState;
RF24 radio(PIN_RF_CE, PIN_RF_CS);
bool radioReady = false;

void setup() {
  // Initialise Serial first
  Serial.begin(115200);

  // Pin modes
  pinMode(PIN_LED_RED, OUTPUT);
  pinMode(PIN_LED_GREEN, OUTPUT);
  pinMode(PIN_LED_BLUE, OUTPUT);
  pinMode(PIN_BTN_RED, INPUT);
  pinMode(PIN_BTN_GREEN, INPUT);
  pinMode(PIN_BTN_BLUE, INPUT);

  // Configure the Radio
  int failCount = 0;

  while (!radioReady && failCount < 10) {
    radioReady = radio.begin();
    if (!radioReady) {
      failCount++;
      Serial.print("Radio Initialisation Failed ");
      Serial.print(failCount);
      Serial.println(" times.");
    }
  }

  if (!radioReady) {
    Serial.println("Radio could not be initialised!");
    return;
  }

  radio.setDataRate(RF24_2MBPS); // Maximum Bandwidth
  radio.setPALevel(RF24_PA_MAX); // Maximum Range

  radio.setPayloadSize(sizeof(RGBState)); // Size of the Data we will Transmit
  radio.setAutoAck(true); // Allows us to check if the Transmission Succeeded

  // We technically don't need to open a Reading Pipe for a Transmit-Only Device!
  radio.openReadingPipe(1, CHANNEL_READ); // For Incoming Data
  // We need to open the Writing Pipe in order to Transmit data
  radio.openWritingPipe(CHANNEL_WRITE); // For Outgoing Data
}

inline void sendState() {
  if (!radio.write(&currentState, sizeof(RGBState))) {
    Serial.println("Transmission failed!"); // We output errors to Serial.
  }
}

void loop() {
  if (!radioReady) {
    digitalWrite(PIN_LED_RED, HIGH); // Turn the Red LED on to show failure
    return; // We cannot continue if the Radio isn't working!
  }

  // We need a LOCAL State so we can Compare later!
  RGBState newState;
  
  // Let's populate the LOCAL State
  newState.Red = digitalRead(PIN_BTN_RED);
  newState.Green = digitalRead(PIN_BTN_GREEN);
  newState.Blue = digitalRead(PIN_BTN_BLUE);

  // Now we see if anything changed
  if (
    newState.Red != currentState.Red ||
    newState.Green != currentState.Green ||
    newState.Blue != currentState.Blue
  ) {
    // Update the Current State
    currentState = newState;
    // Show the State on the Controller's LEDs
    digitalWrite(PIN_LED_RED, currentState.Red);
    digitalWrite(PIN_LED_GREEN, currentState.Green);
    digitalWrite(PIN_LED_BLUE, currentState.Blue);

    sendState(); // Send the State to all Receivers
  }
}

The example code (above) is fully-annotated, so I won’t conflate this article by repeating what has already been said. Simply read through the above code… it is pretty simple to understand.

RGB Display (Receiver) Code

#include <Arduino.h>

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

#define PIN_LED_RED     2   // D2
#define PIN_LED_GREEN   3   // D3
#define PIN_LED_BLUE    4   // D4

#define PIN_RF_CE       9   // D9 = Chip Enable (CE) for nRF24L01+
#define PIN_RF_CS       10  // D10 = Chip Select (CS) for nRF24L01+

#define CHANNEL_READ    123456789 // Opposite of the Remote code
#define CHANNEL_WRITE   987654321 // Opposite of the Remote code

/*
  RGBState
  We will Transmit and Receive this State data.
*/
struct RGBState {
  bool Red;   // True if the Red button is Down
  bool Green; // True if the Green button is Down
  bool Blue;  // True if the Blue button is Down
};

RGBState currentState;
RF24 radio(PIN_RF_CE, PIN_RF_CS);
bool radioReady = false;

void setup() {
  // Initialise Serial first
  Serial.begin(115200);

  // Pin modes
  pinMode(PIN_LED_RED, OUTPUT);
  pinMode(PIN_LED_GREEN, OUTPUT);
  pinMode(PIN_LED_BLUE, OUTPUT);

  // Configure the Radio
  int failCount = 0;

  while (!radioReady && failCount < 10) {
    radioReady = radio.begin();
    if (!radioReady) {
      failCount++;
      Serial.print("Radio Initialisation Failed ");
      Serial.print(failCount);
      Serial.println(" times.");
    }
  }

  if (!radioReady) {
    Serial.println("Radio could not be initialised!");
    return;
  }

  radio.setDataRate(RF24_2MBPS); // Maximum Bandwidth
  radio.setPALevel(RF24_PA_MAX); // Maximum Range

  radio.setPayloadSize(sizeof(RGBState)); // Size of the Data we will Transmit
  radio.setAutoAck(true); // Allows us to check if the Transmission Succeeded

  // We need to open the Reading Pipe in order to Receive data
  radio.openReadingPipe(1, CHANNEL_READ); // For Incoming Data
  // We don't need to open the Writing Pipe on a Receive-only Device
  radio.openWritingPipe(CHANNEL_WRITE); // For Outgoing Data

  radio.startListening(); // This starts the radio listening for incoming messages
}

void loop() {
  if (!radioReady) {
    digitalWrite(PIN_LED_RED, HIGH); // Turn the Red LED on to show failure
    return; // We cannot continue if the Radio isn't working!
  }

  if (!radio.available()) { return; } // No need to continue

  RGBState inboundState;
  radio.read(&inboundState, sizeof(RGBState));

  digitalWrite(PIN_LED_RED, inboundState.Red);
  digitalWrite(PIN_LED_GREEN, inboundState.Green);
  digitalWrite(PIN_LED_BLUE, inboundState.Blue);
}

Again, the above code is heavily-annotated to describe in sequence what is happening. You simply need to read through it carefully.

What I will point out is that the main differences are at the end of the setup() and loop() methods, which deal with the specifics of receiving rather than transmitting.

Grab the Sample Code on GitHub

Flowduino has a GitHub account specifically to provide complete sample projects accompanying the articles on this website.

The complete Sample Projects for this article can be found here.

Running the Demo

RF-Nano RGB Remote/Display Demo in use

So, we now have a Remote (Transmitter) and an RGB Display (Receiver). Whenever you press one of the buttons representing a colour (Red, Green, and Blue – respectively) the lights will simultaneously illuminate on both devices.

If you press multiple buttons, you will combine colours… which is pretty fun.

What’s important to note is that we are transmitting multiple values in a structured object. We can transmit basically any kind of data we want this way.

The Price

The RF-Nano is what I would call “competitively-priced”. While there are certainly cheaper Arduino Nano R3 clones on the market, these don’t feature the integrated radio. Once the cost of the radio module is factored in, the RF-Nano ultimately comes in at approximately the same overall price.

When you consider the reduced complexity, potential time-savings when it comes to fault-finding and troubleshooting, the price becomes a bargain.

In Conclusion…

The RF-Nano is an extremely useful development board, which eliminates the potential fault-finding effort we have to endure when a device-to-device project starts experiencing communication problems.

Since the radio is integrated directly into the development board, we can rule out radio hardware issues entirely, and focus on the software possibilities.

The overall quality is impressively high, and easy to use.

If you’re using an Arduino with the ATmega328 microcontroller, and you want to add a low-latency, high-frequency radio… swap out your dev board for the RF-Nano. It’s pin-compatible; albeit you can’t attach anything to the SPI pins, as explained previously – but an external radio would have to occupy these pins anyway.

The Photographs in this Article…

Gratuitous photo by Flowduino, showing 4 RF-Nano development boards “artfully” arranged.

We just want to take a moment to point out that every single photograph of the RF-Nano used in this article has been taken by the Simon, of Flowduino, whom also authored this article.

The images were all taken, and – where applicable – edited, on a mobile phone.

We hope you like them… and if you do decide to use them on your own publications (online or physical) we would very-much appreciate it if you would provide accreditation. Something like “Photo by Flowduino.com” would be perfect. Permission for use elsewhere is explicitly granted under that sole condition.

Exit mobile version