Serial Communication Help

Hello,
I am looking to send a ph sensors data from my uno, to my mega, and then display it on an LCD. I will explain why I can't just attach the uno to the lcd in a sec.
Right now the issue is that for my application, I cannot find a suitable way to send that data from the uno to the mega. I have looked into union implementation and other serial methods, but I can't seem to find anything that fits the application and is suitable.
I have an understanding that in order for the Serial.write() function to work, I need to have either a string, int, or byte to send. I have tried to convert the ph value to an int because it seemed the easiest but the values are getting lost or misread.
I know that the best solution is probably to convert the float to a byte array, however none of the online tutorials have really worked for me and I haven't seen any way to implement them into sending data across the arduinos.

why am i doing all this? Because i made a crappy arduino shield design that didnt have external access to the dig pins, so now i can either solder on jumper connections from the lcd to the uno shield or write the proper code to display the ph without a computer screen. The goal here is to have a working hydroponics system to give my parents by this friday, before i move out for college. So far I have the ph monitoring and flood timing system ready, I am just looking to get the last few kinks out of the way before its ready.

anyways, heres the uno (sender) code

void loop() {
  timer.tick();
  if (Serial.available() > 0) {                                                      
    user_bytes_received = Serial.readBytesUntil(13, user_data, sizeof(user_data));   
  }

  if (user_bytes_received) {                                                      
    parse_cmd(user_data);                                                          
    user_bytes_received = 0;                                                        
    memset(user_data, 0, sizeof(user_data));                                         
  }
  float ph = (pH.read_ph());
  ph = ph * 100;
  int x = ph;

  Serial.write(x);                                       
  delay(1000);
}

and heres the mega (receiver) code

#include <LiquidCrystal.h>

const int rs = 9, en = 8, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
int inByte = 0;
double ph;
void setup(){
  Serial.begin(9600);
  Serial1.begin(9600);
  lcd.begin(16,2);
  lcd.print("pH: ");
  lcd.setCursor(4, 0);
}

void loop(){
  if(Serial.available()){
    inByte = Serial1.read();
    ph = inByte;
    lcd.print(ph);
    lcd.setCursor(4, 0);
  }
  delay(1000);
}

For reliable, human readable serial communications, with message start and end markers, study the Serial Input Basics tutorial.

I read though the article, went through the example progressions and it does make more sense on the receiving end, but how would I be sending the data from the uno to the mega? could a simple byte cast work?

To send an int x on uno is 2 bytes..
Using serial write, would look like this..

 Serial.write((uint8_t *)&x,sizeof(x));

good luck.. ~q

1 Like

I recommend sending human readable ASCII decimal numbers, using Serial.print, with start and end markers, as advised in the tutorial. That way you can both read the transmissions and sensibly decode them.

Example transmit code:

Serial.print("<");
Serial.print(data);  //integer, use atoi() to decode. For float, use atof() to decode.
Serial.println(">");

Will the shield work on the Mega? If so, then the LCD can be connected to any of the pins that are not obscured by the shield, and you can eliminate the UNO.

Here is a method to send a struct over a serial connection. Tested on 2 Uno boards (SoftwareSerial).

Sender:

#include <SoftwareSerial.h>

const byte ssRX = 5;
const byte ssTX = 6;

SoftwareSerial ss(ssRX, ssTX);

const byte numChars = 32; // tailor to your use 
char receivedChars[numChars];   // an array to store the received data
bool newData = false;

struct Payload
{
   int integer;
   unsigned long timer;
   float floatNum;
   char str[6];
};

Payload payload = {85, 102522, 3.1415, "hello"};

void setup()
{
   Serial.begin(115200);
   ss.begin(9600);
   Serial.println("I send a payload in the form of a struct");
}

void loop()
{
   send();
}

void send()
{
   static unsigned long timer = 0;
   unsigned long interval = 1000;
   if (millis() - timer >= interval)
   {
      timer = millis();
      payload.timer = millis();
      Serial.write((byte*)&payload, sizeof(payload)); 
      Serial.write('\n');
      //Serial.print("sizeof(payload)  ");
      //Serial.println(sizeof(payload));

      ss.write((byte*)&payload, sizeof(payload));
      ss.write('\n');
   }
}

Receiver, uses methods from the serial input basics tutorial:

#include <SoftwareSerial.h>

const byte ssRX = 5;
const byte ssTX = 6;

SoftwareSerial ss(ssRX, ssTX); 

const byte numBytes = 32;
byte receivedChars[numBytes];   // an array to store the received data
bool newData = false;
byte bytesReceived = 0;

struct Payload
{
   int integer;
   unsigned long timer;
   float floatNum;
   char str[6];
} payload;


void setup()
{
   Serial.begin(115200);
   ss.begin(9600);
   Serial.println("I receive a payload in the form of a struct");
}

void loop()
{
   recvWithEndMarker();
   //showNewData();
   parseData();
   if (newData)
   {
      if (!swapPayload())
      {
         Serial.print("bad data");
         while (1);
      }
      else
      {

         newData = false;
      }
   }
}

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

   while (ss.available() > 0 && newData == false)
   {
      rc = ss.read();
      //Serial.print(rc);
      if (rc == '\r') // ignore carriage return
      {
         return;
      }
      if (rc != endMarker)
      {
         receivedChars[ndx] = rc;
         ndx++;
         if (ndx >= numBytes)
         {
            ndx = numBytes - 1;
         }
      }
      else
      {
         receivedChars[ndx] = '\0'; // terminate the string
         bytesReceived = ndx;
         ndx = 0;
         newData = true;
      }
   }
}

void parseData()
{
   if (newData)
   {
      if (!swapPayload())
      {
         Serial.println(F("bad data"));
         newData = false;
         return;
      }

      Serial.print(payload.integer);
      Serial.print("\t ");
      Serial.print(payload.timer);
      Serial.print("\t ");
      Serial.print(payload.floatNum, 3);
      Serial.print("\t ");
      Serial.println(payload.str);
      newData = false;
   }
}

bool swapPayloadP()
{
   memcpy(&payload, receivedChars, sizeof(payload));
   return 1;
}

bool swapPayload()
{
   /*
   Serial.print("bytesReceived  ");
   Serial.print(bytesReceived);
   Serial.print("\t\t ");
   Serial.print("sizeof(payload)  ");
   Serial.println(sizeof(payload));
   */
   
   if ((bytesReceived) == sizeof(payload))
   {
      memcpy(&payload, receivedChars, sizeof(payload));
      return 1;
   }
   else
   {
      return 0;
   }
}
1 Like

in my previous attempts i dont think serial.print worked but i can retry it tomorrow and let you know, i'll edit this once i find out

checking the pins now it could work that could legitimately work, I will try that out tomorrow and let you know

i could check this out but would def be the most intensive one just because i have to resolder connections, but if all else fails I will keep this one in mind

will try this and let you know

You did something wrong.

For help on this forum, post the code, explain what it should do, and what it did instead. People will be happy to help if you provide some information.

Theres no error, all thats happening is that the data is being printed in the serial monitor rather than sending over to the mega. The serial monitor open for the mega displays nothing; the serial monitor for the uno displays good data.
This was the case previously too, so i thought my only other option then was to rely on serial.write

Ok, check the mega code..
You're reading from serial1 but never check if any bytes are available..
You do check Serial.available(), so maybe that's a typo..

The mega code should look something like this..


int16_t x;

 if (Serial1.available()>= sizeof(x)){
    byte aByte = Serial1.read();
    byte bByte = Serial1.read();
    x = (aByte << 8) | bByte;
  }

good luck.. ~q

Yep this is what iwas missing. I figured out that i would need to change the serial.read to serial1, but overlooked changing the serial.available
Everything is working fine now, for future reference; I essentially copied example 4 from Serial Input Basics and changed the serial commands accordingly. for the uno, print statements did work once i had the mega code working. Thank you, everyone for your help and patience!!

1 Like

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