COUVEUSE V2.0

bonjour les fous,
ayant pu récupérer une vitrine réfrigérée chez un pote restaurateur et ayant besoin d'une couveuse plus grande cette année, je me lance dans une V 2.0.

Déjà, une après midi pour faire la mise en place sur l'écran touchscreen 7", un peu galère
Voilà la 1ère mouture de la console, reste a faire toute la partie touch pour la température.
Le design, n'est pas aussi beau que pour certaines réalisations, mais c'est un peu en urgence.

Matériel utilisé :

  • une vitrine réfrigérée vidée de son compresseur, seuls restent le ventilo et la lumière.
    démontage du ventilo double hélice pour inverser le sens de rotation, coup de bol un deux fils :slight_smile:

  • un 2560

  • un CTE70 de 7" avec son support

  • 2 sondes ds18b20 '1 en haut, 1 en bas)

  • 1 dht 21 pour l'humidité

  • 1 résitance souple 50w 230v

  • une alim pc

  • des relais
    ------------ pas mal de cheveux pour en garder à la fin
    ------------pas mal de café et clopes (je sais, c'est pas bien pour le café )

je mettrai le code plus tard, car là, il est plutot en mode crapouette, c'est la 1ere fois que je jouai avec un touchscreen qui trainait dans un tiroir :frowning:

pour éviter les galères que l'on connait avec le 7" et la carte, les pins 5 et 3.3v sont écartées et non connectées à la carte.
j'ai juste alimenté l'écran par du 5v sans connecter le 3.3v, sur l'alim pc, ca évite l'écran blanc et le plantage.

la photo a du mal a passer, y a des restrictions ou quoi?
140ko pourtant

bonsoir IB
quelle capacité en "zeufs" :grin: ta nouvelle couveuse ?

Joli l'affichage avec une arduino! Chapeau l'artiste

Artouste:
bonsoir IB
quelle capacité en "zeufs" :grin: ta nouvelle couveuse ?

de 1 à 150 en canard
de 1 à 100 en oie
de 1 à 450 en caille
environ à la louche
je ferai une photo demain de la machine :slight_smile:

Jambe:
Joli l'affichage avec une arduino! Chapeau l'artiste

merci, mais certains ont fait nettement mieux, là, je fais dans l'urgence et j'essaye de piger comment ca fonctionne un touch en même temps que je code.

Bonsoir infobarquee,
Il manque une donnée.
Combien d'oeufs d'autruche ?

:slight_smile:
de 1 à 4
:wink:

#include <UTFT.h>
#include <UTouch.h>
#include <EEPROM.h>                   // needed for EEPROM
#include "EEPROMAnything.h"           // needed for EEPROM
#include <OneWire.h> // Inclusion de la librairie OneWire

// #define EEPROMSIZE 512              // ATMEGA168 512 EEPROM
#define EEPROMSIZE 1024               // ATMEGA328P 1024 EEPROM
UTFT    myGLCD(CTE70, 38, 39, 40, 41);
UTouch  myTouch( 6, 5, 4, 3, 2);
extern uint8_t BigFont[];

int x, y;
char stCurrent[20] = "";
int stCurrentLen = 0;
char stLast[20] = "";
boolean relay = false;

struct config_t {
  int validdata;       // if this is 99 then data is valid
  float temperature;
} mydata;

int datasize;      // will hold size of the struct myfocuser - 6 bytes
int nlocations;    // number of storage locations available in EEPROM
int currentaddr;   // will be address in eeprom of the data stored
boolean writenow;     // should we update values in eeprom
boolean found;        // did we find any stored values?
long numwrites = 0L;        // number of eeprom writes this session


float temp;
float temp1;
float moyennetemp;
#define relais 10
#define DS18B20 0x28     // Adresse 1-Wire du DS18B20
#define BROCHE_ONEWIRE 8 // Broche utilisée pour le bus 1-Wire
OneWire ds(BROCHE_ONEWIRE); // Création de l'objet OneWire ds

#define DS18B201 0x28     // Adresse 1-Wire du DS18B20
#define BROCHE_ONEWIRE1 9 // Broche utilisée pour le bus 1-Wire
OneWire ds1(BROCHE_ONEWIRE1); // Création de l'objet OneWire ds

// Fonction récupérant la température depuis le DS18B20
// Retourne true si tout va bien, ou false en cas d'erreur
boolean getTemperature(float *temp) {
  byte data[9], addr[8];
  // data : Données lues depuis le scratchpad
  // addr : adresse du module 1-Wire détecté

  if (!ds.search(addr)) { // Recherche un module 1-Wire
    ds.reset_search();    // Réinitialise la recherche de module
    return false;         // Retourne une erreur
  }

  if (OneWire::crc8(addr, 7) != addr[7]) // Vérifie que l'adresse a été correctement reçue
    return false;                        // Si le message est corrompu on retourne une erreur

  if (addr[0] != DS18B20) // Vérifie qu'il s'agit bien d'un DS18B20
    return false;         // Si ce n'est pas le cas on retourne une erreur

  ds.reset();             // On reset le bus 1-Wire
  ds.select(addr);        // On sélectionne le DS18B20

  ds.write(0x44, 1);      // On lance une prise de mesure de température
  delay(500);             // Et on attend la fin de la mesure

  ds.reset();             // On reset le bus 1-Wire
  ds.select(addr);        // On sélectionne le DS18B20
  ds.write(0xBE);         // On envoie une demande de lecture du scratchpad

  for (byte i = 0; i < 9; i++) // On lit le scratchpad
    data[i] = ds.read();       // Et on stock les octets reçus

  // Calcul de la température en degré Celsius
  *temp = ((data[1] << 8) | data[0]) * 0.0625;

  // Pas d'erreur
  return true;
}

// Fonction récupérant la température depuis le DS18B20
// Retourne true si tout va bien, ou false en cas d'erreur
boolean getTemperature1(float *temp1) {
  byte data[9], addr[8];
  // data : Données lues depuis le scratchpad
  // addr : adresse du module 1-Wire détecté

  if (!ds1.search(addr)) { // Recherche un module 1-Wire
    ds1.reset_search();    // Réinitialise la recherche de module
    return false;         // Retourne une erreur
  }

  if (OneWire::crc8(addr, 7) != addr[7]) // Vérifie que l'adresse a été correctement reçue
    return false;                        // Si le message est corrompu on retourne une erreur

  if (addr[0] != DS18B201) // Vérifie qu'il s'agit bien d'un DS18B20
    return false;         // Si ce n'est pas le cas on retourne une erreur

  ds1.reset();             // On reset le bus 1-Wire
  ds1.select(addr);        // On sélectionne le DS18B20

  ds1.write(0x44, 1);      // On lance une prise de mesure de température
  delay(500);             // Et on attend la fin de la mesure

  ds1.reset();             // On reset le bus 1-Wire
  ds1.select(addr);        // On sélectionne le DS18B20
  ds1.write(0xBE);         // On envoie une demande de lecture du scratchpad

  for (byte i = 0; i < 9; i++) // On lit le scratchpad
    data[i] = ds1.read();       // Et on stock les octets reçus

  // Calcul de la température en degré Celsius
  *temp1 = ((data[1] << 8) | data[0]) * 0.0625;

  // Pas d'erreur
  return true;
}

void drawButtons()
{
  myGLCD.setColor(0, 0, 255);
  myGLCD.fillRoundRect (0, 0, 300, 450);
  myGLCD.setColor(255, 255, 255);
  myGLCD.drawRoundRect (0, 0, 300, 450);
  myGLCD.setColor(255, 255, 255);
  myGLCD.print("Temperature haut", 15, 5);
  myGLCD.setColor(255, 255, 255);
  myGLCD.print("Humidite", 80, 150);
  myGLCD.setColor(255, 255, 255);
  myGLCD.print("Temperature bas", 20, 300);
  myGLCD.setColor(255, 255, 255);
  myGLCD.print("Resistance ", 5, 400);

  myGLCD.setColor(0, 0, 255);
  myGLCD.fillRoundRect (310, 0, 780, 65);
  myGLCD.setColor(255, 255, 255);
  myGLCD.drawRoundRect (310, 0, 780, 65);
  myGLCD.setColor(255, 255, 255);
  myGLCD.print("Moyenne temperature ", 400, 5);


  myGLCD.setColor(0, 0, 255);
  myGLCD.fillRoundRect (310, 80, 780, 150);
  myGLCD.setColor(255, 255, 255);
  myGLCD.drawRoundRect (310, 80, 780, 150);
  myGLCD.setColor(255, 255, 255);
  myGLCD.print("Temperature memoire", 400, 85);
  /*  myGLCD.setColor(255, 0, 0);
    myGLCD.print("38.700", 490, 115); */

  myGLCD.setColor(118, 238, 0);
  myGLCD.fillRoundRect (310, 160, 780, 450);
  myGLCD.setColor(255, 255, 255);
  myGLCD.drawRoundRect (310, 160, 780, 450);
  myGLCD.setColor(255, 255, 255);
  myGLCD.setBackColor(118, 218, 0);
  myGLCD.print("Temperature a memoiriser", 350, 165);

  //chiffre de 1 a 5
  for (x = 0; x < 6; x++)
  {
    myGLCD.setColor(0, 0, 255);
    myGLCD.fillRoundRect (315 + (x * 60), 185, 370 + (x * 60), 225);
    myGLCD.setColor(255, 255, 255);
    myGLCD.drawRoundRect (315 + (x * 60), 185, 370 + (x * 60), 225);
    myGLCD.printNumI(x + 1, 335 + (x * 60), 195);
  }
  //chiffre de 6 a 0
  for (x = 0; x < 6; x++)
  {
    myGLCD.setColor(0, 0, 255);
    myGLCD.fillRoundRect (315 + (x * 60), 235, 370 + (x * 60), 285);
    myGLCD.setColor(255, 255, 255);
    myGLCD.drawRoundRect (315 + (x * 60), 235, 370 + (x * 60), 285);
    if (x < 3) myGLCD.printNumI(x + 7, 335 + (x * 60), 255);
  }
  myGLCD.setColor(255, 255, 255);
  myGLCD.print("0", 515 , 255);
  myGLCD.print(".", 575 , 255);
  myGLCD.print("*", 635 , 255);

  myGLCD.setColor(0, 0, 255);
  myGLCD.fillRoundRect (315, 300, 450, 350);
  myGLCD.setColor(255, 255, 255);
  myGLCD.drawRoundRect (315, 300, 450, 350);
  myGLCD.print("EFFACER", 325, 315);

  myGLCD.setColor(0, 0, 255);
  myGLCD.fillRoundRect (470, 300, 670, 350);
  myGLCD.setColor(255, 255, 255);
  myGLCD.drawRoundRect (470, 300, 670, 350);
  myGLCD.print("MEMORISER", 500, 315);


  //   myGLCD.setColor(0, 255, 0);

  // myGLCD.print("38.569 C", 450, 400);


}


void updateStr(int val)
{
  String tempupdate = "";
  if (stCurrentLen < 6)
  {


    stCurrent[stCurrentLen] = val;
    stCurrent[stCurrentLen + 1] = '\0';
    stCurrentLen++;
    myGLCD.setColor(0, 0, 0);
    myGLCD.setBackColor(118, 218, 0);

    myGLCD.print(stCurrent, 420, 375);
    if (stCurrent != "*") {

      tempupdate += stCurrent;
      Serial.println(tempupdate);
      mydata.validdata = 99;
      mydata.temperature = tempupdate.toFloat();
      EEPROM_writeAnything(currentaddr, mydata);    // update values in EEPROM
      numwrites++;
      writenow = true;
    }
  }
  else
  {
    myGLCD.setColor(255, 0, 0);
    myGLCD.print("BUFFER FULL!", 450, 400);
    delay(500);
    myGLCD.print("            ", 450, 400);
    delay(500);
    myGLCD.print("BUFFER FULL!", 450, 400);
    delay(500);
    myGLCD.print("            ", 450, 400);
    myGLCD.setColor(118, 238, 0);
  }
}
// Draw a red frame while a button is touched
void waitForIt(int x1, int y1, int x2, int y2)
{
  myGLCD.setColor(0, 255, 0);
  myGLCD.drawRoundRect (x1, y1, x2, y2);
  while (myTouch.dataAvailable())
    myTouch.read();
  myGLCD.setColor(255, 255, 255);
  myGLCD.drawRoundRect (x1, y1, x2, y2);
}
void setup() {
  // Initial setup
  myGLCD.InitLCD();
  myGLCD.clrScr();

  myTouch.InitTouch();
  myTouch.setPrecision(LOW);

  myGLCD.setFont(BigFont);
  myGLCD.setBackColor(0, 0, 255);
  drawButtons();

  currentaddr = 0;    // start at 0 if not found later
  found = false;
  writenow = false;
  datasize = sizeof( mydata );    // should be 14 bytes
  nlocations = EEPROMSIZE / datasize;  // for AT328P = 1024 / datasize = 73 locations

  for (int lp1 = 0; lp1 < nlocations; lp1++ ) {
    int addr = lp1 * datasize;
    EEPROM_readAnything( addr, mydata );
    // check to see if the data is valid
    if ( mydata.validdata == 99 ) {
      // data was erased so write some default values
      currentaddr = addr;
      found = true;
    }
  }

  if ( found == true ) {

    EEPROM_readAnything( currentaddr, mydata );
    mydata.validdata = 0;
    EEPROM_writeAnything(currentaddr, mydata);    // update values in EEPROM
    // goto next free address and write data
    currentaddr += datasize;
    // bound check the eeprom storage and if greater than last index [0-EEPROMSIZE-1] then set to 0
    if ( currentaddr >= (nlocations * datasize) ) currentaddr = 0;

    mydata.validdata = 99;
    EEPROM_writeAnything(currentaddr, mydata);    // update values in EEPROM
    numwrites++;
  }
  else {
    // set defaults because not found
    mydata.validdata = 99;
    mydata.temperature = 38.7;
    // now write the data to EEPROM
    EEPROM_writeAnything(currentaddr, mydata);    // update values in EEPROM
    numwrites++;
  }
  Serial.begin(9600);
  Serial.println(mydata.validdata);
  Serial.println(mydata.temperature);

  pinMode(relais, OUTPUT);
  digitalWrite(relais, HIGH);
}

void loop() {
  while (true)
  {
    if (myTouch.dataAvailable())
    {
      myTouch.read();
      x = myTouch.getX();
      y = myTouch.getY();

      if ((y >= 185) && (y <= 225)) // Upper row
      {
        if ((x >= 315) && (x <= 365)) // Button: 1
        {
          waitForIt(315, 185, 365, 225);
          updateStr('1');
        }
        if ((x >= 375) && (x <= 425)) // Button: 2
        {
          waitForIt(375, 185, 425, 225);
          updateStr('2');
        }
        if ((x >= 435) && (x <= 485)) // Button: 3
        {
          waitForIt(435, 185, 485, 225);
          updateStr('3');
        }
        if ((x >= 495) && (x <= 545)) // Button: 4
        {
          waitForIt(495, 185, 545, 225);
          updateStr('4');
        }
        if ((x >= 555) && (x <= 605)) // Button: 5
        {
          waitForIt(555, 185, 605, 225);
          updateStr('5');
        }
        if ((x >= 615) && (x <= 665)) // Button: 6
        {
          waitForIt(615, 185, 665, 225);
          updateStr('6');
        }
      }

      if ((y >= 235) && (y <= 285)) // Upper row
      {
        if ((x >= 315) && (x <= 365)) // Button: 1
        {
          waitForIt(315, 235, 365, 285);
          updateStr('7');
        }
        if ((x >= 375) && (x <= 425)) // Button: 2
        {
          waitForIt(375, 235, 425, 285);
          updateStr('8');
        }
        if ((x >= 435) && (x <= 485)) // Button: 3
        {
          waitForIt(435, 235, 485, 285);
          updateStr('9');
        }
        if ((x >= 495) && (x <= 545)) // Button: 4
        {
          waitForIt(495, 235, 545, 285);
          updateStr('0');
        }
        if ((x >= 555) && (x <= 605)) // Button: 5
        {
          waitForIt(555, 235, 605, 285);
          updateStr('.');
        }
        if ((x >= 625) && (x <= 675)) // Button: 5
        {
          waitForIt(625, 235, 675, 285);
          updateStr('*');
        }

      }

      if ((y >= 300) && (y <= 350)) // Upper row
      {
        if ((x >= 315) && (x <= 450)) // Button: Clear
        {
          waitForIt(315, 300, 450, 350);
          stCurrent[0] = '\0';
          stCurrentLen = 0;
          myGLCD.setColor(118, 238, 0);
          myGLCD.fillRect(315, 370, 650, 430);
        }
        if ((x >= 470) && (x <= 670)) // Button: Enter
        {
          waitForIt(470, 300, 670, 350);
          if (stCurrentLen > 0)
          {
            for (x = 0; x < stCurrentLen + 1; x++)
            {
              stLast[x] = stCurrent[x];
            }
            stCurrent[0] = '\0';
            stCurrentLen = 0;
            myGLCD.setColor(118, 238, 0);
            myGLCD.fillRect(315, 420, 700, 400);
            myGLCD.setColor(0, 0, 0);
            myGLCD.print("memorise", 420, 400);
            delay(500);
            myGLCD.print("            ", 420, 400);
            delay(500);
            myGLCD.print("memorise", 420, 400);
            delay(500);
            myGLCD.print("            ", 420, 400);
            myGLCD.setColor(118, 238, 0);
            myGLCD.fillRect(315, 370, 650, 430);
          }
          else
          {
            myGLCD.setColor(255, 0, 0);
            myGLCD.print("BUFFER EMPTY", 450, 400);
            delay(500);
            myGLCD.print("            ", 450, 400);
            delay(500);
            myGLCD.print("BUFFER EMPTY", 450, 400);
            delay(500);
            myGLCD.print("            ", 450, 400);
            //myGLCD.setColor(118, 238, 0);
          }
        }



      }

    }

    TEMPERATURE();
    HUMIDITE();
    RELAY();
    TEMPERATUREMEMOIRE();

  }
}
void TEMPERATUREMEMOIRE() {
  myGLCD.setColor(255, 0, 0);
  myGLCD.print(String(mydata.temperature), 490, 115);

}
void TEMPERATURE() {
  // delay(500);
  // Lit la température ambiante à ~1Hz
  if (getTemperature(&temp)) {

    // Affiche la température
    /*  Serial.print("Temperature1 : ");
      Serial.print(temp);
      Serial.write(176); // caractère °
      Serial.write('C');
      Serial.println();*/
    myGLCD.setColor(255, 0, 0);
    myGLCD.printNumF(temp, 3 , 100, 30);
  }
  /*else{
    myGLCD.setColor(255, 0, 0);
    myGLCD.print("LECTURE", 100, 30);
    }*/

  // delay(500);
  if (getTemperature1(&temp1)) {

    // Affiche la température
    /*  Serial.print("Temperature2 : ");
      Serial.print(temp1);
      Serial.write(176); // caractère °
      Serial.write('C');
      Serial.println();*/
    myGLCD.setColor(255, 0, 0);
    myGLCD.printNumF(temp1, 3, 100, 330);
  }
  /*else{
            myGLCD.setColor(255, 0, 0);
            myGLCD.print("LECTURE", 100, 330);
    }
  */




  moyennetemp = (temp + temp1) / 2;
  myGLCD.setColor(255, 0, 0);
  myGLCD.printNumF(moyennetemp, 3 , 490, 35);






  return;
}

void HUMIDITE() {
  myGLCD.setColor(255, 0, 0);
  myGLCD.print("70", 130, 180);
  return;
}

void RELAY() {
  float tempcomp = mydata.temperature;
  float resultattemp = (moyennetemp - tempcomp);
  /*Serial.print("tempcomp");
    Serial.println(tempcomp);
    Serial.print("moyennetemp");
    Serial.println(moyennetemp);
    Serial.print("resultattemp");
    Serial.println(resultattemp);*/
  if ( resultattemp < 0) {
    relay = true;
  } else {
    relay = false;

  }
  if (relay == true) {
    digitalWrite(relais, LOW);
    myGLCD.setColor(255, 0, 0);
    myGLCD.print("ON ", 200, 400);
  } else {
    digitalWrite(relais, HIGH);

    myGLCD.setColor(255, 255, 255);
    myGLCD.print("OFF", 200, 400);
  }
  return;

}

interface complète
photo1.jpg

bonsoir IB
tu a en tête d’intégrer le retournement ? pas sur le zeufs d'autruches bien sur :grin:

oui, mais pas forcément pour cette saison.
quoique, une rtc qui traine sur le bureau un servomoteur, une tige sur un axe.
mais bon, un copain éleveur pro a perdu 1500-1600 oeufs il y a 15j, ca couveuse pro a pété un cable et plus de retournement.
j'aime bien mirer les oeufs le soir et voir l'évolution avec ma petite.
demain phase de montage de tout le bastringue dans la machine.

j'espère simplement que ma résistance sera assez puissante, j'ai pas fait le calcul de chauffe par rapport au volume :frowning:
sinon j'ai d'autres solutions de secours, mais ca va rallonger d'une bonne demi journée le projet et ca urge de chez urge.

infobarquee:
oui, mais pas forcément pour cette saison.
...
j'aime bien mirer les oeufs le soir et voir l'évolution avec ma petite.
...
demain phase de montage de tout le bastringue dans la machine.

A ton echelle "d’éleveur amateur éclairé" :grin: , il faut que ça reste encore ludique
J'etais dans "ma campagne" en week-end il y a 15 jours, je n'ai malheureusement pas eu le temps d'aller voir In situ "mon éleveur préféré" :sunglasses:

:slight_smile:
j'ai eu 9 canetons il y a 4 jours.
et ca arrive encore dans les parcs, mais je choisis ce que je veux faire reproduire, sinon c'est la débacle.

belle réa, qui me rappelle ce que j'ai a la maison même principe du congelo vitrine !

je suis pas souvent sur le forum avec mes etude mais j'aime bien voir ce que vous faite pendant ce temps la!

perso je chauffe par contre avec une ressistance a boitier aluminium monter sur un radiateur en alu avec un ventilo qui brasse l'aire !
elle est alimenter en 230V et piloter par la carte a relais en TOR pas de PID pour le moment( car pas de statique)

a quelle température tu doit monter car si la solution intéresse je peut tester avec mon volume si une résistance suffi a monter a ta température car momentanément le mien est vide.

bientot plein de coin coin dans le coin

la tienne est plus grande, pour reptiles si je ne me trompe pas.

je dois monter aux alentours de 37.7-8C avec une hygro poussée à 70-85% les derniers jours.
je vais faire le cubage dans la matinée et essayer de me souvenir des formules calorifiques.

pour les coin coin, disont que c'est pas encore le top après la perte de 10 oeufs d'oie dans une couveuse prêtée.
déjà 2+9 canetons en éleveuse

j'ai lancer une température de 37.8°C avec un hystérésis de 0.25°C a 8H20 donc monter en cours

formule de thermo : Q=Mc(T2-T1)
M=Masse ...1,184 kg/m3.
C=capacité calorifique :1004 j/kg.K
T les températures

si changement d’état Q=MLv
Lv chaleur latente

bien sure tout est en joule donc tu divise par nombre de secondes de la variation tu aura la puissance nécessaire.

j'avais une autre formule

P=(Rho*V*Cp*(Tf-Ti)*1,2)/Dt
ou:
P = puissance (W),
Rho = masse volumique (Kg/m2), 1.184kg/m3
V = Volume (m3), 
Cp = (J*Kg-1*k-1), soit 730 pour l'air a 20°C
Tf = temperature final (°C),
Ti = " initiale (°C), 
Dt = temps de chauffage (s), 
1,2 = coeff de sécurité

Dt = (1.184*0.648*730*(37.8-20)*1.2)/50w
DT = (560.079*(17.8)*1.2)/50
Dt = 239.265

ce qui me donne en gros si je ne me trompe pas 4mn

tout est monté à blanc sur la vitrine et tout fonctionne.
reste la partie hard 230v, résistance, ventilo, éclairage, coupure générale.
je posterai des photos dans la journée :wink: