Atlas Scientific pH project - serialEvent3 problems

I am trying to get this pH project working and I've noticed that the serialEvent3 never sets the boolean value sensor_string_complete to true. I am not sure if it is actually capturing the values from the probe. What I want is for every loop through it should grab a pH value and that is not happening right now. Most times through the loop the serial3 port is not providing any values. Here is my code:

String sensorstring = "";
boolean sensor_string_complete = false;
float pH;

void setup() {
  Serial.begin(38400);
  Serial3.begin(38400); // pH stamp
}

void serialEvent3() {                                 //if the hardware serial port_3 receives a char
  sensorstring = Serial3.readStringUntil(13);         //read the string until we see a <CR>
  sensor_string_complete = true;                      //set the flag used to tell if we have received a completed string from the PC
}

void loop() {
  getPh();
  if (sensor_string_complete == true) readph();
}

void getPh() {
  Serial.println("we are here");
  Serial3.print("r");
  Serial3.print(13);
}

void readph(){
  Serial.println("read ph here");
  if (isdigit(sensorstring[0])) {
    pH = sensorstring.toFloat();
    Serial.println(pH);
  }
  else{
    Serial.println(sensorstring);
  }

  sensorstring = ""; 
  sensor_string_complete = false;
}

This returns values such as
we are here
we are here
we are here
read ph here
7.0
we are here
read ph here
7.0
we are here
we are here
we are here
read ph here
7.0

I want this to return these values every loop. I expect to see:
We are here
read ph here
7.0
We are here
read ph here
7.0

Any help on this would be great. Thanks so much!

You are likely requesting a reading faster than sensor can respond. Try slowing down the requests like below.

Also try using parseFloat() and avoid the String class machinations:

(compiles but not tested)

boolean sensorRead = false;
float pH;

unsigned long lastMillis =0;

void setup() {
  Serial.begin(38400);
  Serial3.begin(38400); // pH stamp
}

void serialEvent3()                //if the hardware serial port_3 receives a char
{                  
  pH = Serial3.parseFloat();        //read the float until we see a <CR>  EDIT corrected to Serial3
  sensorRead = true;               //set the flag used to tell if we have received a completed string from the PC
}

void loop() 
{
  if(millis() - lastMillis > 1000UL)  // set your sensor reading frequency
  {
    getPh();
    lastMillis = millis();
  }
  if (sensorRead) 
  {
    readph();
  }
}

void getPh() 
{
  Serial.println("we are here");
  Serial3.print("r");
  Serial3.print(13);  //Carriage Return
}

void readph()
{
  Serial.println("read ph here");
  Serial.print("pH = "); 
  Serial.println(pH, 2);
  sensorRead = false;
}

EDIT: corrected Serial3 as noted above

So the reason for the strings is because according to Jordan at Atlas scientific the probe will return "Junk" sometimes. Not just a value able to be parsed as a float. So thats why there is the isdigit function there. so this is what I refactored to using your sketch combined with mine:

boolean sensorRead = false;
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_string_complete = false;                 //have we received all the data from the PC
boolean sensor_string_complete = false;                //have we received all the data from the Atlas Scientific product
float pH;                                             //used to hold a floating point number that is the pH. 


unsigned long lastMillis =0;

void setup() {
  Serial.begin(38400);
  Serial3.begin(38400); // pH stamp
}

void serialEvent3()                //if the hardware serial port_3 receives a char
{                  
  pH = Serial.parseFloat();        //read the float until we see a <CR>
  sensor_string_complete = true;               //set the flag used to tell if we have received a completed string from the PC
}

void loop() 
{
  if(millis() - lastMillis > 1000UL)  // set your sensor reading frequency
  {
    getPh();
    lastMillis = millis();
  }
  if (sensor_string_complete) 
  {
    readph();
  }
}

void getPh() 
{
  Serial.println("we are here");
  Serial3.print("r");
  Serial3.print(13);  //Carriage Return
}

void readph()
{
//  Serial.println("read ph here");
//  Serial.print("pH = "); 
//  Serial.println(pH, 2);
//  sensorRead = false;

  Serial.println("read ph here");
  if (isdigit(sensorstring[0])) {
   // pH = sensorstring.toFloat();
    Serial.println(pH);
  }
  else{
    Serial.println(pH);
  }

  sensorstring = ""; 
  sensor_string_complete = false;
}

I now see this:
we are here
read ph here
7.00
read ph here
7.00
read ph here
7.00
we are here
we are here
we are here
we are here
we are here
we are here
we are here
we are here
we are here
we are here
read ph here
7.00
read ph here
7.00

Any other thoughts?

vin7250:
So the reason for the strings is because according to Jordan at Atlas scientific the probe will return "Junk" sometimes. Not just a value able to be parsed as a float. So thats why there is the isdigit function there. so this is what I refactored to using your sketch combined with mine:

Can you try it with parseFloat() and show what happens?

What exactly does the sensor send... have you tried to just print the String?

junk is junk, and we can handle that also.

Here is what we return using the exact sketch you posted above:

we are here
we are here
we are here
we are here
read ph here
pH = 4.13
read ph here
pH = 4.13
we are here
read ph here
pH = 4.13
read ph here
pH = 0.00
we are here
we are here
we are here
we are here
we are here
we are here
we are here
we are here
we are here
read ph here
pH = 4.13
read ph here
pH = 4.13
we are here
read ph here
pH = 4.13
read ph here
pH = 0.00
we are here
we are here

Here are my values as printed using a string directly from the probe:
pH = 4.11
Actual Return From Probe (string val):
we are here
read ph here
pH = 4.13
Actual Return From Probe (string val):
we are here
read ph here
pH = 0.00
we are here
we are here
we are here
we are here
we are here
we are here
we are here
we are here
Actual Return From Probe (string val): 4.13
read ph here
pH = 4.13
Actual Return From Probe (string val):
we are here
read ph here
pH = 4.11
Actual Return From Probe (string val):
we are here
read ph here
pH = 0.00

OK, i see.

What do those junky values show in your code if printed as a String?

It may be better to parse them as C strings...

you can also try to dump bad values (in my code) like this:

void serialEvent3()                //if the hardware serial port_3 receives a char
{                  
  float value = Serial.parseFloat();        //read the float until we see a <CR>
  if(isnan(value))
  {
    // do nothing
  }
  else
  {
    pH = value;
    sensorRead = true;               //set the flag used to tell if we have received a completed string from the PC
  }
}

I figured this out like so:

String inputstring = "";
String sensorstring = "";
boolean input_string_complete = false;
boolean sensor_string_complete = false;
float pH;

void setup() {
 Serial.begin(38400);
 Serial3.begin(38400);
 inputstring.reserve(10);
 sensorstring.reserve(30);
}

void serialEvent() {
 inputstring = Serial.readStringUntil(13);
 input_string_complete = true;
}
void serialEvent3() {
 sensorstring = Serial3.readStringUntil(13);
 sensor_string_complete = true;
}

void loop(){
 getPh();
 
 readPh();
}

void readPh() {
  if (sensor_string_complete == true) {
  Serial.println(sensorstring);
  if (isdigit(sensorstring[0])) {
    pH = sensorstring.toFloat();
    if (pH >= 7.0) {
      Serial.println("high");
    }
    if (pH <= 6.99) {
      Serial.println("low");
    }
  }
 }
 
 sensorstring = "";
 sensor_string_complete = false;
}

void getPh() {
  Serial3.print('r');
  Serial3.print('\r');
}

Any thoughts on why the first two times through the loop we get 0 for pH but then every subsequent time its fine? Maybe the sensor is initializing? I dont know

OK, you can try get rid of the junk like this

void serialEvent3()                //if the hardware serial port_3 receives a char
{
  char myChar = Serial.peek();
  if (myChar < '0' || myChar > '9')
  {
    Serial.read();  // dispose of non-numeric junk
  }
  else
  {
    pH = Serial.parseFloat();
    //Serial.read();               // you may need!
    Serial.print("pH = ");
    Serial.println(pH, 2);
  }
}

In my last post I described how I solved this and put up some code. Its funny though because the first two times through the loop the pH returns a 0 but after that it works flawlessly. Which I can live with if that's the best I can do. Any thoughts on that?

You may like to try the second example in Serial Input Basics. It should be able to receive junk and display it. There is also a parse example for when you get good data.

...R