thanks a very lot! I was blind to that and I wonder that I didn't got an error message while compiling.
Changed it to long and now its working again, but still have the problem, that every second read goes wrong.
Oxygen 200.20
Temperature 22.10
Pressure 988
Percent 20.27 correct!
Oxygen 200.30
Temperature 22.00
Pressure 98 wrong
Percent 0.00 wrong
Oxygen 198.50
Temperature 23.70
Pressure 988
Percent 20.09 correct
Oxygen 198.40
Temperature 23.80
Pressure 98 wrong
Percent 0.00 wrong
Oxygen 197.60
Temperature 24.90
Pressure 988
Percent 20.00 correct
Oxygen 197.60
Temperature 24.80
Pressure 98 wrong
Percent 0.00 wrong
found another issue maybe:
The sensor is sending and expecting 3.3 V USART. I connected simply to Pin 10 and 11 which work with 5 V. Can that cause the misread? And when, is there a simple tinker solution or do I have to buy a level shifter like e.g. BSS138 to solve that?
thanks to your help. It works now very reliable. The poll mode did not work for me.
I had a bug in the function "void recvWithStartEndMarkers()".
Additionally I installed the mentioned level shifter.
That's what my code looks like now:
#include <SoftwareSerial.h>
/*
sensor Pin3(TX) to Arduino Pin 10(RX)
sensor Pin4(RX) to Arduino Pin 11(TX)
*/
SoftwareSerial mySerial(10, 11); // RX, TX
const byte numChars = 41;
char receivedChars[numChars];
char tempChars[numChars]; // temporary array for use when parsing
float oxygen = 0.0; // variables to hold the parsed data
float temperature = 0.0;
int pressure = 0;
float percentage = 0.0;
boolean newData = false;
unsigned long currentMillis = 0;
unsigned long previousReadOxySenMillis = 0;
//unsigned long previousReadDHTMillis = 0;
const long ReadOxySenInterval = 10000;
//============
void setup() {
Serial.begin(9600);
mySerial.begin(9600);
}
//============
void loop() {
currentMillis = millis(); // capture the latest value of millis()
updateReadOxySen();
}
//============
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = 'O';
char endMarker = 'e';
char rc;
while (mySerial.available() > 0 && newData == false) {
rc = mySerial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
//============
void parseData() { // split the data into its parts
char * strtokIndx; // this is used by strtok() as an index
//data from sensor send looks like: "O xxxx.x T yxx.x P xxxx % xxx.xx e xxxx\r\n"
//e.g. "O 0020.1 T +19.3 P 1013 % 020.16 e 0001\r\n"
strtokIndx = strtok(tempChars,"T"); // get the first part - the string
oxygen = atof(strtokIndx); // copy it to oxygen
strtokIndx = strtok(NULL, "P"); // this continues where the previous call left off
temperature = atof(strtokIndx); // convert this part to a float
strtokIndx = strtok(NULL, "%"); // this continues where the previous call left off
pressure = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, "e"); // this continues where the previous call left off
percentage = atof(strtokIndx); // convert this part to a float
}
//============
void showParsedData() {
Serial.print("Oxygen ");
Serial.println(oxygen);
Serial.print("Temperature ");
Serial.println(temperature);
Serial.print("Pressure ");
Serial.println(pressure);
Serial.print("Percent ");
Serial.println(percentage);
}
void updateReadOxySen() {
if (currentMillis - previousReadOxySenMillis >= ReadOxySenInterval) {
// time is up, so make anew read
recvWithStartEndMarkers();
if (newData == true) {
strcpy(tempChars, receivedChars);
// this temporary copy is necessary to protect the original data
// because strtok() used in parseData() replaces the commas with \0
parseData();
showParsedData();
newData = false;
}
// and save the time of change
previousReadOxySenMillis += ReadOxySenInterval;
}
}
In general the above code is working fine, but there must be still a bug inside, I can't find out.
Every second read the value for pressure and percentage is wrong.
Both values are read from the sensor. It looks like the sensor is sending wrong values every second time.
If I try another sensor (I have two of them), it's the same behavior. After a while the wrong readings become randomly.
If I read in a very simple way, the sensors are sending correct data.
#include <SoftwareSerial.h>
/*
sensor Pin3 OxySen (TX) to Arduino Pin 10(RX)
sensor Pin4 OxySen (RX) to Arduino Pin 11(TX)
*/
SoftwareSerial mySerial(10, 11); // RX, TX
const byte numChars = 43;
char receivedChars[numChars];
char tempChars[numChars]; // temporary array for use when parsing
float oxygen = 0.0; // variables to hold the parsed data
float tempo = 0.0;
int pressure = 0;
float percentage = 0.0;
int errorox = 0;
boolean newData = false;
unsigned long currentMillis = 0;
unsigned long previousReadOxySenMillis = 0;
const long ReadOxySenInterval = 2000;
//============
void setup() {
Serial.begin(9600);
mySerial.begin(9600);
}
//============
void loop() {
currentMillis = millis(); // capture the latest value of millis()
updateReadOxySen();
}
//============
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = 'O';
//char endMarker = 'e';
char endMarker = '\n';
char rc;
while (mySerial.available() > 0 && newData == false) {
rc = mySerial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
//============
void parseData() { // split the data into its parts
char * strtokIndx; // this is used by strtok() as an index
//data from sensor send looks like: "O xxxx.x T yxx.x P xxxx % xxx.xx e xxxx\r\n"
//e.g. "O 0020.1 T +19.3 P 1013 % 020.16 e 0001\r\n"
strtokIndx = strtok(tempChars,"T"); // get the first part - the string
oxygen = atof(strtokIndx); // copy it to oxygen
strtokIndx = strtok(NULL, "P"); // this continues where the previous call left off
tempo = atof(strtokIndx); // convert this part to a float
strtokIndx = strtok(NULL, "%"); // this continues where the previous call left off
pressure = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, "e"); // this continues where the previous call left off
percentage = atof(strtokIndx); // convert this part to a float
strtokIndx = strtok(NULL, "\n"); // this continues where the previous call left off
errorox = atoi(strtokIndx); // convert this part to an integer
}
//============
void showParsedData() {
Serial.print("Oxygen ");
Serial.println(oxygen);
Serial.print("TemperatureO ");
Serial.println(tempo);
Serial.print("Pressure ");
Serial.println(pressure);
Serial.print("Percent ");
Serial.println(percentage);
Serial.print("Error from sensor ");
Serial.println(errorox);
}
void updateReadOxySen() {
if (currentMillis - previousReadOxySenMillis >= ReadOxySenInterval) {
// time is up, so make anew read
recvWithStartEndMarkers();
if (newData == true) {
strcpy(tempChars, receivedChars);
// this temporary copy is necessary to protect the original data
// because strtok() used in parseData() replaces the commas with \0
parseData();
showParsedData();
newData = false;
}
// and save the time of change
previousReadOxySenMillis += ReadOxySenInterval;
}
}
Try cranking up the baud rate on serial, 115200 perhaps. No need to have it running at the same speed as the sensor. How frequently does the sensor send data?
Hi Zega, Thanks for your code, I have spent several days trying to parse the string before I found your post.
I found changing the ReadOxySenInterval to 1000 and the Serial Terminal to 115200 gave consistent results.
I then added a 16x2 LCD display to display the results on an test instrument and commented out the Serial Terminal.
/*****************************************************************************
Arduino program to read LuminOx O2 Sensor into sensorString and display
on the Serial Monitor, Extract the Oxygen, Temperature and Pressure
and display on an LCD display.
******************************************************************************/
#include <SoftwareSerial.h>
#include <LiquidCrystal.h>
/*
sensor Pin3 OxySen (TX) to Arduino Pin 10(RX)
sensor Pin4 OxySen (RX) to Arduino Pin 9(TX)
*/
SoftwareSerial mySerial(10, 9); // RX, TX
LiquidCrystal lcd(7,6,5,4,3,2); //RS,EN,D4,D3,D2,D1 connections
const byte numChars = 43;
char receivedChars[numChars];
char tempChars[numChars]; // temporary array for use when parsing
float oxygen = 0.0; // variables to hold the parsed data
float tempo = 0.0;
int pressure = 0;
float percentage = 0.0;
int errorox = 0;
boolean newData = false;
unsigned long currentMillis = 0;
unsigned long previousReadOxySenMillis = 0;
const long ReadOxySenInterval = 1000;
//============
void setup() {
Serial.begin(115200);
mySerial.begin(9600);
lcd.begin(16,2);
}
//============
void loop() {
currentMillis = millis(); // capture the latest value of millis()
updateReadOxySen();
}
//============
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = 'O';
char endMarker = '\n';
char rc;
while (mySerial.available() > 0 && newData == false) {
rc = mySerial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
//============
void parseData() { // split the data into its parts
char * strtokIndx; // this is used by strtok() as an index
//data from sensor send looks like: "O xxxx.x T yxx.x P xxxx % xxx.xx e xxxx\r\n"
//e.g. "O 0020.1 T +19.3 P 1013 % 020.16 e 0001\r\n"
strtokIndx = strtok(tempChars,"T"); // get the first part - the string
oxygen = atof(strtokIndx); // copy it to oxygen
strtokIndx = strtok(NULL, "P"); // this continues where the previous call left off
tempo = atof(strtokIndx); // convert this part to a float
strtokIndx = strtok(NULL, "%"); // this continues where the previous call left off
pressure = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, "e"); // this continues where the previous call left off
percentage = atof(strtokIndx); // convert this part to a float
strtokIndx = strtok(NULL, "\n"); // this continues where the previous call left off
errorox = atoi(strtokIndx); // convert this part to an integer
}
//============
void showParsedData() {
/* Serial.print("Oxygen ");
Serial.println(oxygen);
Serial.print("Temperature ");
Serial.println(tempo);
Serial.print("Pressure ");
Serial.println(pressure);
Serial.print("Percent ");
Serial.println(percentage);
Serial.print("Error from sensor ");
Serial.println(errorox);
*/
// Print to LCD display
lcd.setCursor(0,0); //first row
lcd.print("O2 ");
lcd.print(oxygen); lcd.print(" ");
lcd.print(percentage); lcd.print("%");
lcd.setCursor(0,1); //second row
lcd.print(tempo); lcd.print((char)223); lcd.print("C ");
lcd.print(pressure); lcd.print(" hPa ");
}
void updateReadOxySen() {
if (currentMillis - previousReadOxySenMillis >= ReadOxySenInterval) {
// time is up, so make anew read
recvWithStartEndMarkers();
if (newData == true) {
strcpy(tempChars, receivedChars);
// this temporary copy is necessary to protect the original data
// because strtok() used in parseData() replaces the commas with \0
parseData();
showParsedData();
newData = false;
}
// and save the time of change
previousReadOxySenMillis += ReadOxySenInterval;
}
}