XBee Receiver polling two XBee Transmitters

Hi guys,

I have configured three XBees to communicate TX1 <==> RX and TX2 <==> RX. And I even tested them individually, with the point to point temperature sensor code. But I am having troubling with the actual code for point to multipoint now.

I think the problem is with the polling signals. I am using “*” and “(” as my polling signals and also as my start characters for my data from each of the sensors. The first sensor TX1 is sending 2 bytes of temperature data, the second one TX2 is sending 2 bytes (unsigned int) of rpm data.

My intention is this – The RX broadcasts polling signal for TX1, TX1 sends data, after this is read by RX, RX broadcasts polling signal for TX2, TX2 sends data to RX, after this is read the cycle repeats.

I have three codes : one for the receiver, one for the transmitter of the Hall sensor and one for the transmitter of the Temperature sensor.

I have used ‘*’ and ‘(’ as the data_start signals, and the same for the polling signals. The hall sensor sends data (starting with a ‘(’ character) when polled with ‘(’, and the temperature sensor sends data starting with a ‘*’ when polled with ‘*’

I think its the polling signals that I am messing up. Can someone help me with this?

Temperature Sensor code (TX 1)

#include <SoftwareSerial.h>
#include <i2cmaster.h>

SoftwareSerial XBeeTX(2, 3); // RX, TX

const byte dev = 0x5A<<1; 
const char data_start = '*'; 
const char data_format[] = "%c%02X%02X"; 
char dataStream[6]; // data_format will result in 5 characters plus 1 NULL character automatically applied by the sprintf() function so we need a 6 element array as a buffer
byte data_low;
byte data_high;
byte pec;
char data_in;

void setup()
{  
  Serial.begin(9600);
  XBeeTX.begin(9600);
  
  i2c_init(); //Initialise the i2c bus
  PORTC = (1 << PORTC4) | (1 << PORTC5);//enable pullups
}

void loop()
{  
  i2c_start_wait(dev+I2C_WRITE);
  i2c_write(0x07);

  // read
  i2c_rep_start(dev+I2C_READ);
  data_low = i2c_readAck(); //Read 1 byte and then send ack
  data_high = i2c_readAck(); //Read 1 byte and then send ack
  pec = i2c_readNak();
  i2c_stop();

if (XBeeTX.available())
{ 
  data_in = XBeeTX.read();
  if (data_in == data_start)
  { 
  sprintf(dataStream, data_format, data_start, data_high, data_low); 
  XBeeTX.print(dataStream);
  Serial.print(dataStream); 
  Serial.println(F(" Sent over XBee."));
  delay(100); // adjust to what ever delay you want.
  } 
}
}

Hall sensor code (TX 2)

#include <SoftwareSerial.h>

SoftwareSerial XBeeTX(2, 3);  // RX, TX

const char data_start = '(';
const char data_format[] = "%c%04X";
char dataStream[6];
volatile byte revolutions;                                                   
unsigned int rpm;
unsigned int rpm_send;
unsigned long timeold;
unsigned long k;
char data_in;

void setup()
{
  Serial.begin(9600);
  XBeeTX.begin(9600);
  attachInterrupt(0, rpm_fun, FALLING);
  revolutions = 0;
  rpm = 0;
  timeold = 0;
  k = 0;
}

void loop()
{ 
  if (revolutions >= 10)                         //** Update RPM every 10 counts**
 { 
   
    k = millis() - timeold;
    rpm = 60000/k*revolutions;          // **calculate the revolutions per minute
    timeold = millis();
    revolutions = 0;
 }
 
 if (XBeeTX.available())
  {
    data_in = XBeeTX.read();
    
  if(data_in == data_start)   // if polling signal has arrived
  { // send data
    sprintf(dataStream, data_format, data_start, rpm);
    XBeeTX.print(dataStream);
    Serial.println(F("Sent over XBee"));
    delay(100);
  }
}
}
void rpm_fun()
{
  revolutions++;
}

Receiver code

Okay, here is probably where I messed up in the XBeeRX.print(poll_1) and XBeeRX.print(poll_2), signals.

#include <SoftwareSerial.h>

SoftwareSerial XBeeRX(2, 3); // RX, TX

const char poll_1 = '*'; // This is a constant, so use the const keyword to allow the compiler to decide how best to optimize
const char poll_2 = '(';

const char data_format_1[] = "%c%02X%02X"; // for sprintf() %c is a single character and %02X is a 2 character ASCII encoded hex number representing 1 byte
const char data_format_2[] = "%c%02X%02X";
char dataStream_1[6]; // data_format will result in 5 characters plus 1 NULL character automatically applied by the sprintf() function so we need a 6 element array as a buffer
char dataStream_2[6];

boolean newReading_1 = false; // Because we use this before explicitly setting it, just to make sure the default is false we set it here.
boolean newReading_2 = false;
byte readPosition_1;
byte readPosition_2;

byte data_temp_1;
byte data_temp_2;

byte data_rpm_1;
byte data_rpm_2;

char data_in;

void setup()
{
  Serial.begin(9600);
  XBeeRX.begin(9600);
}

void loop()
{
  XBeeRX.print(poll_2)   // it sends polling signal 1 later
  delay(1000);
  
  // READING DATA
  if (XBeeRX.available())
  {         
    data_in = XBeeRX.read();
    switch (readPosition_1)
    { 
     case 0:
      {
    if (data_in == poll_1)
    readPosition_1++;
    break;
      } 
    case 1: 
      { 
        data_temp_1 = HexCharToValue(data_in)<<4;
        readPosition_1++;
        break;
      } 
    case 2:
      { 
        data_temp_1 = HexCharToValue(data_in)+data_temp_1;
        readPosition_1++;
        break;
      } 
    case 3:
      {  
        data_temp_2 = HexCharToValue(data_in)<<4;
        readPosition_1++;
        break;
      }  
    case 4:
      {  
        data_temp_2 = HexCharToValue(data_in)+data_temp_2;
        readPosition_1 = 0;  
        newReading_1 = true;
      } 
    } 
    
  // READING HALL SENSOR DATA
  
  switch(readPosition_2)
  {
    case 0:
    {
    if (data_in == poll_2)
     readPosition_2++;
     break;
    }
    
    case 1: 
      { 
        data_rpm_1 = HexCharToValue(data_in)<<4;
        readPosition_2++;
        break;
      }  
    case 2: 
      { 
        data_rpm_1 = HexCharToValue(data_in)+data_rpm_1;
        readPosition_2++;
        break;
      } 
    case 3: 
      {  
        data_rpm_2 = HexCharToValue(data_in)<<4;
        readPosition_2++;
        break;
      } 
    case 4: 
      {  
        data_rpm_2 = HexCharToValue(data_in)+data_rpm_2;
        readPosition_2 = 0; 
        newReading_2 = true;   
      }  
    } 
  }
  
  if (newReading_1 == true) // newReading is a boolean type
  {
    sprintf(dataStream_1, data_format_1, poll_1, data_temp_1, data_temp_2);
    //Serial.print(dataStream); // diagnostics
    
    
    double tempFactor = 0.02; 
    unsigned int tempData; 
    float kelvin; 
    float celsius; 
    
    tempData = ((data_temp_1 & 0x007F) << 8) + data_temp_2; 
    kelvin = (tempData * tempFactor); 
    
    celsius = kelvin - 273.15; 
    
    Serial.print(F(" Celsius: ")); // Save SRAM by using F() macro for constant text messages
    Serial.println(celsius);
    newReading_1 = false;
  }
  
  if (newReading_2 == true) // newReading is a boolean type
  {
    sprintf(dataStream_2, data_format_2, poll_2, data_rpm_1, data_rpm_2); 
    
    unsigned int rpm;  
    rpm = ((data_rpm_1 & 0x007F) << 8) + data_rpm_2; 
    
    Serial.print(F("RPM: ")); // Save SRAM by using F() macro for constant text messages
    Serial.println(rpm);
    XBee.print(poll_1);      // RX polls TX1 after data 2 has been read
    delay(100);
    newReading_2 = false;
  }
}

byte HexCharToValue (char x)
{
  byte value;
  char upper; // Should match x, so make this a char. (will save 1 byte of stack space in the process).
  byte first_result;

  if (isxdigit(x))
  {
    upper = toupper(x);
    first_result = upper - 0x30;
    if (first_result < 0x0A)
    {
      value = first_result;
    }
    else
    { 
      value = first_result - 0x10;
      value = value + 9; 
    }
  }
  else
  {
    value = 0;
  }

  return value;
}

PS : Moderators, this is a modified version of another in the Arduino forum. I thought it better to post it here under “Programming Questions”, because that is what this is actually. You guys could remove the other post, I shifted it here because I wasn’t getting any responses in the other one.

The hall sensor sends data

No, it doesn’t. There IS an Arduino involved that is doing something. I really doubt that your hall sensor has a radio built in.

const char data_format_1[] = "%c%02X%02X"; // for sprintf() %c is a single character and %02X is a 2 character ASCII encoded hex number representing 1 byte
const char data_format_2[] = "%c%02X%02X";

Are these somehow different? Why do you need two?

char dataStream_1[6]; // data_format will result in 5 characters plus 1 NULL character automatically applied by the sprintf() function so we need a 6 element array as a buffer
char dataStream_2[6];

Why do you need two?

That code for reading data is complete nonsense. You are reading and storing data in both arrays after polling #2.

  delay(100); // adjust to what ever delay you want.

How about 0? There is NO reason to wait any time before reading the sensor again or before checking to see if the Arduino is being paged again.

It would be a lot simpler to send the data in base 10. Combine the high and low bytes on the transmitters, and send the value as 7 bytes (ID and 6 (max) for the value, to allow for -32768.) Yes, it will take slightly longer, but then you don’t have to deal with HEX to DEC conversion and byte manipulation on the receiver. Sending some kind of end-of-data marker would be better than relying on a fixed length string, too.

Hey Paul,

I took help from Sembazuru on this, and I can correct the double data_format[] and other things too. But how do I exactly poll the two transmitters? Is the present logic correct, or if its wrong I can't seem to understand why.

While I can do point to point for both of them, its the polling signals I feel I am messing up.

How would you say the polling should be done? I have tried some other methods, one of them gives me correct temperature data, but it messes the RPM data.

PS: When I say the hall sensor is sending data, I mean the XBee connected to the Arduino connected to it. The hardware is fine, its worked in point to point, its just the code.

Thanks.

Here is another attempt I did today. This time I get both data in the COM port, but its clearly mixed up and wrong. I got RPM readings when I didn’t put the magnet near the hall sensor, and I can be pretty sure my room was not that cold lol

I used a variable called polling number, and incremented it every time a polling signal is sent. If its value is 0 or even, it means its going to poll the temperature sensor Arduino, if its value is odd it means its going to poll the hall sensor Arduino.

I still can’t understand where my logic fails.

Temperature sensor Arduino code (TX 1)

#include <SoftwareSerial.h>
#include <i2cmaster.h>

SoftwareSerial XBeeTX(2, 3); // RX, TX

const byte dev = 0x5A<<1; // This is a constant, so use the const keyword to allow the compiler to decide how best to optimize
const char data_start = '*'; // This is a constant, so use the const keyword to allow the compiler to decide how best to optimize
const char data_format[] = "%c%02X%02X"; // %c is a single character, %02X is a 2 character ASCII encoded hex number representing 1 byte
char dataStream[6]; // data_format will result in 5 characters plus 1 NULL character automatically applied by the sprintf() function so we need a 6 element array as a buffer
byte data_low;
byte data_high;
byte pec;

void setup()
{  
  Serial.begin(9600);
  XBeeTX.begin(9600);
  
  i2c_init(); //Initialise the i2c bus
  PORTC = (1 << PORTC4) | (1 << PORTC5);//enable pullups
}

void loop()
{   // Level 0
  i2c_start_wait(dev+I2C_WRITE);
  i2c_write(0x07);

  // read
  i2c_rep_start(dev+I2C_READ);
  data_low = i2c_readAck(); //Read 1 byte and then send ack
  data_high = i2c_readAck(); //Read 1 byte and then send ack
  pec = i2c_readNak();
  i2c_stop();

if (XBeeTX.available() && XBeeTX.read() == data_start)
 {   
  sprintf(dataStream, data_format, data_start, data_high, data_low); 
  XBeeTX.print(dataStream);
  Serial.print(dataStream); // for diagnostics
  Serial.println(F(" Sent over XBee.")); 
  delay(250); // adjust to what ever delay you want.
  }
}

Hall sensor Arduino code (TX 2)

#include <SoftwareSerial.h>

SoftwareSerial XBeeTX(2, 3);  // RX, TX

volatile byte revolutions;                                                   
unsigned int rpm;
unsigned long timeold;
unsigned long k;
const char data_start = '(';
const char data_format[] = "%c%04X";
char dataStream[6];
char data_in;

void setup()
{
  Serial.begin(9600);
  XBeeTX.begin(9600);
  attachInterrupt(0, rpm_fun, FALLING);
  revolutions = 0;
  rpm = 0;
  timeold = 0;
  k = 0;
}

void loop()
{ 
  if (revolutions >= 3)                         //** Update RPM every 3 counts**
 {
   
    k = millis() - timeold;
    rpm = 60000/k*revolutions;          // **calculate the revolutions per minute
    timeold = millis();
    revolutions = 0;
 }
 
 
 if (XBeeTX.available() && XBeeTX.read() == data_start)
  {
    sprintf(dataStream, data_format, data_start, rpm);
    XBeeTX.print(dataStream);
    Serial.println(dataStream);        // diagnostics
    Serial.println(F("Sent over XBee"));
    delay(250);        
  }

}
void rpm_fun()
{
  revolutions++;
}

Receiver code (RX)

#include <SoftwareSerial.h>

SoftwareSerial XBeeRX(2, 3); // RX, TX

const char poll_1 = '*'; 
const char poll_2 = '(';

const char data_format[] = "%c%02X%02X";
char dataStream_1[6]; // data_format will result in 5 characters plus 1 NULL character automatically applied by the sprintf() function so we need a 6 element array as a buffer
char dataStream_2[6];

boolean newReading_1 = false; // Because we use this before explicitly setting it, just to make sure the default is false we set it here.
boolean newReading_2 = false;
byte readPosition_1;
byte readPosition_2;
byte polling_number = 0;

byte data_temp_1;
byte data_temp_2;

byte data_rpm_1;
byte data_rpm_2;

char data_in;

void setup()
{
  Serial.begin(9600);
  XBeeRX.begin(9600);
}

void loop()
{
  // POLLING BLOCK
  if (polling_number%2 == 0)
  {
  XBeeRX.print(poll_1);
  delay(1000);
  }
  else if (polling_number%2 == 1)
  {
  XBeeRX.print(poll_2);
  delay(1000);
  }
  
  // READING DATA
  if (XBeeRX.available())
  {        
    data_in = XBeeRX.read();
    
    switch (readPosition_1)
    { 
     case 0:
      {
      if (data_in == poll_1)
      {
      readPosition_1++;
      }
      break;
      } 
    case 1: 
      {  
        data_temp_1 = HexCharToValue(data_in)<<4;
        readPosition_1++;
        break;
      } 
    case 2:
      { 
        data_temp_1 = HexCharToValue(data_in)+data_temp_1;
        readPosition_1++;
        break;
      } 
    case 3:
      { 
        data_temp_2 = HexCharToValue(data_in)<<4;
        readPosition_1++;
        break;
      } 
    case 4:
      {   // Level 3
        data_temp_2 = HexCharToValue(data_in)+data_temp_2;
        readPosition_1 = 0;  
        newReading_1 = true;
        polling_number++;
      }
    }  // close switch statement
    
  // READING HALL SENSOR DATA
  
  switch(readPosition_2)
  {
    case 0:
    {
    if (data_in == poll_2)
    {
     readPosition_2++;
    }
     break;
    } 
    
    case 1: 
    {  
     data_rpm_1 = HexCharToValue(data_in)<<4;
     readPosition_2++;
     break;
    }  
    case 2: 
    { 
     data_rpm_1 = HexCharToValue(data_in)+data_rpm_1;
     readPosition_2++;
     break;
    } 
    case 3: 
    {  
     data_rpm_2 = HexCharToValue(data_in)<<4;
     readPosition_2++;
     break;
    }  
    case 4: 
    {  
     data_rpm_2 = HexCharToValue(data_in)+data_rpm_2;
     readPosition_2 = 0; 
     newReading_2 = true;
     polling_number++;
    } 
   }  // end of SWITCH
  } // end of XBee.available()
  
  if (newReading_1 == true) // newReading is a boolean type
  {
    sprintf(dataStream_1, data_format, poll_1, data_temp_1, data_temp_2); // reconvert converted serial input to verify the deconversion process worked
    //Serial.print(dataStream); // diagnostics
    
    // This whole section of declarations should properly be at the top of either loop() as local variables, or at the top of the sketch as globals. If globals, tempFactor should be a constant
    double tempFactor = 0.02; // double and float are the same datatype. Only use one of the two to avoid confusion unless there is a really good reason not to.
    unsigned int tempData; // floating point math is executionally expensive on AVR processors. All we really need here is a 16-bit holding bin, polarity is not important.
    float kelvin; 
    float celsius; 
    
    tempData = ((data_temp_1 & 0x007F) << 8) + data_temp_2; 
    kelvin = (tempData * tempFactor); 
    
    celsius = kelvin - 273.15; 
    
    Serial.print(F(" Celsius: ")); // Save SRAM by using F() macro for constant text messages
    Serial.println(celsius);
    newReading_1 = false;
  }
  
  if (newReading_2 == true) // newReading is a boolean type
  {
    sprintf(dataStream_2, data_format, poll_2, data_rpm_1, data_rpm_2); // reconvert converted serial input to verify the deconversion process worked
    
    unsigned int rpm;  
    rpm = ((data_rpm_1 & 0x007F) << 8) + data_rpm_2; 
    
    Serial.print(F("RPM: ")); // Save SRAM by using F() macro for constant text messages
    Serial.println(rpm, DEC);
    newReading_2 = false;
  }
}

byte HexCharToValue (char x)
{
  byte value;
  char upper; // Should match x, so make this a char. (will save 1 byte of stack space in the process).
  byte first_result;

  if (isxdigit(x))
  {
    upper = toupper(x);
    first_result = upper - 0x30;
    if (first_result < 0x0A)
    {
      value = first_result;
    }
    else
    { 
      value = first_result - 0x10;
      value = value + 9; 
    }
  }
  else
  {
    value = 0;
  }

  return value;
}

BIT.jpg

Hi Paul,

Could you tell me what seems wrong with my code? I tried yet another code today and it didn’t work either, I removed the delay() commands too. The polling mechanism seems pretty straight forward. I increment polling_number() every time a data is received and displayed.

Subsequently, the the polling number increments and changes from even to odd, or odd to even. The blocks inside the loop() of the receiver, are divided into :

1. Polling block
2. Condition for reading temperature data
3. Condition for reading hall sensor data
4. Displaying temperature data
5. Displaying hall sensor data.

Are the codes in the transmitters right at least?

Code of Temperature sensor Arduino (TX1)

#include <SoftwareSerial.h>
#include <i2cmaster.h>

SoftwareSerial XBeeTX(2, 3); // RX, TX

const byte dev = 0x5A<<1; // This is a constant, so use the const keyword to allow the compiler to decide how best to optimize
const char data_start = '*'; // This is a constant, so use the const keyword to allow the compiler to decide how best to optimize
const char data_format[] = "%c%02X%02X"; // %c is a single character, %02X is a 2 character ASCII encoded hex number representing 1 byte
char dataStream[6]; // data_format will result in 5 characters plus 1 NULL character automatically applied by the sprintf() function so we need a 6 element array as a buffer
byte data_low;
byte data_high;
byte pec;

void setup()
{  
  Serial.begin(9600);
  XBeeTX.begin(9600);
  
  i2c_init(); //Initialise the i2c bus
  PORTC = (1 << PORTC4) | (1 << PORTC5);//enable pullups
}

void loop()
{
  if (XBeeTX.available() > 0 && XBeeTX.read() == data_start)
  {
    i2c_start_wait(dev+I2C_WRITE);
    i2c_write(0x07);

    // READ
    i2c_rep_start(dev+I2C_READ);
    data_low = i2c_readAck(); //Read 1 byte and then send ack
    data_high = i2c_readAck(); //Read 1 byte and then send ack
    pec = i2c_readNak();
    i2c_stop();
   
    sprintf(dataStream, data_format, data_start, data_high, data_low); // 1(data_start) + 2(data_high) + 2(data_low) + 1(NULL) = 6 bytes
    XBeeTX.print(dataStream);
    Serial.print(dataStream); // for diagnostics
  }
}

Code of Hall sensor Arduino (TX 2)

#include <SoftwareSerial.h>

SoftwareSerial XBeeTX(2, 3);  // RX, TX

volatile byte revolutions;                                                   
unsigned int rpm;
unsigned long timeold;
unsigned long k;
const char data_start = '@';
const char data_format[] = "%c%04X";
char dataStream[6];

void setup()
{
  Serial.begin(9600);
  XBeeTX.begin(9600);
  attachInterrupt(0, rpm_fun, FALLING);
  revolutions = 0;
  rpm = 0;
  timeold = 0;
  k = 0;
}

void loop()
{ 
 if (XBeeTX.available() > 0 && XBeeTX.read() == data_start)
 {
    if (revolutions >= 10)                         //** Update RPM every 10 counts**
   {
   
      k = millis() - timeold;
      rpm = 60000/k*revolutions;          // **calculate the revolutions per minute
      timeold = millis();
      revolutions = 0;
    
      sprintf(dataStream, data_format, data_start, rpm);
      XBeeTX.print(dataStream);
      //Serial.println(dataStream);        // diagnostics
      //Serial.println(F("Sent over XBee"));
   }
 }

}
void rpm_fun()
{
  revolutions++;
}

Receiver Code (RX)

#include <SoftwareSerial.h>

SoftwareSerial XBeeRX(2, 3); // RX, TX

const char poll_1 = '*'; 
const char poll_2 = '@';

const char data_format[] = "%c%02X%02X";
char dataStream[6];

boolean newReading_1 = false; 
boolean newReading_2 = false;
byte readPosition_1;
byte readPosition_2;
byte polling_number = 0;

byte data_temp_1;
byte data_temp_2;

byte data_rpm_1;
byte data_rpm_2;

char data_in;

void setup()
{
  Serial.begin(9600);
  XBeeRX.begin(9600);
}

void loop()
{
  // ############POLLING BLOCK, #1/5 of MAIN################
  if (polling_number%2 == 0)
  {
  XBeeRX.print(poll_1);
  }
  else if (polling_number%2 == 1)
  {
  XBeeRX.print(poll_2);
  }
  
  // ##############BLOCK #2/5 OF MAIN######################
  if (XBeeRX.available() > 0 && polling_number%2 == 0)
  {        
    data_in = XBeeRX.read();
 
    switch (readPosition_1)
    { 
     case 0:
      {
      if (data_in == poll_1)
      readPosition_1++;
      break;
      } 
    case 1: 
      {  
        data_temp_1 = HexCharToValue(data_in)<<4;
        readPosition_1++;
        break;
      } 
    case 2:
      { 
        data_temp_1 = HexCharToValue(data_in)+data_temp_1;
        readPosition_1++;
        break;
      } 
    case 3:
      { 
        data_temp_2 = HexCharToValue(data_in)<<4;
        readPosition_1++;
        break;
      } 
    case 4:
      { 
        data_temp_2 = HexCharToValue(data_in)+data_temp_2;
        readPosition_1 = 0;  
        newReading_1 = true;
      }
    }  // close switch statement
  }
 
 // #####################BLOCK #3/5 OF MAIN####################
 if (XBeeRX.available() > 0 && polling_number%2 == 1)
 { 
  data_in = XBeeRX.read();
  
  switch(readPosition_2)
  {
    case 0:
    {
    if (data_in == poll_2)
     readPosition_2++;
     break;
    } 
    
    case 1: 
    {  
     data_rpm_1 = HexCharToValue(data_in)<<4;
     readPosition_2++;
     break;
    }  
    case 2: 
    { 
     data_rpm_1 = HexCharToValue(data_in)+data_rpm_1;
     readPosition_2++;
     break;
    } 
    case 3: 
    {  
     data_rpm_2 = HexCharToValue(data_in)<<4;
     readPosition_2++;
     break;
    }  
    case 4: 
    {  
     data_rpm_2 = HexCharToValue(data_in)+data_rpm_2;
     readPosition_2 = 0; 
     newReading_2 = true;
    } 
   }  
  } 
  
  // #################BLOCK #4/5 OF MAIN#################
  if (newReading_1 == true) // newReading is a boolean type
  {
    sprintf(dataStream, data_format, poll_1, data_temp_1, data_temp_2); 
    //Serial.print(dataStream); // diagnostics
    
    double tempFactor = 0.02; 
    unsigned int tempData; 
    float kelvin; 
    float celsius; 
    
    tempData = ((data_temp_1 & 0x007F) << 8) + data_temp_2; 
    kelvin = (tempData * tempFactor); 
    
    celsius = kelvin - 273.15; 
    
    Serial.print(F(" Celsius: ")); 
    Serial.println(celsius);
    polling_number++;
    newReading_1 = false;
  }
  
  //###### BLOCK #5/5 OF MAIN################
  if (newReading_2 == true) // newReading is a boolean type
  {
    sprintf(dataStream, data_format, poll_2, data_rpm_1, data_rpm_2); 
    
    unsigned int rpm;  
    rpm = ((data_rpm_1 & 0x007F) << 8) + data_rpm_2; 
    
    Serial.print(F("RPM: ")); 
    Serial.println(rpm, DEC);
    polling_number++;
    newReading_2 = false;
  }
  
}   // END OF MAIN

byte HexCharToValue (char x)
{
  byte value;
  char upper; // Should match x, so make this a char. (will save 1 byte of stack space in the process).
  byte first_result;

  if (isxdigit(x))
  {
    upper = toupper(x);
    first_result = upper - 0x30;
    if (first_result < 0x0A)
    {
      value = first_result;
    }
    else
    { 
      value = first_result - 0x10;
      value = value + 9; 
    }
  }
  else
  {
    value = 0;
  }

  return value;
}

Could you tell me what seems wrong with my code?

Every time you read a character from the XBee, you should print the value and the value of polling_number (which is NOT a function).

You should not need to call XBee.available() but once. If there is data to read, read and use the data depending on the value of polling_number.

What you are sending is still too complex. The XBees should be transmitting ASCII data. Far easier to parse.

What you are sending is still too complex. The XBees should be transmitting ASCII data.

I am sending ASCII data, that is why I have the HexCharToValue function.

Every time you read a character from the XBee, you should print the value and the value of polling_number (which is NOT a function).

polling_number is a variable in my code, not a function, yes.

But I don't understand, are you saying I should print the value of the polling_number for diagnostic / verification purpose? I really just need the data to be displayed.

Is there a problem with all the codes or just the code of RX?

I have tried many ways, I can't seem to get the data displayed right. :~ How would you modify these codes?

I am sending ASCII data, that is why I have the HexCharToValue function.

Why would you NOT just send the value of the integer/float as a string in decimal format? So much easier to deal with.

are you saying I should print the value of the polling_number for diagnostic / verification purpose?

Yes.

How would you modify these codes?

    data_low = i2c_readAck(); //Read 1 byte and then send ack
    data_high = i2c_readAck(); //Read 1 byte and then send ack

    int value = data_high << 8 + data_low;

    sprintf(dataStream, data_format, data_start, value);
    XBeeTX.print(dataStream);

after changing this:

const char data_format[] = "%c%05d";

and this:

char dataStream[8];

Why would you NOT just send the value of the integer/float as a string in decimal format? So much easier to deal with.

User Sembazuru helped me earlier. He mentioned the XBees transmitted the ASCII value of the variable. Doesn't XBee read it one character value at a time? Because using that concept in the temperature sensor code (point to point, just one TX and one RX), worked fine.