what would be a good strategy to exclude the readings where a strange character appeared ?
I have an Atlas Scientific stamp that reads ORP values. Every few hundreds readings a strange character will sneak in. I am charting these readings and the corrupted one will cause a drop to zero. Not a big deal, but annoying.
I can put the float values in a vector and run an average over a certain number of readings and graph the average, but the strange characters are nagging me
#include <Wire.h>
#include <SoftwareSerial.h>
// --------------- Serial ports --------------------------------------
#define ORPrx 4Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â //define what pin orp rx is going to be
#define ORPtx 3Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â //define what pin orp Tx is going to be
SoftwareSerial ORPserial(ORPrx, ORPtx);Â Â Â //define the ORP soft serial port
const byte ORP_ADDRESS = 42;
volatile byte* ORP_FloatPtr;
// --------------- Define ORP variables ------------------------------
char inData_ORP[18];Â Â Â Â Â // receiving serial buffer
char string_ORP[18];Â Â Â Â Â // transfer buffer
float ORP_val = 0;
byte holding_ORP;Â Â Â Â Â Â // number of bytes received
byte j;Â Â Â Â Â Â Â Â Â Â Â
// --------------- Set measurement interval---------------------------
long ORPReadInterval = 2000;
long previousMillisORP = 0;
void setup()
{
 Serial.begin (9600);
 ORPserial.begin(9600);
 Wire.begin(ORP_ADDRESS);
 Wire.onRequest(requestEvent);
}Â
void loop()
{
 unsigned long currentMillisORP = millis();
 if(currentMillisORP - previousMillisORP > ORPReadInterval)
 {
  previousMillisORP = currentMillisORP;
 Â
  memset(&inData_ORP[0], 0, sizeof(inData_ORP)); // clear/prepare receiving buffer
  holding_ORP = 0;
 Â
  ORPserial.print("read()\r");          // send it the command to take a single reading.       Â
  delay(75);
 Â
  while(ORPserial.available() > 0) {       // wait until serial gets something
   holding_ORP = ORPserial.available();     // hold how many bytes were received from ORP stamp
   // Serial.println(holding_ORP);
   for(j=0; j <= holding_ORP; j++) {       // assemble stamp data
    inData_ORP[j] = ORPserial.read();
   }
  }
  inData_ORP[holding_ORP]='\0';          // null terminate the string
  Serial.println(inData_ORP);
  sscanf(inData_ORP, "%*s %s %*s", string_ORP);  // select the usful part of string method #1
  // Serial.println(string_ORP);
 Â
  ORP_val = atof(string_ORP);           // get the float value
  Serial.print("ORP Sensor output: ");
  Serial.println(ORP_val); Â
 }    Â
}Â // end of loop
void requestEvent()
{
 byte* Data;
 ORP_FloatPtr = (byte*) &ORP_val;
 Data[0] = ORP_FloatPtr[0];
 Data[1] = ORP_FloatPtr[1];
 Data[2] = ORP_FloatPtr[2];
 Data[3] = ORP_FloatPtr[3];Â
 Wire.write(Data, 4);
}
I noticed that the delay after sending the read()\r command to the stamp is important. No delay increases the frequency of receiving bad characters, too much messes up the response.
The stamp always responds with 14 characters (ORP= xx.xx mv)
while(ORPserial.available() > 0) { // wait until serial gets something
holding_ORP = ORPserial.available(); // hold how many bytes were received from ORP stamp
// Serial.println(holding_ORP);
for(j=0; j <= holding_ORP; j++) { // assemble stamp data
inData_ORP[j] = ORPserial.read();
}
}
There are a lot of problems there. For one thing, you shouldn't need a delay at all.
Next, if you receive holding_ORP characters you are storing holding_ORP+1 (because you are going from zero) so you are reading too many.
You should be using a state machine (see link above) and start a new sequence when receiving "ORP" and finish when receiving "mv".
ORP_FloatPtr = (byte*) &ORP_val;
ORP_val should be volatile as it is being read in an ISR.
volatile byte* ORP_FloatPtr;
ORP_FloatPtr should not be volatile, nor do I see why it is a global variable.
void requestEvent()
{
 byte* Data;
 ORP_FloatPtr = (byte*) &ORP_val;
 Data[0] = ORP_FloatPtr[0];
 Data[1] = ORP_FloatPtr[1];
 Data[2] = ORP_FloatPtr[2];
 Data[3] = ORP_FloatPtr[3]; Â
 Wire.write(Data, 4);
}
See I2C_Anything:
That saves a lot of mucking around.
eg.
void requestEvent()
 {
 I2C_writeAnything (ORP_val);
 }
void requestEvent()
{
 byte* Data;
 ORP_FloatPtr = (byte*) &ORP_val;
 Data[0] = ORP_FloatPtr[0];
 Data[1] = ORP_FloatPtr[1];
 Data[2] = ORP_FloatPtr[2];
 Data[3] = ORP_FloatPtr[3];Â
 Wire.write(Data, 4);
}
Is this even valid? You aren't allocating any memory for the data array, you're just declaring the pointer. Doesn't this have the potential to cause severe trouble?
Nick - you are right about the variables, but for whatever reasons without that small delay, this stamp is misbehaving. I did try the I2C_Anything. I like your elegant solution, but I failed on the receiving event. I have three Arduino Nano acting as slaves sending over I2C floats to a master. How would you build the onReceive event on master ?
I never used state machine before. Would love to learn. Thank you. Checking for character "v" every receive event works for the time being. I see the reading being discharged whenever the character is not received.
And yes, I checked the the last character was alway empty. Many thanks for your effort.
Ninja, I don't understand your point (my knowledge is rather limited), but it works very well the way it is. How would you write it different ?
I see a bit of discussion on the software aspects of things.
But my question to you would be have your verified that you have the proper value of pull-up resistance in the data lines (SDA, SCL) it should be pretty much 4.7K. If you have two devices on line with both adding pull ups the signal will distort, Same thing if you have no pull ups the signal can corrupt..
Nick - you are right about the variables, but for whatever reasons without that small delay, this stamp is misbehaving. I did try the I2C_Anything. I like your elegant solution, but I failed on the receiving event.
Assuming it is a coding problem, you need to post the code for both the sending and receiving end. Otherwise everthing is guesswork. And can you define "failed"?