Pages: [1]   Go Down
Author Topic: Serial input manipulation  (Read 1043 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

My goal is to end a process when the PH reaches a certain level. I have a PH probe attached to a PH stamp, that inputs into the arduino through the serial input. I am using a arduino Uno. The serial Ph comes in this format XX.XX. I am having trouble manipulating this to a point that i can use it as a integer or just use a set of switch states. Here is what i have so far.

Code:
String PH_V="";
  if(Serial.available() > 3) //if we see the more than three bytes have been received by the Arduino
  {
    holding=Serial.available();//lets read how many bytes have been received
    // lcd.print(Serial.read());
        lcd.setCursor(0, 1);
        lcd.print("PH");
        lcd.setCursor(2, 1);
       
    for(i=1; i <= holding;i++){                 
      stamp_data[i]= Serial.read();     
      //we make a loop that will read each byte we received
      //and load that byte into the stamp_data array
      if (stamp_data[i] != 13) //13 being the break between ph
        {
       
          PH_V = stamp_data[i];
         
       
        }
        else
        {
          lcd.setCursor(0,0);
          lcd.print(PH_V);
          lcd.setCursor(2,1);
          holding = i;
          Serial.flush();
          PH_V = PH_V.replace(".","");//remove the . so just the numbers remain
          lcd.print(ph_convert(PH_V));
          String PH_V="";


String ph_convert(String PH){
  length = PH.length();
  if(length == 4){
   first = (PH.charAt(1)-48)*1000;
   second = (PH.charAt(2)-48)*100;
   third = (PH.charAt(3)-48)*10;
   fourth = PH.charAt(4)-48;
  }
  else{
    first=0;
    second = (PH.charAt(1)-48)*100;
    third = (PH.charAt(2)-48)*10;
    fourth = PH.charAt(3)-48;
    }
  return PH_R = first+second+third+fourth;

This was my attempt to convert the string to a int. It didn't work, so any advice would be great.


Moderator edit: [code] [/code] tags added.
« Last Edit: May 04, 2012, 08:04:56 am by rburnham87 » Logged

Offline Offline
Edison Member
*
Karma: 9
Posts: 1018
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Let's start to tell us more:
  • Which PH stamp do you use, a link would be nice.
  • What is the exact format, is it "XX.XX\r" ? (Carriage Return = 13 = '\r').
  • What is the baudrate?
  • How does the PH stamp know when to send it's data, by a command ?
  • How do you use the Arduino, if the serial connection is used for the PH stamp. Can you upload a schematic?
  • Why do you use the Serial.flush() ?

Your code is hard to read for me, because of the String class and your code.
Since the format of the string is known, you could use a character array.
You better use a seperate function, this makes debugging a lot easier.

Code:
// Example code, not tested yet.
// It used old-style code.

setup()
{
  initPH();
}

loop()
{
  int ph, error;
  char buffer[40];

  error = getPH (&ph);
  if (error == 0)
  {
    itoa(ph, buffer, 10);          // itoa, or sprintf, or something else.
    lcd.setCursor(0,0);
    lcd.print(buffer);
  }
}

void initPH(void)
{
  Serial.begin(???);         // ??? is baudrate
}

// getPH returns an error, and writes the PH value to the integer.
int getPH(int *phvalue)
{
  char buffer[10];       // 10 should be enough to hold data
  int error = 0;            // start with no error.

  // clear the buffer for any characters we don't want.
  while (Serial.available() > 0)
    Serial.read();

  Serial.print ("????????");      // send command to PH stamp to sends its data ???????

  // Here comes the real code to convert the string
  // A timeout could be added later
  for (i=0; i<6; i++)
  {
    while (Serial.available() == 0)
    {
      // some timeout here, for now, just an empty statement.
      ;
    }
    buffer[i] = Serial.read();
  }

  // Check the format
  if (buffer[2] == '.' && buffer[5] == '\r')
  {
    *ph = (buffer[0] * 1000) + (buffer[1] * 100) + (buffer[3] * 10) + (buffer[4]);
  }
  else
  {
    error = 2;
    *ph = 0;
  }

  return (error);
}


Perhaps you use a programmer to upload your program, and use the LCD for debug output? That's a good solution. If you use it like that, I'm beginning to understand your code.
« Last Edit: May 03, 2012, 05:16:10 am by Krodal » Logged

Germany
Offline Offline
Faraday Member
**
Karma: 57
Posts: 3001
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I understand CR (13) is the only delimiter between two values and the rest is only digits and a decimal dot.

IMO, it's easier not to use a String variable, but implement something like Nick's State machine (http://gammon.com.au/serial)
Should be even easier than there: interpret the characters as they come and update an intermediate numeric value, do final processing the number after the 5th character or when the delimiter arrives. Receiving the delimiter initializes the intermediate value.

The real issues are, how to sync initially, and how to handle unexpected data.
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 610
Posts: 49048
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Did that mess that you posted even compile? I didn't think so. You can NOT nest one function (ph_convert) inside another one.

Code:
    for(i=1; i <= holding;i++){                 
      stamp_data[i]= Serial.read();     
Array indices start at 0, not 1.

Code:
          Serial.flush();
Get rid of this. Period. Clearly, you have no idea what this does.

Code:
          PH_V = stamp_data[i];
PH_V, whatever it is, will only ever contain one character.
Logged

Central MN, USA
Offline Offline
Tesla Member
***
Karma: 73
Posts: 7188
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You are facing a simple task. Collect characters until you find a new line. Once a new line is found, look at what you got and get a number out of it. Think about how to do part one and part two only needs one line. I'll be waiting gift part one answer before I give out part two answer.
Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

OK sorry for the lack of info. The ph stamp if from Atlas Scientific http://atlas-scientific.com/product_pages/embedded/ph.html. It connects to the arduino through the Tx and the Rx I/Os. It runs at a 34800 Baud rate and the format is XX.XX\r or it can be X.XX\r depending on the actual PH. I have an lcd screen attached for readouts and debugging. There are a few other elements to this code but those aspects work. The code for setting up the stamp if example code from Atlas and it is done first. After that it is continually fed into the arduino. That's why I flush the buffer after I get a full ph value. This seams like a good way to do it but idn if its efficient or not. After the stamp is setup I go into my main loop where I start up my other hardware and start checking the ph. Once the PH reaches a certain point i want to sample it. With enough samples meeting the PH requirements I know I can stop my test. I worked on the code some last night and fixed a lot of errors I had. It will compile now. Thank you for the great advice and I've made some changes. Thank you



Code:
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 6);


//RX|TX
//setup and rename soft uart.
char stamp_data[15];
byte holding; //used to tell us the number of bytes that have been received by the Arduino and are
//holding in the buffer holding
byte i;
byte startup=0;
char in_Data_ph[24];

//counter
//used to control the start-up sequence
//Set up the Ph string to CHAR converter
int ph;
int PH_R;
void setup() {
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  lcd.print("Starting Up");
  Serial.begin(38400);
 
}     
//set up the hardware serial port to run at 38400
void loop() {          //main loop

  startup_PH();
 
 
  char PH_V[15];
  if(Serial.available() > 3) //if we see the more than three bytes have been received by the Arduino
  {
    holding=Serial.available();//lets read how many bytes have been received
    // lcd.print(Serial.read());
        lcd.setCursor(0, 1);
        lcd.print("PH");
        lcd.setCursor(2, 1);
       
    for(i=0; i < 6;i++){                 
      stamp_data[i]= Serial.read();
    }
 
   
      if (stamp_data[2] == '.' && stamp_data[5] == '\r') //if format is XX.XX
        {
         ph = (stamp_data[0] * 1000) + (stamp_data[1] * 100) + (stamp_data[3] * 10) + (stamp_data[4]);
         }
      if (stamp_data[2] == '.' && stamp_data[5] == '\r') //if format is X.XX
        {
         ph =(stamp_data[1] * 100) + (stamp_data[3] * 10) + (stamp_data[4]);
         }
          lcd.print(ph);
         
         
       
     // for(i=1; i <= 6;i++){ 
    //    String stringTwo = stringTwo + stamp_data[i];
    //    lcd.print(stringTwo);
    //  }
   
        delay(500)   ;         
     
      //Serial.println("");                               
    }
   // lcd.setCursor(6,1);
 //   ph_val = atof(in_Data_ph);
  //  lcd.print(ph_val);
  }



//Startup the PH stamp
int startup_PH(){
  if(startup==0){          //if the start-up sequence has not been run                       
    for(i=1; i <= 2;i++){  //we go through this for-loop twice, turning on/ off the stamp leds                     
      delay(1000);       //wait 1 second                       
      Serial.print("l0");  //turn off the led               
      Serial.print(13);   //ALWAYS end a command with <CR> (which is simply the number 13) or // (print("/r")     
      delay(1000);            //wait 1 second                 
      Serial.print("l1");     //turn on the led     
      Serial.print(13);     
    }
    startup=1; //stop the star-up loop from happening by setting the start-up var to 1
    delay(1000);     //after the stamp leds flashed twice, lets wait 1 second before we give the
    // stamp a new command
    Serial.print("c");                 
    Serial.print(13);//ALWAYS end a command with <CR> (which is simply the number 13) or//(print("/r")
    lcd.clear();
  }
}[\code]
« Last Edit: May 04, 2012, 08:06:19 am by rburnham87 » Logged

Central MN, USA
Offline Offline
Tesla Member
***
Karma: 73
Posts: 7188
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

well, if you say it works...
Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

It compiles, I still need to actually test the hardware.
Logged

Offline Offline
Edison Member
*
Karma: 9
Posts: 1018
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The PH circuit comes with sample code for the Arduino. Why not use that?
They use the normal serial connection for the Arduino to the computer. And they have two pins which are used as software serial pins. That's a good solution.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I would use that sample code if I was looking to use the computer to crunch the numbers. But I want it be  stand alone. So i need to get the serial input into a format that I can use normally.
Logged

Offline Offline
Edison Member
*
Karma: 9
Posts: 1018
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Well, it's an example to get the data from the sensor.
Changing it into an other format is just an extra function you could add.
« Last Edit: May 04, 2012, 04:25:12 pm by Krodal » Logged

Central MN, USA
Offline Offline
Tesla Member
***
Karma: 73
Posts: 7188
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I can see that you have changed how you read your data now, but still quite wrong. You should pay attention to what I described in the simple "Collect characters until you find a new line" rule, which is the only way to understand data the way it is sent. This means, no FOR LOOPS! Should I rephrase "Collect characters WHILE you DON'T find a new line" as a hint what loop you should use?
Logged


Pages: [1]   Go Up
Jump to: