#include <SPI.h>
#include <Wire.h> // The pins for I2C are defined by the Wire-library. On an arduino UNO:A4(SDA), A5(SCL)
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h> // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#include <SoftwareSerial.h> // Define a Software Serial object
#include <EEPROM.h>
#include <RunningAverage.h>
RunningAverage myRAFlow1(40);
RunningAverage myRAFlow2(40);
//RunningAverage myRASensor1(25);
RunningAverage myRATheretical(1);
int samples = 0;
//pin definition
const int sensorpin = 8 ; //pin connected to the CO2 sensor
const int CO2flow = A0; //pin connected to the CO2 flow sensor
const int N2flow = A1; //pin connected to the N2 flow sensor
const int buttonPin = 7 ; //pin connected to the calibration button
const int magicValueAddress = 0; //EEPROM address for magic value
const int calibrationOffsetaddress = 4; //EEPROM address for calibration offset
//magic value set up as a 4-byte array for compatibility with your EEPROM storage
const uint8_t magicValue [4] = {0xDE, 0xAD, 0xBE, 0xEF};
float calibrationOffset = 0.0; // Variable to store calibration offset
float theoretical = 0.0;//variable for reading runningaverage of theretical
float flowRate1 = 0.0;//variable for reading runningaverage of avgflowrate1
float flowRate2 = 0.0;//variable for reading runningaverage of avgflowrate2
float avgTheoretical = 0.0;//variable for reading runningaverage of avgtheoretical
float avgSensor = 0.0; //variable for reading runningaverage avgsensor
int buttonState = HIGH; //variable for reading the button status
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
SoftwareSerial softSerial(8, 9); //the used pins; RX, TX
void setup() {
//pinMode(sensorpin, INPUT);
pinMode(buttonPin, INPUT_PULLUP);
pinMode(CO2flow, INPUT);
pinMode(N2flow, INPUT);
Serial.begin(9600);
softSerial.begin(9600);
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
display.display(); // Show initial display buffer contents on the screen. The library initializes this with an Adafruit splash screen.
delay(500); // Holds splash screen. Must legally be included if redistributed.
display.clearDisplay(); // Clear the buffer
display.setTextColor(WHITE);
display.setTextSize(2);
pinMode(9, OUTPUT); //Red led
pinMode(10, OUTPUT); //Green led
digitalWrite(9, LOW);
digitalWrite(10, HIGH);
// EEPROM Check for existing calibration
uint8_t storedMagic[4];
EEPROM.get(magicValueAddress, storedMagic);
if (memcmp(magicValue, storedMagic, 4) == 0) {
EEPROM.get(calibrationOffsetaddress, calibrationOffset);
} else {
// Store a magic value first time a new board is used
EEPROM.put(magicValueAddress, magicValue); // Ensure magicValue is an appropriately sized and declared variable
calibrationOffset = 0.0; // Default to no calibration offset
// Store the calibration offset in EEPROM
EEPROM.put(calibrationOffsetaddress, calibrationOffset); // Make sure calibrationOffsetAddress is correctly declared
}
}
void ReadFlows() {
//read the raw sensorvalues
int sensorValue1 = analogRead(CO2flow);
int sensorValue2 = analogRead(N2flow);
// Convert the sensor values to flow rate (assuming 1-5V corresponds to 0.1-5 L/min)
float voltage1 = sensorValue1 * (5.0 / 1023.0);
float voltage2 = sensorValue2 * (5.0 / 1023.0);
float flowRate1 = ((voltage1 - 1) * (5.0 / 4.0));
float flowRate2 = ((voltage2 - 1) * (5.0 / 4.0));
// Calculate the theoretical concentration flowRate1 / (flowRate1 + flowRate2)
myRAFlow1.addValue(flowRate1);
float avgFlowRate1 = myRAFlow1.getAverage();
myRAFlow2.addValue(flowRate2);
float avgFlowRate2 = myRAFlow2.getAverage();
Serial.print(myRAFlow1.getCount());
Serial.print(" ");
Serial.print(myRAFlow2.getCount());
Serial.print(" ");
//Serial.print(myRASensor1.getCount());
//Serial.print(" ");
theoretical = avgFlowRate1 / (avgFlowRate1 + avgFlowRate2) * 100;
myRATheretical.addValue(theoretical);
float avgTheoretical = myRATheretical.getAverage();
Serial.print(avgFlowRate1);
Serial.print(" ");
Serial.print(avgFlowRate2);
Serial.print(" ");
Serial.println(avgTheoretical);
}
//was here
void loop() {
ReadFlows();
buttonState = digitalRead(buttonPin); // Read the button state and store it in buttonState
if (buttonState == LOW) { // Check if the button is pressed
delay(50); // Simple debounce delay
if (digitalRead(buttonPin) == LOW) { // Confirm button press after debounce
calibrateSensor(); // Call your calibration function
}}
String Z;
String filtered1;
String filtered2;
String filtered3;
String H;
float h;
float polynomium;
float A2;
float C;
String output1;
Z = softSerial.readStringUntil('\n'); //getting string input in variable "Z". String has format Z XXXXX z XXXXX where Z is filtered data and z is raw, both in decippm
filtered1 = Z.substring(3,5); //first two numbers of filtered data, corresponding to whole percent.
filtered2 = Z.substring(5,7); //last two numbers of unfiltered data, corresponding to decimals of percent. One more decimal is avivable.
filtered3 = Z.substring(3,8); //all filtered data
h = filtered3.toFloat()/1000;
H = String(h);
//output = "CO2 sensor\n "+ filtered1 + "." + filtered2 + "%"; //Prepares filtered data for display. "/n" moves to the next line.
polynomium = 2.37472 * pow(10, -30) * pow(h, 6)
- 2.70695 * pow(10, -25) * pow(h, 5)
+ 1.24012 * pow(10, -20) * pow(h, 4)
- 2.91716 * pow(10, -16) * pow(h, 3)
+ 3.62939 * pow(10, -12) * pow(h, 2)
- 1.82753 * pow(10, -8) * h
- 1.35129 * pow(10, -3);
A2 = (h / (1 + polynomium * (1013 - 1012.6)));
//delay(250);
//myRASensor1.addValue(A2);
//avgSensor = myRASensor1.getAverage();
C = A2 + calibrationOffset;
Serial.println(C);
String ValueAsText;
if (C < 10.0) {
ValueAsText = ' ' + String(A2,1);
}
if (theoretical >= 10.0) {
ValueAsText = ' ' + ValueAsText;
}
output1 = "S:" + ValueAsText + "%"; //Prepares filtered data for display. "/n" moves to the next line.
//output += "\nDir: " + String(direct_conversion) + "%";
String output2;
output2 = "F: " + String(theoretical,1) + "%";
display.setCursor(0, 0); //Set start of line for sensor concentration
display.clearDisplay();
display.println(output1); //Sends prepared filtered data to display buffer
display.setCursor(150,0); //set start of line for theoretical concentration
display.println(output2);
display.display(); //Updates display from display buffer
//Define led status
if (filtered1 ==""){ //If no signal from sensor, red led on, green led off
digitalWrite(9, HIGH);
digitalWrite(10, LOW);
} else if (filtered1 =="20"){ //If sensor is outputting "20" (maximum percentage of CO2 in air measurable), red and green led on,
digitalWrite(9, HIGH);
digitalWrite(10, HIGH);
} else { //If sensor is outbutting somthing else, all should be fine. Green on, red off.
digitalWrite(9, LOW);
digitalWrite(10, HIGH);
}
}
void calibrateSensor(void) {
// Assuming you're reading a sensor value as a float for calibration
String sensorData = softSerial.readStringUntil('\n');
//float sensorValue = sensorData.toFloat(10.0); // Convert sensor data to float
if(A2 == theoretical){
calibrationOffset == A2;
}
else {
calibrationOffset = theoretical - A2;
}
//if(A2 != theoretical){
//calibrationOffset == theoretical - A2;
//}
// Store the calibration offset in EEPROM
EEPROM.put(calibrationOffsetaddress, calibrationOffset); // Make sure calibrationOffsetAddress is correctly declared
Serial.println("Calibration completed.");
}
im using this code, and the theoretical calculations are correct and working, but the calibration of the CO2 sensor isn't i dont know if it is the button or the calibration loop that isn't working. i have used chatGPT to try and find a solution to my problems, but they don't work. do any of you guys have some ideas of how i could solve my problem