[Solved] Printing to LCD from incoming XBee Data

Hi Everyone,

I'm new to Arduino and programing in general. I've been trying to complete a project for quite some time, and just can't seem to get it. Any help or suggestions would be much appreciated. I'm trying to create a weather station that transmits data via XBee and displays the data on the Rx's LCD screen. Below is the hardware I'm using:

The Tx contains:

  • Arduino Fio
  • XBee Series 1
  • DHT - for temperature and humidity
  • BMP180 - for barometric pressure, temperature and altitude

The Rx:

  • Arduino Uno
  • XBee Shield
  • XBee Series 1
  • LCD screen (16X2)

I believe the Tx is sending the data in the form of an array. It is currently printing in the following format:

<18,64,18,66,18,66,83.20,14,101900.00,764.25,30.09>

which correlates to
<TempC (bmp), TempF (bmp), TempC (dht), TempF (dht), HeatIndexC (dht), HeatIndexF (dht), Humidity, Dew Point C, Pressure Pa, Preasure mmHg, Pressure inHg>

I have read that it's important to send data in the form of an array so the receiver can collect the data, and when Serial is not busy, print it to the LCD. To concatenate the data array I used a combination of the "sprintf" and "dtostrf" functions.

TX CODE POSTED HERE:

#include "DHT.h"
#define DHTPIN 7     // what digital pin we're connected to
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321

// Connect pin 1 (on the left) of the sensor to +5V
// NOTE: If using a board with 3.3V logic like an Arduino Due connect pin 1
// to 3.3V instead of 5V!
// Connect pin 2 of the sensor to whatever your DHTPIN is
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor

// Initialize DHT sensor.
// Note that older versions of this library took an optional third parameter to
// tweak the timings for faster processors.  This parameter is no longer needed
// as the current DHT reading algorithm adjusts itself to work on faster procs.
DHT dht(DHTPIN, DHTTYPE);

#include <Wire.h>
#include <Adafruit_BMP085.h>

/***************************************************
BMP085 Barometric Pressure & Temp Sensor
  ----> https://www.adafruit.com/products/391

  These displays use I2C to communicate, 2 pins are required to
  interface
 ****************************************************/

// Connect VCC of the BMP085 sensor to 3.3V (NOT 5.0V!)
// Connect GND to Ground
// Connect SCL to i2c clock - on '168/'328 Arduino Uno/Duemilanove/etc thats Analog 5
// Connect SDA to i2c data - on '168/'328 Arduino Uno/Duemilanove/etc thats Analog 4
// EOC is not used, it signifies an end of conversion
// XCLR is a reset pin, also not used here

Adafruit_BMP085 bmp;
int tempC;  // Variable for holding temp in C | originally float, changed to int
int tempF;  // Variable for holding temp in F | originally float, changed to int
float pressure; //Variable for holding pressure reading in Pa | originally float, changed to int
float pressuremmHg; // Variable for holding pressure reading in mmHg | originally float, changed to int
float pressureinHg; // Variable for holding pressure reading in inHg| originally float, changed to int
int dewpoint; // Variable for holding pressure reading in *C| originally float, changed to int

// We'll use SoftwareSerial to communicate with the XBee:
#include <SoftwareSerial.h>
// XBee's DOUT (TX) is connected to pin 2 (Arduino's Software RX)
// XBee's DIN (RX) is connected to pin 3 (Arduino's Software TX)
SoftwareSerial XBee(2, 3); // RX, TX

  char dataPacket [64]; //an array with 12 elements, but 64 total characters
  int i; //used as an index into the array
  char P1[15]; // these are values created through the "dtostrf" function because the "sprintf" doesn't allow floats
  char P2[15]; // these are values created through the "dtostrf" function because the "sprintf" doesn't allow floats
  char P3[15]; // these are values created through the "dtostrf" function because the "sprintf" doesn't allow floats
  char H1[15]; // these are values created through the "dtostrf" function because the "sprintf" doesn't allow floats

void setup() {
  XBee.begin(9600);
  Serial.begin(9600);
  Serial.println("DHTxx test!");
  dht.begin();
  bmp.begin();
    }
    
void loop() {
//DHT Values Below:
  // Reading temperature or humidity takes about 250 milliseconds! | originally float, changed to int
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity(); 
  // Read temperature as Celsius (the default) | originally float, changed to int
  int t = dht.readTemperature();
  // Read temperature as Fahrenheit (isFahrenheit = true) | originally float, changed to int
  int f = dht.readTemperature(true);
  // Compute heat index in Fahrenheit (the default) | originally float, changed to int
  int hif = dht.computeHeatIndex(f, h);
  // Compute heat index in Celsius (isFahreheit = false)| originally float, changed to int
  int hic = dht.computeHeatIndex(t, h, false);
  int DP = (t - ((100 - h) / 5)); // Calculates the Dew Point in *C if Humidity >50% (DHT) dd.dd

//DHT Values Below:
  tempC = bmp.readTemperature(); //  Read Temperature (bmp)
  tempF = tempC * 1.8 + 32.; // Convert degrees C to F (bmp)
  pressure = bmp.readPressure(); //Read Pressure (bmp)
  pressuremmHg = (pressure * .0075); //(bmp) 
  pressureinHg = (pressure / 3386.39); //(bmp)

    dtostrf(pressure,9,2,P1); // due to issues showing pressure in the "sprintf" function because it's a float value. 9 digits, 0 significant digits
    dtostrf(pressuremmHg,6,2,P2); // due to issues showing pressure in the "sprintf" function because it's a float value.
    dtostrf(pressureinHg,5,2,P3); // due to issues showing pressure in the "sprintf" function because it's a float value.
    dtostrf(h,5,2,H1); // due to issues showing pressure in the "sprintf" function because it's a float value.

{
// sprintf(dataPacket, "X%d" ,gx) - this is used to compile multiple datastrings together
// d=integer, f=float 
sprintf(dataPacket,"<%d,%d,%d,%d,%d,%d,%s,%d,%s,%s,%s>",tempC,tempF,t,f,hic,hif,H1,DP,P1,P2,P3);
Serial.println(dataPacket);
XBee.print(dataPacket);
delay (2000);
}
}

I'm receiving the data in the receiver but I can't display the values to the LCD screen. I would like to be able to display the following: "TempC: 18" in the LCD and then have it update as new data comes from the Tx.

Questions:

  • I believe "TestData" is declared as an array but I haven't been able to extract values using the "strtok" function. Is this the wrong function to use? If so, what is a better function?
  • Once the values are extracted from the array, how would you pause Serial and print the values to the lcd? Any suggestions?

RX CODE POSTED HERE:

// We'll use SoftwareSerial to communicate with the XBee:
#include <SoftwareSerial.h>
// XBee's DOUT (TX) is connected to pin 2 (Arduino's Software RX)
// XBee's DIN (RX) is connected to pin 3 (Arduino's Software TX)
SoftwareSerial XBee(2, 3); // RX, TX

#include <Wire.h>
#include <LiquidCrystal.h>
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 7, d5 = 6, d6 = 5, d7 = 4;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

#include <stdio.h>
#include <string.h>
char TestData [12];

void setup()
{
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  lcd.clear ();
  // Set up both ports at 9600 baud. This value is most important
  // for the XBee. Make sure the baud rate matches the config
  // setting of your XBee.
  XBee.begin(9600);
  Serial.begin(9600);
}

void loop()
{
  if (XBee.available()) {
    char TestData = XBee.read(); // If data comes in from XBee, send it out to serial monitor
    Serial.print(TestData);
  }
}

Any help would be greatly appreciated!
Hope you all have a nice Turkey Day!

Thanks for replying. Correct, the previous code posted only prints to the Serial Monitor. I was curious how others might attempt at solving my problem of having the data print to the SerialMoitor as well as the LCD.

For General Reference I used this forum posting: sending all sensor read in one time via xbee (my home monitor project) - Networking, Protocols, and Devices - Arduino Forum
For Parsing Reference I used this forum posting: Parsing serial data sent to an arduino - Troubleshooting - Arduino Forum

I attempt to use the "strtok()" and print TempC and TempF values to only the LCD with the following code.

Receiver Code:

/*****************************************************************
  XBee_Serial_Passthrough.ino
  Set up a software serial port to pass data between an XBee Shield
  and the serial monitor.
  Hardware Hookup:
  The XBee Shield makes all of the connections you'll need
  between Arduino and XBee. If you have the shield make
  sure the SWITCH IS IN THE "DLINE" POSITION. That will connect
  the XBee's DOUT and DIN pins to Arduino pins 2 and 3.

*****************************************************************/
// We'll use SoftwareSerial to communicate with the XBee:
#include <SoftwareSerial.h>
// XBee's DOUT (TX) is connected to pin 2 (Arduino's Software RX)
// XBee's DIN (RX) is connected to pin 3 (Arduino's Software TX)
SoftwareSerial XBee(2, 3); // RX, TX

#include <Wire.h>
#include <LiquidCrystal.h>
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 7, d5 = 6, d6 = 5, d7 = 4;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

#include <string.h>
#include <stdio.h>

#define SOP '<'
#define EOP '>'

bool started = false;
bool ended = false;

char inData[12];
// string that will be split
char TestData[12]; // I would like this array to be the incomeing data from the Xbee
byte index = 0;

void setup()
{
  char *str; // declaring string
  
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  lcd.clear ();
  // Set up both ports at 9600 baud. This value is most important
  // for the XBee. Make sure the baud rate matches the config
  // setting of your XBee.
  XBee.begin(9600);
  Serial.begin(9600);
}

void loop()
{
  // Read all XBee data available, as fast as possible


  while (XBee.available())
  {
    char TestData = XBee.read();
    if(TestData == SOP)  // if TestData is SOP or "<"
    {                   // I don't fully undersatnd what this section does.
      index = 0;      
      inData[index] = '\0';
      started = true;
      ended = false;
    }
    else if (TestData == EOP)
    {
      ended = true;
      break;
    }
    else
    {
      if(index < 12)
      {
        inData[index] = TestData;
        index++;
        inData[index] = '\0';
      }
    }
  }
  // We are here either becuase all pending XBee 
  // data has been read OR because an end of
  // packet parker arrived. Which is it?
  if (started && ended)
  {
    // The end of the packet marker arrived. Process the packet.
    // Use strtok() and atoi() to get the tokens, separated by commas, 
    // and convert them to ints, storing the values in an array.
    
    char *p = inData;  // assign the string to *p
    char *str;        //intialize str
    int counter = 0;   // initialise the counter
    
    while (str = strtok_r(p, ",", &p)) // delimiter is the comma
    {
      TestData[counter] = *str; //use the counter as an index to add each value to the array
      counter++; //increment the counter

      
      p = NULL; //clear the serial data storage outside of the loop after all the data has been retrieved
    }
    
      //using the liquid crystal library print out info
      //kind of coding from memory so imagine that the cursor has been setup and everything
      lcd.print("TempC (bmp): "); lcd.println(TestData[0]); //print out the data stored in the value storage array index '0'
      
      //set cursor to next line using appropiate commands again
      lcd.print("TempF (bmp): "); lcd.println(TestData[1]); //ditto
      // and so on and so on
      //only thing i can figure now is to null the array by looping through and clearing it using a loop that repeats the number of times of "counter"
      
      // Reset for te next packet
      started = false;
      ended = false;
      index = 0;
      inData[index] = '\0';
      }
}
    //Data comes through to the XBee in arduino in the following format. 
    // It isn't displayed this way currently because using XBee, Serial, and LCD
    // Seems to garble the data.
    //<18,64,19,66,19,66,82.70,15,101335.00,760.01,29.92>

The code uploads fine, but the LCD doesn't display the data the way that I thought it would. It includes weird characters and doesn't always start a new line with TempC or TempF. See attached image.

Also, I was hoping to be able to see the data in the Serial Monitor as well as the LCD. When I add the following "Serial.print (Xbee.read());" code in the loop section

char TestData = XBee.read();
    Serial.print(XBee.read()); 
    if(TestData == SOP)  // if TestData is SOP or "<"

with this new added part, there is no output to the LCD and the Serial monitor displays the following:

4-144-1-149-154-1-153-148-156-1-149-149-148-1-150-154-148-1-162-1-1-1-1-1-154-157-155-157-155-153-1-144-144-149-153-1-144-150-157-148-1-162-1-1-1-1-1-1-144-1-154-149-154-157-148-1-156-148-154-1-148-154-152-1-148-150-110-1-1-1-154-1-144-144-144-1-157-148-149-149-1-154-148-155-146-144-1-148-113-1-1-1-1-154-157-1-144-144-144-1-148-149-149-1-154-148-155-1-152-151-1-150........

All wonky.

Any suggestions would be greatly appreciated.

Thanks again for the help

LcdDisplay1.JPG

char dataPacket [64]; 
XBee.print(dataPacket);

You send 64 chars, so your receive buffer should also be 64 chars.

//char TestData[12]; // I would like this array to be the incomeing data from the Xbee
char TestData[64];

You do not need to do all the messing around with dtostrf and sprintf and the concatenation into one string.

Xbee.print() using software serial is going to send chars. You might as well send

Xbee.print('<');
Xbee.print(tempC);
Xbee.print(',');
Xbee.print(tempF);
Xbee.print(',');
Xbee.print(t);
Xbee.print(',');
Xbee.print(f);
Xbee.print(',');
Xbee.print(hic);
Xbee.print(',');
Xbee.print(hif);
Xbee.print(',');
Xbee.print(h,2);//print float with 2 after dp
Xbee.print(',');
Xbee.print(DP);
Xbee.print(',');
Xbee.print(pressure,2);
Xbee.print(',');
Xbee.print(pressuremmHg,2);
Xbee.print(',');
Xbee.print(pressureinHg,2);
Xbee.print('>');

Thank you so much for your comments. The Serial Input Basics is a great resource and the clarifications regarding array format were both very helpful. I have been wondering that for a long time and it is now clear! Thanks! The weather station is closer, but still not ideal.

The LCD is displaying labels and values but there are still issues.

  1. There are weird characters being displayed. Ex: TempC, TempF, HIC, H (see Image 2a attached).
  2. Values are not being displayed at all. Ex: TempC (see Image 2a attached).
  3. Variables seem to be displaying incorrect values. Ex: P(Pa) displayed the value 90 one cycle and then -30336 the next cycle through. P(in) displays 100742 which should be displayed for P(Pa). (see images 2d & 2e attached).

When checking Tx code Serial monitor it displays the following data as expected

<20,68,20,68,20,68,89.80,17,100768.00,755.76,29.76>

but this isn't how it is being read on the LCD display. Thoughts?

UPDATED Rx Code (modeled after Example 5 in Serial Input Basics)

#include <SoftwareSerial.h>
SoftwareSerial XBee(2, 3); // RX, TX

#include <Wire.h>
#include <LiquidCrystal.h>
const int rs = 12, en = 11, d4 = 7, d5 = 6, d6 = 5, d7 = 4;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

#include <string.h>
#include <stdio.h>

const byte numChars = 64;  //This means 64 characters are expected.
char receivedChars[numChars]; // array that is received
char tempChars [numChars]; // temporary array for use when parsing

//variables to hold the parsed data
char messageFromPC[numChars]={0};
int TempCbmp = 0;
int TempFbmp = 0;
int TempCdht = 0;
int TempFdht = 0;
int HICdht = 0;
int HIFdht = 0;
float H1dht = 00.00;
float DPdht = 00.00;
int P1bmp = 000000;
float P2bmp = 000.00;
float P3bmp = 00.00;

boolean newData = false;

void setup()
{
  lcd.begin(16, 2);
  lcd.clear ();
  XBee.begin(9600);
  Serial.begin(9600);
}

void loop(){
 
  recvWithEndMarker();
  if (newData == true) {
    strcpy(tempChars, receivedChars);
      // this temporary copy is necessary to protect the original data
      //   because strtok() used in parseData() replaces the commas with �
      parseData();
      showParsedData();
      newData = false;
  }
}

//========

void recvWithEndMarker() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;

  while (XBee.available() > 0 && newData == false) { // If Xbee is receiving data AND newData is false, THEN "rc" is the XBee data
    rc = XBee.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {  
        receivedChars[ndx] = rc;  //if rc is NOT the endMarker, then index "rc" to the "receivedChars" array.
        ndx++;                    // go to the next character and index it as well
        if (ndx >= numChars) {    // what does this mean? why would ndx ever be greater than 64?
          ndx = numChars - 1;     // what does this do?
        }
      }
      else {
        receivedChars[ndx] = '�';  //terminate the string when the endMarker is received
        recvInProgress = false;     // and mark as NOT recvInProgress
        ndx = 0;                    // move index back to 0 position?
        newData = true;             // why is new data here marked as true? shouldn't it be above the "ndx=0"?
      }
    }
    else if (rc == startMarker) {
      recvInProgress = true;
      if (newData == true) {        // I don't understand what this section does? If recvInProgress = True, then we shouldn't have new data at this time, correct?
        newData = false;
      }   
    }
  }
}


//=======

void parseData() { // split the data into it's parts

  char * strtokIndx; // this is used by strtok() as an index

  strtokIndx = strtok(tempChars,","); // get the first part - the string
  TempCbmp, atoi(strtokIndx); // copy it to TempCbmp

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  TempFbmp = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  TempCdht = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  TempFdht = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  HICdht = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  HIFdht = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ",");
  H1dht = atof(strtokIndx);     // convert this part to a float

  strtokIndx = strtok(NULL, ",");
  DPdht = atof(strtokIndx);     // convert this part to a float

  strtokIndx = strtok(NULL, ",");
  P1bmp = atoi(strtokIndx);     // convert this part to a float

  strtokIndx = strtok(NULL, ",");
  P2bmp = atof(strtokIndx);     // convert this part to a float

  strtokIndx = strtok(NULL, ",");
  P3bmp = atof(strtokIndx);     // convert this part to a float
}

void showParsedData() {
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("TempC(bmp): ");
  lcd.println(TempCbmp);

  lcd.setCursor(0,1);
  lcd.print("TempF(bmp): ");
  lcd.println(TempFbmp);  // first round of data display complete

  delay(4000);

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("HIC: ");
  lcd.println(HICdht);

  lcd.setCursor(0,1);
  lcd.print("HIF ");
  lcd.print(HIFdht);  // second round of data display complete

  delay(4000);

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("H: ");
  lcd.println(H1dht);

  lcd.setCursor(0,1);
  lcd.print("DP ");
  lcd.print(DPdht);  // third round of data display complete

  delay(4000);

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("P(Pa): ");
  lcd.print(P1bmp);

  lcd.setCursor(0,1);
  lcd.print("P(mm): ");
  lcd.print(P2bmp);

  delay(4000);

  lcd.setCursor(0,1);
  lcd.print("P(in): ");
  lcd.print(P3bmp);

  delay(4000);
  }
 
// Data comes through to the XBee in arduino in the following format.
//18,64,19,66,19,66,82.70,15,101335.00,760.01,29.92

In Example 5 on the Serial Input Basics page, I don't fully understand the following code. Is someone willing to answer my questions/comments?

void recvWithEndMarker() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;

  while (XBee.available() > 0 && newData == false) { // If Xbee is receiving data AND newData is false, THEN "rc" is the XBee data
    rc = XBee.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {  
        receivedChars[ndx] = rc;  //if rc is NOT the endMarker, then index "rc" to the "receivedChars" array.
        ndx++;                    // go to the next character and index it as well
        if (ndx >= numChars) {    // what does this mean? why would ndx ever be greater than 64?
          ndx = numChars - 1;     // what does this do?
        }
      }
      else {
        receivedChars[ndx] = '�';  //terminate the string when the endMarker is received
        recvInProgress = false;     // and mark as NOT recvInProgress
        ndx = 0;                    // move index back to 0 position?
        newData = true;             // why is new data here marked as true? shouldn't it be above the "ndx=0"?
      }
    }
    else if (rc == startMarker) {
      recvInProgress = true;
      if (newData == true) {        // I don't understand what this section does? If recvInProgress = True, then we shouldn't have new data at this time, correct?
        newData = false;
      }   
    }
  }
}

Thanks again for all the help!!

Photos are attached here.

  1. There are weird characters being displayed. Ex: TempC, TempF, HIC, H (see Image 2a attached)
lcd.println

You have several statements like this. The lcd library does not use the new line instruction. It will produce garbage on the screen. Use cursor placement for new line location control.

I think you also have a typo here:

//TempCbmp, atoi(strtokIndx); // copy it to TempCbmp
TempCbmp = atoi(strtokIndx);

Thank you. All the wierd characters now seem to be gone but I'm correct values are still not displaying on the LCD screen consistently. It shifts from values like THIS:

Temp(dht)C: 17
H: 95.40
P(Pa): -29574
P(mm): 761.23
P(in): 29.971

TO VALUES LIKE THIS:
Temp(dht)C: 1
H: 17.00
P(Pa): 95
P(mm): 16.00
P(in): 101489

I don't understand why the values are changing so greatly over 24 seconds.

Any thoughts or suggestions?
Thanks

LCDdisplay2.zip (145 KB)

Post your latest code.

Latest Rx code is below:

//used Example 5 from: http://forum.arduino.cc/index.php?topic=396450

#include <SoftwareSerial.h>
SoftwareSerial XBee(2, 3); // RX, TX

#include <Wire.h>
#include <LiquidCrystal.h>
const int rs = 12, en = 11, d4 = 7, d5 = 6, d6 = 5, d7 = 4;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

#include <string.h>
#include <stdio.h>

const byte numChars = 64;  //This means 64 characters are expected. 
char receivedChars[numChars]; // array that is received
char tempChars [numChars]; // temporary array for use when parsing

//variables to hold the parsed data
int TempCbmp = 0;
int TempFbmp = 0;
int TempCdht = 0;
int TempFdht = 0;
int HICdht = 0;
int HIFdht = 0;
float H1dht = 00.00;
float DPdht = 00.00;
int P1bmp = 000000;
float P2bmp = 000.00;
float P3bmp = 00.00;

boolean newData = false;

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

void setup()
{
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  lcd.clear ();
  // Set up both ports at 9600 baud. This value is most important
  // for the XBee. Make sure the baud rate matches the config
  // setting of your XBee.
  XBee.begin(9600);
  Serial.begin(9600);
}

void loop(){
 
  recvWithEndMarker();
  if (newData == true) {
    strcpy(tempChars, receivedChars);
      // this temporary copy is necessary to protect the original data
      //   because strtok() used in parseData() replaces the commas with \0
      parseData();
      showParsedData();
      newData = false;
  }
}

//========

void recvWithEndMarker() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;

  while (XBee.available() > 0 && newData == false) { // If Xbee is receiving data AND newData is false, THEN "rc" is the XBee data
    rc = XBee.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {  
        receivedChars[ndx] = rc;  //if rc is NOT the endMarker, then index "rc" to the "receivedChars" array.
        ndx++;                    // go to the next character and index it as well
        if (ndx >= numChars) {    // what does this mean? why would ndx ever be greater than 64?
          ndx = numChars - 1;     // what does this do?
        }
      }
      else {
        receivedChars[ndx] = '\0';  //terminate the string when the endMarker is received
        recvInProgress = false;     // and mark as NOT recvInProgress
        ndx = 0;                    // move index back to 0 position?
        newData = true;             // why is new data here marked as true? shouldn't it be above the "ndx=0"?
      }
    }
    else if (rc == startMarker) {
      recvInProgress = true;
      if (newData == true) {        // I don't understand what this section does? If recvInProgress = True, then we shouldn't have new data at this time, correct?
        newData = false;
      }   
    }
  }
}


//=======

void parseData() { // split the data into it's parts

  char * strtokIndx; // this is used by strtok() as an index

  strtokIndx = strtok(tempChars,","); // get the first part - the string
  TempCbmp = atoi(strtokIndx); // copy it to TempCbmp

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  TempFbmp = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  TempCdht = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  TempFdht = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  HICdht = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  HIFdht = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ",");
  H1dht = atof(strtokIndx);     // convert this part to a float

  strtokIndx = strtok(NULL, ",");
  DPdht = atof(strtokIndx);     // convert this part to a float

  strtokIndx = strtok(NULL, ",");
  P1bmp = atoi(strtokIndx);     // convert this part to a float

  strtokIndx = strtok(NULL, ",");
  P2bmp = atof(strtokIndx);     // convert this part to a float

  strtokIndx = strtok(NULL, ",");
  P3bmp = atof(strtokIndx);     // convert this part to a float
}

  //======

void showParsedData() {
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("TempC(bmp): ");
  lcd.print(TempCbmp);

  lcd.setCursor(0,1);
  lcd.print("TempF(bmp): ");
  lcd.print(TempFbmp);  // Round 1 of data display complete

  delay(4000);

    lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("TempC(dht): ");
  lcd.print(TempCdht);

  lcd.setCursor(0,1);
  lcd.print("TempF(dht): ");
  lcd.print(TempFdht);  // Round 2 of data display complete

  delay(4000);

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("HIC: ");
  lcd.print(HICdht);

  lcd.setCursor(0,1);
  lcd.print("HIF: ");
  lcd.print(HIFdht);  // Round 3 of data display complete

  delay(4000);

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("H: ");
  lcd.print(H1dht);

  lcd.setCursor(0,1);
  lcd.print("DP: ");
  lcd.print(DPdht);  // Round 4 of data display complete

  delay(4000);

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("P(Pa): ");
  lcd.print(P1bmp);

  lcd.setCursor(0,1);
  lcd.print("P(mm): ");
  lcd.print(P2bmp);

  delay(4000);    // Round 5 of data display complete

  lcd.setCursor(0,1);
  lcd.print("P(in): ");
  lcd.print(P3bmp);

  delay(4000);    // Round 6 of data display complete
  }
  
// Data comes through to the XBee in arduino in the following format.
//18,64,19,66,19,66,82.70,15,101335.00,760.01,29.92

Thanks again for your help and time.

Not sure if this fixes things, but you send a packet every 2 seconds or so, but you wait for an astounding 24 seconds every time you receive one of those messages.

You might want to find a way to work around calling delay() in your code so that you can process serial data and get it out of the serial buffer as soon as possible. Nobody like serial buffer overflow - even if you're using start markers, end markers, and delimiters.

Good progress

Please post the transmit code.

I'm not familiar with the Xbees, but are there serial buffers independent of the Arduino serial buffer?
Are they each send/receive? Can one Xbee request data from the other?

Thanks Power_Broker and cattledog. I updated the Tx code (see below) as suggested to have a longer delay (30 seconds) but the errors described before still remain.

Cattledog, I'm not sure about the answers to your questions regarding Xbee Series 1 but I'll try:

Are there serial buffers independent of the Arduino serial buffer?

I have no idea and I didn't even think about this. I thought the Xbee (on the Tx) would just send the data to the Rx once it was read it from the Tx sensors.

Are they each send/receive?

I believe so. The Xbee Radio can send data, receive data, or serve both roles if requested but I haven't looked into coding this.

Can one Xbee request data from the other?

I believe so but haven't looked into this too much. Do you think this would be a better way to go about it...? Have the Rx request the data, and then have the Tx send it?

CURRNET Tx CODE:

#include "DHT.h"
#define DHTPIN 7     // what digital pin we're connected to

#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
DHT dht(DHTPIN, DHTTYPE);

#include <Wire.h>
#include <Adafruit_BMP085.h>

Adafruit_BMP085 bmp;
int tempC;  // Variable for holding temp in C | oringinally float, changed to int
int tempF;  // Variable for holding temp in F | oringinally float, changed to int
float pressure; //Variable for holding pressure reading in Pa | oringinally float, changed to int
float pressuremmHg; // Variable for holding pressure reading in mmHg | oringinally float, changed to int
float pressureinHg; // Variable for holding pressure reading in inHg| oringinally float, changed to int
int dewpoint; // Variable for holding pressure reading in *C| oringinally float, changed to int

// We'll use SoftwareSerial to communicate with the XBee:
#include <SoftwareSerial.h>
// XBee's DOUT (TX) is connected to pin 2 (Arduino's Software RX)
// XBee's DIN (RX) is connected to pin 3 (Arduino's Software TX)
SoftwareSerial XBee(2, 3); // RX, TX

  char dataPacket [64]; //an array with 12 integer elements, but 64 total characters
  int i; //used as an index into the array
  char P1[15]; // these are values created through the "dtostrf" function because the "sprintf" doesn't allow floats
  char P2[15]; // these are values created through the "dtostrf" function because the "sprintf" doesn't allow floats
  char P3[15]; // these are values created through the "dtostrf" function because the "sprintf" doesn't allow floats
  char H1[15]; // these are values created through the "dtostrf" function because the "sprintf" doesn't allow floats

void setup() {
  // Set up both ports at 9600 baud. This value is most important
  // for the XBee. Make sure the baud rate matches the config
  // setting of your XBee.
  XBee.begin(9600);
  Serial.begin(9600);
  Serial.println("DHTxx test!");
  dht.begin();
  bmp.begin();
    }
    
void loop() {
//DHT Values Below:
  // Reading temperature or humidity takes about 250 milliseconds! | oringinally float, changed to int
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity(); 
  // Read temperature as Celsius (the default) | oringinally float, changed to int
  int t = dht.readTemperature();
  // Read temperature as Fahrenheit (isFahrenheit = true) | oringinally float, changed to int
  int f = dht.readTemperature(true);
  // Compute heat index in Fahrenheit (the default) | oringinally float, changed to int
  int hif = dht.computeHeatIndex(f, h);
  // Compute heat index in Celsius (isFahreheit = false)| oringinally float, changed to int
  int hic = dht.computeHeatIndex(t, h, false);
  int DP = (t - ((100 - h) / 5)); // Calculates the Dew Point in *C if Humidity >50% (DHT) dd.dd

//DHT Values Below:
  tempC = bmp.readTemperature(); //  Read Temperature (bmp)
  tempF = tempC * 1.8 + 32.; // Convert degrees C to F (bmp)
  pressure = bmp.readPressure(); //Read Pressure (bmp)
  pressuremmHg = (pressure * .0075); //(bmp) 
  pressureinHg = (pressure / 3386.39); //(bmp)

    dtostrf(pressure,9,2,P1); // due to issues showing pressue in the "sprintf" function because it's a float value. 9 digits, 0 significant digits
    dtostrf(pressuremmHg,6,2,P2); // due to issues showing pressue in the "sprintf" function because it's a float value.
    dtostrf(pressureinHg,5,2,P3); // due to issues showing pressue in the "sprintf" function because it's a float value.
    dtostrf(h,5,2,H1); // due to issues showing pressue in the "sprintf" function because it's a float value.

{
// sprintf(dataPacket, "X%d" ,gx) - this is used to compile multiple datastrings togeter
// d=integer, f=float ,s=
sprintf(dataPacket,"<%d,%d,%d,%d,%d,%d,%s,%d,%s,%s,%s>",tempC,tempF,t,f,hic,hif,H1,DP,P1,P2,P3);
Serial.println(dataPacket);
XBee.print(dataPacket);
delay (30000);
  // all together the output to the serial monitor is going to be the following
  //tt(2),ff(2),II(2),ii(2),hh(2),dd(2),HH.HH(5),DD.DD(5),PPPPPP(6),mmm.mm(6),NN.NN(5) 39 characters
}
}

If you're curious there is this site here regarding Xbee Series 1 Radios:
https://learn.sparkfun.com/tutorials/exploring-xbees-and-xctu

Thanks again for your guidance and time!

With the correction to 30 second send timing, I'm not certain that the current issue is buffer overflow and some sort of data intermixing. To help refine the problem statement can you provide the complete sent/received data for a period of time where the data is correct, goes bad, and then recovers. A pattern of offsets or errors may show up.

To avoid buffer overflows and synchronize the send/receive, the best architecture is to ask for the data and then receive it, but I think there are some things you can do with your current arrangement.

Here's some modifications which may help with buffer overflows or scrambled data.

  1. Put the display on a non blocking millis() timer so incoming xbee read is not blocked.
  2. Set newData = false after parse to enable new receive
  3. clear the temporary buffer before new data is copied in.
  4. clear the receive buffer after data is copied out.
//used Example 5 from: http://forum.arduino.cc/index.php?topic=396450

#include <SoftwareSerial.h>
SoftwareSerial XBee(2, 3); // RX, TX

#include <Wire.h>
#include <LiquidCrystal.h>
const int rs = 12, en = 11, d4 = 7, d5 = 6, d6 = 5, d7 = 4;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

#include <string.h>
#include <stdio.h>

const byte numChars = 64;  //This means 64 characters are expected.
char receivedChars[numChars]; // array that is received
char tempChars [numChars]; // temporary array for use when parsing

//variables to hold the parsed data
int TempCbmp = 0;
int TempFbmp = 0;
int TempCdht = 0;
int TempFdht = 0;
int HICdht = 0;
int HIFdht = 0;
float H1dht = 00.00;
float DPdht = 00.00;
int P1bmp = 000000;
float P2bmp = 000.00;
float P3bmp = 00.00;

boolean newData = false;

//non blocking display control variables
unsigned long lastDisplaySwitch;
unsigned long interval = 4000; //4 seconds for each lcd screen
byte count = 0;// for display screen

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

void setup()
{
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  lcd.clear ();
  // Set up both ports at 9600 baud. This value is most important
  // for the XBee. Make sure the baud rate matches the config
  // setting of your XBee.
  XBee.begin(9600);
  Serial.begin(9600);
}

void loop() {

  recvWithEndMarker();

  if (newData == true) {
    //this temporary copy is necessary to protect the original data
    //because strtok() used in parseData() replaces the commas with \0
    memset(tempChars, '\0', 64); //clear tempChars
    strcpy(tempChars, receivedChars);
    memset(receivedChars, '\0', 64);//clear receivedChars
    parseData();
  }
  //showParsedData();
  showDisplay();
  //newData = false;
}

//========

void recvWithEndMarker() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;

  while (XBee.available() > 0 && newData == false) { // If Xbee is receiving data AND newData is false, THEN "rc" is the XBee data
    rc = XBee.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;  //if rc is NOT the endMarker, then index "rc" to the "receivedChars" array.
        ndx++;                    // go to the next character and index it as well
        if (ndx >= numChars) {    // what does this mean? why would ndx ever be greater than 64?
          ndx = numChars - 1;     // what does this do?
        }
      }
      else {
        receivedChars[ndx] = '\0';  //terminate the string when the endMarker is received
        recvInProgress = false;     // and mark as NOT recvInProgress
        ndx = 0;                    // move index back to 0 position?
        newData = true;             // why is new data here marked as true? shouldn't it be above the "ndx=0"?
      }
    }
    else if (rc == startMarker) {
      recvInProgress = true;
      if (newData == true) {        // I don't understand what this section does? If recvInProgress = True, then we shouldn't have new data at this time, correct?
        newData = false;
      }
    }
  }
}

//=======

void parseData() { // split the data into it's parts

  char * strtokIndx; // this is used by strtok() as an index

  strtokIndx = strtok(tempChars, ","); // get the first part - the string
  TempCbmp = atoi(strtokIndx); // copy it to TempCbmp

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  TempFbmp = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  TempCdht = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  TempFdht = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  HICdht = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  HIFdht = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ",");
  H1dht = atof(strtokIndx);     // convert this part to a float

  strtokIndx = strtok(NULL, ",");
  DPdht = atof(strtokIndx);     // convert this part to a float

  strtokIndx = strtok(NULL, ",");
  P1bmp = atoi(strtokIndx);     // convert this part to a float

  strtokIndx = strtok(NULL, ",");
  P2bmp = atof(strtokIndx);     // convert this part to a float

  strtokIndx = strtok(NULL, ",");
  P3bmp = atof(strtokIndx);     // convert this part to a float

  newData = false;
}

//======

void showDisplay()
{
  if (millis() - lastDisplaySwitch > interval)
  {
    lastDisplaySwitch += interval;
    count++;
    if (count == 7) //display screens 1-6
    {
      count = 1;
    }
    
    switch (count) {
      case 1:
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("TempC(bmp): ");
        lcd.print(TempCbmp);
        lcd.setCursor(0, 1);
        lcd.print("TempF(bmp): ");
        lcd.print(TempFbmp);  // Round 1 of data display complete
        break;
      case 2:
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("TempC(dht): ");
        lcd.print(TempCdht);
        lcd.setCursor(0, 1);
        lcd.print("TempF(dht): ");
        lcd.print(TempFdht);  // Round 2 of data display complete
        break;
      case 3:
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("HIC: ");
        lcd.print(HICdht);
        lcd.setCursor(0, 1);
        lcd.print("HIF: ");
        lcd.print(HIFdht);  // Round 3 of data display complete
        break;
      case 4:
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("H: ");
        lcd.print(H1dht);
        lcd.setCursor(0, 1);
        lcd.print("DP: ");
        lcd.print(DPdht);  // Round 4 of data display complete
        break;
      case 5:
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("P(Pa): ");
        lcd.print(P1bmp);
        lcd.setCursor(0, 1);
        lcd.print("P(mm): ");
        lcd.print(P2bmp);
        break;
      case 6:
        lcd.setCursor(0, 1);
        lcd.print("P(in): ");
        lcd.print(P3bmp);
        newData = false;
        break;
      default:
        // if nothing else matches, do the default
        // default is optional
        break;
    }
  }
}

/*
  void showParsedData() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("TempC(bmp): ");
  lcd.print(TempCbmp);

  lcd.setCursor(0, 1);
  lcd.print("TempF(bmp): ");
  lcd.print(TempFbmp);  // Round 1 of data display complete

  delay(4000);

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("TempC(dht): ");
  lcd.print(TempCdht);

  lcd.setCursor(0, 1);
  lcd.print("TempF(dht): ");
  lcd.print(TempFdht);  // Round 2 of data display complete

  delay(4000);

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("HIC: ");
  lcd.print(HICdht);

  lcd.setCursor(0, 1);
  lcd.print("HIF: ");
  lcd.print(HIFdht);  // Round 3 of data display complete

  delay(4000);

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("H: ");
  lcd.print(H1dht);

  lcd.setCursor(0, 1);
  lcd.print("DP: ");
  lcd.print(DPdht);  // Round 4 of data display complete

  delay(4000);

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("P(Pa): ");
  lcd.print(P1bmp);

  lcd.setCursor(0, 1);
  lcd.print("P(mm): ");
  lcd.print(P2bmp);

  delay(4000);    // Round 5 of data display complete

  lcd.setCursor(0, 1);
  lcd.print("P(in): ");
  lcd.print(P3bmp);

  delay(4000);    // Round 6 of data display complete
  }
*/

// Data comes through to the XBee in arduino in the following format.
//18,64,19,66,19,66,82.70,15,101335.00,760.01,29.92

Thank you cattledog. I'm sorry for the delayed response. You're suggestions work great and seem to have solved the issue regarding data being displayed inconsistently. I don't fully understand what the changes do so I'll need to do some reading on the changes. Thank you for your suggestions suggestions.

There is still an error when displaying the Pressure in Pascals ("P(Pa)") to the LCD screen. The Tx data being sent is displayed as "101900.00" in the outgoing data:

<19,66,19,67,19,67,84.60,15,101919.00,764.39,30.10>
<19,66,19,67,19,67,84.70,15,101904.00,764.28,30.09>
<19,66,19,67,19,67,84.70,15,101906.00,764.29,30.09>
<19,66,19,67,19,67,84.60,15,101908.00,764.31,30.09>
<19,66,19,67,19,67,84.20,15,101908.00,764.31,30.09>
<19,66,19,67,19,67,84.40,15,101900.00,764.25,30.09>

...but the Rx displays the value on the LCD screen as -29142. Not too sure why this is happening. Any thoughts?

Thanks again for the support.

Don't have time to dig in to the specifics (cooking dinner) but your issue smells like use of an int to store a number that won't fit. 101904 is such a number, so I suspect that somewhere in your RX code, the pressure value is passing through a sixteen bit signed integer.

Wildbill is correct. Very good sense of smell :slight_smile:

int P1bmp = 000000;
P1bmp = atoi(strtokIndx);
lcd.print("P(Pa): ");
lcd.print(P1bmp);

Declare P1bmp as a long and Use atol() instead of atoi.

P1bmp = atol(strtokIndx);

Sorry for the late reply and thanks for your reply cattledog. This didn't seem to help the values printed out on the lcd screen though. The LCD screen still displays a negative number of "-29963". I don't understand why?

Full Rx code pasted below:

//used Example 5 from: http://forum.arduino.cc/index.php?topic=396450
//cattledog helped with this code and helped reduce data error issues.

#include <SoftwareSerial.h>
SoftwareSerial XBee(2, 3); // RX, TX

#include <Wire.h>
#include <LiquidCrystal.h>
const int rs = 12, en = 11, d4 = 7, d5 = 6, d6 = 5, d7 = 4;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

#include <string.h>
#include <stdio.h>

const byte numChars = 64;  //This means 64 characters are expected.
char receivedChars[numChars]; // array that is received
char tempChars [numChars]; // temporary array for use when parsing

//variables to hold the parsed data
int TempCbmp = 0;
int TempFbmp = 0;
int TempCdht = 0;
int TempFdht = 0;
int HICdht = 0;
int HIFdht = 0;
float H1dht = 00.00;
float DPdht = 00.00;
int P1bmp = 000000;
float P2bmp = 000.00;
float P3bmp = 00.00;

boolean newData = false;

//non blocking display control variables
unsigned long lastDisplaySwitch;
unsigned long interval = 4000; //4 seconds for each lcd screen
byte count = 0;// for display screen

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

void setup()
{
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  lcd.clear ();
  // Set up both ports at 9600 baud. This value is most important
  // for the XBee. Make sure the baud rate matches the config
  // setting of your XBee.
  XBee.begin(9600);
  Serial.begin(9600);
}

void loop() {

  recvWithEndMarker();

  if (newData == true) {
    //this temporary copy is necessary to protect the original data
    //because strtok() used in parseData() replaces the commas with \0
    memset(tempChars, '\0', 64); //clear tempChars
    strcpy(tempChars, receivedChars);
    memset(receivedChars, '\0', 64);//clear receivedChars
    parseData();
  }
  //showParsedData();
  showDisplay();
  //newData = false;
}

//========

void recvWithEndMarker() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;

  while (XBee.available() > 0 && newData == false) { // If Xbee is receiving data AND newData is false, THEN "rc" is the XBee data
    rc = XBee.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;  //if rc is NOT the endMarker, then index "rc" to the "receivedChars" array.
        ndx++;                    // go to the next character and index it as well
        if (ndx >= numChars) {    // what does this mean? why would ndx ever be greater than 64?
          ndx = numChars - 1;     // what does this do?
        }
      }
      else {
        receivedChars[ndx] = '\0';  //terminate the string when the endMarker is received
        recvInProgress = false;     // and mark as NOT recvInProgress
        ndx = 0;                    // move index back to 0 position?
        newData = true;             // why is new data here marked as true? shouldn't it be above the "ndx=0"?
      }
    }
    else if (rc == startMarker) {
      recvInProgress = true;
      if (newData == true) {        // I don't understand what this section does? If recvInProgress = True, then we shouldn't have new data at this time, correct?
        newData = false;
      }
    }
  }
}

//=======

void parseData() { // split the data into it's parts

  char * strtokIndx; // this is used by strtok() as an index

  strtokIndx = strtok(tempChars, ","); // get the first part - the string
  TempCbmp = atoi(strtokIndx); // copy it to TempCbmp

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  TempFbmp = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  TempCdht = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  TempFdht = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  HICdht = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  HIFdht = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ",");
  H1dht = atof(strtokIndx);     // convert this part to a float

  strtokIndx = strtok(NULL, ",");
  DPdht = atof(strtokIndx);     // convert this part to a float

  strtokIndx = strtok(NULL, ",");
  P1bmp = atol(strtokIndx);     // convert this part to a long

  strtokIndx = strtok(NULL, ",");
  P2bmp = atof(strtokIndx);     // convert this part to a float

  strtokIndx = strtok(NULL, ",");
  P3bmp = atof(strtokIndx);     // convert this part to a float

  newData = false;
}

//======

void showDisplay()
{
  if (millis() - lastDisplaySwitch > interval)
  {
    lastDisplaySwitch += interval;
    count++;
    if (count == 7) //display screens 1-6
    {
      count = 1;
    }
   
    switch (count) {
      case 1:
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("TempC(bmp): ");
        lcd.print(TempCbmp);
        lcd.setCursor(0, 1);
        lcd.print("TempF(bmp): ");
        lcd.print(TempFbmp);  // Round 1 of data display complete
        break;
      case 2:
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("TempC(dht): ");
        lcd.print(TempCdht);
        lcd.setCursor(0, 1);
        lcd.print("TempF(dht): ");
        lcd.print(TempFdht);  // Round 2 of data display complete
        break;
      case 3:
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("HIC: ");
        lcd.print(HICdht);
        lcd.setCursor(0, 1);
        lcd.print("HIF: ");
        lcd.print(HIFdht);  // Round 3 of data display complete
        break;
      case 4:
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("H: ");
        lcd.print(H1dht);
        lcd.setCursor(0, 1);
        lcd.print("DP: ");
        lcd.print(DPdht);  // Round 4 of data display complete
        break;
      case 5:
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("P(Pa): ");
        lcd.print(P1bmp);
        lcd.setCursor(0, 1);
        lcd.print("P(mm): ");
        lcd.print(P2bmp);
        break;
      case 6:
        lcd.setCursor(0, 1);
        lcd.print("P(in): ");
        lcd.print(P3bmp);
        newData = false;
        break;
      default:
        // if nothing else matches, do the default
        // default is optional
        break;
    }
  }
}

/*
  void showParsedData() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("TempC(bmp): ");
  lcd.print(TempCbmp);

  lcd.setCursor(0, 1);
  lcd.print("TempF(bmp): ");
  lcd.print(TempFbmp);  // Round 1 of data display complete

  delay(4000);

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("TempC(dht): ");
  lcd.print(TempCdht);

  lcd.setCursor(0, 1);
  lcd.print("TempF(dht): ");
  lcd.print(TempFdht);  // Round 2 of data display complete

  delay(4000);

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("HIC: ");
  lcd.print(HICdht);

  lcd.setCursor(0, 1);
  lcd.print("HIF: ");
  lcd.print(HIFdht);  // Round 3 of data display complete

  delay(4000);

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("H: ");
  lcd.print(H1dht);

  lcd.setCursor(0, 1);
  lcd.print("DP: ");
  lcd.print(DPdht);  // Round 4 of data display complete

  delay(4000);

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("P(Pa): ");
  lcd.print(P1bmp);

  lcd.setCursor(0, 1);
  lcd.print("P(mm): ");
  lcd.print(P2bmp);

  delay(4000);    // Round 5 of data display complete

  lcd.setCursor(0, 1);
  lcd.print("P(in): ");
  lcd.print(P3bmp);

  delay(4000);    // Round 6 of data display complete
  }
*/

// Data comes through to the XBee in arduino in the following format.
//18,64,19,66,19,66,82.70,15,101335.00,760.01,29.92

Thanks again for any input possible.

Declare P1bmp as a long and Use atol() instead of atoi.

The posted code still has

int P1bmp = 000000;

Oh, you're so right and this did it! It all works. This feels like a huge milestone. :slight_smile: Thanks again everyone for their help and advice! Final code is paste below for those who are interested.

//used Example 5 from: http://forum.arduino.cc/index.php?topic=396450
//Delta_G, cattledog, wildbill, Power_Broker all helped with this code and helped reduce data error issues.
//https://forum.arduino.cc/index.php?topic=581004.0

#include <SoftwareSerial.h>
SoftwareSerial XBee(2, 3); // RX, TX

#include <Wire.h>
#include <LiquidCrystal.h>
const int rs = 12, en = 11, d4 = 7, d5 = 6, d6 = 5, d7 = 4;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

#include <string.h>
#include <stdio.h>

const byte numChars = 64;  //This means 64 characters are expected.
char receivedChars[numChars]; // array that is received
char tempChars [numChars]; // temporary array for use when parsing

//variables to hold the parsed data
int TempCbmp = 0;
int TempFbmp = 0;
int TempCdht = 0;
int TempFdht = 0;
int HICdht = 0;
int HIFdht = 0;
float H1dht = 00.00;
float DPdht = 00.00;
long P1bmp = 000000;
float P2bmp = 000.00;
float P3bmp = 00.00;

boolean newData = false;

//non blocking display control variables
unsigned long lastDisplaySwitch;
unsigned long interval = 4000; //4 seconds for each lcd screen
byte count = 0;// for display screen

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

void setup()
{
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  lcd.clear ();
  // Set up both ports at 9600 baud. This value is most important
  // for the XBee. Make sure the baud rate matches the config
  // setting of your XBee.
  XBee.begin(9600);
  Serial.begin(9600);
}

void loop() {

  recvWithEndMarker();

  if (newData == true) {
    //this temporary copy is necessary to protect the original data
    //because strtok() used in parseData() replaces the commas with \0
    memset(tempChars, '\0', 64); //clear tempChars
    strcpy(tempChars, receivedChars);
    memset(receivedChars, '\0', 64);//clear receivedChars
    parseData();
  }
  //showParsedData();
  showDisplay();
  //newData = false;
}

//========

void recvWithEndMarker() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;

  while (XBee.available() > 0 && newData == false) { // If Xbee is receiving data AND newData is false, THEN "rc" is the XBee data
    rc = XBee.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;  //if rc is NOT the endMarker, then index "rc" to the "receivedChars" array.
        ndx++;                    // go to the next character and index it as well
        if (ndx >= numChars) {    // what does this mean? why would ndx ever be greater than 64?
          ndx = numChars - 1;     // what does this do?
        }
      }
      else {
        receivedChars[ndx] = '\0';  //terminate the string when the endMarker is received
        recvInProgress = false;     // and mark as NOT recvInProgress
        ndx = 0;                    // move index back to 0 position?
        newData = true;             // why is new data here marked as true? shouldn't it be above the "ndx=0"?
      }
    }
    else if (rc == startMarker) {
      recvInProgress = true;
      if (newData == true) {        // I don't understand what this section does? If recvInProgress = True, then we shouldn't have new data at this time, correct?
        newData = false;
      }
    }
  }
}

//=======

void parseData() { // split the data into it's parts

  char * strtokIndx; // this is used by strtok() as an index

  strtokIndx = strtok(tempChars, ","); // get the first part - the string
  TempCbmp = atoi(strtokIndx); // copy it to TempCbmp

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  TempFbmp = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  TempCdht = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  TempFdht = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  HICdht = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  HIFdht = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ",");
  H1dht = atof(strtokIndx);     // convert this part to a float

  strtokIndx = strtok(NULL, ",");
  DPdht = atof(strtokIndx);     // convert this part to a float

  strtokIndx = strtok(NULL, ",");
  P1bmp = atol(strtokIndx);     // convert this part to a long

  strtokIndx = strtok(NULL, ",");
  P2bmp = atof(strtokIndx);     // convert this part to a float

  strtokIndx = strtok(NULL, ",");
  P3bmp = atof(strtokIndx);     // convert this part to a float

  newData = false;
}

//======

void showDisplay()
{
  if (millis() - lastDisplaySwitch > interval)
  {
    lastDisplaySwitch += interval;
    count++;
    if (count == 7) //display screens 1-6
    {
      count = 1;
    }
   
    switch (count) {
      case 1:
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("TempC(bmp): ");
        lcd.print(TempCbmp);
        lcd.setCursor(0, 1);
        lcd.print("TempF(bmp): ");
        lcd.print(TempFbmp);  // Round 1 of data display complete
        break;
      case 2:
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("TempC(dht): ");
        lcd.print(TempCdht);
        lcd.setCursor(0, 1);
        lcd.print("TempF(dht): ");
        lcd.print(TempFdht);  // Round 2 of data display complete
        break;
      case 3:
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("HIC: ");
        lcd.print(HICdht);
        lcd.setCursor(0, 1);
        lcd.print("HIF: ");
        lcd.print(HIFdht);  // Round 3 of data display complete
        break;
      case 4:
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("H: ");
        lcd.print(H1dht);
        lcd.setCursor(0, 1);
        lcd.print("DP: ");
        lcd.print(DPdht);  // Round 4 of data display complete
        break;
      case 5:
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("P(Pa): ");
        lcd.print(P1bmp);
        lcd.setCursor(0, 1);
        lcd.print("P(mm): ");
        lcd.print(P2bmp);
        break;
      case 6:
        lcd.setCursor(0, 1);
        lcd.print("P(in): ");
        lcd.print(P3bmp);
        newData = false;
        break;
      default:
        // if nothing else matches, do the default
        // default is optional
        break;
    }
  }
}

/*
  void showParsedData() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("TempC(bmp): ");
  lcd.print(TempCbmp);

  lcd.setCursor(0, 1);
  lcd.print("TempF(bmp): ");
  lcd.print(TempFbmp);  // Round 1 of data display complete

  delay(4000);

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("TempC(dht): ");
  lcd.print(TempCdht);

  lcd.setCursor(0, 1);
  lcd.print("TempF(dht): ");
  lcd.print(TempFdht);  // Round 2 of data display complete

  delay(4000);

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("HIC: ");
  lcd.print(HICdht);

  lcd.setCursor(0, 1);
  lcd.print("HIF: ");
  lcd.print(HIFdht);  // Round 3 of data display complete

  delay(4000);

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("H: ");
  lcd.print(H1dht);

  lcd.setCursor(0, 1);
  lcd.print("DP: ");
  lcd.print(DPdht);  // Round 4 of data display complete

  delay(4000);

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("P(Pa): ");
  lcd.print(P1bmp);

  lcd.setCursor(0, 1);
  lcd.print("P(mm): ");
  lcd.print(P2bmp);

  delay(4000);    // Round 5 of data display complete

  lcd.setCursor(0, 1);
  lcd.print("P(in): ");
  lcd.print(P3bmp);

  delay(4000);    // Round 6 of data display complete
  }
*/

// Data comes through to the XBee in arduino in the following format.
//18,64,19,66,19,66,82.70,15,101335.00,760.01,29.92

Quick follow up question. I notice when I unplug the Tx, the latest values received by the Rx are still displayed. Is there an easy way for these values to go to "0" or "error" if the Tx goes offline?

Thanks again!