Skip to content

14. Networking and Communication

NRF24L01+ and I2C OLED

This week I decided to go with NRF24L01+ with the RF24 Arduino Library. After first tests made with my previous boards and an Arduino UNO, I implemented in a new board, using ATmega328P, the nRF24 for radio communication and a 0.91” 128x32 OLED connected trough I2C protocol.

There are other ways to talk to the NRF24L01 that you will find here http://playground.arduino.cc/InterfacingWithHardware/Nrf24L01

Here is how to wire the NRF24L01 to your boards, in my case I made my own with ATmega328p, which is the same as the Arduino UNO below.

https://github.com/TMRh20/RF24

PIN NRF24L01+ Arduino UNO ATtiny25/45/85 ATtiny44/84
1 GND GND pin 4 pin 14
2 VCC 3.3V pin 8 pin 1
3 CE D7 pin 2 pin 12
4 CSN D8 pin 3 pin 11
5 SCK D13 pin 7 pin 9
6 MOSI D11 pin 6 pin 7
7 MISO D12 pin 5 pin 8
8 IRQ - - -

I used this site as my guide to program NRF24L01 with RF24

https://www.deviceplus.com/how-tos/arduino-guide/nrf24l01-rf-module-tutorial/

Note

The Chip can take 5V, there is no need to regulate the voltage, but to extend the life of the nRF24 I use a voltage regulator on the board, AMS1117 3.3

The New Board

As you can see, I’ve replaced the analog pins to facilitate the connections between the I2C-Oled and the board at the corresponding pins: GND - VCC - SCL - SDA. I also derived the pinout to directly attach the nf24 on the board.

Program the board

Through Arduino IDE I’ve made a Sketch as follows, implementing in it RF24.h, SPI.h and U8glib.h libraries:

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


U8GLIB_SSD1306_128X32 u8g(U8G_I2C_OPT_NONE);

/****************** User Config ***************************/
/***      Set this radio as radio number 0 or 1         ***/
bool radioNumber = 0;
/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */
RF24 radio(7,8);
/**********************************************************/
byte addresses[][6] = {"1Node","2Node"};
// Used to control whether this node is sending or receiving
bool role = 0;

void drawSend() {
 u8g.setFont(u8g_font_unifont);
  u8g.setPrintPos(0, 16);
  u8g.print("Sending MSG -->");
}

void drawRecive() {
 u8g.setFont(u8g_font_unifont);
  u8g.setPrintPos(0, 16);
  u8g.print("Reciving MSG <--");
}

void setup() {
  // assign default color value
  if ( u8g.getMode() == U8G_MODE_R3G3B2 ) {
    u8g.setColorIndex(255);     // white
  }
  else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) {
    u8g.setColorIndex(3);         // max intensity
  }
  else if ( u8g.getMode() == U8G_MODE_BW ) {
    u8g.setColorIndex(1);         // pixel on
  }
  else if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
    u8g.setHiColorByRGB(255,255,255);
  }

  Serial.begin(115200);
  Serial.println(F("RF24/examples/GettingStarted"));
  Serial.println(F("*** PRESS 'T' to begin transmitting to the other node"));

  radio.begin();
  // Set the PA Level low to prevent power supply related issues since this is a
 // getting_started sketch, and the likelihood of close proximity of the devices. RF24_PA_MAX is default.
  radio.setPALevel(RF24_PA_LOW);

  // Open a writing and reading pipe on each radio, with opposite addresses
  if(radioNumber){
    radio.openWritingPipe(addresses[1]);
    radio.openReadingPipe(1,addresses[0]);
  }else{
    radio.openWritingPipe(addresses[0]);
    radio.openReadingPipe(1,addresses[1]);
  }

  // Start the radio listening for data
  radio.startListening();
}
void loop() {


/****************** Ping Out Role ***************************/  
if (role == 1)  {

    radio.stopListening();                                    // First, stop listening so we can talk.


    Serial.println(F("Now sending"));

    unsigned long start_time = micros();                             // Take the time, and send it.  This will block until complete
     if (!radio.write( &start_time, sizeof(unsigned long) )){
       Serial.println(F("failed"));
     }

    radio.startListening();                                    // Now, continue listening

    unsigned long started_waiting_at = micros();               // Set up a timeout period, get the current microseconds
    boolean timeout = false;                                   // Set up a variable to indicate if a response was received or not

    while ( ! radio.available() ){                             // While nothing is received
      if (micros() - started_waiting_at > 200000 ){            // If waited longer than 200ms, indicate timeout and exit while loop
          timeout = true;
          break;
      }      
    }

    if ( timeout ){                                             // Describe the results
        Serial.println(F("Failed, response timed out."));
    }else{
        unsigned long got_time;                                 // Grab the response, compare, and send to debugging spew
        radio.read( &got_time, sizeof(unsigned long) );
        unsigned long end_time = micros();

        // Spew it
        Serial.print(F("Sent "));
        Serial.print(start_time);
        Serial.print(F(", Got response "));
        Serial.print(got_time);
        Serial.print(F(", Round-trip delay "));
        Serial.print(end_time-start_time);
        Serial.println(F(" microseconds"));
    }
    // Try again 1s later
    delay(1000);
  }
/****************** Pong Back Role ***************************/
  if ( role == 0 )
  {
    unsigned long got_time;

    if( radio.available()){
                                                                    // Variable for the received timestamp
      while (radio.available()) {                                   // While there is data ready
        radio.read( &got_time, sizeof(unsigned long) );             // Get the payload
      }

      radio.stopListening();                                        // First, stop listening so we can talk   
      radio.write( &got_time, sizeof(unsigned long) );              // Send the final one back.      
      radio.startListening();                                       // Now, resume listening so we catch the next packets.     

      Serial.print(F("Sent response "));
      Serial.println(got_time);  
   }
 }
/****************** Change Roles via Serial Commands ***************************/
  if ( Serial.available() )
  {
    char c = toupper(Serial.read());
    if ( c == 'T' && role == 0 ){      
      Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK"));
      role = 1;                  // Become the primary transmitter (ping out)

    // picture loop
  u8g.firstPage();  
  do {
    drawSend();
  } while( u8g.nextPage() );

   }else
    if ( c == 'R' && role == 1 ){
      Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK"));      
       role = 0;                // Become the primary receiver (pong back)
       radio.startListening();

    // picture loop
  u8g.firstPage();  
  do {
    drawRecive();
  } while( u8g.nextPage() );
    }
  }
} // Loop

Tip

Upload the compiled program on the two boards, but Remember to change the radioNumber from 0 to 1 for the second board that initially is the receiver. change

Once connected the two boards to the their FTDI232 5v adapter, boards

You can read the PING PONG feedbacks between two boards, and read it from the Serial Monitor on the FTDI serial COM connect to your PC: board

And this is the Final Video: