Ok on va y aller pas à pas, essaies cette version:
/*
*Peripherals connections
*b0 - pin 28 //start - stop button
*mo_IPTG pin 30 //IPTG pump
*m1_HARVEST pin 31 //Harvest pump
*m2_STIRRER pin 32 //Stirrer motor
*m3_OD600 pin 33 //Flow pump for external sensor (eg optical density sensor)
*lt - pin A8 //Light sensor for optical density measurement analog input
*ph - pin A9 //PH sensor analog input
*h_HEATER - pin 35 //Heater controll output
*m4_OH_PUMP - pin 36 //OH pump output (for PH correction)
*flow sensor pin 18 //To make sure the flow pump for external sensors is working
*temperature sensor pin 29 //Digital temperature sensor
*/
#include <Dhcp.h>
#include <Dns.h>
#include <Ethernet2.h>
#include <EthernetClient.h>
#include <EthernetServer.h>
#include <Wire.h>
#include <DS1307RTC.h>
#include <Time.h>
#include <TimeAlarms.h>
#include <SPI.h>
#include <EthernetUdp2.h>
#include <SD.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <util.h>
//hardware implementation specific constants
#define OD600 8 // OD600 analog sensor connected to A8
#define PH 9 // ph anaolg sensor connected to A9
#define ONE_WIRE_BUS 29 // Temperature Data wire is connected to pin 29
#define M0_PIN 30
#define M1_PIN 31
#define M2_PIN 32
#define M3_PIN 33
#define H_PIN 35
#define OH_PUMP_PIN 36
#define AIR_PIN 37
#define B0_PIN 28
// process parameters and installed sensors calibration constants;
unsigned int l0 = 427; // light intensity reading through 1 cm path of LB medium (no bacteria present!)
unsigned char l0_saved = 0;
float OD_IPTG = 0.7;
float OD_MAX = 4 ;
unsigned char HARVEST_MINUTES = 10;
unsigned char MIN_GROWING_MINUTES = 2;
unsigned char MIN_IPTG_MINUTES = 2;
unsigned int IPTG_PUMPING_SECONDS = 60;
unsigned int SD_LOG_FREQ_SEC = 600;
// linear regresion ph sensor calibration curve : ph_instant = PH_A * ph_adc +PH_B!
float PH_A = 0.0335768807;
float PH_B = -5.9885198198;
float PH_MIN = 7.0;
float PH_MAX = 7.4;
unsigned int OH_FLOW = 438; //438 uL/s, pump constant.
unsigned int OH_DROP_VOLUME = 20; //uL 5N NaOH
unsigned int OH_ON_OFF_MILISEC = 60000;
OneWire oneWire(ONE_WIRE_BUS);// Setup a oneWire instance to communicate with any OneWire devices
DallasTemperature sensors(&oneWire);// Pass our oneWire reference to Dallas Temperature
// Enter a MAC address for your controller bellow.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = {0x90, 0xA2, 0xDA, 0x10, 0xDE, 0xE4};
EthernetClient client;
EthernetServer server(80);
byte ip[] = {10, 5, 5, 171}; // to be used if DHCP fails
IPAddress subnet(255, 255, 255, 0);
IPAddress gateway(10, 5, 5, 1);
IPAddress dnServer(8,8,8,8);
IPAddress timeServer(80,96,120,253); // NTP server, to be used if dns resolve fails.
IPAddress ntpIP = IPAddress (0,0,0,0);
unsigned int localPort = 8888; // local port to listen for UDP packets
const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[NTP_PACKET_SIZE]; // buffer to hold incoming and outgoing packets
// A UDP instance to let us send and receive packets over UDP
EthernetUDP Udp;
// timeZoneOffset = (Time Zone) * 3600L eg. (+2) * 3600L = 7200L for Romania
const long timeZoneOffset = 7200L;
// sync to NTP server every "ntpSyncTime" seconds, set to 1 hour or more to be reasonable
unsigned long ntpSyncTime = 3600;
// adjust the sync latency with computer NTP client in seconds
unsigned int syncLatency = 2;
// sd card variables
File file;
//const uint8_t SD_CS = 53; // SD chip select for ethernet shield v1
const uint8_t SD_CS = 4; // SD chip select for ethernet shield v2
String file_name = "bioreactor.log"; //generic default name for log file
String fn = "";
int i=0;
int displayAtSecond = 0;
time_t t;
unsigned char mo_IPTG=0;
unsigned char m1_HARVEST=0;
unsigned char m2_STIRER=0;
unsigned char m3_OD600=0;
unsigned char m4_OH_PUMP=0;
unsigned char h_HEATER=0;
unsigned char b0=0;
unsigned char od_over_1 = 0;
unsigned char od_over_2 = 0;
char t0=0;
float od = 0.00;
float lt = 0.0;
unsigned char stage = 0;
unsigned long stage_uptime = 0;
unsigned long stage_milliseconds = 0;
unsigned long oh_on_milliseconds = 0;
unsigned long oh_off_milliseconds = 0;
unsigned long log_seconds = 0;
unsigned long total_OH_uL = 0;
unsigned int consecutive_OH_pulses = 0;
float ph_instant = 0;
unsigned long main_loop_millis = 0;
unsigned long old_millis = 0;
unsigned long current_millis = 0;
String LCD_string = "";
String serial_string = "";
String web_string = "";
//------------------------------------------------------------------------------
//FlowMeter variables
volatile int flow_frequency; // Measures flow meter pulses
unsigned int l_hour; // flow in litres per hour
unsigned char flowmeter_pin = 18; // Flow Meter Pin number
unsigned long currentTime;
unsigned long cloopTime;
//-------------------------------------------------------------------------------
/*
Udp NTP Client
Get the time from a Network Time Protocol (NTP) time server
created 4 Sep 2010
by Michael Margolis
modified 9 Apr 2012
by Tom Igoe
modified 02 Sept 2015
by Arturo Guadalupi
addapted by Catalin Marinescu
*/
// send an NTP request to the time server at the given address, hoping to get the time!
unsigned long sendNTPpacket(IPAddress& address) {
// set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clodk
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
// all NTP fields have been initialized,
// send a packet requesting a timestamp:
Udp.beginPacket(address, 123);
Udp.write(packetBuffer, NTP_PACKET_SIZE);
Udp.endPacket();
}
// Real Time Clock functions:
void ntpSyncDS1307() {
ntpIP = timeServer;
Serial.print("NTP IP: ");
Serial.println(ntpIP);
sendNTPpacket(ntpIP); // send an NTP packet to a time server
// wait to see if a replay is available
delay(1000);
if (Udp.parsePacket()) {
// We've received a packet, read the data from it
Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
// the timstamp starts at byte 40 of the received packet and is four bytes,
// or two words, long. First, extract the two words:
unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
// combine the four bytes (two words) into a long integer
// this is NTP time (seconds since Jan 1 1900)
unsigned long secsSince1900 = highWord << 16 | lowWord;
// now convert NTP time into everyday time:
// Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
const unsigned long seventyYears = 2208988800L;
// substract seventy years:
unsigned long epoch = secsSince1900 - seventyYears + timeZoneOffset + syncLatency;
setTime(epoch);
RTC.set(epoch);
// print time and "Sync OK" message
Serial.print(year());
Serial.print('-');
Serial.print(month());
Serial.print('-');
Serial.print(day());
Serial.print(' ');
Serial.print(hour());
Serial.print(':');
Serial.print(minute());
Serial.print(':');
Serial.print(second());
Serial.print(' ');
Serial.println("Sync OK");
}
else {
Serial.println("UDP parse failed");
}
}
//FlowMeter Interrupt function
void flow ()
{
flow_frequency++;
}
void refreshDisplay() //update LCD display
{
LCD_string = String(year(t), DEC);
LCD_string += ".";
if (month(t) < 10) {
LCD_string = String(LCD_string + '0' + String(month(t), DEC));
}
else {
LCD_string = String(LCD_string +String(month(t), DEC));
}
LCD_string += ".";
if (day(t) < 10) {
LCD_string = String(LCD_string + '0' + String(day(t), DEC));
}
else {
LCD_string = String(LCD_string +String(day(t), DEC));
}
LCD_string += " ";
if (hour(t) < 10) {
LCD_string = String(LCD_string + '0' + String(hour(t), DEC));
}
else {
LCD_string = String(LCD_string +String(hour(t), DEC));
}
LCD_string += ":";
if (minute(t) < 10) {
LCD_string = String(LCD_string + '0' + String(minute(t), DEC));
}
else {
LCD_string = String(LCD_string +String(minute(t), DEC));
}
LCD_string += ":";
if (second(t) < 10) {
LCD_string = String(LCD_string + '0' + String(second(t), DEC));
}
else {
LCD_string = String(LCD_string +String(second(t), DEC));
}
LCD_string +=" "; //spacer to fill the first LCD line
LCD_string +="S";
LCD_string = String(LCD_string +String(stage, DEC));
switch (stage) {
case 0:
LCD_string +=":Ready ";
break;
case 1:
LCD_string +=":Growing";
break;
case 2:
LCD_string +=":IPTG ON";
break;
case 3:
LCD_string +=":Harvest";
break;
case 4:
LCD_string +=":Done ! ";
break;
}
LCD_string +=" ";
stage_uptime = (millis()-stage_milliseconds)/3600000;
if (stage_uptime <10) LCD_string +="0";
LCD_string = String(LCD_string +String(stage_uptime, DEC));
LCD_string +=":";
stage_uptime = ((millis()-stage_milliseconds)/60000)%60;
if (stage_uptime <10) LCD_string +="0";
LCD_string = String(LCD_string +String(stage_uptime, DEC));
LCD_string +=":";
stage_uptime = ((millis()-stage_milliseconds)/1000)%60;
if (stage_uptime <10) LCD_string +="0";
LCD_string = String(LCD_string +String(stage_uptime, DEC));
serial_string = String(LCD_string); //we use this part of LCD string also for serial port log.
LCD_string +=" OD600 H Tc Lt PH ";
if (od >0) LCD_string +=" ";
LCD_string = String(LCD_string +String(od,2));
LCD_string +=" ";
LCD_string = String(LCD_string +String(h_HEATER, DEC));
LCD_string +=" ";
LCD_string = String(LCD_string +String(t0, DEC));
LCD_string +=" ";
LCD_string = String(LCD_string + String(lt,0));
LCD_string +=" ";
LCD_string = String(LCD_string +String(ph_instant, 2));
LCD_string +=" ";
if (second(t) %10 == 0) { // log once every 10 seconds on the serial port!
serial_string += String(" Sensors_flow:"+String(l_hour,DEC)+" Light:"+String(lt,0)+" OD600:"+String(od,2)+" Heater:"+String(h_HEATER, DEC)+" Tc:"+String(t0, DEC)+" pH:"+String(ph_instant, 2)+" OHuL:"+String(total_OH_uL,DEC));
web_string = serial_string;
Serial.println(String(serial_string));
}
}
void sdlog(){
String log_string = ""; //start constructing a csv log file
// timestamp,stage,light sensor adc,od600,ph,heater,Tc,total OH uL,ext. sensors flow L/h
log_string = String(log_string +String(t, DEC));
log_string +=",";
log_string = String(log_string +String(stage, DEC));
log_string +=",";
log_string = String(log_string + String(lt,0));
log_string +=",";
log_string = String (log_string +String(od,2));
log_string +=",";
log_string = String(log_string +String(ph_instant, 2));
log_string +=",";
log_string = String(log_string +String(h_HEATER, DEC));
log_string +=",";
log_string = String(log_string +String(t0, DEC));
log_string +=",";
log_string = String(log_string +String(total_OH_uL, DEC));
log_string +=",";
log_string = String(log_string +String(l_hour, DEC));
File file = SD.open(fn, FILE_WRITE);
if (file) {
file.println(log_string);
file.close();
Serial.print("log file updated: ");
Serial.println(fn);
}
else {
Serial.print("error opening ");
Serial.println(fn);
Serial.println(log_string);
}
}
// Saving & Loading Settings on SD Card with Arduino. Addapted from:
// http://overskill.alexshu.com/saving-loading-settings-on-sd-card-with-arduino/
// initial version written by Alex Shu
void deleteSDnvmemory(){
if (SD.remove("nvmemory.txt")) {
Serial.println("nvmemory.txt removed from SD card.");
}
else {
Serial.println("file delete failed: nvmemory.txt does not exist or SD card error.");
}
}
void writeSDsettings(){
if (SD.remove("nvmemory.txt")) {
Serial.println("Old nvmemory.txt found and removed");
}
else {
Serial.println("nvmemory.txt not found on SD card. Trying to create it");
}
File pFile = SD.open("nvmemory.txt", FILE_WRITE);
if (pFile) {
Serial.println("File nvmemory.txt created");
unsigned int fwbcount = 0;
fwbcount += pFile.print("["); //we store the necessary startup sensors readings to be used in case of controller reset. In this case the initial optical density (l0);
fwbcount += pFile.print("l0="); // reference light intensity reading of optical density sensor
fwbcount += pFile.print(l0);
fwbcount += pFile.println("]");
fwbcount += pFile.print("[");
fwbcount += pFile.print("l0_saved="); // current process stage
fwbcount += pFile.print(l0_saved);
fwbcount += pFile.println("]");
Serial.println(String(fwbcount,DEC)+" bytes written");
pFile.close();
}
else Serial.println("Unable to create nvmemory.txt file on SD card !");
}
// converting string to Float
float toFloat(String settingValue){
char floatbuf[settingValue.length()+1];
settingValue.toCharArray(floatbuf, sizeof(floatbuf));
float f = atof(floatbuf);
return f;
}
long toLong(String settingValue){
char longbuf[settingValue.length()+1];
settingValue.toCharArray(longbuf, sizeof(longbuf));
long l = atol(longbuf);
return l;
}
void applySetting(String settingName, String settingValue) {
if(settingName == "l0") {
l0=settingValue.toInt();
}
if(settingName == "l0_saved") {
l0_saved=settingValue.toInt();
}
if(settingName == "OD_IPTG") {
OD_IPTG=toFloat(settingValue);
}
if(settingName == "OD_MAX") {
OD_MAX=toFloat(settingValue);
}
if(settingName == "PH_MIN"){
PH_MIN=toFloat(settingValue);
}
if(settingName == "PH_MAX") {
PH_MAX=toFloat(settingValue);
}
if(settingName == "PH_A") {
PH_A=toFloat(settingValue);
}
if(settingName == "PH_B") {
PH_B=toFloat(settingValue);
}
if(settingName == "OH_FLOW") {
OH_FLOW=settingValue.toInt();
}
if(settingName == "OH_DROP_VOLUME") {
OH_DROP_VOLUME=settingValue.toInt();
}
if(settingName == "OH_ON_OFF_MILISEC") {
OH_ON_OFF_MILISEC=settingValue.toInt();
}
if(settingName == "HARVEST_MINUTES") {
HARVEST_MINUTES=settingValue.toInt();
}
if(settingName == "MIN_GROWING_MINUTES") {
MIN_GROWING_MINUTES=settingValue.toInt();
}
if(settingName == "MIN_IPTG_MINUTES") {
MIN_IPTG_MINUTES=settingValue.toInt();
}
if(settingName == "IPTG_PUMPING_SECONDS") {
IPTG_PUMPING_SECONDS=settingValue.toInt();
}
if(settingName == "SD_LOG_FREQ_SEC") {
SD_LOG_FREQ_SEC=settingValue.toInt();
}
}
void readSDSettings(const char *filetoread){
char character;
String settingName;
String settingValue;
//File myFile = SD.open("nvmemory.txt");
File myFile = SD.open(filetoread);
if (myFile) {
Serial.println(String(filetoread) +" variables:");
while (myFile.available()) {
character = myFile.read();
while((myFile.available()) && (character != '[')){
character = myFile.read();
}
character = myFile.read();
while((myFile.available()) && (character != '=')){
settingName = settingName + character;
character = myFile.read();
}
character = myFile.read();
while((myFile.available()) && (character != ']')){
settingValue = settingValue + character;
character = myFile.read();
}
if(character == ']'){
//Serial.print("Name:");
Serial.print(settingName);
Serial.print("=");
Serial.println(settingValue);
// Apply the value to the parameter
applySetting(settingName,settingValue);
// Reset Strings
settingName = "";
settingValue = "";
}
}
// close the file:
myFile.close();
} else {
// if the file didn't open, print an error:
Serial.println("error opening "+ String(filetoread));
}
}
void setup()
{
Serial.begin(9600);
pinMode(B0_PIN, INPUT_PULLUP);
pinMode(M0_PIN, OUTPUT);
pinMode(M1_PIN, OUTPUT);
pinMode(M2_PIN, OUTPUT);
pinMode(M3_PIN, OUTPUT);
pinMode(H_PIN, OUTPUT);
pinMode(OH_PUMP_PIN, OUTPUT);
pinMode(AIR_PIN, OUTPUT);
pinMode(SD_CS, OUTPUT);
digitalWrite(H_PIN, HIGH);
digitalWrite(SD_CS, HIGH);
digitalWrite(OH_PUMP_PIN, HIGH);
m4_OH_PUMP = 0;
digitalWrite(AIR_PIN, HIGH);
m3_OD600 = 0;
digitalWrite(M3_PIN, HIGH);
m2_STIRER = 0;
digitalWrite(M2_PIN, HIGH);
m1_HARVEST = 0;
digitalWrite(M1_PIN, HIGH);
mo_IPTG = 0;
digitalWrite(M0_PIN, HIGH);
// try to avoid a known ethernet shield problem!
// disable SD SPI
pinMode(4, OUTPUT);
digitalWrite(4, HIGH);
// disable w5100 SPI
pinMode(10, OUTPUT);
digitalWrite(10, HIGH);
// try to avoid a known ethernet shield problem!
sensors.begin(); // for temp onewire sensors. IC Default 9 bit. If you have troubles consider setting it to 12.
// LCD2S by Modtronix on i2c bus
Wire.begin(); //Join bus as master
Wire.beginTransmission(0x28); //Start condition at the given I2C address or Mark the beginning of a data packet, change 0x28 to your device's I2C address
Wire.write(0x80); //Initiate Display Commands
Wire.write(0x0c); //Clear display and go to first line
Wire.write("Bioreactor starting"); //Write message
Wire.endTransmission(false); //End condition or Mark the end of data packet and send to LCD and hold bus connection
setSyncProvider(RTC.get); // the function to get the time from the RTC
if (timeStatus() != timeSet){
Serial.println("RTC time error");
}
else{
Serial.println("Time set by RTC");
}
delay(200);
if (Ethernet.begin(mac) == 0) {
Serial.println("Failed to configure Ethernet using DHCP...using default ip settings");
Ethernet.begin(mac, ip, dnServer, gateway, subnet);
}
else {
Serial.println("Ethernet configured by DHCP");
}
// print local IP address:
Serial.print("My IP address: ");
for (byte thisByte = 0; thisByte < 4; thisByte++) {
// print the value of each byte of the IP address:
Serial.print(Ethernet.localIP()[thisByte], DEC);
Serial.print(".");
}
Serial.println();
/*
* // DNS is buggy...!
DNSClient dns;
dnServer = Ethernet.dnsServerIP();
if (dnServer == 0) {
Serial.print("DNS by DHCP failed, using 8.8.8.8");
dnServer = (8,8,8,8);
}
// dns.begin(Ethernet.dnsServerIP());
dns.begin(dnServer);
Serial.print("My DNS address: ");
for (byte thisByte = 0; thisByte < 4; thisByte++) {
// print the value of each byte of the DNS address:
Serial.print(dnServer[thisByte], DEC);
Serial.print(".");
}
Serial.println();
dns.getHostByName("pool.ntp.org",ntpIP);
if (ntpIP!= (0,0,0,0)) {
Serial.print("DNS: pool.ntp.org: ");
}
else {
ntpIP = timeServer;
Serial.print("DNS failed, using default NTP IP: ");
}
*/
ntpIP = timeServer;
Serial.print("NTP IP: ");
Serial.println(ntpIP);
Udp.begin(localPort);
Serial.println("connecting to ntp server");
Serial.print(year());
Serial.print('-');
Serial.print(month());
Serial.print('-');
Serial.print(day());
Serial.print(' ');
Serial.print(hour());
Serial.print(':');
Serial.print(minute());
Serial.print(':');
Serial.print(second());
Serial.println(" --- RTC Time");
ntpSyncDS1307();
// create the alarms
Alarm.alarmRepeat(7,30,0, ntpSyncDS1307); // 7:30am every day
Alarm.alarmRepeat(19,30,0, ntpSyncDS1307); // 7:30pm every day
//web server init
server.begin();
Serial.print("web server is at ");
Serial.println(Ethernet.localIP());
//FlowMeter
pinMode(flowmeter_pin, INPUT_PULLUP);
attachInterrupt(5,flow,RISING); // Setup Interrupt
// see http://arduino.cc/en/Reference/attachInterrupt
sei(); // Enable interrupts
currentTime = millis();
cloopTime = currentTime;
// set date time callback function
//SdFile::dateTimeCallback(dateTime);
// log csv file on SD card gets a unique name from startup timestamp
t = now();
file_name = String(t,DEC);
fn = String(file_name.substring(2) + ".CSV");
Serial.print("File Name: ");
Serial.println(fn);
if (!SD.begin(SD_CS)) {
Serial.println("SD init failed");
}
else Serial.println("SD init ok");
File file = SD.open(fn, FILE_WRITE);
if (file) {
file.println("timestamp,stage,Lt,OD600,PH,Heater,Tc,OHuL,l_hour");
file.close();
Serial.println("log file header written");
}
else Serial.println("Error writing log file header");
readSDSettings("setup.txt"); //read the setup variables if exist on SD card
readSDSettings("nvmemory.txt"); //read the non volatile memory variables if exist on SD card
//watchDog does not work on this device, seams to be buggy :( so we don't use it
//wdt_enable(10000);
}
void loop(){
//wdt_reset(); //watchdog is disabled, so we don't need to reset it.
t = now();
old_millis = current_millis;
current_millis = millis();
main_loop_millis = current_millis - old_millis;
t0 = int(sensors.getTempCByIndex(0));
lt = analogRead(OD600);
//ph_instant = analogRead(PH);
ph_instant = ( analogRead(PH)* PH_A) + PH_B; //regression function resulted from ph probe calibration !
od = -log(lt/l0); // calculate optical density based of light intensity value
if (digitalRead(B0_PIN) == LOW) {
b0 = 1;
}
else {
b0 = 0;
}
if (timeStatus() != timeSet) setSyncProvider(RTC.get); // the function to get the time from the RTC
if (timeStatus() != timeSet) Serial.println("Unable to sync with the RTC");
sensors.requestTemperatures(); // Send the command to get temperatures
//FlowMeterCode
currentTime = millis();
// Every second, calculate and print litres/hour
if(currentTime >= (cloopTime + 1000)){
cloopTime = currentTime; // Updates cloopTime
l_hour = (flow_frequency * 60 / 7.5); // (Pulse frequency x 60 min) / 7.5Q = flow rate in L/hour
flow_frequency = 0; // Reset Counter
// Serial.print(l_hour, DEC); // debug print L/hour
// Serial.println(" L/hour");
}
if ((od > OD_IPTG) ) {
if (od_over_1 <10) od_over_1++; // making sure we get stable light sensor reading
}
else {
od_over_1 = 0;
}
if (od > OD_MAX) {
if (od_over_2 <10) od_over_2++;
}
else {
od_over_2 = 0;
}
if (b0 == 0) { //if button is OFF, stop all the motors/pumps and go to ready state.
h_HEATER = 0;
digitalWrite(H_PIN, HIGH);
digitalWrite(AIR_PIN, HIGH);
m3_OD600 = 0;
digitalWrite(M3_PIN, HIGH);
//Mo3->run(RELEASE);
m2_STIRER = 0;
digitalWrite(M2_PIN, HIGH);
m1_HARVEST = 0;
digitalWrite(M1_PIN, HIGH);
digitalWrite(OH_PUMP_PIN, HIGH);
if (mo_IPTG == 1){
digitalWrite(M0_PIN, HIGH);
mo_IPTG = 0;
}
if (stage >0) deleteSDnvmemory();
stage = 0;
l0_saved = 0;
}
else switch (stage) {
case 0:
stage = 1;
if (l0_saved==0){
l0_saved=1;
l0 = lt; // zero the OD600 sensor.
writeSDsettings(); //write on the sd card as non volatile (reset persistent) memory.
}
stage_milliseconds = millis();
h_HEATER = 1;
digitalWrite(H_PIN, LOW);
digitalWrite(AIR_PIN, LOW);
if (m3_OD600 == 0) {
m3_OD600 = 1;
digitalWrite(M3_PIN, LOW);
}
m2_STIRER = 1;
digitalWrite(M2_PIN, LOW);
break;
case 1:
if ((od_over_1 == 10) and (millis() - stage_milliseconds > MIN_GROWING_MINUTES*60000)) {
Serial.print("millis:");
Serial.print(millis());
Serial.print("-Stage miliseconds:");
Serial.print(stage_milliseconds);
Serial.print(">120000:");
Serial.println(120000);
stage = 2;
writeSDsettings();
stage_milliseconds = millis();
if (mo_IPTG == 0) {
mo_IPTG = 1;
digitalWrite(M0_PIN, LOW);
//Mo0->run(FORWARD);
Serial.println("IPTG pump ON");
}
}
break;
case 2:
if ((mo_IPTG == 1) and (millis() - stage_milliseconds > IPTG_PUMPING_SECONDS*1000)){
mo_IPTG = 0;
digitalWrite(M0_PIN, HIGH);
}
if ((od_over_2 == 10) and (millis() - stage_milliseconds > MIN_IPTG_MINUTES*60000)) {
mo_IPTG = 0;
digitalWrite(M0_PIN, HIGH); // iptg pump off
stage = 3; //Harvest
writeSDsettings();
stage_milliseconds = millis();
h_HEATER = 0;
digitalWrite(H_PIN, HIGH);
digitalWrite(AIR_PIN, HIGH);
if (m3_OD600 == 1) {
m3_OD600 = 0;
digitalWrite(M3_PIN, HIGH);
}
m2_STIRER = 0;
digitalWrite(M2_PIN, HIGH);
m1_HARVEST = 1;
digitalWrite(M1_PIN, LOW);
}
break;
case 3:
if (millis() - stage_milliseconds > HARVEST_MINUTES*60000){
stage = 4; //Done!
writeSDsettings();
stage_milliseconds = millis();
m1_HARVEST = 0;
digitalWrite(M1_PIN, HIGH);
}
break;
}
//WRITE LOG EVERY "SD_LOG_FREQ_SEC" SECONDS
if (t - log_seconds > SD_LOG_FREQ_SEC){
sdlog();
log_seconds = t;
}
//DISPLAY REFRESH EVERY SECOND
if (displayAtSecond != second(t)) {
refreshDisplay();
displayAtSecond = second(t);
}
// OH pump control code, for ph adjustment!
String oh_log = "";
if ((stage >0) and (stage <3) and (ph_instant < PH_MIN) and (millis() - oh_on_milliseconds > OH_ON_OFF_MILISEC)) {
oh_log = "Pumping ";
oh_log += String(OH_DROP_VOLUME, DEC);
oh_log += "uL OH in ";
oh_log += String(OH_DROP_VOLUME*1000 / OH_FLOW, DEC);
oh_log += " milliseconds";
Serial.println(oh_log);
total_OH_uL += OH_DROP_VOLUME;
consecutive_OH_pulses +=1;
oh_log = "Main loop takes ";
Serial.print(oh_log);
Serial.print(main_loop_millis);
oh_log = " milliseconds";
Serial.println(oh_log);
oh_log = "OH Pump ON ";
Serial.println(oh_log);
m4_OH_PUMP = 1;
oh_on_milliseconds = millis();
oh_off_milliseconds = 0;
Serial.println(millis());
digitalWrite(OH_PUMP_PIN, LOW);
delay((OH_DROP_VOLUME*1000 / OH_FLOW) % main_loop_millis); // compensate for main loop delay, useful if calculated pumping time is shorter than main loop delay!
}
if (m4_OH_PUMP == 1 and millis() - oh_on_milliseconds > OH_DROP_VOLUME*1000 / OH_FLOW ){
Serial.println(millis());
digitalWrite(OH_PUMP_PIN, HIGH);
oh_log = "OH Pump OFF ";
Serial.println(oh_log);
m4_OH_PUMP = 0;
oh_off_milliseconds = millis();
}
if ((consecutive_OH_pulses > 10) and (ph_instant < PH_MIN)) {
OH_DROP_VOLUME=OH_DROP_VOLUME*2; //addaptive OH compensation (if default OH drop volume fails to rise pH after 10 drops, we double the drop volume)
consecutive_OH_pulses = 0;
}
//webserver code
//----------------------------------------------------------------------------------------------
// listen for incoming clients
EthernetClient client = server.available();
// if (client) {
if (client.connected()) {
// Serial.println("new Web client connected");
if (client.available()) {
char c1 = client.read();
char c2 = client.read(); //standard http request ends with a blank line.
if (c1 == '\r' && c2 == '\n'){
// send a standard http response header
Serial.write("Sending data to Web client \n");
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close"); // the connection will be closed after completion of the response
client.println("Refresh: 60"); // refresh the page automatically every 60 sec
client.println();
client.println("<!DOCTYPE HTML>");
client.println(web_string); // send actual process values to web client
delay(1);
// close the connection:
client.stop();
Serial.println("Web client disconnected");
}
}
}
//}
}