Reading Serial Data then send via NRF24L01

I have an SPI-TRONIC pro3600 digital level that I want to be able to read the in coming data through the serial port. I have it reading the incoming data and displaying it on the Serial port ok.

So the next step I took was to add the NRF24l01 code so that I could transmit the incoming data. ( I know the TX side is paired and working with the RX side as I ran some test code that counts up and this is working well.)

I still can see the level reading on the TX serial port but on the RX it does not display the data correctly, Now I think this is down to the way I read the serial port and send the data over as the RX only show's a 10.

This is the test code that just reads the incoming data and works ok.

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <SoftwareSerial.h>
SoftwareSerial mySerial(6, 5); // RX, T 2,3
LiquidCrystal_I2C lcd(0x03f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address
//#define mySerial Serial1
#define ECHO_TO_SERIAL 1 //change to zero = no serial output
#include <TimedAction.h>
bool newData = false; // flag for new data
int inByte; //holds the in coming byte


//#######################################################
//# Send out data to Serial monitor, only for debugging #
//#######################################################
void printRecord(Print* pr) {
  pr->print(inByte);
  pr->println();

}
void TimerService03();// Timer service routinte
TimedAction Timedact03 = TimedAction(50, TimerService03);// // read the data
void setup() {
  Serial.begin(9600);
  Serial.println("TEST");
  mySerial.begin(9600);
}

void loop() {
  Timedact03.check();
  if (newData) { //new data received from eLevel
    newData = false;
#if ECHO_TO_SERIAL
    Serial.write(inByte);
#endif //ECHO_TO_SERIAL

  }


}


void TimerService03() { //send the data out to NRF24L01 module
  while (mySerial.available() > 0 && newData == false) {
    inByte = mySerial.read();
    newData = true;
  }
}

The incoming data shows like this:

-  3.47
-  3.47
-  3.47
-  3.47
-  3.27
-  8.19
- 11.17
- 12.47
- 13.36
- 13.59
+  3.79
+  4.18
+  3.92
+  3.88
+  7.95
+ 10.09
+ 12.10
+ 12.10
+  9.52

This is out of the instruction manual.

The Pro 3600 has an ASCII-format RS-232 compatible serial port for remote angle readout. The T&B Ansley 609-1027 connector on the back of the Pro3600 mates with industry

Angle Output Format: The ASCII angle output may be read by a computer, or may directly drive
 a printer. Measured angles cover a full 360° range and the readout is between -180.00° and +180.00°.
Format:
<sign> XXX.XX <carriage return><line feed>
 examples:
 + 124.50
 + 32.70 
+ 9.38 
– 4.32 
– 179.99

I think by me uploading the NRF24L01 code will confuse matters for now as I think I need to read the serial port correctly first.

Which would be the best way to read the serial port and kind of build an array ?

Say like so inByte[0] holds the +/-, Then inByte[1] holds the first X(first digit which is a number or blank space), Then InByte[2] holds the second digit and so on.

until the bit as come in to end the transmisson.
Hopefully I've explained it so that you can understsand

steve

Which would be the best way to read the serial port and kind of build an array ?

The serial input basics tutorial will show how to read in serial data into a string that can easily be sent with an rf24 radio. The second example may be just what you need (input data terminated with a line feed).

groundFungus:
The serial input basics tutorial will show how to read in serial data into a string that can easily be sent with an rf24 radio. The second example may be just what you need (input data terminated with a line feed).

Thanks I will look into this, I thought there was something like this but not sure, I should have done a search

I've just up loaded it and it works great I will now study and play around with it

Thanks
Steve

I've just been playing and added the NRF24l01 code and made some progress with it.

Now on the RX side I am only getting the + or the - sign showing, I think this is been caused by the space and may be I'm not sending the data out in the correct manor,

but has it's late here and got to get up for work I shall look into it more tomorrow,

Here is the TX code:

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <SoftwareSerial.h>
SoftwareSerial mySerial(6, 5); // RX, T 2,3
LiquidCrystal_I2C lcd(0x03f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address
//#define mySerial Serial1
#define ECHO_TO_SERIAL 1 //change to zero = no serial output
#include <TimedAction.h>
const byte numChars = 10;
char receivedChars[numChars];   // an array to store the received data
boolean newData = false;
#define CE_PIN   9
#define CSN_PIN 10
RF24 radio(CE_PIN, CSN_PIN); // Create a Radio
const uint64_t pipeOut = 0xB3B4B5B6A3LL;//0xE8E8F0F0E1LL; //IMPORTANT: The same as in the receiver

void setup() {
  Serial.begin(9600);
  Serial.println("TEST");
  mySerial.begin(9600);

  radio.begin();
  radio.setAutoAck(false);
  radio.setDataRate(RF24_250KBPS);
  radio.setChannel(108);  // Above most Wifi Channels
  radio.setPALevel(RF24_PA_MAX);  // Uncomment for more power
  radio.openWritingPipe(pipeOut);

}

void loop() {
  recvWithEndMarker();
  showNewData();

  //  radio.write( &data, sizeof(MyData) ); //  Transmit the data
}


void recvWithEndMarker() {
  static byte ndx = 0;
  char endMarker = '\n';
  char rc;

  while (mySerial.available() > 0 && newData == false) {
    rc = mySerial.read();

    if (rc != endMarker) {
      receivedChars[ndx] = rc;
      ndx++;
      if (ndx >= numChars) {
        ndx = numChars - 1;
      }
    }
    else {
      receivedChars[ndx] = '\0'; // terminate the string
      ndx = 0;
      newData = true;
    }
  }
}

void showNewData() {
  if (newData == true) {
    Serial.print("This just in ... ");
    Serial.println(receivedChars);
    radio.write( &receivedChars, sizeof(receivedChars) ); //  Transmit the data
    newData = false;
  }
}

And here is the RX code:

//####################################################
//# Include all the libraries                        #
//####################################################
#include <LiquidCrystal.h>// Highlight out when ready to use mian display
#include "RF24.h"  // Download and Install (See above)
#include <TimedAction.h>
#include <AutoPower.h>
//####################################################
//# Define the output,input pins & voltage referance #
//####################################################
#define LED   A2     // Pin 5, Connects to LED wired to Gnd via suitable resistor, such as 220 Ohms
#define HOLD  9     // Pin 2, Connects to HOLD pin on AutoPower module
#define BTN   A1    // Pin 3, Connects to BTN pin on AutoPower module
const uint64_t pipeIn =  0xB3B4B5B6A3LL;//0xE8E8F0F0E1LL64 bit encrypicted code
//####################################################
//# Define the Variables                             #
//####################################################
#define CE_PIN   6
#define CSN_PIN 10
RF24 radio(CE_PIN, CSN_PIN);
char receivedChars;   // an array to store the received data
bool newData = false;
int dataReceived;  // Data that will be received from the transmitter
//####################################################
//#  Specifying the CE and CS pins & LCD Pins        #
//####################################################
LiquidCrystal lcd(2, 4, 5, 3, 7, 8);
//####################################################
//#  SwitchManger routines checks switches           #
//####################################################
// Note: last parameter is optional (defaults to 2 seconds if omitted)
AutoPower power(HOLD, BTN, LED, 2);   // Hold button 2 seconds to power off
void TimerService02();// ADD THIS FUNCTION PROTOTYPE
TimedAction Timedact02 = TimedAction(80, TimerService02);// mS
void setup()   /****** SETUP: RUNS ONCE ******/
{
  Serial.begin(9600);
  lcd.begin(8, 2);                             // Initialize the LCD.

  pinMode(LED, OUTPUT);
  digitalWrite(BTN, LOW);
  digitalWrite( HOLD, HIGH); //Turn it back on after 1.5 seconds
  lcd.clear();
  power.setTimeout(300);
  radio.begin();
  radio.setAutoAck(false);
  radio.setDataRate(RF24_250KBPS); // Both endpoints must have this set the same
  radio.setChannel(108);  // Above most Wifi Channels
  radio.setPALevel(RF24_PA_MAX);  // Uncomment for more power
  radio.openReadingPipe(1, pipeIn);
  radio.startListening();

}





void loop()   /****** LOOP: RUNS CONSTANTLY ******/
{

  power.updatePower();

  if ( radio.available()) // Check for incoming data from transmitter
  {
    while (radio.available())  // While there is data ready
    {
      radio.read( &receivedChars, sizeof(receivedChars) ); // Get the data payload (You must have defined that already!)
    }
  }//--(end main loop )---
  Timedact02.check();
}



void TimerService02() {

  lcd.setCursor(0, 1);
  lcd.print(receivedChars);
  lcd.print("   ");

  // Serial.println(dataReceived);
}

Both work in progress, I think I am sending the data out wrong may be ?

Steve

char receivedChars;   // an array to store the received data

Not an array, receivedChars is only 1 character.

char receivedChars[10];  // an array that matches the size of the sent array

@groundFungus has put his finger on the problem.

Note that Serial receives data one character at a time but the nRF24 sends up to 32 bytes at a time as a complete message. That means that this code

    while (radio.available())  // While there is data ready
    {
      radio.read( &receivedChars, sizeof(receivedChars) ); // Get the data payload (You must have defined that already!)
    }

can be simplified to

    if (radio.available())  // if there is data ready
    {
      radio.read( &receivedChars, sizeof(receivedChars) ); // Get the data payload (You must have defined that already!)
    }

because if any data has been received the whole message will have been received.

...R

Robin2:
@groundFungus has put his finger on the problem.

Note that Serial receives data one character at a time but the nRF24 sends up to 32 bytes at a time as a complete message. That means that this code

    while (radio.available())  // While there is data ready

{
      radio.read( &receivedChars, sizeof(receivedChars) ); // Get the data payload (You must have defined that already!)
    }



can be simplified to


if (radio.available())  // if there is data ready
    {
      radio.read( &receivedChars, sizeof(receivedChars) ); // Get the data payload (You must have defined that already!)

}



because if any data has been received the whole message will have been received.

...R

Thanks I've made the changes for the simpler version as you advised. I've also managed to get rid of some extra rubbish that was been printed on the LCD.

Now all working just need to se about tidying the code up adding me extra bits that's needed and adding all the comments.
Not sure if it could be optimised in any way shape or form ?

Thanks
Steve

Steveiboy:
Not sure if it could be optimised in any way shape or form ?

You have to tell us what you think needs to be optimised? Different people have different preferences.

If my code is readable and if it does what I want I am generally satisfied. Most times when I tinker with working code it is to make it easier to remember (in 6 months time) how it works.

...R

Sorry for the delay in coming back this project, Have been away and not had chance to play.

I've been carrying out some test and added to the RX to display on the LCD if it the TX signal is lost.

After doing so testing I found that the TX SIGNAL lost comes up at random places, Bearing in mind I'm using the hardware set up that I used in another project so I can kind of count the hardware as with my wireless mulitmeter code doe not do this, But this does not have if TX signal is lost code and seems work in the same place as the digital level.

I think it may be to do with the extra code and the way it's set up, I've not really noticed if did not do this before hand. I need some sort of way if the RX does not receive any TX signal as a sort of bit of safety telling the user it's lost or not receiving data from the TX unit.

Here is the latest version of the RX code:

//####################################################
//# Include all the libraries                        #
//####################################################
#include <LiquidCrystal.h>// Highlight out when ready to use mian display
#include <SPI.h>   // Comes with Arduino IDE
#include "RF24.h"  // Download and Install (See above)
#include <TimedAction.h>
#include <AutoPower.h>
//####################################################
//# Define the output,input pins & voltage referance #
//####################################################
#define LED   A2     // Pin 5, Connects to LED wired to Gnd via suitable resistor, such as 220 Ohms
#define HOLD  9     // Pin 2, Connects to HOLD pin on AutoPower module
#define BTN   A1    // Pin 3, Connects to BTN pin on AutoPower module
//const uint64_t pipeIn =  0xB3B4B5B6A3LL;//0xE8E8F0F0E1LL64 bit encrypicted code only left as trying new way(Test 1)
byte addresses[][6] = {"1Node"}; // Create address for 1 pipe. Test 2
//####################################################
//# Define the Variables                             #
//####################################################
#define CE_PIN   6 // set up CE pin fro NRF24l01
#define CSN_PIN 10 // set up CSN pin fro NRF24l01
RF24 Radio(CE_PIN, CSN_PIN); //set the pins
const byte numChars = 8; //After testing this is all I need same setting for the TX
char receivedChars[numChars];   // an array to store the received data
bool newData = false; // se if incoing data is been TX
int dataReceived;  // Data that will be received from the transmitter
const long TX_interval = 500;  //Error flag timer for not recieving from the tx
unsigned long lastRecvTime = 0; // escape from recieve data
unsigned long TX_previousMillis = 0; // stores the last mills
#define Error_led 2
//bool newData = false;
bool lostData = false;
//####################################################
//#  Specifying the CE and CS pins & LCD Pins        #
//####################################################
LiquidCrystal lcd(2, 4, 5, 3, 7, 8);
//####################################################
//#  SwitchManger routines checks switches           #
//####################################################
// Note: last parameter is optional (defaults to 2 seconds if omitted)
AutoPower power(HOLD, BTN, LED, 2);   // Hold button 2 seconds to power off
void TimerService02();// ADD THIS FUNCTION PROTOTYPE
TimedAction Timedact02 = TimedAction(80, TimerService02);// mS

void resetData()
{
  receivedChars[8] = "0.00";
  unsigned long TX_Error = millis();
  newData = false;
  if (TX_Error - TX_previousMillis >= TX_interval) {
    // save the last time you blinked the LED
    TX_previousMillis = TX_Error;
    digitalWrite(Error_led, !digitalRead(Error_led));
  }
  if (newData == false) { //new data received from eLevel
    //newData = false;
    lcd.setCursor(0, 0);
    lcd.print("TX SIGNAL");
    lcd.setCursor(0, 1);
    lcd.print("LOST");
  }
}
void setup()   /****** SETUP: RUNS ONCE ******/
{
  pinMode(Error_led, OUTPUT);
  digitalWrite(Error_led, LOW);
  Serial.begin(9600);
  lcd.begin(8, 2);                             // Initialize the LCD.

  pinMode(LED, OUTPUT);
  digitalWrite(BTN, LOW);
  digitalWrite( HOLD, HIGH); //Turn it back on after 1.5 seconds
  lcd.clear();
  power.setTimeout(300);
  /*
    radio.begin();
    radio.setAutoAck(false);
    radio.setDataRate(RF24_250KBPS); // Both endpoints must have this set the same
    radio.setChannel(108);  // Above most Wifi Channels
    radio.setPALevel(RF24_PA_MAX);  // Uncomment for more power
    radio.openReadingPipe(1, pipeIn);
    radio.startListening();
    lcd.createChar(1, upArrow);
    lcd.createChar(2, downArrow);
  */
  Radio.begin();  // Start up the physical nRF24L01 Radio
  Radio.setChannel(108);  // Above most Wifi Channels
  Radio.setPALevel(RF24_PA_MAX);  // Uncomment for more power
  Radio.setDataRate(RF24_250KBPS); // Fast enough.. Better range
  Radio.openReadingPipe(1, addresses[0]); // Use the first entry in array 'addresses' (Only 1 right now)
  Radio.startListening();
  resetData();
}

void recvData()
{
  while ( Radio.available() ) {
    Radio.read( &receivedChars, sizeof(receivedChars) ); // Get the data payload (You must have defined that already!)
    lastRecvTime = millis();
    newData = true;
  }
}



void loop()   /****** LOOP: RUNS CONSTANTLY ******/
{
  recvData();
  Timedact02.check();
  power.updatePower();
  if (newData == true) { //new data received from eLevel
    lcd.setCursor(0, 0);
    lcd.print("TX GOOD");
  }
  unsigned long now = millis();
  if ( now - lastRecvTime > 1000 ) { //if data stops coming turn everything off with a second
    // signal lost?
    resetData();
  }
  digitalWrite(Error_led, LOW);
}



void TimerService02() {

  if (newData == true) { //new data received from eLevel
    lcd.setCursor(0, 1);
    lcd.print(receivedChars);
  }
  // lcd.setCursor(0, 1);
  // lcd.print(receivedChars);
  // lcd.print("   ");

  // Serial.println(dataReceived);
}

And here is the TX code

#include <SPI.h>
#include "RF24.h"  // Download and Install (See above)
//#######################
//#include <nRF24L01.h>
//#include <RF24.h>
//#########################
//#include <LiquidCrystal_I2C.h>
#include <Wire.h>
//#include <SoftwareSerial.h>
//SoftwareSerial mySerial(6, 5); // RX, T 2,3
//LiquidCrystal_I2C lcd(0x03f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address
//#define mySerial Serial1
//#define ECHO_TO_SERIAL 1 //change to zero = no serial output
//#include <TimedAction.h>
const byte numChars = 8; //After testing this is all I need same setting for the RX
char receivedChars[numChars];   // an array to store the received data
boolean newData = false;
#define CE_PIN   9 // set up CE pin fro NRF24l01
#define CSN_PIN 10 // set up CSN pin fro NRF24l01
RF24 Radio(CE_PIN, CSN_PIN); // Create a Radio
//######################################################
//const uint64_t pipeOut = 0xB3B4B5B6A3LL;//0xE8E8F0F0E1LL; //IMPORTANT: The same as in the receiver
byte addresses[][6] = {"1Node"}; // Create address for 1 pipe.
void setup() {
  Serial.begin(9600);
  // Serial.println("TEST");
  // mySerial.begin(9600);
  /*  radio.begin();
    radio.setAutoAck(false);
    radio.setDataRate(RF24_250KBPS);
    radio.setChannel(108);  // Above most Wifi Channels
    radio.setPALevel(RF24_PA_MAX);  // Uncomment for more power
    radio.openWritingPipe(pipeOut);
  */
  Radio.begin();  // Start up the physical nRF24L01 Radio
  Radio.setChannel(108);  // Above most Wifi Channels
  Radio.setPALevel(RF24_PA_MAX);  // Uncomment for more power
  Radio.setDataRate(RF24_250KBPS); // Fast enough.. Better range
  Radio.openWritingPipe( addresses[0]); // Use the first entry in array 'addresses' (Only 1 right now)
}

void loop() {
  recvWithEndMarker();
  showNewData();

  //  radio.write( &data, sizeof(MyData) ); //  Transmit the data
}


void recvWithEndMarker() {
  static byte ndx = 0;
  char endMarker = '\n';
  char rc;

  while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();

    if (rc != endMarker) {
      receivedChars[ndx] = rc;
      ndx++;
      if (ndx >= numChars) {
        ndx = numChars - 1;
      }
    }
    else {
      receivedChars[ndx] = '\0'; // terminate the string
      ndx = 0;
      newData = true;
    }
  }
}

void showNewData() {
  if (newData == true) {
    //  Serial.print("This just in ... ");
    // Serial.println(receivedChars);
    Radio.write( &receivedChars, sizeof(receivedChars) ); //  Transmit the data
    newData = false;
  }
}

So I guess this what I mean by optimising the code as there may be an more of an elegant way

Steveiboy:
After doing so testing I found that the TX SIGNAL lost comes up at random places, Bearing in mind I'm using the hardware set up that I used in another project so I can kind of count the hardware as with my wireless mulitmeter code doe not do this, But this does not have if TX signal is lost code and seems work in the same place as the digital level.

I think, if you re-read this you will see why I can't understand it.

So I guess this what I mean by optimising the code as there may be an more of an elegant way

I don't do elegant :slight_smile:

My style of programming is pretty well illustrated in Planning and Implementing a Program.

...R

Robin2:
I think, if you re-read this you will see why I can't understand it.

I don't do elegant :slight_smile:

My style of programming is pretty well illustrated in Planning and Implementing a Program.

...R

Yes your correct, Guess my fingers can't keep up with my brain how fast it wants me fingers to type :slight_smile: .

What I meant was that I would lose the signal from between the RX and the TX when I moved away from the transmitter and the distance was not the same sometimes the distance was good and then others it would be just outside the room with the door open. But this was testing between rooms and it will only be used outside.

The hardware that I'm using is what I did my wireless multi-meter with and with this and the meter code I can go to the back of the house without losing the transmission between the RX & TX. So I know it's not an hardware issue and it's more than likely to be software at a guess.

I have changed the code to the same as my meter code but to transmit the level code and this has seemed to cure it with the range increased , SO now I need to look at the RX code I posted above as it may not be losing the signal and it just displaying the lost signal part, As I removed all that lost signal code from the code above and that also seemed to increase the range.

I know that these modules are not the nest for going through walls and stuff, But I will be carrying out more testing at work with the range as my wireless-meter has really good range on it with out losing transmission between them.

Thanks for the link I will be reading that and looking though it for ideas and learn more on better ways to Implementing code :slight_smile:

thanks
Steve