I’m still playing with my nRF24L01+’s, I’ve now got the RPi running the receiver as a daemon and the Arduino transmitter in low-power mode. The 3.3v 8MHz ATmega328p-pu now takes a reading (well at the moment its still a dumb counter!) and transmits it, then turns off the radio and goes to sleep for 30 seconds.

This is why its important that the Pi is constantly listening (well, sleeps every 5secs to reduce CPU load) and only overwrites the file if it receives a good reading. The Pi appends the unix time to the reading, which can then be parsed with Python’s time.localtime() function.

This also means that setAutoAck() and setRetries() aren’t such an issue, as we’ll always have the last reading and the time it was taken if this reading fails, but at once every 30secs we have enough time to retry transmissions.

Arduino code:

#include <SPI.h>
#include <avr/sleep.h>
#include <avr/power.h>
#include "RF24.h"

/*
radio 7 (miso) to uno d12 (pin 18) or mega d50
radio 6 (mosi) to uno d11 (pin 17) or mega d51
radio 5 (sck)  to uno d13 (pin 19) or mega d52
radio 4 (csn)  to uno d10 (pin 16) or mega d48
radio 3 (ce)   to uno d9  (pin 15) or mega d49
radio 2 (3.3v) to uno 3.3v
radio 1 (gnd)  to uno gnd
*/

// ce,csn pins
RF24 radio(9,10);

// init sleep
typedef enum { wdt_16ms = 0, wdt_32ms, wdt_64ms, wdt_128ms, wdt_250ms, 
    wdt_500ms, wdt_1s, wdt_2s, wdt_4s, wdt_8s } wdt_prescalar_e;
void setup_watchdog(uint8_t prescalar);
void do_sleep(void);
const short sleep_cycles_per_transmission = 4;
volatile short sleep_cycles_remaining = sleep_cycles_per_transmission;

// init counter
unsigned long count = 0;

// configure the prr
void setup_watchdog(uint8_t prescalar)
{
    prescalar = min(9,prescalar);
    uint8_t wdtcsr = prescalar & 7;
    if (prescalar & 8)
    {
        wdtcsr |= _BV(WDP3);
    }
    MCUSR &= ~_BV(WDRF);
    WDTCSR = _BV(WDCE) | _BV(WDE);
    WDTCSR = _BV(WDCE) | wdtcsr | _BV(WDIE);
}

// watchdog interrupt
ISR (WDT_vect)
{
  --sleep_cycles_remaining;
}

void do_sleep(void)
{
    // sets mcu sleep mode
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);

    // sleep mcu
    sleep_enable();
    sleep_mode();

    // wake mcu and radio upon watchdog timeout
    sleep_disable();
    radio.powerUp();
}

void setup(void)
{
    // set sleep to 4x8=32secs
    setup_watchdog(wdt_8s);
    
    // init radio for writing
    radio.begin();
    radio.enableDynamicPayloads();
    radio.setAutoAck(1);
    radio.setRetries(15,15);
    radio.setDataRate(RF24_250KBPS);
    radio.setPALevel(RF24_PA_MAX);
    radio.setChannel(76);
    radio.openWritingPipe(0xF0F0F0F0E1LL);
}

void loop(void)
{
    // 32 bytes is maximum payload
    char txBuffer[32]= "";
 
    // pad numbers and convert to string  
    sprintf(txBuffer,"%lu",count);

    // increment counter
    count++;
    
    // transmit
    radio.write(&txBuffer, strlen(txBuffer));
    
    // sleep radio
    radio.powerDown();

    // sleep mcu
    while (sleep_cycles_remaining)
    {
        do_sleep();
    }
    sleep_cycles_remaining = sleep_cycles_per_transmission;
}

Raspberry Pi code:

#include <cstdlib>
#include <iostream>
#include <fstream>
#include <time.h>
#include "../RF24.h"

using namespace std;

/*
radio 7 (miso) to gpio9/bcm21
radio 6 (mosi) to gpio10/bcm19
radio 5 (sck)  to gpio11/bcm23
radio 4 (csn)  to gpio8/bcm24
radio 3 (ce)   to gpio25/bcm22
radio 2 (3.3v) to 3.3v
radio 1 (gnd)  to gnd
*/

// spi device, spi speed, ce gpio pin
RF24 radio("/dev/spidev0.0",8000000,25);

void setup(void)
{
    // setup radio for listening
    radio.begin();
    radio.setAutoAck(1);
    radio.setRetries(15,15);
    radio.enableDynamicPayloads();
    radio.setDataRate(RF24_250KBPS);
    radio.setPALevel(RF24_PA_MAX);
    radio.setChannel(76);
    radio.openReadingPipe(1,0xF0F0F0F0E1LL);
    radio.startListening();
}

void loop(void)
{
    // clear char array
    char rxBuffer[32] = "";

    while (radio.available())
    {
        // read from radio
        int len = radio.getDynamicPayloadSize();
        radio.read(&rxBuffer, len);

        // get time - can be passed to time.localtime()
        time_t rawtime;
        time (&rawtime);

        // write to file and close
        ofstream myfile;
        myfile.open ("/var/tmp/rf24weather.txt");
        myfile << rxBuffer << ':' << rawtime << endl;
        myfile.close();
    }

    // pause to reduce cpu load
    sleep(5);
}

int main(int argc, char** argv)
{
    setup();
    while(1)
        loop();

    return 0;
}