Arduino TTL Oxygen Sensor Help

Hey, (disclaimer: I am relatively new to arduino and especially this forum)

I am attempting to use this oxygen sensor (http://sstsensing.com/product/luminox-optical-oxygen-sensor) with an arduino uno using a modified version of the ‘software serial’ example. I realized that the sensor uses 3.3V logic and the arduino uses 5V logic so I am also using this logic shifter (http://www.adafruit.com/products/757). Wiring wise, I’m 95% confident I am good and have checked it with a multimeter, but I am having zero luck with communicating with the sensor. Like I said I am very new to this stuff so I hope I am making a very obvious mistake. When I run the code below and open the serial monitor, I always get the y double prime outputting a char or 255 outputting a byte. The data sheet for the sensor seems very detailed as well.

Thanks in advance! This is driving me nuts! =(

#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX

void setup()  
{
  // Open serial communications and wait for port to open:
  Serial.begin(9600);

  mySerial.begin(9600);

}

void loop() // run over and over
{
  mySerial.print("0x4F 0x0D 0x0A");
  

    char data = mySerial.read();
    Serial.print(data);   
    delay(1000);
}

I always get the y double prime outputting a char or 255 outputting a byte.

That's what happens when you read a character that hasn't arrived yet. See if Serial.available () helps at all.

Hello Grchrin

The datasheet includes the following comment ...

Stream Mode (M 0): By default stream mode is initiated on sensor power-up and will supply an output string approximately once every second. This pro-vides the data for ppO2 , Temperature, Pressure, O2 and Sensor Status. The format is provided below, for more details on the Argu-ment see Table 2. ? “O xxxx.x T yxx.x P xxxx % xxx.xx e xxxx\r\n”

So without your program needing to send any commands, you should see a string of characters every second.

As a first test, therefore, try replacing your loop() function with this ...

void loop()
{
  if (mySerial.available())
  {
     Serial.write(mySerial.read());
   }
}

This will pass any characters received from the sensor straight through to the serial monitor.

Let us know if that works. If it does, and you need to send commands to the sensor as well, then there are some other changes needed in your current program on that side of things.

Regards

Ray

Thank you very much for you response!!

I tried your modified code and unfortunately nothing is getting printed to the monitor now. Maybe I modified the default somehow accidentally? How would I go about correctly putting it back into poll mode?

Again, I really appreciate your responses!

Greg

mySerial.print("0x4F 0x0D 0x0A");

should be

mySerial.write(0x4F); mySerial.print(0x0D); mySerial.print(0x0A);

to work

best served wrapped in a function

void getOxygen()
{
  mySerial.write('O'); 
  mySerial.write('\r');  
  mySerial.write('\n'); 
}

or simpler

void getOxygen()
{
  mySerial.print("O\r\n");
}

How would I go about correctly putting it back into poll mode?

To put it into poll mode, modify Rob's code to send 5 characters:

mySerial.print("M 1\r\n");

There is a space after the M.

Or for stream mode, send these characters:

mySerial.print("M 0\r\n");

That's a zero.

If you still have problems, please post a diagram of how the Arduino / level converter / sensor are connected.

Still no luck guys, but appreciate the help. I am starting to question my logic shifter connections. I posted a picture outlining how its hooked up. I have 5V and Gnd connected to the sensor as instructed, then the Rx of the sensor going to the Tx of arduino and vise versa. I’m starting to wonder if I damaged something =( =(

The GND of the sensor needs to connect to the Arduino GND.

Are you powering the sensor +5V from the Arduino?

I am starting to question my logic shifter connections.

You could eliminate the logic converter for testing as follows.

Assuming the data sheet is correct, powering off and on the sensor will put it in stream mode, sending out a line of data every second.

Although the serial interface is 3.3V, that is enough for an Arduino input to recognise as a high.

So, you can connect sensor pin 3 (transmit) directly to Arduino pin 10 (which you have defined as receive).

Don't connect anything to sensor receive pin.

Then you could try the minimal code in reply #2 again.

Okay it's working! Right now just in stream mode using the one connection but that is all I need for now, I cannot express enough gratitude, thanks! :) :) :)

can you post some output?

Hello I also bought the senor to monitor a biotechnological fermentation . Is it possible to write a single value e.g. oxygen or temperature in a row?
I tried

mySerial.write(0x4F);
mySerial.print(0x0D);
mySerial.print(0x0A);

but no response.

with the code from you:

#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX

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

}

void loop()
{
if (mySerial.available())
{
Serial.write(mySerial.read());
}
}

I get O 0201.1 T +28.5 P 0984 % 020.44 e 0000

Hello: Newbie here; I wrote the following to read from this LuminOx-02 oxygen sensor at 5 minute intervals. The sensor outputs a data string every second (stream mode). The output works, but the second output line becomes messed up, and the output string is broken into two thereafter. Any help in cleaning up the code or indications as to where I am messing up will be greatly appreciated. Thanks!

The reason for trying to collect once every 5 minutes: I am trying to use the sensor in a cancer research experiment that runs for 72 hours, where the cancer cells are exposed to low oxygen (this mimics the oxygen conditions the tumor is exposed to, inside the body). Collecting data every second just fills up the serial monitor I use to collect data (CoolTerm) and I have to wade through pages of code to extract the data at 5 minute intervals.

#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX

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

void loop()
{
for (byte x = 0; x < 41; x++)
if (mySerial.available())
Serial.write(mySerial.read());
delay(300000);
while(Serial.available() > 0)
Serial.read();
}

The output looks like;

O 0202.1 T +24.9 P 0979 % 020.64 e 0000
O 0202.1 T +24.9 P 097O 0202.1 T +25.0 P 0979 % 020.64 e 0000
O 0202.1 T +24.9 P 0979 % 020.64 e 0000
O 0202.1 T +24.9 P 0979 % 020.64 e 0000
O 0202.1 T +24.9 P 0979 % 020.64 e 0000
O 0202.1 T +24.9 P 0979 % 020.64 e 0000
O 0202.1 T +24.9 P


As PhilippS has described before, if the code

void loop()
{
if (mySerial.available())
Serial.write(mySerial.read());
}

is used, the correct output

O 0201.1 T +28.5 P 0984 % 020.44 e 0000
O 0201.1 T +28.5 P 0984 % 020.44 e 0000
O 0201.1 T +28.5 P 0984 % 020.44 e 0000

is printed. But, it is printed each second as the output from the sensor is per second. I am trying to get the output each 5 minutes and flush everything in between. Thanks.

for (byte x = 0; x < 41; x++)
  if (mySerial.available())
  Serial.write(mySerial.read());

41 times, look to see if there is serial data to read. If so, read it. How many of those 41 times do you suppose that there WILL be serial data? If you REALLY expect 41 bytes EXACTLY, you are dreaming. Oh wait, I mean that you need to WAIT for the data to arrive. While you are waiting, ponder this. Serial data is NOT guaranteed to be delivered. It can be corrupted and discarded. It can get lost.

Thanks. I have tried;

for (int x = 0; x <41; x++)
if (mySerial.available())
Serial.write(mySerial.read()); as well, but the output is the same.

According to manufacturer datasheet, the output per second (per string) will be
“O xxxx.x T yxx.x P xxxx % xxx.xx e xxxx\r\n”

When I counted the bytes between each incoming string (on CoolTerm) it was 40; thus the reason I tried 41. It works with 41 (either int or bytes). But, 40 or less breaks the string. More than 41 adds to the data string from the next line.

Yes, but that code attempts to read 41 times. It does it so fast that there is unlikely to be another character arrived, so it will fail on most of those attempts. It doesn’t retry any failed attempt.

Wait.

for (int x = 0; x <41; x++) {
  while(!mySerial.available()) {
    //do nothing - wait
  }
  Serial.write(mySerial.read());  
}

have a look at the blink without delay example:

only if 5 minutes have passed check the serial

if (millis() - lastTime > (5*60*1000UL)) { read serial until newline; read a complete line print the line

lastTime = millis(); }

Thanks Rob and Morgan! I tried both recommendations, but it seems to be a serial data dump issue. If I leave the delay (or interval) at 1000 ms everything works perfect - one complete string of data per line. But for a delay any larger, I get the messed up second line and then the staggered strings thereafter. I think I will live with it. All I will need to do at the end of the 72 hour experiment is to edit the second line to remove extra bit of serial data that came in, and the last half string of data at the bottom (unfortunately, not exactly scientific; but, neither partial-string involves the oxygen concentration data).

I modified the program as follows to utilize the Millis command; at least I learned to use that, and the command (!mySerial.avaialble()) - this latter did not give a serial read for some reason - I think I need to get more familiar with the ! command.

Thanks again!


#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX

long previousMillis = 0;
long interval = 300000;

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

void loop()
{
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval){
previousMillis = currentMillis;

for (int x = 0; x < 41; x++)
if(mySerial.available())
Serial.write(mySerial.read());
{
while(Serial.available() > 0)
Serial.read();
}
}}

Properly placing the open and close curly braces, and adding the missing ones, your loop() looks like this:

void loop()
{
   unsigned long currentMillis = millis();
   if(currentMillis - previousMillis > interval)
   {
      previousMillis = currentMillis;
 
      for (int x = 0; x < 41; x++)
      {
         if(mySerial.available())
         {
            Serial.write(mySerial.read());
         }
      }

      {
         while(Serial.available() > 0)
         {
            Serial.read();
         }
      }
   }
}

So, first, one useless set of curly braces, around the block that dumps random amounts of unread data. Why you think that is necessary is a complete mystery.

So, loop() is called. You iterate 41 times, looking to see if there is anything to read. On the first call to available(), there might be or there might not be data to read. If there is, you read that one byte. Then, the rest of the for loop iterates so fast that it is done before the next byte has arrived.

Then, you dump any unread data. At most, one byte will have arrived, and be dumped.

Then, loop() iterates again, where maybe nothing useful happens. Maybe one byte arrives and is stored in the array. Maybe one byte arrives and gets dumped.

You NEVER read 41 bytes - not even close!

Get this through your head: Serial data arrives sssslllloooowwwwllllyyyy!

Once you get that, you’ll understand that you can NOT use a for loop to read it. You MUST use a global or static local variable to keep track of how many bytes you have read, and use that variable as an index into the array you store the data in.