Wednesday, March 17, 2021

Arduino RadioHead (not the group) RH_NRF24 Transceiver

Nothing posted in 2020 - well it was that sort of year wasn't it?

Boredom having really set in, 2021 sees me in my Arduino playground. In fact I've been unfaithful and have been using an ESP32 recently, which is quite fun because it has WiFi capabilities - maybe a post about that to follow.

And all that WiFi stuff made me think about my previous delve into the world of radio and so on, using the ubiquitous NRF24L01 Transceiver Module. I bought some of these ages ago, spent days trying to get them to work, eventually succeeded, and, exhausted, then threw them in a box and moved on to something easier.

So, I find them lying in said box... let's have another go. So... I did the classic old-person thing of making all the same mistakes on this attempt as I did on the previous one, what an idiot. Eventually it dawned on me what was going wrong... like last time i had tried to use the TMRh20 library, nRF24L01.h and RF24.h, as nearly everyone seems to do. Trouble is... for me at least, it doesn't work. I mean I suppose it must work for most folk, but not me. No... it was only when I tried the RadioHead offering, RH_NRF24.h, that things started to fall into place. 

I am just not technically proficient enough to know why this is, but as soon as I changed to the RadioHead version, I got results. Here are pictures of my two Arduino/NRF24L01 combinations:



So, at the top we have a Nano, sitting in its IO Shield, which I heartily recommend for this type of job - because you simply plug the RF24 into it, no wires, wonderful. Attached is a little OLED display.

And the other picture shows an Arduino Mega with a handy but unnecessary shield on top, attached to an RF24 sitting in a little holder designed for it, again very recommended, because it's easier to wire up and can be powered by 5volts, avoiding the 3.3 volt limit on the RF24 module.

Now, here's the thing... this all seems very complicated and fraught. The wires you need to connect vary depending on your Arduino, and it all feels a bit of a black art. In the end I connected the right wires, but it took a bit of time. The Mega for example, uses pins 50, 51 and 52, the Nano completely different, whoever came up with all this wasn't making it easy!

Similarly, the code to get all this working really taxed my limited knowledge of C++ or whatever it is, my head was frequently in my hands, but in the end it all worked, see below.

What does it do? Well... the same code runs on both Arduinos. Each one is sending a random number every few seconds and receiving a random number from the other one too. The OLED display on one of them is showing that it has received its 1744th random number from its mate, 6591. What use is this? None that I can think of, but it's nice to know it can be done.

The code is below, if you need any advice, well I might be able to help you. But probably not. And a proper programmer will probably wince at the code. What is it with C++ and strings... type conversion in general, it's bonkers.
 
//-------------------------------------------------------------------------------
//
// Written by Paul Crossley 16/03/2021
//
// www.magmamon.co.uk
//
//-------------------------------------------------------------------------------
#include <SPI.h>
#include <RH_NRF24.h>

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_RESET -1
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define SCREEN_ADDRESS 0x3C


RH_NRF24 nrf24(9,10);

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

int count = 0;
int recvd = 0;
int int_value;
unsigned char char_list[4];

boolean oled = true;
int repeat   = 20;
long rnd = 0;
union myRandU {long unsignedlongValue; uint8_t bytes[4];} myRand;

// --------------------------------------------------------------------

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(9600);
  Serial.println("RF24...");
  if (!nrf24.init()) { 
    Serial.println("init failed"); 
  } else { 
    Serial.println("init good"); 
  }
  if (!nrf24.setChannel(1)) {                                               
    Serial.println("setChannel failed"); 
  }  else { 
    Serial.println("setChannel good"); 
  }
  if (!nrf24.setRF(RH_NRF24::DataRate2Mbps, RH_NRF24::TransmitPower0dBm)) { 
    Serial.println("setRF failed"); 
  } else { 
    Serial.println("setRF good"); 
  }   

  if (oled) { 
    Serial.println("OLED...");
    if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) { 
      Serial.println(F("SSD1306 allocation failed")); for(;;); 
    }
      
    display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(0,0);
    display.println("Listening!");
    display.display();
  }
  Serial.println("Ready!");
}

// --------------------------------------------------------------------

void loop() {

  digitalWrite(LED_BUILTIN, HIGH);
  count++;
  if (count==repeat) {
    rnd = random(0,9999);
    myRand.unsignedlongValue = rnd;
    nrf24.send(myRand.bytes, 4);
    nrf24.waitPacketSent();
    Serial.print("Sent : ");
    Serial.println(rnd);
    count=0;
  } else {
    Serial.print(".");
    uint8_t buf[RH_NRF24_MAX_MESSAGE_LEN];
    uint8_t len = sizeof(buf);
    while (nrf24.waitAvailableTimeout(200) && nrf24.recv(buf, &len)) {   
      Serial.print("Received : ");
      for (int i = 0; i < 4; i++) { char_list[i] = buf[i]; }
      memcpy(&int_value, char_list, 4);
      Serial.println(int_value);

      if (oled) { 
        recvd++;
        display.clearDisplay();
        display.setCursor(0,0);
        display.println("Listening!");
        display.setCursor(0,32);
        display.print(recvd);
        display.print(": ");
  //    display.print((char*)buf);
        display.print(int_value);
        display.display();
      }
    }      
  }
  digitalWrite(LED_BUILTIN, LOW);
  delay(100);
}

No comments: