Go Down

Topic: Mega2560 + Ethernet + DS1307 + LCD ==> Mettre à l'heure le RTC par NTP (Read 22702 times) previous topic - next topic

JLuc

Bonjour,
Voila 2 jours que je galère pour mettre le DS1307 à la bonne date/heure, j'ai bien trouvé des programmes ca et là mais la plupart date un peu, les librairies ayant évoluées, je dois corriger les erreurs avant de les utiliser, mais en plus certains ne fonctionnent pas, d'autres mettent une date complètement erronée...

Bref, quelqu'un aurait il un programme qui marche avec la version 1.5.5 de l'éditeur Arduino ?
L'idée n'est pas de faire une pendule, mais de corriger la dérive du RTC par le NTP, je construis un projet qui nécessite une date et une heure relativement juste, avec changement d'heure été hiver automatique.

Merci d'avance pour toute suggestion.
@+ JLuc

jfs

ça peut peut-être t'aider....

http://forum.arduino.cc/index.php?topic=77849.0
Pas d'aide par MP !!!

Concernant le fonctionnement du forum tout se trouve dans les messages épinglés en tête de page.

JLuc

Merci pour ta réponse, mais j'ai déjà testé et ça ne va pas, d'ailleurs le tropic date de 2011, et je n'arrive pas a trouver quelques choses de récent. Mais merci quand même d'avoir poster.
@+ JLuc

jfs

#3
Jan 14, 2014, 07:52 pm Last Edit: Jan 14, 2014, 07:55 pm by Jean-François Reason: 1
Essaye avec ça :
(le code de l'autre topic remis à jour pour arduino 1.xx)

Code: [Select]
/*
Permet de mettre une horloge ds1307 en synchronisation avec l'heure NTP
Par le biais d'une application Arduino-Processing
*/

/*

Comporte des parties de code écrites par :
- Maurice Ribble
 4-17-2008
 http://www.glacialwanderer.com/hobbyrobotics
 Pour le ds1307

- X. HINAULT
  01/2010
  http://www.mon-club-elec.fr
  Pour le LCD

*/

#include "Wire.h"
#define DS1307_I2C_ADDRESS 0x68

// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
 return ( (val/10*16) + (val%10) );
}

// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
 return ( (val/16*10) + (val%16) );
}

// Stops the DS1307, but it has the side effect of setting seconds to 0
// Probably only want to use this for testing
/*void stopDs1307()
{
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.send(0);
Wire.send(0x80);
Wire.endTransmission();
}*/

// 1) Sets the date and time on the ds1307
// 2) Starts the clock
// 3) Sets hour mode to 24 hour clock
// Assumes you're passing in valid numbers
void setDateDs1307(byte second,        // 0-59
byte minute,        // 0-59
byte hour,          // 1-23
byte dayOfWeek,     // 1-7
byte dayOfMonth,    // 1-28/29/30/31
byte month,         // 1-12
byte year)          // 0-99
{
 Wire.beginTransmission(DS1307_I2C_ADDRESS);
 Wire.write(0);
 Wire.write(decToBcd(second));    // 0 to bit 7 starts the clock
 Wire.write(decToBcd(minute));
 Wire.write(decToBcd(hour));      // If you want 12 hour am/pm you need to set
 // bit 6 (also need to change readDateDs1307)
 Wire.write(decToBcd(dayOfWeek));
 Wire.write(decToBcd(dayOfMonth));
 Wire.write(decToBcd(month));
 Wire.write(decToBcd(year));
 Wire.endTransmission();
}

// Gets the date and time from the ds1307
void getDateDs1307(
byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
 // Reset the register pointer
 Wire.beginTransmission(DS1307_I2C_ADDRESS);
 Wire.write(0);
 Wire.endTransmission();

 Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

 // A few of these need masks because certain bits are control bits
 *second     = bcdToDec(Wire.read() & 0x7f);
 *minute     = bcdToDec(Wire.read());
 *hour       = bcdToDec(Wire.read() & 0x3f);  // Need to change this if 12 hour am/pm
 *dayOfWeek  = bcdToDec(Wire.read());
 *dayOfMonth = bcdToDec(Wire.read());
 *month      = bcdToDec(Wire.read());
 *year       = bcdToDec(Wire.read());
}


#include <LiquidCrystal.h>

const int RS=2; //declaration constante de broche
const int E=3; //declaration constante de broche
const int D4=4; //declaration constante de broche
const int D5=5; //declaration constante de broche
const int D6=6; //declaration constante de broche
const int D7=7; //declaration constante de broche
LiquidCrystal lcd(RS, E, D4, D5, D6, D7);

int octetReception=0; // variable de stockage des valeurs reçues sur le port Série (ASCII)
char caractereRecu=0; // variable pour stockage caractère recu
int compt=0; // variable comptage caractères reçus

String chaineReception=""; // déclare un objet String vide pour reception chaine
int oldSecond;

void setup() {
 byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
 Wire.begin(); // initialise 1wire

 Serial.begin(115200); // Initialise la communication série

 // lit les valeurs de l'horloge pour les replacer si elle est déjà à l'heure
 getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
 if ((year)== NULL){ // si l'année = NULL
 // preinitialise l'horloge mets les valeurs lue précédement (à 0 si premier allumage)
 setDateDs1307(int(second), int(minute), int(hour), int(dayOfWeek), int(dayOfMonth), int(month), int(year));
 }

 //***** LCD *****//
 lcd.begin(20,4); // Initialise le LCD avec 20 colonnes x 4 lignes
 delay(10); // pause rapide pour laisser temps initialisation
 lcd.print("initialisation") ; // affiche la chaîne texte - message de test
 lcd.setCursor(0, 1) ;
 lcd.print("de l'horloge") ;
 delay(2000); // pause de 2 secondes
 lcd.clear(); // // efface écran et met le curseur en haut à gauche
 delay(100); // pour laisser temps effacer écran

 //**** liaison pour l'heure NTP ****//
 Serial.println('A'); // envoi un "top" à Processing
 while (millis()<5000) {  // attente pendant 5 secondes d'une liaison série (ne fonctionne pas en dessous)
   while (Serial.available()>0) { // tant qu'un octet est dans la liaison série

     octetReception=Serial.read(); // Lit le 1er octet reçu et le met dans la variable      

     if (octetReception==13) { // si l'octet reçu est le retour chariot (CR ou 13)

       // converti la chaine en entier pour les valeurs de temps
       second = int((chaineReception.charAt(0)-48)*10)+int(chaineReception.charAt(1)-48) ;
       minute = int((chaineReception.charAt(2)-48)*10)+int(chaineReception.charAt(3)-48);
       hour = int((chaineReception.charAt(4)-48)*10)+int(chaineReception.charAt(5)-48);
       dayOfWeek = 1;
       dayOfMonth = int((chaineReception.charAt(6)-48)*10)+int(chaineReception.charAt(7)-48);
       month = int((chaineReception.charAt(8)-48)*10)+int(chaineReception.charAt(9)-48);
       year = int((chaineReception.charAt(12)-48)*10)+int(chaineReception.charAt(13)-48); //int((chaineReception.charAt(10)-48)*1000)+int((chaineReception.charAt(11)-48)*100)+

       //mets le DS1307 en syncronisation avec l'horloge de l'ordinateur
       setDateDs1307(int(second), int(minute), int(hour), int(dayOfWeek), int(dayOfMonth), int(month), int(year));

       chaineReception=""; //RAZ de la chaine de réception
       break; // sort de la boucle while
     }
     else { // si le caractère reçu n'est pas un saut de ligne
       caractereRecu=char(octetReception); // convertit l'octet reçu en caractère
       chaineReception=chaineReception+caractereRecu; // ajoute le caratère à la chaine
     }
   }
 }
}

void loop(){

 byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;

 getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);

 if(second!=oldSecond){  // change l'affichage uniquement au changement de seconde
   Serial.print(hour, DEC);
   Serial.print(":");
   Serial.print(minute, DEC);
   Serial.print(":");
   Serial.print(second, DEC);
   Serial.print("  ");
   Serial.print(month, DEC);
   Serial.print("/");
   Serial.print(dayOfMonth, DEC);
   Serial.print("/");
   Serial.print(year, DEC);
   Serial.print("  Day_of_week:");
   Serial.println(dayOfWeek, DEC);

   lcd.home();
   if (int(hour)<=9)lcd.print(0);
   lcd.print(int(hour));
   lcd.print (":");
   if (int(minute)<=9)lcd.print(0);
   lcd.print(int(minute));
   lcd.print (":");
   if (int(second)<=9)lcd.print(0);
   lcd.print(int(second));
   lcd.setCursor (0,1);
   if (int(dayOfMonth)<=9)lcd.print(0);
   lcd.print(int(dayOfMonth));
   lcd.print ("/");
   if (int(month)<=9)lcd.print(0);
   lcd.print(int(month));
   lcd.print ("/20");
   lcd.print(int(year));

 }
 oldSecond=second;  // réinitialise oldSecond

}
Pas d'aide par MP !!!

Concernant le fonctionnement du forum tout se trouve dans les messages épinglés en tête de page.

JLuc

Merci pour ton aide, mais ça  aussi j'ai essayé le problème principal que j'ai rencontré avec ce script c'est qu'il faut lancer un autre script pour mettre à l'heure, mais je n'ai pas sus comment le lancer   :smiley-red:
@+ JLuc

jfs

ça fonctionne avec Processing :

http://www.processing.org


Même système qu'arduino, mais sur ton pc....
Pas d'aide par MP !!!

Concernant le fonctionnement du forum tout se trouve dans les messages épinglés en tête de page.

JLuc

Ça c'est une super info !
La ce soir j'ai tout éteint je m'y remet d?s demain et je reviens poster pour les résultats, si ça marche ça pourrait en intéresser d'autre dans le même besoin.
Merci beaucoup.
@+ JLuc

JLuc

Bonjour,
Alors j'ai fais le test, et effectivement l'horloge se met à jour avec l'heure que le PC à envoyé par le script. Bien sur il faut modifier le port 0 par le numéro dans la liste trouvé par "Processing" au bas de l'écran 0 étant le premier, pour moi le 3ème était donc le 2.

Mais, même si ca marche très bien, je voudrai un système autonome, qui aille chercher tout seul sur le net ou en local l'heure et remette le DS1307 à l'heure au rythme d'une fois par semaine par exemple (plus ou moins si nécessaire)

Je continu donc mes investigations, mais si vous avez la moindre proposition je suis preneur.
De même si je trouve soit directement, soit en le créant un script qui marche, je le déposerai ici.

Merci beaucoup pour votre aide.
@+ JLuc

jfs

Là tu cherches du tout fait...et tu trouveras pas.
Avec l'exemple que je t'ai donné, tu peux adapter à ce que tu veux.
Pas d'aide par MP !!!

Concernant le fonctionnement du forum tout se trouve dans les messages épinglés en tête de page.

bricoleau

Bonjour

Si je comprends bien, tu as un shield ethernet sur ton arduino, et souhaites recaler régulièrement l'horloge de ton DS1307 par procédure NTP via internet.

Si c'est ça, je peux t'aider car j'ai déjà fait et ça fonctionne bien.

Tu as déjà dans le code ci-dessus les fonctions qu permettent de lire ou d'écrire l'heure du DS1307.
Sur le site arduino, tu as un exemple d'interrogation NTP que tu peux reprendre.
L'interrogation NTP te retourne l'heure UTC, exprimée en secondes écoulées depuis le 01/01/1900 00:00, en binaire sur 4 octets.
Ton dernier problème est donc de passer ce format au format étendu pour ton DS1307.
Si c'est bien ça, alors je devrais pouvoir te mettre à disposition des bouts de code qu'il te suffira d'assembler.

Dans mon cas, j'utilise aussi la NVRAM du DS1307 pour stocker des informations complémentaires :
- la dernière date/heure lue du DS1307, pour détecter les coupures électriques, au redémarrage de l'arduino
- la date/heure de dernière synchronisation NTP, pour gérer le délai entre les demandes de synchronisation, sans être influencé par les coupures électriques.
Et accessoirement, cela me permet aussi de détecter, au démarrage de l'arduino, que la pile du DS1307 est morte (quand je ne retrouve pas en NVRAM les données attendues).

Concernant l'heure locale : après plusieurs versions de code, j'en suis arrivé à la conclusion que le plus simple est de caler le DS1307 sur l'heure UTC, et de convertir en heure locale uniquement au moment des restitutions (LCD, page WEB, message sur moniteur série, etc.)
Tutoriels arduino : http://forum.arduino.cc/index.php?topic=398112.0

JLuc

Bonjour,
Tout d'abord merci à tous de m'aider, je viens d'y repasser la journée et cette fois je tiens quelques choses qui fonctionne.
Mais je suis quand même intéressé par ton code et ton aide Bricoleau, puisque tu as déjà été confronté au problème.
Pour la mise en situation, j'ai un PC qui tourne en serveur donc allumé 24/24 et que j'ai configuré pour qu'il me fournisse du NTP, comme ca si la box est HS (si, si c'est déjà arrivé) j'ai quand même mon réseau local qui fonctionne et donc le NTP de dispo.

Voici donc le code qui m'a permit de tester, bien entendu tout n'est pas de moi, et je suis parti du code proposé par Jean-François  et dans lequel j'ai ajouté de quoi obtenir le NTP et mettre à jour le RTC.

Code: [Select]

/*
Permet de mettre une horloge ds1307 en synchronisation avec l'heure NTP
Par le biais d'une application Arduino-Processing
*/

/*

Comporte des parties de code écrites par :
- Maurice Ribble
 4-17-2008
 http://www.glacialwanderer.com/hobbyrobotics
 Pour le ds1307

- X. HINAULT
  01/2010
  http://www.mon-club-elec.fr
  Pour le LCD

- Rendu autonome : 01/2014
  Par jean-Luc NAPOLITANO
  Note : Cela sous entend d'avoir (attention aux broches communes) :
         - Un shield W5100 et une connexion reseau valide
         - Un shield afficheur LCD
         - Un shield RTC DS1307 (attention broches 4-5 sur Uno, 20-21 sur Mega2560)
         - Un Aduino (Uno, Mega etc)

*/

#include <Time.h>
#include <Wire.h>
#define DS1307_I2C_ADDRESS 0x68

// Pour l'accès au reseau
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // Utilisez votre MAC address (pas obligé d'en changer)
byte ip[] = { 192, 168, 0, 177 };                    // Pas de DHCP, utilisation d'une IP compatible au reseau local (plus simple)
byte subnet[] = { 255, 255, 255, 0 };                // Masque de sous-reseau
byte gateway[] = { 192, 168, 0, 254 };               // internet access via router (votre box généralement)

//**** liaison pour l'heure NTP ****//
unsigned int localPort = 8888; // Port local pour écouter les paquets UDP
IPAddress timeServer(192, 168, 0, 1); // PC local à paramétrer en serveur NTP ou un serveur NTP sur le net
const int NTP_PACKET_SIZE = 48; // L'horodatage NTP se trouve dans les 48 premiers octets du message
byte packetBuffer[ NTP_PACKET_SIZE]; // Tampon pour maintenir les paquets entrants et sortants

bool maj_heure = false; // Pour la mise à l'heure automatique
bool maj_manu = false;  // Pour la mise à l'heure manuelle

// Un exemple UDP pour envoyer et recevoir des paquets UDP
EthernetUDP Udp;
const long timeZoneOffset = -3600L; // Réglez-le sur le décalage en secondes à votre heure locale
//char isodate[25]; // L'heure actuelle au format ISO est stocké ici


// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
 return ( (val/10*16) + (val%10) );
}

// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
 return ( (val/16*10) + (val%16) );
}

// Stops the DS1307, but it has the side effect of setting seconds to 0
// Probably only want to use this for testing
/*void stopDs1307()
{
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.send(0);
  Wire.send(0x80);
  Wire.endTransmission();
}
*/

// 1) Sets the date and time on the ds1307
// 2) Starts the clock
// 3) Sets hour mode to 24 hour clock
// Assumes you're passing in valid numbers
void setDateDs1307(byte second,        // 0-59
byte minute,        // 0-59
byte hour,          // 1-23
byte dayOfWeek,     // 1-7
byte dayOfMonth,    // 1-28/29/30/31
byte month,         // 1-12
byte year)          // 0-99
{
 Wire.beginTransmission(DS1307_I2C_ADDRESS);
 Wire.write(0);
 Wire.write(decToBcd(second));    // 0 to bit 7 starts the clock
 Wire.write(decToBcd(minute));
 Wire.write(decToBcd(hour));      // If you want 12 hour am/pm you need to set
 // bit 6 (also need to change readDateDs1307)
 Wire.write(decToBcd(dayOfWeek));
 Wire.write(decToBcd(dayOfMonth));
 Wire.write(decToBcd(month));
 Wire.write(decToBcd(year));
 Wire.endTransmission();
}

// Gets the date and time from the ds1307
void getDateDs1307(
byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
 // Reset the register pointer
 Wire.beginTransmission(DS1307_I2C_ADDRESS);
 Wire.write(0);
 Wire.endTransmission();

 Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

 // A few of these need masks because certain bits are control bits
 *second     = bcdToDec(Wire.read() & 0x7f);
 *minute     = bcdToDec(Wire.read());
 *hour       = bcdToDec(Wire.read() & 0x3f);  // Need to change this if 12 hour am/pm
 *dayOfWeek  = bcdToDec(Wire.read());
 *dayOfMonth = bcdToDec(Wire.read());
 *month      = bcdToDec(Wire.read());
 *year       = bcdToDec(Wire.read());
}


#include <LiquidCrystal.h>

const int RS=8; //declaration constante de broche
const int E=9; //declaration constante de broche
const int D4=3; //declaration constante de broche
const int D5=5; //declaration constante de broche
const int D6=6; //declaration constante de broche
const int D7=7; //declaration constante de broche
LiquidCrystal lcd(RS, E, D4, D5, D6, D7);

int octetReception=0;   // variable de stockage des valeurs reçues sur le port Série (ASCII)
char caractereRecu=0;   // variable pour stockage caractère recu
//int compt=0; // variable comptage caractères reçus

String chaineReception=""; // déclare un objet String vide pour reception chaine
int oldSecond;

void setup() {
 byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
 Wire.begin(); // initialise 1wire

 Serial.begin(115200); // Initialise la communication série

 // lit les valeurs de l'horloge pour les replacer si elle est déjà à l'heure
 getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
 if ((year)== NULL){ // si l'année = NULL
   // preinitialise l'horloge mets les valeurs lue précédement (à 0 si premier allumage)
   setDateDs1307(int(second), int(minute), int(hour), int(dayOfWeek), int(dayOfMonth), int(month), int(year));
 }

 //***** LCD *****//
 lcd.begin(20,4); // Initialise le LCD avec 20 colonnes x 4 lignes (à changer en 16/2 en fonction de l'afficheur)
 delay(10); // pause rapide pour laisser temps initialisation
 lcd.print("initialisation") ; // affiche la chaîne texte - message de test
 lcd.setCursor(0, 1) ;
 lcd.print("de l'horloge") ;
 delay(2000); // pause de 2 secondes
 lcd.clear(); // efface écran et met le curseur en haut à gauche
 delay(100);  // pour laisser temps effacer écran

 // Connexion au reseau
 Ethernet.begin(mac, ip);
 Udp.begin(localPort);
 
 Serial.println("waiting for sync");

//  ***************** La remise à l'heure par script n'est plus utilisée *****************
//  Enlever les REMs pour une utilisation ponctuelle (1ère mise en route par exemple)
//  Serial.println('A'); // envoi un "top" à Processing
//  while (millis()<5000) {  // attente pendant 5 secondes d'une liaison série (ne fonctionne pas en dessous)
//    while (Serial.available()>0) { // tant qu'un octet est dans la liaison série
//
//      octetReception = Serial.read(); // Lit le 1er octet reçu et le met dans la variable      
//
//      if (octetReception == 13) { // si l'octet reçu est le retour chariot (CR ou 13)
//
//        // converti la chaine en entier pour les valeurs de temps
//        second = int((chaineReception.charAt(0)-48)*10)+int(chaineReception.charAt(1)-48) ;
//        minute = int((chaineReception.charAt(2)-48)*10)+int(chaineReception.charAt(3)-48);
//        hour = int((chaineReception.charAt(4)-48)*10)+int(chaineReception.charAt(5)-48);
//        dayOfWeek = 1;
//        dayOfMonth = int((chaineReception.charAt(6)-48)*10)+int(chaineReception.charAt(7)-48);
//        month = int((chaineReception.charAt(8)-48)*10)+int(chaineReception.charAt(9)-48);
//        year = int((chaineReception.charAt(12)-48)*10)+int(chaineReception.charAt(13)-48); //int((chaineReception.charAt(10)-48)*1000)+int((chaineReception.charAt(11)-48)*100)+
//
//        // mets le DS1307 en syncronisation avec l'horloge de l'ordinateur
//        setDateDs1307(int(second), int(minute), int(hour), int(dayOfWeek), int(dayOfMonth), int(month), int(year));
//
//        chaineReception=""; //RAZ de la chaine de réception
//        break; // sort de la boucle while
//      }
//      else { // si le caractère reçu n'est pas un saut de ligne
//        caractereRecu=char(octetReception); // convertit l'octet reçu en caractère
//        chaineReception=chaineReception+caractereRecu; // ajoute le caratère à la chaine
//      }
//    }
//  }
}


@+ JLuc

JLuc

Pas assez de place dans le précédent post, voici donc la suite :

Code: [Select]


void loop(){

  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  byte tmp_second, tmp_minute, tmp_hour;

  getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);

  if(second != oldSecond){  // change l'affichage uniquement au changement de seconde
    Serial.print(hour, DEC);
    Serial.print(":");
    Serial.print(minute, DEC);
    Serial.print(":");
    Serial.print(second, DEC);
    Serial.print("  ");
    Serial.print(month, DEC);
    Serial.print("/");
    Serial.print(dayOfMonth, DEC);
    Serial.print("/");
    Serial.print(year, DEC);
    Serial.print("  Day_of_week:");
    Serial.println(dayOfWeek, DEC);

    lcd.home();
    if (int(hour)<=9)lcd.print(0);
    lcd.print(int(hour));
    lcd.print (":");
    if (int(minute)<=9)lcd.print(0);
    lcd.print(int(minute));
    lcd.print (":");
    if (int(second)<=9)lcd.print(0);
    lcd.print(int(second));
    lcd.setCursor (0,1);
    if (int(dayOfMonth)<=9)lcd.print(0);
    lcd.print(int(dayOfMonth));
    lcd.print ("/");
    if (int(month)<=9)lcd.print(0);
    lcd.print(int(month));
    lcd.print ("/20");
    lcd.print(int(year));

  }
  oldSecond=second;  // réinitialise oldSecond
 
  // Pour la mise à l'heure NTP automatique 1 fois par semaine
  // Par exemple le dimanche à 3 heures
  // Pour la prise en compte changement d'heure été/hiver immediate (ou presque)
  // Modifiez ces paramètres à vos besoins.
  if ((dayOfWeek == 1 && hour == 3 && maj_heure == false) || maj_manu == true)
  {
    Serial.println("Mise a l'heure du RTC par NTP en cours...");
    maj_heure = true; // Pour ne faire qu'une fois le dimanche à 3 heures
    maj_manu = false; // Pour ne faire qu'une fois
    time_t dh = getNtpTime();
    Serial.print("Reponse : ");
    Serial.println(dh);

    // Ecrit les heure, minute et second:
    Serial.print("Donne en clair : ");       
    // Ecrit l'heure (86400 egale aux secondes par jour)
    tmp_hour = (dh  % 86400L) / 3600;
    Serial.print(sDigits(tmp_hour,2));
    Serial.print(':');
    // Ecrit les minutes (3600 egale aux secondes par minute)
    tmp_minute = (dh  % 3600) / 60;
    Serial.print(sDigits(tmp_minute,2));
    Serial.print(':');
    // Ecrit les secondes
    tmp_second = dh %60;
    Serial.println(sDigits(tmp_second,2));

    // mets le DS1307 en syncronisation avec l'horloge de l'ordinateur
    setDateDs1307(int(tmp_second), int(tmp_minute), int(tmp_hour), int(dayOfWeek), int(dayOfMonth), int(month), int(year));

  } else if (dayOfWeek == 1 && hour > 3 && maj_heure == true) // Pour réinitialiser et attendre le dimanche d'après
  {
    maj_heure = false;
  }
  // Pour la mise à l'heure NTP manuelle
  if (Serial.available())
  {
    octetReception = Serial.read();
    caractereRecu = char(octetReception); // convertit l'octet reçu en caractère
    if (caractereRecu == 'm' || caractereRecu == 'M') // M ou m = demande de mise à l'heure manuelle
    {
      Serial.println("Mise a l'heure manuelle du RTC par le NTP.");
      maj_manu = true;
    }
  }
}

/*-------- NTP code ----------*/

String sDigits(byte digit, byte format) {
  String nbr = String(digit);
  nbr.trim();
  nbr = "0000" + nbr;
  nbr = nbr.substring(nbr.length() - format);
  return nbr;
}

unsigned long getNtpTime() {
  Serial.println("Requete NTP sur Serveur local.");
  sendNTPpacket(timeServer); // Envoyer un paquet au serveur NTP
  // Attendre pour voir si une réponse est disponible
  delay(1000);
  if ( Udp.parsePacket() ) {
    // Nous avons reçu un paquet et allons lire les données qu'il contient
    Udp.read(packetBuffer,NTP_PACKET_SIZE); // Lire le paquet dans la mémoire tampon

    // l'horodatage commence à l'octet 40 du paquet reçu et est de quatre octets,
    // ou de deux mots, de longues. Tout d'abord, extraire les deux mots:

    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
    // Combiner les quatre octets (deux mots) dans un entier long
    // c'est le temps NTP (en secondes depuis le 1er janvier 1900):
    unsigned long secsSince1900 = highWord << 16 | lowWord;
   
    // Maintenant convertir le temps NTP dans le temps Unix (qui commence le 1 janv. 1970).
    // En secondes, ce qui fait 2208988800:
    const unsigned long seventyYears = 2208988800UL;
    unsigned long epoch = secsSince1900 - seventyYears;
    return epoch - timeZoneOffset;
  }
  Serial.println("Serveur local ne repond pas.");
  return 0; // Retourne 0 en cas d'impossibilité d'obtenir le temps
}

// Envoyer une requête NTP au serveur de temps à l'adresse indiquée
unsigned long sendNTPpacket(IPAddress& address) {
  // Réglez tous les octets de la mémoire tampon à 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialiser les valeurs nécessaires pour former la demande NTP
  // (voir URL ci-dessus pour plus de détails sur les paquets)
  packetBuffer[0] = 0b11100011; // LI, Version, Mode
  packetBuffer[1] = 0; // Strate, ou type d'horloge
  packetBuffer[2] = 6; // Intervalle d'interrogation
  packetBuffer[3] = 0xEC; // Pairs d'horloge de précision
  // 8 octets de zéro pour Délai & Dispersion
  packetBuffer[12] = 49;
  packetBuffer[13] = 0x4E;
  packetBuffer[14] = 49;
  packetBuffer[15] = 52;

  // Tous les champs NTP ont reçu des valeurs,
  // maintenant vous pouvez envoyer un paquet demandant un horodatage:                 
  Udp.beginPacket(address, 123); // Les demandes NTP se font sur le port 123
  Udp.write(packetBuffer,NTP_PACKET_SIZE);
  Udp.endPacket();
}
@+ JLuc

bricoleau

Pour compléter ton programme :

Voici un exemple opérationnel d'interrogation NTP pour arduino équipé d'un shield ethernet, qui te retourne en quelques lignes de code la date et l'heure locale de France métropolitaine, dans des variables directement exploitables pour (par exemple) mettre à jour ton DS1307.
Avec gestion automatique des changements d'heure d'été/hiver

Les quelques lignes intéressantes :
Code: [Select]

void mafonction()
 IPAddress ip_serveur_NTP(132, 163, 4, 101);
 uint32_t timestamp;
 uint8_t annee,mois,jour,joursem,heure,minute,seconde;
 const uint32_t delai_max_attente_en_ms = 5000;

 DemanderHeureNTP(ip_serveur_NTP);
 timestamp = EcouterHeureNTP(delai_max_attente_en_ms);
 if (timestamp != 0)
 {
   timestamp = timestamp - 3155673600UL; //ramène le zéro à l'an 2000
   timestamp = CalculerTimestampLocalFrance(timestamp);//UTC + 1 + heures d'été
   DecomposerTimestamp(timestamp, &annee, &mois, &jour, &joursem, &heure, &minute, &seconde);
   //à partir de là les variables annee,mois,jour,etc. sont à l'heure de France métropolitaine
...


Code complet en pièce jointe.
Tutoriels arduino : http://forum.arduino.cc/index.php?topic=398112.0

JLuc

Bonjour,
Merci beaucoup pour la réponse Bricoleau, ton code me plait vraiment, je le trouve même beaucoup moins lourd que le miens, bon le mien gère l'afficheur, quand il faut déclencher la requête etc... Mais tout de même pour la partie NTP c'est super bien et concis.
Tu as été plus loin dans la conversion Timestamp puisque tout y est, moi je me suis contenté de récupérer seulement l'heure en me disant que de toute façon le RTC ne pouvait pas dériver de plus de quelques secondes par semaines, mais en y repensant, c'est mieux car au moins même lors de la première mise à jour (changement de module, pile...) tout est parfait.
Je vais donc si tu le permet m'en inspirer pour mon projet.

Je ne sais pas si je l'ai déjà dis, mon projet consiste en la régulation d'une vanne 4 voies et de l'accélérateur (circulateur) pour mon chauffage, avec prise de température de l'eau de départ, extérieur, intérieur, retour... Je voudrai pouvoir par le réseau en http (domotique) mettre en service/arrêter le chauffage, modifier les paramètres de températures (jour/nuit/absence...) etc... Je teste d'abord tous les besoins avant de développer le projet final.

Maintenant je m'attaque à la carte SD qui contiendra les pages web et la config (en cas de redémarrage)

Merci pour tout, et connaissant mon projet, si vous avez des suggestions je suis preneur.
@+ JLuc

bricoleau

Bonjour

Bien sûr que tu peux reprendre le code, il est là pour ça.  ;)

Pour la suite, et personnellement, je te conseillerais plutôt :
- d'utiliser l'eeprom de l'arduino pour stocker ta config (plus fiable que la SD) : il te faudra juste prévoir un programme spécifique qui permet son chargement dans l'eeprom.
- d'utiliser la mémoire flash (PROGMEM) pour stocker toute l'information statique de tes pages WEB. Sauf si vraiment tu veux faire autre chose que quelques pages html assez simples (m'enfin t'attends pas à avoir un serveur de type LAMP).
- de conserver en RAM les derniers relevés des données dynamiques que tu veux restituer dans tes pages WEB.
- de réserver la SD uniquement à l'enregistrement de données sous forme de log, pour exploitation ultérieure.

Si c'est à ta portée, tu pourras ultérieurement ajouter un serveur UDP sur ton arduino. C'est assez simple à faire et là tu t'ouvres des portes vers plein d'autres possibilités, mais il y aura aussi du code à produire sur le partenaire à l'autre bout de la ligne, et là c'est potentiellement une autre paire de manche.
Côté arduino, tu développes des fonctions accessibles à distance via UDP, pour par exemple :
- passer en commande manuelle
- modifier les paramètres
- récupérer tout ou partie de la log
Après côté distant, c'est libre cours à ton imagination pour exploiter ses fonctions disponibles :
- développer un programme de type "console à distance" sur ton PC
- développer une appli android pour ta tablette (plus sexy que des pages HTML renvoyées par un mini serveur web arduino)
- monter un vrai serveur web de type LAMP sur un raspberry pi (très tendance chez les geek)
- interfacer ton arduino avec le reste de tes équipements domotiques (ça aussi)
...
Tutoriels arduino : http://forum.arduino.cc/index.php?topic=398112.0

Go Up