lire une image dans une carte sd via arduino mega

Bonjours,
Je suis en terminale STI2D et nous avons pour projet une couveuse.
Pour ce fait, nous utilisons:
-un arduino MEGA
-un shield ethernet
-un shield relai
Une de nos contrainte est de créer un site internet. De ce côté là, aucun problème mais nous voulons mettre des images (question d’esthétique :D). Cependant nous n’arrivons pas a mettre l’image qui est sur la carte sd sur le site internet. Nous avons vue qu’il y avait besoin d’une certaine bibliothèque mais je n’ai aucune idée de ce que s’est.

Voici notre programme pour lire l’image:

#include <SD.h>
#include <SPI.h>
File theFile;
void setup() {
  Serial.begin(9600);
  Serial.println("*************\nInitialisation...");
   if (!SD.begin(4)){//teste la communication avec la carte(pin 4)
       Serial.println("Communication impossible");        
       return; //stoppe le programme
   }; 
  Serial.println("Communication ok !");
}

void loop() {
theFile = SD.open("flocon1.jpg");
  if (theFile) {
    // lecture du fichier jusqu'à la fin:
    cl.print("<img src=theFile>");
    Serial.println("Ouverture du fichier");  
  // Fermeture du fichier:
  theFile.close();
} 
else {
  Serial.println("Ouverture impossible ");
}

}

Nous avons aussi une puce PCF8583. Si vous avez des conseils ou autres^^.

Merci pour votre aide^^

cl.print("<img src=theFile>");
C’est quoi cl ? déclaré où, initialisé comment ?
Je pense de plus qu’il ne suffit pas d’envoyer un bout de header html, il faut un header complet (avec le type, la taille du fichier…), et le contenu du fichier en tant que body.

 if (!SD.begin(4)){
       ../...       
       return; //stoppe le programme
   };

return ne stoppe pas le programme, ça fait juste sortir de la fonction setup()
Pour arrêter le programme : while (1 );

le “cl” vien du code html

Voici le programme complet:

#include <SPI.h> //bibliothèqe pour SPI
#include <Ethernet2.h> //bibliothèque pour Ethernet
#include <Wire.h>
#include <SD.h>
#define DS1621_ID 0x90 >> 1 
#define RELAY_1 4
File theFile;
byte mac[] = {0x90, 0xA2, 0xDA, 0x11, 0x43, 0x6F}; //adresse mac de votre carte
byte ip[] = {192, 168, 1, 177}; //adresse IP
EthernetServer serveur(80); // déclare l'objet serveur au port d'écoute 80
int m;
int h;
int j;
int s;
int val = 0;                                
int valafd= 0; 
int l;
float valr; 
void setup() {
Serial.begin (9600); //initialisation de communication série
Ethernet.begin (mac, ip); //initialisation de la communication Ethernet
Serial.print("*\n-> Le serveur est sur l'adresse : ");
Serial.println(Ethernet.localIP()); //on affiche l'adresse IP de la connexion
serveur.begin(); // démarre l'écoute
Wire.begin();
Wire.beginTransmission(DS1621_ID);           // connection DS1621 (#0)
Wire.write(0xAC);                            // Access Config
Wire.write(0x01);                            // one shot
Wire.endTransmission();
pinMode(RELAY_1, OUTPUT); //Configure la broche RELAIS en sortie
//**********************************initialisation carte sd*************************************
    Serial.println("*************\nInitialisation...");
    if (!SD.begin(4)){//teste la communication avec la carte(pin 4)
        Serial.println("Communication impossible");
        return; //stoppe le programme
    }; 
    Serial.println("Communication ok !");
//**********************************************************************************************     
}
void loop() {
  gestionClient(); // fonction qui gère toute la communication avec le client
  capteur();
  horloge();
      if (valr<37.3){
      chauffer();
    }
    if (valr>37.7) {
      stopchauffage();
    }
    if (valr<37.7){
      if (valr>37.3) {
      }
    }  
}
void gestionClient() {
  EthernetClient client = serveur.available(); //on écoute le port
  if (client) { //si client existe
    Serial.println("Client en ligne"); //on le dit...
    if (client.connected()) { // si le client est connecté
      GET(client); //appel de la fonction de décodage
      //réponse au client
      entete(client); // fonction pour l'entête de la page HTML
      corps(client);// fonction pour le corps
      GET(client);
      piedPage(client); // fonction pour le pied de page
      Serial.println("Fin de communication avec le client\n");
      client.stop(); //on déconnecte le client
    }
  }
}
void entete(EthernetClient cl) {
  //infos pour le navigateur
  cl.println("HTTP/1.1 200 OK"); // type du HTML
  cl.println("Content-Type: text/html; charset=ascii"); //type de fichier et encodage des caractères
  cl.println("Connection: close");  // fermeture de la connexion quand toute la réponse sera envoyée
  cl.println();
  //balises d'entête
  cl.println("<!DOCTYPE HTML>");
  cl.println("<html>");
  cl.println("<head><title>Couveuse</title></head>");
  cl.println("<body><h1><center>Couveuse</center></h1><hr>
");
}
void corps(EthernetClient cl) {
  //boucle pour construire chaque ligne en fonction des LED
    cl.print("
Etat des oeufs ");
    cl.print(j); cl.print("j:"); cl.print(h); cl.print("h:"); cl.print(m);cl.print("min:");cl.print(s);cl.print("sec ");cl.print(" ");
    cl.print("
");
    cl.print("
");
    if (valr<37.3){
      cl.print("<h3 style=color:#ff0000;>ATTENTION PROBLEME DE TEMPERATURE (trop faible)</h3>");
      //cl.print("<img src=""G:/Lycée/TermSTI2D/PROJET/IMAGE/flocon.png>");
//***********************************************carte sd********************************************************
theFile = SD.open(flocon1.jpg);
  if (theFile) {
    // lecture du fichier jusqu'à la fin:
    cl.print("<img src=theFile>");
    Serial.println("Ouverture du fichier");  
  // Fermeture du fichier:
  theFile.close();
} 
else {
  // Ouverture impossible:
  Serial.println("Ouverture impossible de fichier.txt");
}
//***************************************************************************************************************        
    }
    if (valr>37.7) {
      cl.print("<h3 style=color:#ff0000;>ATTENTION PROBLEME DE TEMPERATURE (trop elevee)</h3>");
    }
    if (valr<37.7){
      if (valr>37.3) {
      cl.print("<h3 style=color:#aa00ff;>TEMPERATURE CORRECT </h3>");
     // cl.print("<img src=G:/Lycée/TermSTI2D/PROJET/IMAGE/tenor.gif >");
      }
 
    }
    cl.print("
");
    cl.print("<b><u>Temperature : </b></u>"); cl.print(valr); cl.print("C");
    cl.print("
");
    cl.print("
");
    
//================================CAMERA!!!========================================
    cl.print(" <a href=http://192.168.1.120:8080"); //création du lien inutile de répéter l'adresse du site
    cl.println(" target=_blank >Site Camera</a>
");
//=================================================================================
}
void piedPage(EthernetClient cl) {
  //balises de pied de page
  cl.println("
<hr>");
  cl.println("</body>");
  cl.println("</html>");
}
void GET(EthernetClient cl) {
  boolean lu = 0; //variable pour indiquer l'état de lecture
  while (cl.available()) { // tant qu'il a des infos à transmettre
    char c = cl.read(); // on lit le caractère
    delay(1); //delai de lecture
    if (c == '?' && lu == 0) { //si "?" repéré
      c = cl.read(); //on lit le caractère suivant qui contient la donnée
    }
  }
}
void horloge(){
  if(s<60){
    delay(1000);
    s=s+1;
    Serial.println(s);
  }
  else{
       if(s=60){
        m=m+1;
        s=0;
              }
        Serial.println(m);
      if(m>60){
        h=h+1;
        m=0;
              }
        Serial.println(h);
        if(h>23){
          j=j+1;
          h=0;
                }
        else{     
            Serial.println(j);
            if(j>22){
               Serial.println("Sort les oeufs!!");
               j=0;
                    }
             }     
       }
}

void capteur(){
   Wire.beginTransmission(DS1621_ID);           // restart
   Wire.write(0xEE);                            // start conversion
   Wire.endTransmission();

   Wire.beginTransmission(DS1621_ID);
   Wire.write(0xAA);                          // read temp
   Wire.endTransmission();
   Wire.requestFrom(DS1621_ID, 2);            // request one byte from DS1621
   val = Wire.read(); 
   valafd = Wire.read();                      // get whole degrees reading
   Wire.endTransmission();
   float valafe= int(val);
   if (valafd==0x80)
      valafe+=0.5;  
     
   //  plus précis...
   Wire.beginTransmission(DS1621_ID);
   Wire.write(0xA8);                          
   Wire.endTransmission();
   Wire.requestFrom(DS1621_ID, 1);              // request one byte from DS1621
   float Count_Remain = Wire.read(); 
   Wire.endTransmission();
   Wire.beginTransmission(DS1621_ID);
   Wire.write(0xA9);                        
   Wire.endTransmission();
   Wire.requestFrom(DS1621_ID, 1);              // request one byte from DS1621
   float Count_Per_C = Wire.read(); 
   Wire.endTransmission();
   
   valr = float(val)-0.25+((Count_Per_C - Count_Remain) / Count_Per_C);      
}

void chauffer() {
   digitalWrite(RELAY_1, HIGH); // met la broche de commande dans l'état voulu
   Serial.println("RELAY_1 ON");
}
void stopchauffage() {
   digitalWrite(RELAY_1,LOW);
   Serial.println("RELAY_1 OFF");
}

le “cl” vien du code htm

Non, cl est un objet de la classe EthernetClient passé en argument à une fonction.

 cl.print("<img src=theFile>");

Cette ligne envoie un bout de texte. Elle n’envoie pas le contenu du fichier, que ton programme ne lit même pas.

D'accord. Merci ^^

Comment je peux faire alors pour mettre l'image

d’abord, à la place decl.print("<img src=theFile>");
tu metscl.print("<img src="flocon.jpg">"); c-à-d le vrai nom du fichier. Et c’est tout pour l’instant, tu envoies ça (avec le reste du HTML)

Quand il reçoit ça, le navigateur va te répondre quelque chose comme

GET flocon.jpg HTTP/1.1
Host: 127.0.0.1:56000
Accept: image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5
Connection: keep-alive
Cookie: first=1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8
Accept-Language: fr-fr
Referer: http://127.0.0.1:56000/cgi-bin/CGIProxy.fcgi?usr=xxxxxx&pwd=yyyyy&cmd=snapPicture
Accept-Encoding: gzip, deflate

Tu devras alors lui envoyer quelque chose comme

HTTP/1.1 200 OK
Content-Type: image/jpeg
Accept-Ranges: bytes
ETag: "614911455"
Last-Modified: Fri, 23 Mar 2018 05:37:26 GMT
Content-Length: 242747
Date: Fri, 23 Mar 2018 05:37:31 GMT
Server: lighttpd/1.4.31

suivi du contenu brut de ton fichier JPEG.
N’oublie pas :

  • la ligne vide à la fin
  • de changer la valeur de Content-Length: par la taille de ton fichier.
    Certains champs sont optionnels, fais des essais !

où est-ce que je peut trouver la réponse svp?

Je viens de te la donner. Tu me lis pas ?

Si si mais je voulais juste savoir où tu l'a trouver.

Tu parle d'envoyé

HTTP/1.1 200 OK
Content-Type: image/jpeg
Accept-Ranges: bytes
ETag: "614911455"
Last-Modified: Fri, 23 Mar 2018 05:37:26 GMT
Content-Length: 242747
Date: Fri, 23 Mar 2018 05:37:31 GMT
Server: lighttpd/1.4.31

Je dois l'envoyer où?

Interner n'est pas la seule source de savoir.
Pour trouver ça, j'ai "espionné" les échanges entre mon naviqateur et un serveur HTTP embarqué dans une caméra de surveillance.
J'ai écrit un programme en C qui se place entre le navigateur et le serveur, et qui imprime tout ce qui passe dans un sens et dans l'autre.

Je dois l'envoyer où?

On dirait que tu perds le fil de ce que tu fais.
Tu es en train de réaliser un serveur HTTP sur Arduino. Un client (un navigateur sur une autre machine) se connecte pour afficher une page. Cette page contient une image.
Donc, toi, SERVEUR, tu dois envoyer les données de l'image au CLIENT.
Le client dans ton prog, c'est objet cl, de la classe EthernetClient.
Donc tu réponds au client qui veut faire un GET de l'image, par cl.print(...) ou équivalent.

D'accord merci ^^

Oui en faisant

cl.print ("flocon1.jpg");

Je l'ai essayé mais ça me met des caractères

liche:
Oui en faisant

cl.print ("flocon1.jpg");

Non, là tu n'envoies pas le contenu du fichier JPEG, tu envoies seulement son nom !
Il faut utiliser la bibliothèque SD pour:

  • ouvrir le fichier (genre theFile = SD.open("flocon1.jpg"); )
  • trouver sa taille,
  • charger le fichier dans la mémoire de l'Arduino,
  • envoyer ces données par cl.print(...) ou client.write(...)
  • fermer le fichier.

La mémoire de l'Arduino étant très limitée, tu vas devoir procéder par petits bouts, c-à-d lire un bout du fichier, l'envoyer, lire la suite, l'envoyer... etc.

D'accord merci. Je testerai ça jeudi.

ta fonction void GET (EthernetClient cl) est inexploitable : la requête du client (le navigateur) est perdue.
Déjà tu fais une copie de l’objet cl en le passant en paramètre : cette copie est inutile, voire même source de problèmes. Tu dois passer l’objet cl par référence : void GET (EthernetClient& cl)
note bien le caractère & rajouté.

Ensuite, dans ta fonction, je te suggère d’afficher clairement la question posée par le client:

void GET ( EthernetClient& cl ) {
  while ( cl.available() ) { // tant qu'il a des infos à lire
    char c = cl.read();      // on lit le caractère
    Serial.print ( c );
  }
  // C'EST TOUT POUR L'INSTANT, 
  // APRES IL FAUDRA DECIDER DE LA REPONSE A DONNER 
  // SELON LA QUESTION RECUE
}

Le but est de bien saisir le dialogue qui se déroule entre le navigateur client et ton serveur HTTP dans l’Arduino.

A priori dans ton navigateur, tu vas taper l’adresse IP de l’Arduino (le port 80 est sous entendu), le navigateur va t’envoyer quelque chose comme :

GET / HTTP/1.1
Host: 192.168.1.177:80
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8
Referer: http://192.168.1.177:80/
Cache-Control: max-age=0
Accept-Language: fr-fr

Ca dépend de ton navigateur, ce qui est important, c’est :

  • la ligne GET / qui demande au serveur d’envoyer la ressource de plus haut niveau. Dans ton cas tu n’as qu’une seule page HTML, donc ton serveur Arduino va envoyer le code HTML de cette page (c’est ce que font tes fonctions entete(), corps(), etc).
  • la ligne vide à la fin qui signale la fin du message. Donc quand tu reçois le séquence “\r\n\r\n”, tu sais que la question est finie, pas besoin d’attendre un time-out pour le savoir.

Donc tu envoies le code HTML de ta page, et dans ce code, dans le “body”, il y a la ligne

<img src="flocon.jpg">

Le navigateur reçoit ce code, et il comprend donc qu’il va devoir afficher une image, qui se trouve dans un fichier nommé flocon.jpg. Du coup, il pose au serveur une nouvelle question “envoie moi l’image flocon.jpg”. Donc il envoie:

GET flocon.jpg HTTP/1.1
Host: 192.168.1.177:80
Accept: image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5
Connection: keep-alive
Cookie: first=1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8
Accept-Language: fr-fr
Referer: http://192.168.1.177:80
Accept-Encoding: gzip, deflate

Le contenu exact dépend de ton navigateur, ce qui est important, c’est

  • la ligne GET flocon.jpg : il dit clairement ce qu’il veut !
  • la ligne vide en fin (voir plus haut)

A ce moment ton serveur doit répondre et envoyer le contenu du fichier JPEG. Voici ce qu’il faut envoyer :

HTTP/1.1 200 OK
Content-Type: image/jpeg
Content-Length: LA_TAILLE_DE_TON_FICHIER_JPEG_EN_OCTETS

(ne pas oublier la ligne vide !)
Puis il faut envoyer dans la foulée le contenu du fichier JPEG, comme je te l’ai expliqué plus haut.

Au final tu vois l’importance d’analyser la question posée par le client, afin de lui répondre correctement.

Bon courage !