pH probe - Repeating

Equipment:
pH Probe
Atlas-Scientific pH Stamp

Working? Yes.

Issue:
When I stream my pH and temperature data to Pachube. The temperature works fine, but the pH ends up repeating itself.


I think the issue is because it is a string when it sends the data.

pH/Sensor Code:
-Code just for pH sensor

String inputstring = "";                                                       //a string to hold incoming data from the PC
String sensorstring = "";                                                      //a string to hold the data from the Atlas Scientific product
boolean input_stringcomplete = false;                                          //have we received all the data from the PC
boolean sensor_stringcomplete = false;                                         //have we received all the data from the Atlas Scientific product
   if (input_stringcomplete){                                                   //if a string from the PC has been recived in its entierty 
      Serial3.print(inputstring);                                              //send that string to the Atlas Scientific product
      inputstring = "";                                                        //clear the string:
      input_stringcomplete = false;                                            //reset the flage used to tell if we have recived a completed string from the PC
      }

 if (sensor_stringcomplete){                                                   //if a string from the Atlas Scientific product has been recived in its entierty 
      Serial.println(sensorstring);                                            //send that string to to the PC's serial monitor
      sensorstring = "";                                                       //clear the string:
      sensor_stringcomplete = false;                                           //reset the flage used to tell if we have recived a completed string from the Atlas Scientific product
      }
 void serialEvent() {                                                         //if the hardware serial port_0 receives a char              
               char inchar = (char)Serial.read();                               //get the char we just received
               inputstring += inchar;                                           //add it to the inputString
               if(inchar == '\r') {input_stringcomplete = true;}                //if the incoming character is a <CR>, set the flag
              }  


  void serialEvent3(){                                                         //if the hardware serial port_3 receives a char 
              char inchar = (char)Serial3.read();                              //get the char we just received
              sensorstring += inchar;                                          //add it to the inputString
              if(inchar == '\r') {sensor_stringcomplete = true;}               //if the incoming character is a <CR>, set the flag 
             }

-Code to send data to Pachube

lastConnected = client.connected();
  String dataString = "External_Temperature,";
  dataString += TemperatureF;

  // you can append multiple readings to this String if your
  // pachube feed is set up to handle multiple values:
  dataString += "\nInternal_Temperature,";
  dataString += thermocouple;
  
  dataString += "\npH,";
  dataString += sensorstring;

I feel that if I had a way to turn the string into a integer it would work fine.

I tried:

 String sensorstring;
 int pHsensor = sensorstring.toInt();

Just got a 0 for pH, and temperatures still worked (switched the variable in the code for pachube to pHsensor).

pHsensor = atoi(sensorstring);

Compiling error: CompleteWebServer:106: error: cannot convert 'String' to 'const char*' for argument '1' to 'int atoi(const char*)'

All help I appreciate.

-Miles

Pretty sure i ran into a similar problem awhile back. Nick Gammon's website helped me out a lot: Gammon Forum : Electronics : Microprocessors : How to process incoming serial data without blocking
Here is my PH sketch (doesn't use strings!) that I use with the Atlas Scientific stamp-

float getPH (){
  const unsigned int MAX_INPUT = 50;
  Serial3.print("r");    //   request a reading
  Serial3.print('\r');
  delay (500);
  static char input_line [MAX_INPUT];
  static unsigned int input_pos = 0;

  while (Serial3.available () > 0) 
  {
    char inByte = Serial3.read ();

    switch (inByte)
    {

    case '\r':   // end of text                 
      {
        input_line [input_pos] = 0;  // terminating null byte
        //process_data (input_line);
        char * val (input_line);
        Serial.println(val);
        float phValue = atof(val);

        return phValue;
        input_pos = 0;// reset buffer for next time
        break;
      }

      break;
    case '\n':   // discard carriage return
      break;

    default:
      // keep adding if not full ... allow for terminating null byte
      if (input_pos < (MAX_INPUT - 1))
        input_line [input_pos++] = inByte;
      break;
    }  // end of switch
  }  // end of incoming data
}  // end of function

pHsensor = atoi(sensorstring);

Also, I recall you want a float not an integer.

Alright. It was hard to understand where to apply your code for a bit, but I assume this is how (basic idea?):

float phValue;

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

void loop(){
  getPH();

***************************************Code to Send pH to Pachube, look only in "*" area*********************************************
  lastConnected = client.connected();
  String dataString = "External_Temperature,";
  dataString += TemperatureF;

                          // you can append multiple readings to this String if your
                        // pachube feed is set up to handle multiple values:
  int otherSensorReading = thermocouple;
  dataString += "\nInternal_Temperature,";
  dataString += otherSensorReading;
  
  dataString += "\npH,";
  dataString += phValue;
//*******************************************************************************************************************************
  // if there's incoming data from the net connection.
  // send it out the serial port.  This is for debugging
  // purposes only:
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
  }

  // if there's no net connection, but there was one last time
  // through the loop, then stop the client:
  if (!client.connected() && lastConnected) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
  }

  // if you're not connected, and ten seconds have passed since
  // your last connection, then connect again and send data: 
  if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) {
    sendData(dataString);
  }
  // store the state of the connection for next time through
  // the loop:
  lastConnected = client.connected();
  
}
float getPH (){
  const unsigned int MAX_INPUT = 50;
  Serial3.print("r");    //   request a reading
  Serial3.print('\r');
  delay (500);
  static char input_line [MAX_INPUT];
  static unsigned int input_pos = 0;

  while (Serial3.available () > 0) 
  {
    char inByte = Serial3.read ();

    switch (inByte)
    {

    case '\r':   // end of text                 
      {
        input_line [input_pos] = 0;  // terminating null byte
        //process_data (input_line);
        char * val (input_line);
        Serial.println(val);
        float phValue = atof(val);

        return phValue;
        input_pos = 0;// reset buffer for next time
        break;
      }

      break;
    case '\n':   // discard carriage return
      break;

    default:
      // keep adding if not full ... allow for terminating null byte
      if (input_pos < (MAX_INPUT - 1))
        input_line [input_pos++] = inByte;
      break;
    }  // end of switch
  }  // end of incoming data
}  // end of function

First of all, I do not know how to call a variable from a different void. So I wrote before void setup():

float phValue;

When I turn it to an integer Pachube doesn't understand the data it received. Is there a way to process the data as a integer? Or another way to write the data from the different void() to the loop? I think that would help.

First of all, I do not know how to call a variable from a different void. So I wrote before void setup(): ... Or another way to write the data from the different void() to the loop?

I defined it locally to save on global memory. I'm not exactly sure what you're asking but I think the answer your looking for is to use this snippet within your main loop to take a pH reading:

float PHval = getPH(); If this is not what your asking can you try to clarify your question?

getPH() is function call that returns a pH reading. it does this by first sending the ph stamp the necessary ''R" and carriage return over serial. It waits for the stamp to do its business then reads the serial buffer into a char array and finally converts it into a float. So when you want a pH reading you call getPH() and save it to a float variable called PHval (or whatever you like). Use of functions helps to make code easier to follow, moves the nitty gritty stuff out of sight so you can keep track of what you're really doing : get the reading, evaluate it, and do stuff based on the evaluation.

When I turn it to an integer Pachube doesn't understand the data it received. Is there a way to process the data as a integer?

The integer variable type doesn't keep track of the decimal and everything after it gets truncated. You can multiply the initial reading by 100 to get rid of the decimal without losing accuracy. ( so a pH reading of 7.15 (float) could be processed as 715(int)). You will have to keep in mind the change in magnitude for the rest of your sketch or change it back. I am unfamiliar with Pachuba, so someone else will have to pick it up from here.

Was wondering....could I get a copy of your code?

Here is what I have formulated from using your link and your tips....it still gives me 0.00.

float PHval = getPH();

void setup ()
{
  Serial.begin(9600);
} // end of setup

void loop(){
 Serial.print(PHval);
}
//********************************************************Your Code***********************************************************************************
float getPH (){
  const unsigned int MAX_INPUT = 50;
  Serial3.print("r");    //   request a reading
  Serial3.print('\r');
  delay (500);
  static char input_line [MAX_INPUT];
  static unsigned int input_pos = 0;

  while (Serial3.available () > 0) 
  {
    char inByte = Serial3.read ();

    switch (inByte)
    {

    case '\r':   // end of text                 
      {
        input_line [input_pos] = 0;  // terminating null byte
        //process_data (input_line);
        char * val (input_line);
        Serial.println(val);
        float phValue = atof(val);

        return phValue;
        input_pos = 0;// reset buffer for next time
        break;
      }

      break;
    case '\n':   // discard carriage return
      break;

    default:
      // keep adding if not full ... allow for terminating null byte
      if (input_pos < (MAX_INPUT - 1))
        input_line [input_pos++] = inByte;
      break;
    }  // end of switch
  }  // end of incoming data
}  // end of function

Is that your complete code? Nowhere do you initialize Serial3. This also goes with the assumption that you are using a mega with the ph stamp's rx and tx lines connected to Serial3. If you are using an uno you have to use software serial. Can you verify that the stamp is receiving the request (stamp's LED should flash)? PHval should be updated in your loop, not defined at the start:

void setup ()
{
  Serial.begin(38400);
  Serial3.begin(38400); //for Mega
} 
void loop(){
float PHval= getPH();
 Serial.print(PHval);
}
float getPH ()...{

Every time through the loop you should get 2 prints to serial. the first is "val" being passed straight through from the incoming serial to the computer, the second is the float value that you're after.

Was wondering....could I get a copy of your code?

Short answer- no. Long answer- It is part of a larger project and I really don't want to go through the whole thing and edit it down for you. I think it would be more overwhelming than helpful. I have already given you the relevant parts. Its easier to look at someone else code and accept that it works than to write it yourself and understand why it works. All part of the learning process. And besides I had to ask all the same questions you are. If you have more questions feel free to ask them.

seanz2003:
Is that your complete code? Nowhere do you initialize Serial3.

I am sorry I missed that. I understand what you are talking about when comparing it to Atlas-Scientific's pH code.

seanz2003:
This also goes with the assumption that you are using a mega with the ph stamp's rx and tx lines connected to Serial3. If you are using an uno you have to use software serial. Can you verify that the stamp is receiving the request (stamp's LED should flash)?

I am using a Mega2650, with the pH stamp plugged into the TX3 and RX3 lines. These were the specific digital pins assigned for the pH stamp. With that being said the light does blink :smiley:

void setup ()
{
  Serial.begin(38400);                                                      //set baud rate for the hardware serial port_0 to 38400
     Serial3.begin(38400);
} // end of setup

void loop(){
float PHval= getPH();
float PHVALUE = PHval*1000;
Serial.print(PHVALUE);

I got rid of the global float value of getpH, along with added the Serial3.begin command. The value still reports a 0.00, so I decided I would try to multiply the value by 100, 1000 and even tried dividing by 100 and 1000. Still nothing.

seanz2003:
Short answer- no. Long answer- It is part of a larger project and I really don't want to go through the whole thing and edit it down for you. I think it would be more overwhelming than helpful. I have already given you the relevant parts. Its easier to look at someone else code and accept that it works than to write it yourself and understand why it works. All part of the learning process. And besides I had to ask all the same questions you are. If you have more questions feel free to ask them.

Thank you. It trully is best that I learn how this code works. By learning the code it will only benefit me as a part-time programmer. That being said my question for you is MAX_INPUT in the code below used to designate the number of bytes allowed in the buffer?

float getPH (){
  const unsigned int MAX_INPUT = 50;
  Serial3.print("r");    //   request a reading
  Serial3.print('\r');
  delay (500);
  static char input_line [MAX_INPUT];
  static unsigned int input_pos = 0;

  while (Serial3.available () > 0) 
  {
    char inByte = Serial3.read ();

    switch (inByte)
    {

    case '\r':   // end of text                 
      {
        input_line [input_pos] = 0;  // terminating null byte
        //process_data (input_line);
        char * val (input_line);
        Serial.println(val);
        float phValue = atof(val);

        return phValue;
        input_pos = 0;// reset buffer for next time
        break;
      }

      break;
    case '\n':   // discard carriage return
      break;

    default:
      // keep adding if not full ... allow for terminating null byte
      if (input_pos < (MAX_INPUT - 1))
        input_line [input_pos++] = inByte;
      break;
    }  // end of switch
  }  // end of incoming data
}  // end of function

bump

Alrighty. Forget all that mumbo-jumbo I spoke of earlier. I got the code to print values in the Serial Monitor. Although, here is what happens.....

3.41
33.413.41
33.413.413.41
33.413.413.413.43
33.413.413.413.433.41
33.413.413.413.433.413.41
33.413.413.413.433.413.413.43
33.413.413.413.433.413.413.433.41

It continues to happen in a stream of values......got any advice anyone?

My code:

void setup(){
  Serial.begin(38400);                                                      //set baud rate for the hardware serial port_0 to 38400
} // end of setup

void loop(){
   getPH(); 

}

float getPH (){
  const unsigned int MAX_INPUT = 50;
  Serial3.print("r");    //   request a reading
  Serial3.print('\r');
  delay (500);
  static char input_line [MAX_INPUT];
  static unsigned int input_pos = 0;

  while (Serial3.available () > 0) 
  {
    char inByte = Serial3.read ();

    switch (inByte)
    {

    case '\r':   // end of text                 
      {
        input_line [input_pos] = 0;  // terminating null byte
        //process_data (input_line);
        char * val (input_line);
        Serial.println(val);
        float phValue = atof(val);

        return phValue;
        input_pos = 0;// reset buffer for next time
        break;
      }

      break;
    case '\n':   // discard carriage return
      break;

    default:
      // keep adding if not full ... allow for terminating null byte
      if (input_pos < (MAX_INPUT - 1))
        input_line [input_pos++] = inByte;
      break;
    }  // end of switch
  }  // end of incoming data
}  // end of function

one problem here

        return phValue;
        input_pos = 0;// reset buffer for next time
        break;

The function returns before the input_pos is reset so it is never done. (caused by the use of static buffers)
switch these two lines , and behaviour will be a bit better

another problem

  why request a new read with every call to getPH() ? that might disturb readings in progress!

  Serial3.print("r");    // why not Serial3.println("r"); instead of the 2 lines ?
  Serial3.print('\r');

Furthermore, why do you do the delay(500)?

Final, the function does not return a float if not all chars are available?

a very quick rewrite of your code with some questions embedded, please give it a try

float getPH ()
{
  static bool inProgress = false;

  const unsigned int MAX_INPUT = 50;
  static char input_line [MAX_INPUT];
  static unsigned int input_pos = 0;

  if (inProgress == false)
  {
    Serial3.print("r");   //Serial3.println("r");
    Serial3.print('\r');
    delay (500); 
    inProgress = true;
  }

  while (Serial3.available () > 0) 
  {
    char inByte = Serial3.read ();

    switch (inByte)
    {
    case '\r':   // end of text                 
      {
        input_line [input_pos] = 0; 
        input_pos = 0;

        Serial.println(input_line);

        float phValue = atof(input_line);
        Serial.println(phValue, 3);      // check converted value ==  input buffer?   // note 3 decimal places

        // ask for new reading 
        inProgress = false;

        return phValue;
      }
      break;
    case '\n':   // discard carriage return
      break;

    default:
      // keep adding if not full ... allow for terminating null byte
      if (input_pos < (MAX_INPUT - 1))
      {
        input_line [input_pos++] = inByte;
      }
      else
      {
        Serial.println("\n input buffer overflow...");
      }
      break;
    }  // end of switch (inByte)

  }  // end of  while (Serial3.available () > 0) 

  return -1;  // no end value reached yet, you should still return a float !!
}

I would decouple the reading of data and the conversion to float in 2 functions (In fact making a class of the PH sensor)
That would give code like this

PHsensor aquarium();

...

if (aquarium.readcomplete())
{
   newPH = aquarium.PH();
   // process newPH
  ...
}

why request a new read with every call to getPH() ? that might disturb readings in progress!

 Serial3.print("r");    // why not Serial3.println("r"); instead of the 2 lines ?

Serial3.print('\r');

This makes total sense. I am just kind of a noob when it comes to programming. Thank you.

one problem here

     return phValue;

input_pos = 0;// reset buffer for next time
        break;




The function returns before the input_pos is reset so it is never done. (caused by the use of static buffers)
switch these two lines , and behaviour will be a bit better

I understand now!!!!! Someone advised the code to me previously, and I barely crawled along and got it to compile. xD

Here is what the code looks like when it runs. I like the number of significant figures. It is quite pleasing. Although there is a like about halfway down, that shows a double decimal. Do you know what would be the cause of this (looks like a double print on the same line)?

3.75
3.750
3.71
3.710
3.73
3.730
3.73
3.730
3.75
3.750
3.71
3.710
3.73
3.730
3.73
3.730
3.75
3.750
3.73
3.730
3.73
3.730
3.71
3.710
3.73
3.730
3.73
3.730
3.73
3.730
3.75
3.750
3.73
3.730
3.73
3.730
3.75
3.750
3.71
3.710
3.73
3.730
3.73
3.730
3.73
3.730
3.73.73 //***************************
3.730
3.71
3.710
3.73
3.730
3.73
3.730
3.71
3.710
3.73
3.730
3.73
3.730
3.73
3.730
3.73
3.730
3.73
3.730
3.75
3.750

All your advise was greatly appreciated. By asking these questions I kind of had to go searching for the actual meaning before I could answer. Thanks again.

P.S. In your last post :

I would decouple the reading of data and the conversion to float in 2 functions (In fact making a class of the PH sensor)
That would give code like this

PHsensor aquarium();

...

if (aquarium.readcomplete())
{
  newPH = aquarium.PH();
  // process newPH
  ...[/quote]
}



So you only want to process the code if it is a new value? I think I kind of understand the idea of creating a 2 floats (a float in a float?). Could you not write the code, but kind of give me a brief idea. I kind of want to get my feet wet.

Do you know what would be the cause of this (looks like a double print on the same line)?

Of course I rewrote the code. The value is printed twice, once as text, the input buffer and once as float.
Read the code and thou will see :wink:
just remove the line that prints the buffer.

Someone advised the code to me previously, and I barely crawled along and got it to compile.

You should read the code and understand roughly what it does, before hitting the compile button.
Only then you can see if the program meets your expectations.

So you only want to process the code if it is a new value?

unless you want to process the same value more than once, I do not know your expectations of the program.

I think I kind of understand the idea of creating a 2 floats (a float in a float?)
Could you not write the code, but kind of give me a brief idea. I kind of want to get my feet wet.

No, not a float in a float, you have the input buffer to collect the arriving characters.
This is done in the function bool readcomplete(). It returns true if it hits the \r otherwise false. Code looks quite a lot like what you have.
If the first function hits \r the second function can convert the buffer, resets the index and returns the value of the float.
Only change todo is to make the input buffer and index global variables so they can be reached from both functions.
I have said too much already :wink:

What I also noticed, is that the number is not repeating any more.

Succes,

Of course I rewrote the code. The value is printed twice, once as text, the input buffer and once as float.
Read the code and thou will see smiley-wink
just remove the line that prints the buffer.

Fixed!

No, not a float in a float, you have the input buffer to collect the arriving characters.
This is done in the function bool readcomplete(). It returns true if it hits the \r otherwise false. Code looks quite a lot like what you have.
If the first function hits \r the second function can convert the buffer, resets the index and returns the value of the float.
Only change todo is to make the input buffer and index global variables so they can be reached from both functions.
I have said too much already smiley-wink

I think I understand what you are trying to say. I have a question though. Is it easier on the arduino to break apart two functions? Instead of keeping it in a single function? If it does, why is that?

Also, everyone's help is greatly appreciated. I have learned a lot with each post.

Actually, got a question again. So I am printing this data to a 2.8" TFT and the value comes out as a single number (i.e 3, not 3.4).

What I did was call a global variable, then make phValue equal to the pHsensor. Here are the specific pieces being applied to the TFT.

#include <stdint.h>
#include <TouchScreen.h> 
#include <TFT.h>
#include "Adafruit_MAX31855.h"
#include <cstddef.h>


int pHsensor;      //Global Variable for float getpH();          
char sensor1Char[4];        // Charactor array for pot 1

void setup()
{

  Tft.init();  //init TFT library
  Serial.begin(38400); 
  Serial3.begin(38400); //pH probe

drawScreen(); //Draws the stuff that doesn't change screen
}

void loop()
{
  getPH(); 
  getSensor(); //gets data to write on screen

  Tft.fillRectangle(200,180,60,15,BLACK);       // Clear old text
  Tft.drawString(sensor1Char,200,180,2,WHITE);  // Print Sensor 1
  
delay(1000);

}

void drawScreen(){                
  Tft.drawRectangle(0, 3, 238,30,BLUE);            // HEADER TITLE
  Tft.drawString("Display Data",20,15,2,WHITE);    // header name  
  Tft.drawString("pH:",2,170,2,WHITE);  //pH
}

void getSensor(){  //gets the sensor data and converts them to an array

  itoa(pHsensor, sensor1Char, 10);
}

float getPH () //gets pH data
{
  static bool inProgress = false;

  const unsigned int MAX_INPUT = 50;
  static char input_line [MAX_INPUT];
  static unsigned int input_pos = 0;

  if (inProgress == false)
  {
    Serial3.print("r");   //Serial3.println("r");
    Serial3.print('\r');
    delay (500); 
    inProgress = true;
  }

  while (Serial3.available () > 0) 
  {
    char inByte = Serial3.read ();

    switch (inByte)
    {
    case '\r':   // end of text                 
      {
        input_line [input_pos] = 0; 
        input_pos = 0;

     

        float phValue = atof(input_line);
        Serial.println(phValue, 3);      // check converted value ==  input buffer?   // note 3 decimal places
        
        pHsensor = phValue;  //Sends data to global variable <--------------------------------------------------------------------------------------------------
        // ask for new reading 
        inProgress = false;

        return phValue;
      }
      break;
    case '\n':   // discard carriage return
      break;

    default:
      // keep adding if not full ... allow for terminating null byte
      if (input_pos < (MAX_INPUT - 1))
      {
        input_line [input_pos++] = inByte;
      }
      else
      {
        Serial.println("\n input buffer overflow...");
      }
      break;
    }  // end of switch (inByte)

  }  // end of  while (Serial3.available () > 0) 

  return -1;  // no end value reached yet, you should still return a float !!
}

I would prefer to have the data show at least two figures. It is needed in an aquarium.

int pHsensor; //Global Variable for float getpH();

only floating point numbers have decimal places. change the line above to

float pHsensor.

Sorry miles... I kinda left you hanging there for a minute. It looks like rob helped you connect the dots.

...value comes out as a single number...

Keep in mind the difference between int ( think: whole integer) and float (decimal).

I have a question though. Is it easier on the arduino to break apart two functions? Instead of keeping it in a single function? If it does, why is that?

No, the arduino is a machine that does what it is told. The human programmer is limited to his understanding of what is going on. Sometimes it is helpful to the human ( and easier to trouble shoot) to break up one large block of code into smaller, easier to follow steps, processes or -functions . Its sort of like writing an outline for a research paper, it helps give a sense of direction. The arduino certainly doesn't care about functions, but the use of functions helps the programmer to keep things organized. For example: getPH(); printPHvalToLCD(); printPHvalToSerial(); adjustPH(); - It should be fairly obvious what each of these should do. So then if your LCD is printing something weird you don't have to wade through 150 lines of code while you try to remember where exactly it is you print to the LCD. If you prefer to do it all at once, thats fine. For example

case '\r':   // end of text                 
      {
        input_line [input_pos] = 0; 
        

        float phValue = atof(input_line);
        // Print to lcd 
        // turn peristaltic pumps on depending on reading
        // add water 
        // do whatever else

        input_pos = 0;

So once you get your reading to a float ( a new value), immediately do what you need to do with it( Process it). This is reflected in Nick Gammon's orginal serial sketch. Take a looksy to know what I mean. Then you don't need a global variable or the inProgress flag. However if other parts of your code will reference the value later, Its probably best to keep the global value. Does this make sense?

I think I kind of understand the idea of creating a 2 floats (a float in a float?)

the purpose of 2 prints was troubleshooting. I wanted to make sure i was getting the expected serial output from the stamp (meaning the stamp was working properly) before i converted to float to be processed (my code was working properly). I had issues with an erratic pump and i was trying to see where the problem originated. In the final code, the prints were all ommitted, because my device was not connected to a computer.

Furthermore, why do you do the delay(500)?

The stamp takes .3 to .4 seconds to return a value. While completely unnecessary if the code works as it should, the delay just ensures that something will be waiting in the serial buffer when it is checked.
Another comment- the stamp only returns two decimal places, so including three is unnecessary and not really indicative of the accuracy you are getting.

robtillaart:
int pHsensor; //Global Variable for float getpH();

only floating point numbers have decimal places. change the line above to

float pHsensor.

So I changed the global variable from int to float and STILL it only shows 3. Do you think it might have something to do with the number of bytes that the float is carrying? Here is the changed code:

#include <stdint.h>
#include <TouchScreen.h> 
#include <TFT.h>
#include "Adafruit_MAX31855.h"
#include <cstddef.h>


float pHsensor;      //Global Variable for float getpH();          
char sensor1Char[4];        // Charactor array for pot 1

void setup()
{

  Tft.init();  //init TFT library
  Serial.begin(38400); 
  Serial3.begin(38400); //pH probe

drawScreen(); //Draws the stuff that doesn't change screen
}

void loop()
{
  getPH(); 
  getSensor(); //gets data to write on screen

  Tft.fillRectangle(200,180,60,15,BLACK);       // Clear old text
  Tft.drawString(sensor1Char,200,180,2,WHITE);  // Print Sensor 1
  
delay(1000);

}

void drawScreen(){                
  Tft.drawRectangle(0, 3, 238,30,BLUE);            // HEADER TITLE
  Tft.drawString("Display Data",20,15,2,WHITE);    // header name  
  Tft.drawString("pH:",2,170,2,WHITE);  //pH
}

void getSensor(){  //gets the sensor data and converts them to an array

  itoa(pHsensor, sensor1Char, 10);
}

float getPH () //gets pH data
{
  static bool inProgress = false;

  const unsigned int MAX_INPUT = 50;
  static char input_line [MAX_INPUT];
  static unsigned int input_pos = 0;

  if (inProgress == false)
  {
    Serial3.print("r");   //Serial3.println("r");
    Serial3.print('\r');
    delay (500); 
    inProgress = true;
  }

  while (Serial3.available () > 0) 
  {
    char inByte = Serial3.read ();

    switch (inByte)
    {
    case '\r':   // end of text                 
      {
        input_line [input_pos] = 0; 
        input_pos = 0;

     

        float phValue = atof(input_line);
        Serial.println(phValue, 2);      // check converted value ==  input buffer?   // note 3 decimal places
        
        pHsensor = phValue;  //Sends data to global variable <--------------------------------------------------------------------------------------------------
        // ask for new reading 
        inProgress = false;

        return phValue;
      }
      break;
    case '\n':   // discard carriage return
      break;

    default:
      // keep adding if not full ... allow for terminating null byte
      if (input_pos < (MAX_INPUT - 1))
      {
        input_line [input_pos++] = inByte;
      }
      else
      {
        Serial.println("\n input buffer overflow...");
      }
      break;
    }  // end of switch (inByte)

  }  // end of  while (Serial3.available () > 0) 

  return -1;  // no end value reached yet, you should still return a float !!
}

No, the arduino is a machine that does what it is told. The human programmer is limited to his understanding of what is going on. Sometimes it is helpful to the human ( and easier to trouble shoot) to break up one large block of code into smaller, easier to follow steps, processes or -functions . Its sort of like writing an outline for a research paper, it helps give a sense of direction. The arduino certainly doesn't care about functions, but the use of functions helps the programmer to keep things organized. For example: getPH(); printPHvalToLCD(); printPHvalToSerial(); adjustPH(); - It should be fairly obvious what each of these should do. So then if your LCD is printing something weird you don't have to wade through 150 lines of code while you try to remember where exactly it is you print to the LCD. If you prefer to do it all at once, thats fine. For example
Code:
case '\r': // end of text
{
input_line [input_pos] = 0;

float phValue = atof(input_line);
// Print to lcd
// turn peristaltic pumps on depending on reading
// add water
// do whatever else

input_pos = 0;

So once you get your reading to a float ( a new value), immediately do what you need to do with it( Process it). This is reflected in Nick Gammon's orginal serial sketch. Take a looksy to know what I mean. Then you don't need a global variable or the inProgress flag. However if other parts of your code will reference the value later, Its probably best to keep the global value. Does this make sense?
Quote
I think I kind of understand the idea of creating a 2 floats (a float in a float?)
the purpose of 2 prints was troubleshooting. I wanted to make sure i was getting the expected serial output from the stamp (meaning the stamp was working properly) before i converted to float to be processed (my code was working properly). I had issues with an erratic pump and i was trying to see where the problem originated. In the final code, the prints were all ommitted, because my device was not connected to a computer.

This makes so much sense. It is a machine, and it does what we tell it. No matter the route taken.

Another comment- the stamp only returns two decimal places, so including three is unnecessary and not really indicative of the accuracy you are getting.

Changed in the original code.

Without looking too in depth at your code I think this might be your problem:
itoa(pHsensor, sensor1Char, 10); I think: itoa = integer to ascii. You need a float.

What was this line intended to do, by the way?