Problem with while loop of serial Buffer?

I have been trying to piece together a program from several different examples to create a device that adjusts the pH of a water sample. So far it has become rather cantankerous and ineffective. First of all, I would appreciate any suggestions to clean it up which might solve my problem. My problem is in “case 8” of the main loop which is activated by a button press on analog pin A0. The problem is that the while loop doesn’t seem to execute. If possible, please point me towards a better way to handle the serial data being passed between the Arduino and the pH sensor board which responds to specific characters (r,c,e,t,) followed by a carriage return. Is the getPh function call wrong? Is the while loop properly set up? it seems that once the sensor board is given the “c” command in line 109 (continuous readings taken every ~265 millis), the Arduino just transfers the mySerial data as dictated by the “if (sensor_stringcomplete)…” found towards the end of the main loop (line 148). Is there a better way to approach the logic behind this? Here is the datasheet for the ph board: http://atlas-scientific.com/_files/legacy/ph/pH_Circuit_3.1.pdf. Much thanks in advance. - Sean

  #include <SoftwareSerial.h>
  #include <LiquidCrystal.h>
  #include <OneWire.h>
  #define rxpin 12
  #define txpin 11  

  SoftwareSerial mySerial(rxpin, txpin);
  LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
  String inputstring ="";
  String sensorstring ="";
  boolean input_stringcomplete = false;
  boolean input_stringtemp = false;
  boolean sensor_stringcomplete = false;
  const int sensorPin = A0;
  const int pumpPin = 9;
  const int ledPin = 13;
  const int sensorMin = 0;      // sensor minimum, discovered through experiment
  const int sensorMax = 1023;
  const unsigned int MAX_INPUT = 50;
  int sensorValue = 0;
  int DS18S20_Pin = 10;
  float pHtarget = 5.8;
 

  OneWire ds(DS18S20_Pin);
  
  
  
  void setup(){
    lcd.begin(16, 2);
    Serial.begin(38400);
    mySerial.begin(38400);
    inputstring.reserve(5);
    sensorstring.reserve(30);
    pinMode(9, OUTPUT);
    pinMode(13, OUTPUT);
  }
  
  
  void serialEvent() {
    char inchar = (char)Serial.read();
    inputstring += inchar;
    if(inchar == '\r') {input_stringcomplete = true;}
    if(inchar == 't') {input_stringtemp = true;}
  }
  
  void loop(){
     
    sensorValue = analogRead(sensorPin);
    
    int range = map(sensorValue, sensorMin, sensorMax, 0, 9);
    delay(500);
    switch (range) {
      case 0:                                 //0-102
        break;
      case 1:                                // 54k ohm - 175
      Serial.print(sensorValue);
        Serial.println("Reading Probe...");
        mySerial.print("r");
        mySerial.print('\r');
        lcd.print("Reading Probe...");
        delay(500);
        lcd.clear();
        break;
      case 2:    // 205-306
        Serial.println("0");
        break;
      case 3:    // 307-409 18.5k ohm 378
        Serial.println("Continuous READ");
        mySerial.print("c");
        mySerial.print('\r');
        
        delay(500);
        lcd.clear();
        break;
      case 4:    // 410-511
        break;
      case 5:    // 512-613 8.5k ohm 579
        Serial.println("Exit");
         mySerial.print("e");
         mySerial.print('\r');
        lcd.print("exit");
        delay(500);
        lcd.clear();
        break;
      case 6:    // 614-716 5.5k ohm 682
        Serial.println("Calibration: Seven"); 
         mySerial.print("s");
         mySerial.print('\r');
        lcd.print("Cal. SEVEN");
        delay(500);
        lcd.clear();
        break;
        
      case 7:    // 717-818 3k ohm 807
        Serial.println("Calibration: Four");
         mySerial.print("f");
         mySerial.print('\r');
        lcd.print("Cal. FOUR");
        delay(500);
        lcd.clear();
        break;
      case 8:    // 819-920 1.2k ohm 913
        {
          Serial.println("ph adjust");
          mySerial.print("c");
          mySerial.print('\r');
          float phValue = getPH();
          while (phValue > pHtarget){ 
             Serial.println (phValue);
             lcd.println (phValue);          
             digitalWrite(pumpPin, HIGH);
             delay(100);
             digitalWrite(pumpPin, LOW);
             delay(2000);
             lcd.clear();
             if (phValue <= pHtarget){
                break;
                digitalWrite(ledPin, HIGH);
             } // end of if
          } // end of while
          mySerial.print("e");
          mySerial.print('\r');
        break; // end of case 8
      } 
      case 9:    // 921-1023 0 ohm 
        Serial.println("auto");
        break;
        
    } 
    
    
    if (input_stringtemp){
      float temperature = getTemp();
      lcd.print(temperature);
      Serial.println(temperature);
      mySerial.print(temperature);
      delay(750);
      lcd.clear();
      inputstring = "";
      input_stringtemp = false;
      }
      
    else if (input_stringcomplete){
      mySerial.print(inputstring);
      lcd.print(inputstring);
      delay(750);
      lcd.clear();
      inputstring = "";
      input_stringcomplete = false;
    }
   
  }// end of main loop
  
  float getPH (){
   char input_line [MAX_INPUT];
  static unsigned int input_pos = 0;

  if (mySerial.available () > 0) 
    {
    char inByte = mySerial.read ();

    switch (inByte)
      {

      case '\r':   // end of text                 
        {
        input_line [input_pos] = 0;  // terminating null byte
        char * data = input_line;
        float pHmeasurement = atof(data);
        return pHmeasurement;
        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

   float getTemp(){
      //returns the temperature from one DS18S20 in DEG Celsius

      byte data[12];
      byte addr[8];

      if ( !ds.search(addr)) {
          //no more sensors on chain, reset search
          ds.reset_search();
          return -1000;
      }

      if ( OneWire::crc8( addr, 7) != addr[7]) {
          Serial.print("CRC is not valid!\n");
          return -1000;
      }

      if ( addr[0] != 0x10 && addr[0] != 0x28) {
          Serial.print("Device is not recognized");
          return -1000;
      }

      ds.reset();
      ds.select(addr);
      ds.write(0x44,1); // start conversion, with parasite power on at the end

      byte present = ds.reset();
      ds.select(addr);   
      ds.write(0xBE); // Read Scratchpad

     
      for (int i = 0; i < 9; i++) { // we need 9 bytes
        data[i] = ds.read();
      }
     
      ds.reset_search();
     
      byte MSB = data[1];
      byte LSB = data[0];

      float tempRead = ((MSB << 8) | LSB); //using two's compliment
      float TemperatureSum = tempRead / 16;
     
      return TemperatureSum;
     
    }
float getPH (){
  char input_line [MAX_INPUT];
  static unsigned int input_pos = 0;

  if (mySerial.available () > 0) 
  {
    char inByte = mySerial.read ();
...
  }  // end of incoming data
}  // end of function

If there is no serial data then getPH exits without returning any value.

          float phValue = getPH();
          while (phValue > pHtarget){ 
             Serial.println (phValue);
             lcd.println (phValue);          
             digitalWrite(pumpPin, HIGH);
             delay(100);
             digitalWrite(pumpPin, LOW);
             delay(2000);
             lcd.clear();
             if (phValue <= pHtarget){
                break;
                digitalWrite(ledPin, HIGH);
             } // end of if
          } // end of while

There is no call to getPh() inside the while loop. The phValue variable will never change.

          float phValue = getPH();
          while (phValue > pHtarget){ 
             Serial.println (phValue);
             lcd.println (phValue);          
             digitalWrite(pumpPin, HIGH);
             delay(100);
             digitalWrite(pumpPin, LOW);
             delay(2000);
             lcd.clear();
             phValue = getPH();
          } // end of while

is how you should construct your While loop.

Take a look at my Introduction to Programming: The While Loop tutorial for an explanation on how to properly use while.

In your getPH() function you are only reading one character.

You have, essentially:

  1. Read characher.
  2. Decide what to do with character: 2.1. If return character, calculate value and retrun. 2.2. Other character, add to string.
  3. End function.

You read the first character, then just finish. You're never going to get a PH value.

Instead of an "if serial character available" you need a "while serial character is available" so it will loop through until it finds the \r.

Thank for the helpful information. After making the suggested changes to the while loop and the getPH() function, I noticed that I had to hold the button down for a second for the while loop to execute. Below is the output from the serial monitor.

7.01 7.00 7.05

174Reading Probe... 7.01

ph adjust // 1st button press 7.07

7.07

7.03 7.00 7.05

7.07 7.05

ph adjust // button hold 7.01 7.01 7.01 7.01

The first button press is represented by the the first instance of " ph adjust". at this point the pump is not running; arduino is just taking readings. Then I held the button down and the while loop appears to execute (pump switches on and off), but the ph measurement does not update even after I made the changes. Any other suggestions, constructive criticism, or tutorials?

Can we see your new code? It would help to see where you have placed various function calls, and where you have any delay() calls.

I realized last night that I think all of the delays () were causing problems, so i am in the process of replacing them and adding an analog switch debounce. will post that later today. but here are the changes i made yesterday:

  #include <SoftwareSerial.h>
  #include <LiquidCrystal.h>
  #include <OneWire.h>
  #define rxpin 12
  #define txpin 11  

  SoftwareSerial mySerial(rxpin, txpin);
  LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
  String inputstring ="";
  String sensorstring ="";
  boolean input_stringcomplete = false;
  boolean input_stringtemp = false;
  boolean sensor_stringcomplete = false;
  const int sensorPin = A0;
  const int pumpPin = 9;
  const int ledPin = 13;
  const int sensorMin = 0;      // sensor minimum, discovered through experiment
  const int sensorMax = 1023;
  const unsigned int MAX_INPUT = 50;
  int sensorValue = 0;
  int DS18S20_Pin = 10;
  float pHtarget = 5.8;
 

  OneWire ds(DS18S20_Pin);
  
  
  
  void setup(){
    lcd.begin(16, 2);
    Serial.begin(38400);
    mySerial.begin(38400);
    inputstring.reserve(5);
    sensorstring.reserve(30);
    pinMode(9, OUTPUT);
    pinMode(13, OUTPUT);
  }
  void process_data (char * data)
  { // for now just display it
  Serial.println (data);
  }
  
  void serialEvent() {
    char inchar = (char)Serial.read();
    inputstring += inchar;
    if(inchar == '\r') {input_stringcomplete = true;}
    if(inchar == 't') {input_stringtemp = true;}
  }
  
  void loop(){
     if (input_stringtemp){
      float temperature = getTemp();
      lcd.print(temperature);
      Serial.println(temperature);
      mySerial.print(temperature);
      delay(750);
      lcd.clear();
      inputstring = "";
      input_stringtemp = false;
      }
      
    else if (input_stringcomplete){
      mySerial.print(inputstring);
      lcd.print(inputstring);
      delay(750);
      lcd.clear();
      inputstring = "";
      input_stringcomplete = false;
    }
   while (mySerial.available()){     
      char inchar = (char)mySerial.read();
      sensorstring += inchar;
      if (inchar=='\r'){sensor_stringcomplete = true;}
  }
    if (sensor_stringcomplete){
      Serial.println(sensorstring);
      lcd.print(sensorstring);
      delay(750);
      lcd.clear();
      sensorstring = "";
      sensor_stringcomplete = false;
    }
    sensorValue = analogRead(sensorPin);
    
    int range = map(sensorValue, sensorMin, sensorMax, 0, 9);
    delay(500);
    switch (range) {
      case 0:                                 //0-102
        break;
      case 1:                                // 54k ohm - 175
      Serial.print(sensorValue);
        Serial.println("Reading Probe...");
        mySerial.print("r");
        mySerial.print('\r');
        lcd.print("Reading Probe...");
        delay(500);
        lcd.clear();
        break;
      case 2:    // 205-306
        Serial.println("0");
        break;
      case 3:    // 307-409 18.5k ohm 378
        Serial.println("Continuous READ");
        mySerial.print("c");
        mySerial.print('\r');
        
        delay(500);
        lcd.clear();
        break;
      case 4:    // 410-511
        break;
      case 5:    // 512-613 8.5k ohm 579
        Serial.println("Exit");
         mySerial.print("e");
         mySerial.print('\r');
        lcd.print("exit");
        delay(500);
        lcd.clear();
        break;
      case 6:    // 614-716 5.5k ohm 682
        Serial.println("Calibration: Seven"); 
         mySerial.print("s");
         mySerial.print('\r');
        lcd.print("Cal. SEVEN");
        delay(500);
        lcd.clear();
        break;
        
      case 7:    // 717-818 3k ohm 807
        Serial.println("Calibration: Four");
         mySerial.print("f");
         mySerial.print('\r');
        lcd.print("Cal. FOUR");
        delay(500);
        lcd.clear();
        break;
      case 8:    // 819-920 1.2k ohm 913
        {
          Serial.println("ph adjust");
          mySerial.print("c");
          mySerial.print('\r');
          float phValue = getPH();
          while (phValue > pHtarget){ 
             Serial.println (phValue);
             lcd.println (phValue);          
             digitalWrite(pumpPin, HIGH);
             delay(100);
             digitalWrite(pumpPin, LOW);
             delay(2000);
             lcd.clear();
             float phValue = getPH();
             
             } // end of while
          if (phValue <= pHtarget){
             digitalWrite(ledPin, HIGH);
          }
          mySerial.print("e");
          mySerial.print('\r');
        break; // end of case 8
      } 
      case 9:    // 921-1023 0 ohm 
        Serial.println("auto");
        break;
        
    } 
    
    
    if (input_stringtemp){
      float temperature = getTemp();
      lcd.print(temperature);
      Serial.println(temperature);
      mySerial.print(temperature);
      delay(750);
      lcd.clear();
      inputstring = "";
      input_stringtemp = false;
      }
      
    else if (input_stringcomplete){
      mySerial.print(inputstring);
      lcd.print(inputstring);
      delay(750);
      lcd.clear();
      inputstring = "";
      input_stringcomplete = false;
    }
   while (mySerial.available()){     
      char inchar = (char)mySerial.read();
      sensorstring += inchar;
      if (inchar=='\r'){sensor_stringcomplete = true;}
  }
    if (sensor_stringcomplete){
      Serial.println(sensorstring);
      lcd.print(sensorstring);
      delay(750);
      lcd.clear();
      sensorstring = "";
      sensor_stringcomplete = false;
    }
  }// end of main loop
  
  float getPH (){
   char input_line [MAX_INPUT];
  static unsigned int input_pos = 0;

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

    switch (inByte)
      {

      case '\r':   // end of text                 
        {
        input_line [input_pos] = 0;  // terminating null byte
        char * data = input_line;
        float pHmeasurement = atof(data);
        return pHmeasurement;
        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

   float getTemp(){
      //returns the temperature from one DS18S20 in DEG Celsius

      byte data[12];
      byte addr[8];

      if ( !ds.search(addr)) {
          //no more sensors on chain, reset search
          ds.reset_search();
          return -1000;
      }

      if ( OneWire::crc8( addr, 7) != addr[7]) {
          Serial.print("CRC is not valid!\n");
          return -1000;
      }

      if ( addr[0] != 0x10 && addr[0] != 0x28) {
          Serial.print("Device is not recognized");
          return -1000;
      }

      ds.reset();
      ds.select(addr);
      ds.write(0x44,1); // start conversion, with parasite power on at the end

      byte present = ds.reset();
      ds.select(addr);   
      ds.write(0xBE); // Read Scratchpad

     
      for (int i = 0; i < 9; i++) { // we need 9 bytes
        data[i] = ds.read();
      }
     
      ds.reset_search();
     
      byte MSB = data[1];
      byte LSB = data[0];

      float tempRead = ((MSB << 8) | LSB); //using two's compliment
      float TemperatureSum = tempRead / 16;
     
      return TemperatureSum;
     
    }

Inside the while() you have:

float phValue = getPH();

That re-defines phValue as local to the while() loop I think. Drop the "float" part of it so it modifies the existing one.