pH/ORP stamp using UART port

Greetings,

I have recently discovered these pH and ORP stamps made by Atlas-Scientific: https://www.atlas-scientific.com/Embedded_Solutions.html

They seem to work as RS232 using low voltage so no need for any interfacing with an Arduino UART ports.

Where I am a bit confused is the data reading part. It looks like the temperature argument needs to be passed for a temperature corrected pH value; i.e. read(26.5) where 26.5 is the temperature in Celsius.

Would a line like this work with the serial library:
val_pH = Serial.read(26.5) ???

cheers,
Marian

Would a line like this work with the serial library:
val_pH = Serial.read(26.5) ???

No. The Serial.read() function does not take any arguments. It simply reads whatever is on the serial port.

You send the device commands, like "read(someTemp)" using Serial.print() assuming that you have the device connected to the serial port pins. It responds with character data that you read using Serial.read(), one character at a time.

They seem to work as RS232 using low voltage so no need for any interfacing with an Arduino UART ports.

A serial device without the need to use the serial port. How's that working for you?

Paul many thanks.

what I meant with no need for interfacing was no need for the typical 12V RS232 levels and the involvement of a MAX circuit to adjust.

here is the set of instructions that this stamp has:
https://www.atlas-scientific.com/00_other/pHStampManual.pdf

Would you help me with a simple skatch exemple ?

Thank you very much,
Marian

The device communicates via the serial port.

Serial.println("led(on)"); // turn the LED on

Serial.println("read(22.0)"); // Read the pH level assuming temp is 22.0 degrees

Once you've told the sensor to do something, you need to read it's reply.

char inData[24];
byte index = 0;
while(Serial.available() > 0 && index < 24)
{
   inData[index] = Serial.read();
   index++;
   inData[index] = '\0';
}

Then, do whatever you need to with inData.

Paul, many, many thanks.

I do understand your approach. What I don't is why you made inData a 24 positions vector (why 24 ??) and what this line does; inData[index] = '\0';

cheers,
Marian

What I don't is why you made inData a 24 positions vector (why 24 ??)

It needs to be some size. I didn't look at the size of the responses sent back by the sensor, but I don't think they are going to be all that long. If necessary, you can increase the size.

what this line does; inData[index] = '\0';

It adds a NULL to that position in the array (after the last character added). The NULL is necessary to tell the string functions (print(), strlen(), strcmp(), etc.) where the end of the string is.

Hello,

I followed Paul's instructions using this little sketch, but when I run it I get always the same value in the Port Monitor: 16961
What's wrong ?

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

void loop() {
char inData[24];
byte index = 0;
int ORP;
while (Serial.available() && index <24)
{
inData[index] = Serial.read();
index++;
inData[index] = '\0';
ORP = atoi(inData);
}
Serial.println(ORP);
delay(1000);
}

Many thanks,
Marian

You have this code:

void loop() {
  char inData[24];
  byte index = 0;
  int ORP;
  while (Serial.available() && index <24)
 {
   inData[index] = Serial.read();
   index++;
   inData[index] = '\0';
   ORP = atoi(inData);
 }
 Serial.println(ORP);

Suppose that there is no serial data available. I'll explain, in a minute, why this is probably always true.

What does this code do? It prints the value in ORP. What value is in ORP? It's a local variable that is not initialized. So, who knows? It's value is whatever that memory location was last used for.

Local variables are not initialized by default, so YOU must initialize them.

So, why is there no serial data to read? Because you haven't asked the sensor to send you any.

You need to send a request to the sensor, to make it send you a reply.

Paul, thank you very much for your answer.
I have connected the stamp to the Rx/Tx of Arduino and the green led for transmission blinks. I assume somehow serial data is available.

I am not an expert at this (the first time programming for the serial port) so bear with my innocence.

I was under the assumption that the inData cycle will read on bit at a time from the serial device and will store it in this vector. After that I thought that atoi() will convert the char string into a decimal value.
Are all this correct ? Can you please help me understand how to read the ORP from this stamp.

I don't' have the physical ORP probe connected, but the stamp should change the output when the probe pin goes to gnd.

cheers,
Marian

Are all this correct ?

Yes it all are.

Can you please help me understand how to read the ORP from this stamp.

Sure. First, you request information. Then, you read the response. Like this:

Arduino: "Hey, stamp! What is the temperature there?"
Stamp: "The temperature is mighty cold"

You use Serial.print() to send messages to the stamp. You look at the link you provided way back when, to see what messages to send. I'm pretty sure that "Hey, stamp! What is the temperature there?" isn't valid, but the document you linked to does have the correct messages.

Then, the code that you have will listen for a response. That response might be just an integer value as a string, or it might not. You'll probably want to connect the stamp to a different pair of pins, and use NewSoftSerial to talk to it, so you can use the main serial port to talk to the Serial Monitor, to confirm what you get back from the stamp, before you can figure out how to parse the reply.

Paul,

I have tried using your suggestion and my limited knowledge. Still getting 0 on hardware serial monitor. Here is the code:

#include <NewSoftSerial.h>

NewSoftSerial ORP(2, 3);

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

void loop()
{
char inData[24];
int index =0;
int ORP_val = 0;
ORP.println("read()");
while (ORP.available() > 0 && index <24)
{
inData[index] = (char)ORP.read();
index++;
}
ORP_val = atoi(inData);
Serial.println(ORP_val);
}

Can you please help with a suggestion ?

Thank you,
Marian

There is an assumption implicit in this code that may not be true:

while (ORP.available() > 0 && index <24)
  {
    inData[index] = (char)ORP.read();
    index++;
  }
  ORP_val = atoi(inData);

Suppose the sensor returns "temp = 22.5 degrees". That string can't be converted to an int, so atoi return 0.

The first thing that you need to do is confirm what, if anything, is being read from the serial port that the sensor is connected to.

You also need to ULL terminate the array as characters are added, because that is what atoi uses to determine when to stop reading.

while (ORP.available() > 0 && index <24)
  {
    inData[index] = (char)ORP.read();
[glow]    Serial.print("Read from sensor: ");
    Serial.println(inData[index]);
[/glow]    index++;
    [glow]inData[index] = '\0';[/glow]
  }
  [glow]Serial.print("Sensor output: [");
  Serial.print(inData);  Serial.println("]");[/glow]
  ORP_val = atoi(inData);

Well... it works. First for some reasons the NewSoftSerial library is not working or it works kind of randomly. I couldn't figure why.

Here is a copy of the output for pH and ORP with real probes as input:

Sensor output: [ORP= 392.81 mv]
read()c
Sensor output: [ORP= 397.49 mv]
read()c
Sensor output: [ORP= 392.49 mv]
read()c
Sensor output: [ORP= 391.87 mvORP= 392.]
read()c
Sensor output: [49 mvORP= 393.12 mv]
read()c
Sensor output: [ORP= 392.49 mv]
read()c
Sensor output: [ORP= 393.12 mv]

read(26.0)c
Sensor output: [pH=8.02pH=8.01]
read(26.0)c
Sensor output: [pH=8.00]
read(26.0)c
Sensor output: [pH=8.00]
read(26.0)c
Sensor output: [pH=8.00]
read(26.0)c
Sensor output: [pH=8.10pH=8.00]
read(26.0)c
Sensor output: [pH=8.00]

As you can see there are some intermittent glitches. It looks like the '\0' is not present all the time. Should I impose inData[23] = 0 ???

And the biggest problem now (at least for me since I have zero experience handling strings) the stamps for some reason respond prefixing the measurements with "ORP=" and "pH=" followed by the numerical value. How can I extract only the numerical value ?
pH and ORP measurement are not instantaneous measurements they are suppose to be averaged over some time.

Many thanks,
Marian

code:

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

void loop()
{
char inData_pH[24];
int index =0;
float pH_val = 0.0;
Serial.println("read(26.0)c");
delay(1000);
while (Serial.available() > 0 && index < 24)
{
inData_pH[index] = Serial.read();
index++;
inData_pH[index] = '\0';
}

Serial.print("Sensor output: [");
Serial.print(inData_pH); Serial.println("]");
// pH_val = atof(inData_pH);
// Serial.println(pH_val);

}

Ok. Fixed both problems. The stamp now reliably generates float ORP values.

I had to go and extract a substring from inData_ORP after the first null character. Kind of strange.

I have tried also:

float ORP_val;
sscanf(inData_ORP, "%f", ORP_val);
but it didn't work. Would have been a bit simpler.

Here is the code that works:

#include <stdio.h>

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

void loop()
{
char inData_ORP[24];
char string_ORP[8];
int index =0;
float ORP_val = 0.0;
Serial.println("read()c");
delay(750);
while (Serial.available() > 0 && index < 24)
{
inData_ORP[index] = Serial.read();
index++;
}
inData_ORP[index] = '\0';
sscanf(inData_ORP, "%*s %s", string_ORP);
ORP_val = atof(string_ORP);
// Serial.print("Sensor output: [");
// Serial.print(inData_ORP); Serial.println("]");
Serial.print("ORP value: ");
Serial.println(ORP_val);
}