The sensor communicates via USART. My goal is to get every 10 minutes the values and to write it into a mariadb database. The sensor has 3 modes: Stream, Poll and Off. On startup the default is “Stream”. In Stream mode it gives values every second. This I got to work, but I don’t know how to reduce the data flood in a reliable way! Maybe someone knows how to do that? Or would it be better to use the Poll mode?
I found some discussion on that sensor here, but the examples didn’t work.
I’m new to Arduino and coding. Any help would be great!
An interesting sample with another sensor (but I don’t come along):
#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()
{
if (mySerial.available())
{
Serial.write(mySerial.read());
}
}
Readings look like:
O 0201.6 T +22.8 P 0997 % 020.22 e 0000
O 0201.6 T +22.8 P 0997 % 020.22 e 0000
O 0201.1 T +21.7 P 0997 % 020.17 e 0000
O 0201.1 T +22.9 P 0997 % 020.17 e 0000
O 0201.1 T +22.8 P 0997 % 020.17 e 0000
O 0200.8 T +21.8 P 0997 % 020.14 e 0000
O 0200.8 T +22.9 P 0997 % 020.14 e 0000
O 0200.8 T +23.0 P 0997 % 020.14 e 0000
O 0200.8 T +22.9 P 0997 % 020.14 e 0000
O 0200.8 T +22.8 P 0997 % 020.14 e 0000
O 0200.8 T +23.0 P 0997 % 020.14 e 0000
O 0200.8 T +23.0 P 0997 % 020.14 e 0000
O 0200.8 T +23.0 P 0997 % 020.14 e 0000
O 0200.8 T +23.0 P 0997 % 020.15 e 0000
O 0200.9 T +23.0 P 0997 % 020.15 e 0000
O 0200.9 T +23.1 P 0997 % 020.15 e 0000
O 0200.9 T +23.1 P 0997 % 020.15 e 0000
O 0200.9 T +23.1 P 0997 % 020.15 e 0000
O 0200.9 T +23.2 P 0997 % 020.15 e 0000
O 0200.9 T +23.0 P 0997 % 020.15 e 0000
O 0200.9 T +23.0 P 0997 % 020.15 e 0000
I would like to write to mariadb: O, T, P and %.
The database connection I already got to work with another sensor, that’s not my topic now.
How to get reliable data in steps of 10 minutes to e.g. variables?
I'm just using the sensor. I connected the sensors
Pin 1 to Arduino 5V supply
Pin 2 to Arduino GND
Pin 3 to Arduino DIGITAL 10
Pin 4 to Arduino DIGITAL 11
using a Breadboard.
I use Arduino Mega 2560 with Ethernet Shield 2.
If you don't want the flood method, which is the default method, then you need to tell the device to use the poll method by sending it a message "M1\r\n". Then begin polling for data.
#include <SoftwareSerial.h>
/*
sensor Pin3(TX) to Arduino Pin 19(RX)
sensor Pin4(RX) to Arduino Pin 18(TX)
*/
SoftwareSerial mySerial(19, 18); // RX, TX
char receivedData = '0'; //variable for received data from sensor
void setup() {
Serial.begin(9600); // Open serial communications and wait for port to open
mySerial.begin(9600);
mySerial.write("M 1\r\n");
}
void loop() {
if (mySerial.available()) { //checks, if connection available
//mySerial.read(("O T P %\r\n"));
Serial.write("O T P %\r\n");
receivedData = mySerial.read();
Serial.print(receivedData);
//Serial.write(mySerial.read());
delay(10000); //waits for 10 seconds --> later change to 10 minutes!
}
}
Unfortunately I’m only a script kiddie, not knowing where I’m wrong, but step by step:
My “void setup()” is correct?
Is the request for data correct?
Is the way to print the data in the serial monitor correct?
it helped me a lot!
Pol mode I wasn’t able to initialize. Every try gave me E1 or E2, working in stream mode further.
First: Robin made a more compact overview, which is found here.
Second: It took me nearly the hole night to get it run, but I learned a lot!
Third: I still have a problem. Depending on where I put the wanted delay, I get some interesting behavior. Sometimes (every second read) the sketch starts again with the “void setup()”, what I can identify by printing “Ardunio O2 Sensor\n\n” to the serial monitor (which is the case e.g. in the example further down). In other cases the read breaks every third read.
Where would you put the delay??
Do anybody see potential for improvements?
Thanks in advance for any hint.
Triaenodon
#include <SoftwareSerial.h>
/*
This sketch reads the measured values of a LuminOx Optical Oxygen Sensor wich is quiet the same
as the XYO oxygen sensor from first-sensor.
sensor Pin3(TX) to Arduino Pin 10(RX)
sensor Pin4(RX) to Arduino Pin 11(TX)
*/
SoftwareSerial mySerial(10, 11); // RX, TX
int o2;
uint8_t buffer[41]; //get values from stream mode including \r
uint8_t ind =0;
uint8_t index =0;
int timer = 2000; // The higher the number, the slower the timing.
int arrayCount = 41; // the length of the data array excluding "\n"
int fill_buffer(); // initialisation of needed functions
int format_output();
void setup() {
Serial.begin(9600); // Open serial communications
Serial.print("\n\n");
Serial.println("Ardunio O2 Sensor\n\n");
mySerial.begin(9600); // Start serial communications with sensor
}
void loop() {
//delay(timer);
fill_buffer(); // function that reeds O2 sensor and fills buffer
//Serial.print("Buffer contains: ");
//for(int j=0; j<ind; j++)Serial.print(buffer[j],HEX);
//delay(timer);
Serial.println("");
//delay(timer);
for(int i=0; i<arrayCount; i++) { // loop from the lowest index to the highest
index = i;
format_output();
}
//delay(timer);
//Serial.println("");
}
int fill_buffer(void) { // Fill buffer with sensor ascii data
//delay(timer);
ind = 0;
while(buffer[ind-1] != 0x0A){ // Read sensor and fill buffer up to 0XA = CR
if(mySerial.available()){
buffer[ind] = mySerial.read();
ind++;
}
//delay(timer);
}
//delay(timer);
// buffer() now filled with sensor ascii data
// ind contains the number of characters loaded into buffer up to 0xA = CR
ind = ind -2; // decrement buffer to exactly match last numerical character
//delay(timer);
}
int format_output(void){ // read buffer, extract ASCII chars and print
o2 = buffer[index],HEX;
Serial.print((char)o2);
delay(timer);
}
My idea was to generate a read only once in 10 minutes not to flush the mariadb, otherwise I could work with the very first code posted. Am I wrong?
Still confused from generating my very first code.
Your program timing is only based on how often you send the poll message. Completely clean up the message reading code. The reading can be done as often and as fast as possible and nothing will happen.
If this was my program, I would use the logic of " doing many things at once", using the "millis" to watch the milliseconds go by and when your last poll message was sent more than 600,000 milliseconds ago, it's time to send another poll. And save the current millis value as the value for the last poll time.
I red the very good explained examples from Robin2 and tinkered based on this two posts (“Serial Input Basics - updated” and “Demonstration code for several things at the same time”) the following code. In general it works fine as I want it. But there is still a bug inside, I can’t find. Their are somehow randomly wrong reads (–>false data). First I thought to see a pattern, like every second read the value for pressure and percentage were incomplete, but the pattern changes with time. Maybe and hopefully one of you has an idea?
Here’s the code and further down an example of the read.
Many thank’s in advance!
Triaenodon
Code:
#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 = 43;
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 int ReadOxySenInterval = 5000;
//============
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'; //first sign from the data stream
char endMarker = 'e'; //from here on I don't need the data
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;
}
}
Sample read:
.87
Oxygen 195.00
Temperature 27.60
Pressure 984
Percent 19.82
Oxygen 195.00
Temperature 27.70
Pressure 98
Percent 0.00
Oxygen 195.30
Temperature 27.60
Pressure 984
Percent 19.84
Oxygen 195.30
Temperature 27.50
Pressure 98
Percent 0.00
Oxygen 195.40
Temperature 27.60
Pressure 984
Percent 19.86
Oxygen 195.50
Temperature 27.70
Pressure 98
Percent 0.00
Oxygen 195.50
Temperature 27.60
Pressure 984
Percent 19.87
Oxygen 195.50
Temperature 27.60
Pressure 98
Percent 0.00
Oxygen 195.50
Temperature 27.70
Pressure 984
Percent 19.87
Oxygen 195.50
Temperature 27.60
Pressure 98
Percent 0.00
Oxygen 195.50
Temperature 27.60
Pressure 984
Percent 19.87
Oxygen 195.50
Temperature 27.70
Pressure 98
Percent 0.00
Oxygen 195.60
Temperature 27.70
Pressure 984
Percent 19.88
Oxygen 195.60
Temperature 27.60
Pressure 98
Percent 0.00
Oxygen 195.70
Temperature 27.50
Pressure 984
Percent 19.88
Oxygen 195.70
Temperature 27.70
Pressure 98
Percent 0.00
Oxygen 195.70
Temperature 27.70
Pressure 984
Percent 19.89
Oxygen 195.70
Temperature 27.70
Pressure 0
Percent 19.89
Oxygen 195.70
Temperature 27.70
Pressure 0
Percent 19.89
Oxygen 19.00
Temperature 27.60
Pressure 984
Percent 19.89
Oxygen 195.70
Temperature 0.00
Pressure 984
Percent 19.89
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