Problème code pour LCD

Bonjour,
je suis nouveau dans le monde arduino et j'ai besoin d'un coup de main, dans un projet de réalisation d'un bioreacteur je suis tombé sur un code qui m intéresse beaucoup. (source Open-Source bioreactor controller for bacterial protein expression [PeerJ Preprints])
le code : https://d3amtssd1tejdt.cloudfront.net/2018/27150/1/S6_bioreactor_2.5.ino

je le téléverse dans un arduino mega avec le câblage comme décrit dans l'article sauf que j'utilise un LCD 2004 (20x4) avec adaptateur i2c au lieu du LCD2S-204BIW Modtronix.
l'afficheur flash au démarrage mais rien d'afficher ni d'éclairage par la suite .
j'ai deja testé l'afficheur avec d'autre code il marche très bien avec l'adresse i2c (0x27), l'adresse indiqué dans le code du bioreacteur est la (0x28) pour l'afficheur LCD2S by Modtronix j'ai essayé de la changer pour (0x27) mais rien ne marche.
merci d'avance de votre aide

Salut

La fonction refreshDisplay() est la où tout se passe sans doute avec accès direct à wire). Il faudrait la réécrire en utilisant les commandes fournies par une bibliothèque adaptée à votre écran

merci pour la réponse, comme je l ai cité je suis un débutant d'autant plus je ne suis pas du domaine (biologiste) serait il possible de remplacer refreshDisplay() par qlq chose d'autre genre LiquidCrystal_I2C ?

Oui mais faudrait comprendre ce qu’ils font dans cette fonction au niveau affichage et changer ces commandes d’affichage par celles de la bibliothèque

(Je ne connais pas le LCD2S-204BIW Modtronix)

Bonjour,
Le problème c'est que le carte d'interface LCD possède un microcontrôleur qui reste une boite noir vue de l'extérieur.
Soit vous utilisez le même matériel soit il va falloir réécrire tout le code de la partie affichage.

Bonjour cherif27

Ça devrait être possible, l'essentiel de refreshDisplay est un concaténation de LCD_screen et l'accès au bus i2C.
Je fais un essai, dans la matinée avec un LCD 20x4.

Cordialement
jpbbricole

Bonjour jpbbricole
effectivement à un moment je me suis dit refaire un autre code pour cette partie car j'ai l'impression que tt le système ne continue pas le procès tant qu il n y a pas d'affichage sur LCD .... ou bien je n'ai pas bien compris le code , je suis débutant :slight_smile:

Bonjour cherif27

Peut-être ça bloque dans la partie Wire (i2c) du fait du manque de l'affichage, je ne peut pas certifier.
Je fais un essai d'intégration du LCD 2004.

A+
Cordialement
jpbbricole

merci bien pour ton aide
cordialement

Bonjour Cherif27

Je crois que c'est tout bon, au retour du marché, je poste ça.

A+
Cordialement
jpbbricole

Le code cité utilise une profusion de String. Il serait étonnant que cela fonctionne très longtemps.

Bonjour hbachetti

Moi qui ne suis pas du tout "du sérail", comme on dit, mais un Arduiniste convaincu, je m'étonne de cette aversion, de certaines personnes envers, la classe String. Classe qui simplifie grandement les choses et est surtout largement prônée par "l'équipe" Arduino. Se seraient ils trompés à ce point là et, depuis le temps, pourquoi n'ont il pas corrigé le tir?
Plein de questions sans réponses.

Cordialement
jpbbricole

Bonjour Cherif27

Voilà les correctifs

Chaque ligne est dans la section où elle doit être
refreshDisplay() est complète et doit remplacer entièrement ton actuelle.
La bibliothèque utilisée est celle-ci. Suivant les versions, l'initialisation s'écrit

lcd2004.init();
ou
lcd2004.begin();

L'adresse de l'affichage est 0x27

Comme je n'ai pas l'environnement complet, j'ai du faire "comme si"
Problème que tu risques d'avoir est la mise en page, mais là, il n'y a que toi qui peut le dire.
Si jamais, dis moi ce qu'il doit y avoir sur la ligne 1, ligne 2... je t'indiquerai comment faire

#include <LiquidCrystal_I2C.h>     // https://www.arduino.cc/reference/en/libraries/liquidcrystal-i2c/

LiquidCrystal_I2C lcd2004(0x27,20,4);  // set the LCD address to 0x27 for a 16 chars and 2 line display

void setup()
{
	Serial.begin(115200);
	lcd2004.init();
	lcd2004.backlight();
	
}

void loop()
{
}

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));
  }

lcd2004.clear();
lcd2004.home();
lcd2004.print(LCD_string);
}

A+
Cordialement
jpbbricole

Je pense que tu n'as pas lu mon article, ou de travers. Il y a un exemple de code simple, exécuté sur NANO et MEGA. Il suffit d'essayer.

La classe String est largement déconseillée par bon nombre de membres du forum, et cela ne date pas d'hier.
On voit beaucoup de tutoriels utilisant la classe String, écrits par des néophytes qui ne connaissent pas la fragmentation mémoire.
Sur ESP8266 et ESP32 je ne m'en prive pas, mais sur ARDUINO il est préférable de s'en passer.

je viens de tester le code, malheureusement j'ai beaucoup d'erreur lors de la compil concernant "wire" (error: 'Wire' does not name a type)

l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:325:3: error: 'Wire' does not name a type
   Wire.beginTransmission(0x28);  //Start condition at 0x28 (LCD) I2C address or Mark the beginning of a data packet.
   ^~~~
l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:326:3: error: 'Wire' does not name a type
   Wire.write(0x80);  //Initiate I2C Display Commands
   ^~~~
l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:327:3: error: 'Wire' does not name a type
   Wire.write(0x0c);  //Clear display and go to first line
   ^~~~
l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:328:3: error: expected unqualified-id before 'for'
   for (i=0;i<20;i++) {
   ^~~
l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:328:12: error: 'i' does not name a type
   for (i=0;i<20;i++) {
            ^
l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:328:17: error: 'i' does not name a type
   for (i=0;i<20;i++) {
                 ^
l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:331:3: error: 'Wire' does not name a type
   Wire.endTransmission(true);
   ^~~~
l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:332:3: error: 'Wire' does not name a type
   Wire.beginTransmission(0x28);
   ^~~~
l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:333:3: error: 'Wire' does not name a type
   Wire.write(0x80);
   ^~~~
l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:334:3: error: expected unqualified-id before 'for'
   for (i=20;i<40;i++) {
   ^~~
l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:334:13: error: 'i' does not name a type
   for (i=20;i<40;i++) {
             ^
l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:334:18: error: 'i' does not name a type
   for (i=20;i<40;i++) {
                  ^
l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:338:3: error: 'Wire' does not name a type
   Wire.endTransmission(true);
   ^~~~
l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:339:3: error: 'Wire' does not name a type
   Wire.beginTransmission(0x28);
   ^~~~
l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:340:3: error: 'Wire' does not name a type
   Wire.write(0x80);
   ^~~~
l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:341:3: error: expected unqualified-id before 'for'
   for (i=40;i<60;i++) {
   ^~~
l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:341:13: error: 'i' does not name a type
   for (i=40;i<60;i++) {
             ^
l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:341:18: error: 'i' does not name a type
   for (i=40;i<60;i++) {
                  ^
l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:345:3: error: 'Wire' does not name a type
   Wire.endTransmission(true);
   ^~~~
l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:346:3: error: 'Wire' does not name a type
   Wire.beginTransmission(0x28);
   ^~~~
l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:347:3: error: 'Wire' does not name a type
   Wire.write(0x80);
   ^~~~
l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:348:3: error: expected unqualified-id before 'for'
   for (i=60;i<80;i++) {
   ^~~
l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:348:13: error: 'i' does not name a type
   for (i=60;i<80;i++) {
             ^
l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:348:18: error: 'i' does not name a type
   for (i=60;i<80;i++) {
                  ^
l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:353:3: error: 'Wire' does not name a type
   Wire.endTransmission(false); // gracefully closing 12c bus
   ^~~~
l:\Telechargements\S6_bioreactor_2.5 v or\S6_bioreactor_2.5 v or.ino:354:1: error: expected declaration before '}' token
 }
 ^
Multiple libraries were found for "DallasTemperature.h"
 Used: H:\Mes documents\Arduino\libraries\DallasTemperature
 Not used: H:\Mes documents\Arduino\libraries\MAX31850_DallasTemp
Multiple libraries were found for "DS1307RTC.h"
 Used: H:\Mes documents\Arduino\libraries\DS1307RTC
 Not used: H:\Mes documents\Arduino\libraries\DS1307RTC-master
Multiple libraries were found for "TimeLib.h"
 Used: H:\Mes documents\Arduino\libraries\Time-master
 Not used: H:\Mes documents\Arduino\libraries\Time
Multiple libraries were found for "OneWire.h"
 Used: H:\Mes documents\Arduino\libraries\OneWire
 Not used: H:\Mes documents\Arduino\libraries\MAX31850_OneWire
 Not used: L:\ARDUINO\ArduinoAug_0.70.16_EXP\libraries\A1_Duinoedu_OneWire
Multiple libraries were found for "LiquidCrystal_I2C.h"
 Used: H:\Mes documents\Arduino\libraries\LiquidCrystal_I2C
 Not used: H:\Mes documents\Arduino\libraries\Arduino-LiquidCrystal-I2C-library-master
 Not used: H:\Mes documents\Arduino\libraries\New-LiquidCrystal-master
Multiple libraries were found for "Dhcp.h"
 Used: H:\Mes documents\Arduino\libraries\Ethernet2
 Not used: L:\ARDUINO\ArduinoAug_0.70.16_EXP\libraries\Ethernet
Multiple libraries were found for "SD.h"
 Used: H:\Mes documents\Arduino\libraries\SD
 Not used: L:\ARDUINO\ArduinoAug_0.70.16_EXP\libraries\SD
Compilation error: Error: 2 UNKNOWN: exit status 1

Bonsoir cherif27

Je pense que tu as un problème d'intégration des modifications que je t'ai proposeés.
Je te prépare une versuin complète.

A+
Cordialement
jpbbricole

merci . sinon histoire d'apprendre comme je suis débutant, j'aimerai savoir à quoi renvois cette erreur ? es que j'ai oublié un crochet ou un point-virgule...

Bonsoircherif27

Comme je n'ai pas l'environnement nécessaire, il m'est assez difficile d'intégrer les modifications et de tester l'entier du programme, voici la version complète, essaies et passes-moi les erreurs éventuelles.
Il peut avoir une erreur à l'initialisation de l'affichage, il y a 2 modes dépendant de la bibliothèque utilisée:
lcd2004.init();
ou
lcd2004.begin();

L'adresse de l'affichage est 0x27

Le programme complet:`
/*
*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 <LiquidCrystal_I2C.h> // LiquidCrystal I2C - Arduino Reference
#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;

LiquidCrystal_I2C lcd2004(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display

// 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));
}

lcd2004.clear();
lcd2004.home();
lcd2004.print(LCD_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);

lcd2004.init();
lcd2004.backlight();

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.

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 :frowning: 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_MINUTES60000)) {
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_MINUTES60000)) {
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_VOLUME1000 / 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_VOLUME1000 / 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("");
client.println(web_string); // send actual process values to web client
delay(1);
// close the connection:
client.stop();
Serial.println("Web client disconnected");
}
}
}
//}
}
`
Je crois les doigts :blush:

A+
Cordialement
jpbbricole

bon changement d'erreur :smiley: je crois qu il point le Shield Ethernet ,

h:\Mes documents\Arduino\test bioR corr\test bioR corr.ino:70:6: error: scalar object 'mac' requires one element in initializer
byte mac = {0x90, 0xA2, 0xDA, 0x10, 0xDE, 0xE4};
     ^~~
h:\Mes documents\Arduino\test bioR corr\test bioR corr.ino:73:6: error: scalar object 'ip' requires one element in initializer
byte ip = {10, 5, 5, 171}; // to be used if DHCP fails
     ^~
h:\Mes documents\Arduino\test bioR corr\test bioR corr.ino: In function 'void loop()':
h:\Mes documents\Arduino\test bioR corr\test bioR corr.ino:733:60: error: 'MIN_GROWING_MINUTES60000' was not declared in this scope
if ((od_over_1 == 10) and (millis() - stage_milliseconds > MIN_GROWING_MINUTES60000)) {
                                                           ^~~~~~~~~~~~~~~~~~~~~~~~
h:\Mes documents\Arduino\test bioR corr\test bioR corr.ino:733:60: note: suggested alternative: 'MIN_GROWING_MINUTES'
if ((od_over_1 == 10) and (millis() - stage_milliseconds > MIN_GROWING_MINUTES60000)) {
                                                           ^~~~~~~~~~~~~~~~~~~~~~~~
                                                           MIN_GROWING_MINUTES
h:\Mes documents\Arduino\test bioR corr\test bioR corr.ino:752:57: error: 'IPTG_PUMPING_SECONDS1000' was not declared in this scope
if ((mo_IPTG == 1) and (millis() - stage_milliseconds > IPTG_PUMPING_SECONDS1000)){
                                                        ^~~~~~~~~~~~~~~~~~~~~~~~
h:\Mes documents\Arduino\test bioR corr\test bioR corr.ino:752:57: note: suggested alternative: 'IPTG_PUMPING_SECONDS'
if ((mo_IPTG == 1) and (millis() - stage_milliseconds > IPTG_PUMPING_SECONDS1000)){
                                                        ^~~~~~~~~~~~~~~~~~~~~~~~
                                                        IPTG_PUMPING_SECONDS
h:\Mes documents\Arduino\test bioR corr\test bioR corr.ino:756:60: error: 'MIN_IPTG_MINUTES60000' was not declared in this scope
if ((od_over_2 == 10) and (millis() - stage_milliseconds > MIN_IPTG_MINUTES60000)) {
                                                           ^~~~~~~~~~~~~~~~~~~~~
h:\Mes documents\Arduino\test bioR corr\test bioR corr.ino:756:60: note: suggested alternative: 'MIN_IPTG_MINUTES'
if ((od_over_2 == 10) and (millis() - stage_milliseconds > MIN_IPTG_MINUTES60000)) {
                                                           ^~~~~~~~~~~~~~~~~~~~~
                                                           MIN_IPTG_MINUTES
h:\Mes documents\Arduino\test bioR corr\test bioR corr.ino:776:37: error: 'HARVEST_MINUTES60000' was not declared in this scope
if (millis() - stage_milliseconds > HARVEST_MINUTES60000){
                                    ^~~~~~~~~~~~~~~~~~~~
h:\Mes documents\Arduino\test bioR corr\test bioR corr.ino:776:37: note: suggested alternative: 'HARVEST_MINUTES'
if (millis() - stage_milliseconds > HARVEST_MINUTES60000){
                                    ^~~~~~~~~~~~~~~~~~~~
                                    HARVEST_MINUTES
h:\Mes documents\Arduino\test bioR corr\test bioR corr.ino:804:18: error: 'OH_DROP_VOLUME1000' was not declared in this scope
oh_log += String(OH_DROP_VOLUME1000 / OH_FLOW, DEC);
                 ^~~~~~~~~~~~~~~~~~
h:\Mes documents\Arduino\test bioR corr\test bioR corr.ino:804:18: note: suggested alternative: 'OH_DROP_VOLUME'
oh_log += String(OH_DROP_VOLUME1000 / OH_FLOW, DEC);
                 ^~~~~~~~~~~~~~~~~~
                 OH_DROP_VOLUME
h:\Mes documents\Arduino\test bioR corr\test bioR corr.ino:823:57: error: 'OH_DROP_VOLUME1000' was not declared in this scope
if (m4_OH_PUMP == 1 and millis() - oh_on_milliseconds > OH_DROP_VOLUME1000 / OH_FLOW ){
                                                        ^~~~~~~~~~~~~~~~~~
h:\Mes documents\Arduino\test bioR corr\test bioR corr.ino:823:57: note: suggested alternative: 'OH_DROP_VOLUME'
if (m4_OH_PUMP == 1 and millis() - oh_on_milliseconds > OH_DROP_VOLUME1000 / OH_FLOW ){
                                                        ^~~~~~~~~~~~~~~~~~
                                                        OH_DROP_VOLUME
h:\Mes documents\Arduino\test bioR corr\test bioR corr.ino:832:16: error: 'OH_DROP_VOLUME2' was not declared in this scope
OH_DROP_VOLUME=OH_DROP_VOLUME2; //addaptive OH compensation (if default OH drop volume fails to rise pH after 10 drops, we double the drop volume)
               ^~~~~~~~~~~~~~~
h:\Mes documents\Arduino\test bioR corr\test bioR corr.ino:832:16: note: suggested alternative: 'OH_DROP_VOLUME'
OH_DROP_VOLUME=OH_DROP_VOLUME2; //addaptive OH compensation (if default OH drop volume fails to rise pH after 10 drops, we double the drop volume)
               ^~~~~~~~~~~~~~~
               OH_DROP_VOLUME
Multiple libraries were found for "TimeLib.h"
Used: H:\Mes documents\Arduino\libraries\Time-master
Not used: H:\Mes documents\Arduino\libraries\Time
Multiple libraries were found for "SD.h"
Used: H:\Mes documents\Arduino\libraries\SD
Not used: L:\ARDUINO\ArduinoAug_0.70.16_EXP\libraries\SD
Multiple libraries were found for "OneWire.h"
Used: H:\Mes documents\Arduino\libraries\OneWire
Not used: L:\ARDUINO\ArduinoAug_0.70.16_EXP\libraries\A1_Duinoedu_OneWire
Multiple libraries were found for "Dhcp.h"
Used: H:\Mes documents\Arduino\libraries\Ethernet2
Not used: L:\ARDUINO\ArduinoAug_0.70.16_EXP\libraries\Ethernet
Multiple libraries were found for "LiquidCrystal_I2C.h"
Used: H:\Mes documents\Arduino\libraries\LiquidCrystal_I2C
Not used: H:\Mes documents\Arduino\libraries\New-LiquidCrystal-master
Not used: H:\Mes documents\Arduino\libraries\Arduino-LiquidCrystal-I2C-library-master
Compilation error: Error: 2 UNKNOWN: exit status 1

Si tu charges le programme d'origine, que se passe-t-il?