Created
December 3, 2018 22:09
-
-
Save marcozecchini/a7095cc867fee2fb63b7c41bb3161fbd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <avr/pgmspace.h> | |
#include <EEPROM.h> | |
#include <OneWire.h> | |
#define DoSensorPin A4 //dissolved oxygen sensor analog output pin to arduino mainboard | |
#define TemperaturePin A0 | |
#define VREF 5000 //for arduino uno, the ADC reference is the AVCC, that is 5000mV(TYP) | |
float doValue; //current dissolved oxygen value, unit; mg/L | |
float temperature = 25; //default temperature is 25^C, you can use a temperature sensor to read it | |
#define EEPROM_write(address, p) {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) EEPROM.write(address+i, pp[i]);} | |
#define EEPROM_read(address, p) {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) pp[i]=EEPROM.read(address+i);} | |
#define ReceivedBufferLength 20 | |
char receivedBuffer[ReceivedBufferLength+1]; // store the serial command | |
byte receivedBufferIndex = 0; | |
#define SCOUNT 30 // sum of sample point | |
int analogBuffer[SCOUNT]; //store the analog value in the array, readed from ADC | |
int analogBufferTemp[SCOUNT]; | |
int analogBufferIndex = 0,copyIndex = 0; | |
#define SaturationDoVoltageAddress 12 //the address of the Saturation Oxygen voltage stored in the EEPROM | |
#define SaturationDoTemperatureAddress 16 //the address of the Saturation Oxygen temperature stored in the EEPROM | |
float SaturationDoVoltage,SaturationDoTemperature; | |
float averageVoltage; | |
OneWire ds(TemperaturePin); //Temperature chip i/o on A0 | |
const float SaturationValueTab[41] PROGMEM = { //saturation dissolved oxygen concentrations at various temperatures | |
14.46, 14.22, 13.82, 13.44, 13.09, | |
12.74, 12.42, 12.11, 11.81, 11.53, | |
11.26, 11.01, 10.77, 10.53, 10.30, | |
10.08, 9.86, 9.66, 9.46, 9.27, | |
9.08, 8.90, 8.73, 8.57, 8.41, | |
8.25, 8.11, 7.96, 7.82, 7.69, | |
7.56, 7.43, 7.30, 7.18, 7.07, | |
6.95, 6.84, 6.73, 6.63, 6.53, | |
6.41, | |
}; | |
void setup() | |
{ | |
Serial.begin(115200); | |
pinMode(DoSensorPin,INPUT); | |
readDoCharacteristicValues(); //read Characteristic Values calibrated from the EEPROM | |
Serial.print("DO value at beginning: "); | |
Serial.println(SaturationDoVoltage); | |
Serial.print("Temp at beginning: "); | |
Serial.println(SaturationDoTemperature); | |
} | |
void loop() | |
{ | |
static unsigned long analogSampleTimepoint = millis(); | |
if(millis()-analogSampleTimepoint > 30U) //every 30 milliseconds,read the analog value from the ADC | |
{ | |
analogSampleTimepoint = millis(); | |
analogBuffer[analogBufferIndex] = analogRead(DoSensorPin); //read the analog value and store into the buffer | |
analogBufferIndex++; | |
if(analogBufferIndex == SCOUNT) | |
analogBufferIndex = 0; | |
} | |
static unsigned long tempSampleTimepoint = millis(); | |
if(millis()-tempSampleTimepoint > 500U) // every 500 milliseconds, read the temperature | |
{ | |
tempSampleTimepoint = millis(); | |
temperature = getTemp(); // add your temperature codes here to read the temperature, unit:^C | |
} | |
static unsigned long printTimepoint = millis(); | |
if(millis()-printTimepoint > 1000U) | |
{ | |
printTimepoint = millis(); | |
for(copyIndex=0;copyIndex<SCOUNT;copyIndex++) | |
{ | |
analogBufferTemp[copyIndex]= analogBuffer[copyIndex]; | |
} | |
averageVoltage = getMedianNum(analogBufferTemp,SCOUNT) * (float)VREF / 1024.0; // read the value more stable by the median filtering algorithm | |
Serial.print(F("Temperature:")); | |
Serial.print(temperature,1); | |
Serial.print(F("^C")); | |
doValue = pgm_read_float_near( &SaturationValueTab[0] + (int)(SaturationDoTemperature+0.5) ) * averageVoltage / SaturationDoVoltage; //calculate the do value, doValue = Voltage / SaturationDoVoltage * SaturationDoValue(with temperature compensation) | |
Serial.print(F(", DO Value:")); | |
Serial.print(doValue,2); | |
Serial.println(F("mg/L")); | |
} | |
if(serialDataAvailable() > 0) | |
{ | |
byte modeIndex = uartParse(); //parse the uart command received | |
doCalibration(modeIndex); // If the correct calibration command is received, the calibration function should be called. | |
} | |
} | |
float getTemp(){ | |
//returns the temperature from one DS18S20 in DEG Celsius | |
byte data[12]; | |
byte addr[8]; | |
if ( !ds.search(addr)) { | |
//no more sensors on chain, reset search | |
ds.reset_search(); | |
return -1000; | |
} | |
if ( OneWire::crc8( addr, 7) != addr[7]) { | |
Serial.println("CRC is not valid!"); | |
return -1000; | |
} | |
if ( addr[0] != 0x10 && addr[0] != 0x28) { | |
Serial.print("Device is not recognized"); | |
return -1000; | |
} | |
ds.reset(); | |
ds.select(addr); | |
ds.write(0x44,1); // start conversion, with parasite power on at the end | |
byte present = ds.reset(); | |
ds.select(addr); | |
ds.write(0xBE); // Read Scratchpad | |
for (int i = 0; i < 9; i++) { // we need 9 bytes | |
data[i] = ds.read(); | |
} | |
ds.reset_search(); | |
byte MSB = data[1]; | |
byte LSB = data[0]; | |
float tempRead = ((MSB << 8) | LSB); //using two's compliment | |
float TemperatureSum = tempRead / 16; | |
return TemperatureSum; | |
} | |
boolean serialDataAvailable(void) | |
{ | |
char receivedChar; | |
static unsigned long receivedTimeOut = millis(); | |
while ( Serial.available() > 0 ) | |
{ | |
if (millis() - receivedTimeOut > 500U) | |
{ | |
receivedBufferIndex = 0; | |
memset(receivedBuffer,0,(ReceivedBufferLength+1)); | |
} | |
receivedTimeOut = millis(); | |
receivedChar = Serial.read(); | |
if (receivedChar == '\n' || receivedBufferIndex == ReceivedBufferLength) | |
{ | |
receivedBufferIndex = 0; | |
strupr(receivedBuffer); | |
return true; | |
}else{ | |
receivedBuffer[receivedBufferIndex] = receivedChar; | |
receivedBufferIndex++; | |
} | |
} | |
return false; | |
} | |
byte uartParse() | |
{ | |
byte modeIndex = 0; | |
if(strstr(receivedBuffer, "CALIBRATION") != NULL) | |
modeIndex = 1; | |
else if(strstr(receivedBuffer, "EXIT") != NULL) | |
modeIndex = 3; | |
else if(strstr(receivedBuffer, "SATCAL") != NULL) | |
modeIndex = 2; | |
return modeIndex; | |
} | |
void doCalibration(byte mode) | |
{ | |
char *receivedBufferPtr; | |
static boolean doCalibrationFinishFlag = 0,enterCalibrationFlag = 0; | |
float voltageValueStore; | |
switch(mode) | |
{ | |
case 0: | |
if(enterCalibrationFlag) | |
Serial.println(F("Command Error")); | |
break; | |
case 1: | |
enterCalibrationFlag = 1; | |
doCalibrationFinishFlag = 0; | |
Serial.println(); | |
Serial.println(F(">>>Enter Calibration Mode<<<")); | |
Serial.println(F(">>>Please put the probe into the saturation oxygen water! <<<")); | |
Serial.println(); | |
break; | |
case 2: | |
if(enterCalibrationFlag) | |
{ | |
Serial.println(); | |
Serial.println(F(">>>Saturation Calibration Finish!<<<")); | |
Serial.println(); | |
EEPROM_write(SaturationDoVoltageAddress, averageVoltage); | |
EEPROM_write(SaturationDoTemperatureAddress, temperature); | |
SaturationDoVoltage = averageVoltage; | |
SaturationDoTemperature = temperature; | |
doCalibrationFinishFlag = 1; | |
} | |
break; | |
case 3: | |
if(enterCalibrationFlag) | |
{ | |
Serial.println(); | |
if(doCalibrationFinishFlag) | |
Serial.print(F(">>>Calibration Successful")); | |
else | |
Serial.print(F(">>>Calibration Failed")); | |
Serial.println(F(",Exit Calibration Mode<<<")); | |
Serial.println(); | |
doCalibrationFinishFlag = 0; | |
enterCalibrationFlag = 0; | |
} | |
break; | |
} | |
} | |
int getMedianNum(int bArray[], int iFilterLen) | |
{ | |
int bTab[iFilterLen]; | |
for (byte i = 0; i<iFilterLen; i++) | |
{ | |
bTab[i] = bArray[i]; | |
} | |
int i, j, bTemp; | |
for (j = 0; j < iFilterLen - 1; j++) | |
{ | |
for (i = 0; i < iFilterLen - j - 1; i++) | |
{ | |
if (bTab[i] > bTab[i + 1]) | |
{ | |
bTemp = bTab[i]; | |
bTab[i] = bTab[i + 1]; | |
bTab[i + 1] = bTemp; | |
} | |
} | |
} | |
if ((iFilterLen & 1) > 0) | |
bTemp = bTab[(iFilterLen - 1) / 2]; | |
else | |
bTemp = (bTab[iFilterLen / 2] + bTab[iFilterLen / 2 - 1]) / 2; | |
return bTemp; | |
} | |
void readDoCharacteristicValues(void) | |
{ | |
EEPROM_read(SaturationDoVoltageAddress, SaturationDoVoltage); | |
EEPROM_read(SaturationDoTemperatureAddress, SaturationDoTemperature); | |
if(EEPROM.read(SaturationDoVoltageAddress)==0xFF && EEPROM.read(SaturationDoVoltageAddress+1)==0xFF && EEPROM.read(SaturationDoVoltageAddress+2)==0xFF && EEPROM.read(SaturationDoVoltageAddress+3)==0xFF) | |
{ | |
SaturationDoVoltage = 1127.6; //default voltage:1127.6mv | |
EEPROM_write(SaturationDoVoltageAddress, SaturationDoVoltage); | |
} | |
if(EEPROM.read(SaturationDoTemperatureAddress)==0xFF && EEPROM.read(SaturationDoTemperatureAddress+1)==0xFF && EEPROM.read(SaturationDoTemperatureAddress+2)==0xFF && EEPROM.read(SaturationDoTemperatureAddress+3)==0xFF) | |
{ | |
SaturationDoTemperature = 25.0; //default temperature is 25^C | |
EEPROM_write(SaturationDoTemperatureAddress, SaturationDoTemperature); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment