A simple clean code to send some data

Hi !!

Was wondering if someone would like to share an simple code to send 3 different int variabels when some of the 3 int variabels have changed.

I have attached the code from Robin2´s guide, that code works fine with my hardware.
I use NRF24 as reciever and transmitter.

Best Regards
Andreas

// SimpleTx - the master or the transmitter

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


#define CE_PIN   9
#define CSN_PIN 10

const byte slaveAddress[5] = {'R','x','A','A','A'};


RF24 radio(CE_PIN, CSN_PIN); // Create a Radio

char dataToSend[10] = "Message 0";
char txNum = '0';


unsigned long currentMillis;
unsigned long prevMillis;
unsigned long txIntervalMillis = 1000; // send once per second


void setup() {

    Serial.begin(9600);

    Serial.println("SimpleTx Starting");

    radio.begin();
    radio.setDataRate( RF24_250KBPS );
    radio.setRetries(3,5); // delay, count
    radio.openWritingPipe(slaveAddress);
}

//====================

void loop() {
    currentMillis = millis();
    if (currentMillis - prevMillis >= txIntervalMillis) {
        send();
        prevMillis = millis();
    }
}

//====================

void send() {

    bool rslt;
    rslt = radio.write( &dataToSend, sizeof(dataToSend) );
        // Always use sizeof() as it gives the size as the number of bytes.
        // For example if dataToSend was an int sizeof() would correctly return 2

    Serial.print("Data Sent ");
    Serial.print(dataToSend);
    if (rslt) {
        Serial.println("  Acknowledge received");
        updateMessage();
    }
    else {
        Serial.println("  Tx failed");
    }
}

//================

void updateMessage() {
        // so you can see that new data is being sent
    txNum += 1;
    if (txNum > '9') {
        txNum = '0';
    }
    dataToSend[8] = txNum;
}
// SimpleRx - the slave or the receiver

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

#define CE_PIN   9
#define CSN_PIN 10

const byte thisSlaveAddress[5] = {'R','x','A','A','A'};

RF24 radio(CE_PIN, CSN_PIN);

char dataReceived[10]; // this must match dataToSend in the TX
bool newData = false;

//===========

void setup() {

    Serial.begin(9600);

    Serial.println("SimpleRx Starting");
    radio.begin();
    radio.setDataRate( RF24_250KBPS );
    radio.openReadingPipe(1, thisSlaveAddress);
    radio.startListening();
}

//=============

void loop() {
    getData();
    showData();
}

//==============

void getData() {
    if ( radio.available() ) {
        radio.read( &dataReceived, sizeof(dataReceived) );
        newData = true;
    }
}

void showData() {
    if (newData == true) {
        Serial.print("Data received ");
        Serial.println(dataReceived);
        newData = false;
    }
}

Fill the "dataToSend" buffer with any data you like. Can be binary data, or formatted ASCII data.

sprintf() is a handy way to format data into ASCII, but floats are not supported by sprintf() on many Arduinos.

sprintf (dataToSend, "%d plus %d is %d", a, b, a+b);

Better, to avoid buffer overflow and program crashes:

snprintf (dataToSend, sizeof(dataToSend), "%d plus %d is %d", a, b, a+b);

Hi !

Thank you for the quick answer.
I tried to add some values in to " dataToSend" but something is not right. The original code works and updates the value on the reciever but not value1, value2, value3. Best Regards

TX

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

// Nano oldbootloader
#define CE_PIN   7
#define CSN_PIN 8

const byte slaveAddress[5] = {'R','x','A','A','A'};


RF24 radio(CE_PIN, CSN_PIN); // Create a Radio

char dataToSend[10] = "Message 0";
char txNum = '0';

int value1 = 10;
int value2 = 11;
int value3 = 12; 


unsigned long currentMillis;
unsigned long prevMillis;
unsigned long txIntervalMillis = 1000; // send once per second


void setup() {

    Serial.begin(9600);

    Serial.println("SimpleTx Starting");

   
    radio.begin();
    radio.setDataRate( RF24_250KBPS );
    radio.setRetries(3,5); // delay, count
    radio.openWritingPipe(slaveAddress);
}

//====================

void loop() {
    currentMillis = millis();
    if (currentMillis - prevMillis >= txIntervalMillis) {
        send();
        prevMillis = millis();
    }
}

//====================

void send() {

    bool rslt;
    rslt = radio.write( &dataToSend, sizeof(dataToSend) );
    rslt = radio.write( &dataToSend, sizeof(value1) );
    rslt = radio.write( &dataToSend, sizeof(value2) );
    rslt = radio.write( &dataToSend, sizeof(value3) );
    
        // Always use sizeof() as it gives the size as the number of bytes.
        // For example if dataToSend was an int sizeof() would correctly return 2

    Serial.print("Data Sent ");
    Serial.print(dataToSend);
    if (rslt) {
        Serial.println("  Acknowledge received");
        updateMessage();
    }
    else {
        Serial.println("  Tx failed");
    }
}

//================

void updateMessage() {
        // so you can see that new data is being sent
    txNum += 1;
    if (txNum > '9') {
        txNum = '0';
    }
    dataToSend[8] = txNum;
}

RX

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

// UNO 

#define CE_PIN   9
#define CSN_PIN 10

const byte thisSlaveAddress[5] = {'R','x','A','A','A'};

RF24 radio(CE_PIN, CSN_PIN);

char dataReceived[10]; // this must match dataToSend in the TX
bool newData = false;


int value1;
int value2;
int value3;


//===========

void setup() {

    Serial.begin(9600);

    Serial.println("SimpleRx Starting");
    
    radio.begin();
    radio.setDataRate( RF24_250KBPS );
    radio.openReadingPipe(1, thisSlaveAddress);
    radio.startListening();
}

//=============

void loop() {
    getData();
    showData();
}

//==============

void getData() {
    if ( radio.available() ) {
        radio.read( &dataReceived, sizeof(dataReceived) );
        radio.read( &dataReceived, sizeof(value1) );
        radio.read( &dataReceived, sizeof(value2) );
        radio.read( &dataReceived, sizeof(value3) );
        newData = true;
        
    }
}

void showData() {
    if (newData == true) {
        Serial.print("Data received ");
        Serial.print(dataReceived);
        Serial.print(value1);
        Serial.print(value2);
        Serial.println(value3);
        
        newData = false;
    }
}

You should populate your dataToSend buffer with ALL the data you need to send in one go - within the constraints of the hardware - max 32 bytes I think.

If you send each piece of data individually, you will end up with synchronisation issues between the Tx and the Rx.

Follow the advice in post #2 regarding sprintf or snprintf to send your data as ASCII text.

If you want/need to send/receive binary data, then there are examples of sending a struct. That way you don't need to handle the conversion to/from ASCII chars. However, there are issues (which are easily solvable) if the sender and receiver use different processors, such as AVR to ARM.

this is what was suggested.
your dataToSend[] is too small, only 10 bytes. so s[] was used. and strlen() is used to determine the # of characters in the s[] buffer, not the total size of s[]

void send ()
{
    char s [80];

    sprintf (s, "val1 %d, val2 %d, val3 %d\n", value1, value2, value3);

    bool rslt = radio.write (s, strlen (s));

    Serial.print ("Data Sent ");
    Serial.print (s);
    if (rslt) {
        Serial.println ("  Acknowledge received");
        updateMessage ();
    }
    else {
        Serial.println ("  Tx failed");
    }
}

and on the received side, the code read a single message, a character array.
define dataReceived[80], large enough to hold any possible message.

void getData() {
    if (radio.available() ) {
        radio.read( &dataReceived, sizeof(dataReceived) );

        Serial.println (dataReceived);
    }
}

That will cause problems as NRF24 packets are limited to 32 data bytes.

Plus converting all the numerical data to a c-string simply makes for extra work on both the TX and RX ends. The transmission is packetized. So the simplest thing to do is pack the data into a struct and send the whole thing at once (up to 32 bytes). At the RX end you simply receive the same size struct and pull out your values.

In another thread I suggested replacing snprintf() with dtostrf() and demonstrated for printing formatted floats, but I wonder if it is not a valid method (not for all compilers, et c).

apparently the OP didn't understand the suggestion in post #2 and i tried to explain it more clearly. the OP's code did separate writes and reads, suggesting he didn't understand the concept of a message containing multiple data.

seems like a single c-string msg was a good place to start before optimizing the message format

Does anyone have any example code with sprintf that works so i can rebuild it to send yust 3 int values?

I´m not so good with writing this code from scratch :), sometimes i manage to rebuild some working code to fit.

Best Regards.

    sprintf (s, "%d %d %d\n", value1, value2, value3);

Hi !

Thank you for the help, i was not able to write the sprintf code on sender and reciever side.

I modified this code instead,

// SimpleTx - the master or the transmitter

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

//not all #defines used but here for documentation
#define CE_PIN   9
#define CSN_PIN 10
#define MOSI_PIN 11
#define MISO_PIN 12
#define SCK_PIN 13

const byte slaveAddress[5] = {'R', 'x', 'A', 'A', 'A'};

RF24 radio(CE_PIN, CSN_PIN); // Create a Radio

char txNum = '0';

struct data
{
  byte pinState;
  byte temperature;
} sentData;

unsigned long currentMillis;
unsigned long prevMillis;
unsigned long txIntervalMillis = 1000;

void setup()
{
  Serial.begin(115200);
  Serial.println("SimpleTx Starting");
  radio.begin();
  radio.setDataRate( RF24_250KBPS );
  radio.setRetries(3, 5); // delay, count
  radio.openWritingPipe(slaveAddress);
}

void loop()
{
  currentMillis = millis();
  if (currentMillis - prevMillis >= txIntervalMillis)
  {
    sentData.pinState = !sentData.pinState;
    sentData.temperature = sentData.temperature + 1;
    send();
    prevMillis = millis();
  }
}

void send()
{
  bool rslt;
  rslt = radio.write( &sentData, sizeof(sentData) );
  if (rslt)
  {
    Serial.println("  Acknowledge received");
  }
  else
  {
    Serial.println("  Tx failed");
  }
}
// SimpleRx - the slave or the receiver

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

//not all #defines used but here for documentation
#define CE_PIN   9
#define CSN_PIN 10
#define MOSI_PIN 11
#define MISO_PIN 12
#define SCK_PIN 13

const byte thisSlaveAddress[5] = {'R', 'x', 'A', 'A', 'A'};

RF24 radio(CE_PIN, CSN_PIN);

struct data
{
  byte pinState;
  int temperature;
} receivedData;

bool newData = false;

void setup()
{
  Serial.begin(115200);
  Serial.println("SimpleRx Starting");
  radio.begin();
  radio.setDataRate( RF24_250KBPS );
  radio.openReadingPipe(1, thisSlaveAddress);
  radio.startListening();
}

void loop()
{
  getData();
  showData();
}

void getData()
{
  if ( radio.available() )
  {
    radio.read( &receivedData, sizeof(receivedData) );
    newData = true;
  }
}

void showData()
{
  if (newData == true)
  {
    Serial.print("Data received\tpinState : ");
    Serial.print(receivedData.pinState);
    Serial.print("\t");
    Serial.print("temperature : ");
    Serial.println(receivedData.temperature);
    newData = false;
  }
}

From this tread: Problem in sending structure using nRF24L01 - #14 by UKHeliBob

In this code i could change the byte temperature to int temperature and it worked fine.

Now i ony have to figure out how to make the transmitter only send data when either the "pinstate" or "temperature" have changed.

Best Regards
Andreas

byte pinLst;

{
    ...
    byte pin = digitalRead (Pin);
    if (pinLst != pin) {
        pinLst = pin;

        ....
    }
    ...
}

or temp & tempLst

Hi @2178an,

you seem to try to get a code that does what you want right out of the box without learning.

The latest code not

  • check if one out of 3 int-variables has changed and then send all three values
  • it does not even send 3 int values

The usual way of help in this forum is:
asking an initial question. If the question is very general you get generalised answers. It is very unusual to get a ready to use code.
You won't get ready to use code even if you ask 50 times.

If something is unclear you have to to do two things:

  1. making an attempt how it might work. It doesn't matter if your attempt not even compiles.The important thing is to have made an own attempt.
  2. ask for what the error-message means or how to modify your attempt to make a certain detail work.

In this way you learn from it.

Your attempt was

You did not yet understand how the command write works:
the first parameter &dataToSend must contain the data
hence the variable name that says exactly that dataToSend
the second parameter specifies how many bytes shall be transmitted

with comments what your code does

rslt = radio.write( &dataToSend, sizeof(dataToSend) ); // send content of variable with name "dataToSend" with "X" bytes. Where "X" is the number of bytes that variable "dataToSend" occupies in RAM
 
    rslt = radio.write( &dataToSend, sizeof(value1) ); // send content of variable with name "dataToSend" with "X" bytes. Where "X" is the number of bytes that variable "**value1**" occupies in RAM

This means still the same data that is stored in variable "dataToSend" will be send but only a part of 
all data. The number of bytes beeing send is the number of bytes the variable value1 occupies in RAM.

    rslt = radio.write( &dataToSend, sizeof(value2) );
    rslt = radio.write( &dataToSend, sizeof(value3) );

The way to go is:

store your value1 in variable dataToSend
append your value2 in variable dataToSend after value1
append your value3 in variable dataToSend after value2

then send variable "dataToSend"

This is the basic principle.
If you know nothing yet about different variable-types
and if you don't know nothing yet about "struct" you completely dependant on somebody else to write readyto use code which will not happen.
Because you would stay dependant without learning some basics and with each modification of the code you would have to beg other for again writing the ready to use code

The ususal way is:
showing some own effort and asking a question
getting an answer
showing some own effort in proceeding at least a small step
and asking a question
showing some own effort in proceeding at least a small step
and asking a question
showing some own effort in proceeding at least a small step
and asking a question
...
best regards Stefan

Post 8.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.