RTC DS1307 - Retour du numéro du jour (Dim, Lun, etc.) avec RTClib

Bonjour à tous,

Utilisation de la bibliothèque (lien de téléchargement) téléchargée depuis :

Dans la fiche technique du DS1307 (lien), il est mentionné, en page 8, tableau 2, que le jour retourné est dans la gamme 1-7.

Mais je constate, avec le programme suivant :

#include <Wire.h>
#include "RTClib.h" 

RTC_DS1307 RTC;

const char *daysArray[] = {"Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"};

void setup () 
{
  Serial.begin(9600);
  Wire.begin();
  RTC.begin();
  RTC.adjust(DateTime(F(__DATE__), F(__TIME__)));
}


void loop () 
{
    DateTime now = RTC.now();
    
    Serial.println();
    Serial.print("Numéro du jour: ");
    Serial.print(now.dayOfWeek()); // Retourne O et non pas 1 pour dimanche !
    Serial.println();
    Serial.print("Jour : ");
    Serial.print(daysArray[now.dayOfWeek()]); // Affiche Dimanche pour indice 0.
    Serial.println();
    delay(900);
}

que le jour retourné est 0 pour dimanche qui n'est donc pas dans la gamme 1-7 comme l'indique la documentation.

En fait, dans RTClib.cpp, ligne 161, il est indiqué que Samedi correspond à '6'.

Donc, sauf errer de ma part, en utilisant cette bibliothèque, pensez à cette particularité.

En fait, dans RTClib.cpp, ligne 161, il est indiqué que Samedi correspond à '6'.

Oui les anglais commencent la semaine le dimanche et non le lundi comme nous.
Nous on commence par un jour de travail eux ils commencent par se reposer, bande de faignasses :grin:

Mais il me semble bien que cela peut se changer.

Bonjour,

La "library" RTClib ignore le registre "jour de semaine" (le 4°) de la DS1307. Et impose par division du temps passé depuis 1/1/2000, l'indexation des jours (0 à 6), retourné par la fonction "now.dayOfWeek()".

La correspondance index (0-6) <-> jour semaine (L-D) est à faire dans le programme Uno.
Et là on fait ce qu'on veut... même la semaine des 4 jeudis.

Pour ceux qui se méfient des "library" , il suffit d'écrire et lire (hors RTClib) dans le 4° registre de la DS1307, registre toujours disponible. Avec la lib Wire, sans mettre les mains dans le cambouis du hard.

Bonjour

J'ai pas mal galéré avec cette lib, et apparemment, les mises à jour supérieures à 1.0.0 posent

problèmes, car chaque fois que j'ai effectué les màj, ça ne fonctionnais plus pour cette fonction , et en

revenant à 1.0.0, ça refonctionne .

On peut effectivement utiliser le registre joursem du DS1307
Celui-ci varie de manière cyclique de 1 à 7

Mais attention : sauf erreur de ma part, le DS1307 n'assure aucune cohérence entre ce registre et la date. Il se contente de faire +1 à chaque passage de minuit.
On peut donc l'utiliser avec la convention que l'on veut : il faut de toute manière l'initialiser à une valeur correcte.
Par conséquent il y a souvent au moins un premier calcul à faire par l'arduino.

Pour cela, la fonction ci-dessous (issue de ma lib simpleRTC) est plus efficace que celle embarquée dans la RTClib.

uint8_t _RTCcalculerJoursem(uint8_t annee, uint8_t mois, uint8_t jour)
{
  //Formule maison, économe en calculs fin d'épargner le petit processeur 8 bits
  uint8_t somme = annee + (annee >> 2) + jour;
  switch (mois)
  {
    case  2 :
    case  3 :
    case 11 : somme++;    break;
    case  6 : somme += 2; break;
    case  9 :
    case 12 : somme += 3; break;
    case  4 :
    case  7 : somme += 4; break;
    case  1 :
    case 10 : somme += 5; break;
    case  5 : somme += 6;
  }
  if (mois > 2 || (annee & 3)) somme++;
  return somme % 7;
}

Extrait de la RTClib :

uint8_t DateTime::dayOfTheWeek() const {     
    uint16_t day = date2days(yOff, m, d); 
    return (day + 6) % 7; // Jan 1, 2000 is a Saturday, i.e. returns 6 
} 
 
const uint8_t daysInMonth [] PROGMEM = { 31,28,31,30,31,30,31,31,30,31,30,31 }; 
 
// number of days since 2000/01/01, valid for 2001..2099 
static uint16_t date2days(uint16_t y, uint8_t m, uint8_t d) { 
    if (y >= 2000) 
        y -= 2000; 
    uint16_t days = d; 
    for (uint8_t i = 1; i < m; ++i) 
        days += pgm_read_byte(daysInMonth + i - 1); 
    if (m > 2 && y % 4 == 0) 
        ++days; 
    return days + 365 * y + (y + 3) / 4 - 1; 
}

standardUser:
Dans la fiche technique du DS1307 (lien), il est mentionné, en page 8, tableau 2, que le jour retourné est dans la gamme 1-7.

ce qui est presque vrai.

Car pour ajouter à la confusion, la fonction
RTC.adjust(DateTime(DATE, TIME)); ou ces semblables
RTC.adjust(DateTime(2016,6,13,14,35,0)); .........
force le fameux registre à 0 , c'est accepté par la DS1307, puis il passera le lendemain à 1
Enfin il commencera son cycle normal (1-7)

pour les adeptes de la mise à (jour) heure manuelle

 RTC.adjust(DateTime(2016,6,13,14,35,0));      //aaaa,mm,jj,hh,mn mn,ss

 Wire.beginTransmission(0x68);
 Wire.write(0x03);                 //adresse pour le pointeur du registre visé dans la RTC (le 4°)
 Wire.write(decToBcd(jourSem));                   //jour choisi: 1 à 7
 Wire.endTransmission();
....


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

écriture du 4° registre après "adjust"

Sauf que du coup :

  1. la fonction RTC.adjust "lessive" à zéro le registre joursem : il faut donc veiller à aller y réécrire systématiquement la bonne valeur après chaque appel à RTC.adjust

  2. il reste nécessaire de calculer jourSem avant de l'envoyer au DS1307, donc de disposer d'une fonction de calcul quelque part dans son code (dans ton exemple, la variable jourSem est valorisée comment?)

  3. en lecture, RTClib ignore le registre joursem. Il faut donc relancer un Wire.Read() spécifique pour en récupérer la valeur.

  4. la lecture spécifique du registre joursem via le protocole I2C, est plus lente qu'un recalcul purement cpu, surtout dans la version optimisée que j'ai donnée ci-dessus.

Donc au final l'intérêt de la chose me semble assez difficile à cerner.
Me goure-je ?

  1. c'est pour cela que j'ai insisté sur le après, à la fin du #6

2)pour une mise à l'heure en téléversant avec RTC.adjust(DateTime(aaaa,mm,jj,hh,mn mn,ss) en principe on connait le jour du téléversement

3)bien sûr qu'il faut lire le registre

void lireJourSem()
{   byte octetReg;  
    Wire.beginTransmission(0x68);
    Wire.write(0x03);         //Positionnement sur l'octet à lire: ( ici 4° octet de la RAM)
    Wire.endTransmission(0x68);
   
    Wire.requestFrom(0x68, 1) ;      //Lecture d'1 octet à la position précédemment indiquée      
    octetReg = Wire.read();           //le jour est dans l'octet, (3bits significatifs)  
 }

4)pour une horloge qui a tout son temps pour faire défiler les secondes, la lenteur de l'I2C ne gêne pas.

Bien sûr, c'est OK pour un usage de base.

En revanche, avec des mises à l'heure automatique ( NTP, ...) ta méthode convient mieux ça c'est sûr.

A vue de nez : lecture du registre I2C = 400µs là où un recalcul va en prendre moins de 100.

Ce qui est vraiment dommage, c'est que la RTCLib lit bien le registre mais ne remonte pas sa valeur.

Autant la modifier, ou mieux : laisser tomber cette grosse bouse au profit d'une autre bibliothèque, bien plus efficace et userfriendly : la mienne !! :smiling_imp:

Merci pour vos réponses constructives.

Bien qu'objet d'un autre post, je reprends ici le code réalisé à partir de vos indications au cas où cette discussion, et surtout la solution complète, intéresserait quelqu'un.

#include <Wire.h>
#include "RTClib.h" 
RTC_DS1307 RTC;

const char *tableauDesJours[] = {"Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche"};

void setup () 
{
  Serial.begin(9600);
  Wire.begin();
  RTC.begin();
  
  // 'if' commenté : le RTC est mis à jour après chaque compilation.
  // 'if' non commenté : le RTC n'est PAS mis à jour après chaque compilation. 
  //if (! RTC.isrunning()) 
  {
    RTC.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // Ecriture spécifique du dayOfWeek oublié par la library "RTClib".
    Wire.beginTransmission(0x68);
    Wire.write(0x03);            // Pointe sur le registre dayOfWeek #4 d'adresse 0x003.
    Wire.write(decToBcd(1));     // Ecrit le dayOfWeek (ici Lundi = 1).
                               // A modifier manuellement en fonction du jour réel.
    Wire.endTransmission();
  }
}


void loop () 
{
  DateTime now = RTC.now();

  //Récupère la valeur du dayOfWeek oubliée par la library 'RTClib'.
  Wire.beginTransmission(0x68);   // Accède au RTC I2C d'adresse 0x68.
  Wire.write(0x03);               // Pointe le registre du dayOfWeek (0x03).
  Wire.endTransmission();
  Wire.requestFrom(0x68, 1);      // Demande de reception d'un octet depuis registre (0x03).
  byte dayOfWeek = Wire.read();   // Stocke la valeur reçue.
  Wire.endTransmission();


  Serial.println();
  Serial.print("Numero du jour de la semaine : ");
  Serial.print(dayOfWeek);
  Serial.println();
  Serial.print("Jour de la semaine: ");
  Serial.print(tableauDesJours[dayOfWeek-1]);
  Serial.println();
    
  Serial.print("Heure : ");
  print2digits(now.hour());
  Serial.print(":");
  print2digits(now.minute());
  Serial.print(":");
  print2digits(now.second());
  Serial.println();
    
  Serial.print("Jour : ");
  print2digits(now.day());
  Serial.println();
  Serial.print("Mois : ");
  print2digits(now.month());
  Serial.println();
  Serial.print("Annee : ");
  print2digits(now.year());  
  Serial.println();  
  delay(900);
}


void print2digits(int valeur) 
{
  if (valeur >= 0 && valeur < 10) {
    Serial.print('0');
  }
  Serial.print(valeur);
}


byte decToBcd(byte valeur) 
{
  return ((valeur/10*16) + (valeur%10));
}

Bon codage à tous.

Bonjour,

Est-il possible avec un RTC DS1307 (ou autre) d'extraire un numero de semaine ?
je dois realiser un systeme avec un clavier a code qui ouvrira une barriere avec le numero de semaine et l'année.
exemple : semaine 10 année 2016 : code 1016

le DS1307 donne le jour, le mois et l'année. faudrait-il creer une table année par année ? ou faire une algorithme ?

Une autre solution ???

merci de vos reponse.

Bonjour,
Une des solutions possibles

Je dirais que la détermination du numéro de semaine passe obligatoirement par le calcul du nombre de jours écoulés depuis le 1er janvier.

Ensuite il est nécessaire de calculer quel jour de la semaine était le 1er janvier, pour savoir quand se termine la semaine 1.

Et après ce n'est qu'une question de division par 7

Nb : la semaine 1 est la première semaine qui comporte plus de jours dans la nouvelle année que dans l'ancienne.
Application : si le 1er janvier tombe un vendredi samedi ou dimanche il est en semaine 0, sinon il est en semaine 1

bonjour a toutes et a tous je post ne pas me tromper si je post ici car c'est exactement ce que je cherche j'ai deja un code avec la date mais pas les jours de la semaine je suis tres novice sur arduino j'ai trouver different post et code sur ce sujet mais je n arrive pas a l integrer avec mon code faut il que je change mon code de la date completement ou il est possible d integrer la partie "jour de la semaine" a mon code actuel merci d'avance pour votre aide

// LIBRAIRIES
 
   #include <DHT.h> // inclure les librairies
   #include <Wire.h>
   #include <LiquidCrystal_I2C.h>
   #include <RTClib.h> //librairie à télécharger en ZIP sur https://github.com/jcw/rtclib

// FIN

// DHT 22

   const int relayPin = 13; // PIN 13 pour test sur une LED de la carte
   const int DHTPIN = 13;

   // Type de capteur utiliser
   #define DHTTYPE DHT22   // DHT 11
   DHT dht(DHTPIN, DHTTYPE);// Initialise le capteur DHT11

// FIN

//RTC

   #if defined(ARDUINO) && ARDUINO >= 100
   #define printByte(args)  write(args);
   #else
   #define printByte(args)  print(args,BYTE);
   #endif
   uint8_t clock[8] = {0x0,0xe,0x15,0x17,0x11,0xe,0x0}; 
   RTC_DS1307 RTC;

//FIN

// ECRAN

   LiquidCrystal_I2C lcd(0x27, 16,2); // Initialise le module 1602 I2C
   LiquidCrystal_I2C lcd2 (0x3f,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display

// FIN

   void setup() {

// DATE

  lcd.init();  // initialisation du LCD
  lcd.backlight();
  lcd.print("Initialisation...."); //afficher un message sur l'afficheur LCD
  lcd.createChar(2, clock);
  Wire.begin();
  RTC.begin();
  RTC.adjust(DateTime(__DATE__, __TIME__)); //Ajuster la clock avec l'heure et la date de l'ordinateur


  lcd2.init();  // initialisation du LCD
  lcd2.backlight();
  lcd2.print("Initialisation...."); //afficher un message sur l'afficheur LCD
 
  
  Serial.begin(9600);
  pinMode(relayPin, OUTPUT);
  dht.begin();
  // Définit l'écran LCD 16 colonnes par 2 lignes
  lcd.init();
  // Réglage du rétroéclairage
  lcd.setBacklight(HIGH);

// FIN

// MESSAGE LCD
  
  lcd2.init(); // initialize the lcd 

  // Print a message to the LCD.

    
   lcd2.backlight();
   lcd2.setCursor(5,0);
   lcd2.print("Salut");
   lcd2.setCursor(0,1);
   lcd2.print("Surcoufle breton");
   
// FIN
  
}
   void loop()
{

// BOUCLE TEMPERATURE
  
   // Lecture de température et de l'humiditer environ 250 millisecondes
   // La durer des capteurs peuvent etre regler jusqu'a 2 secondes (capteur tres lent)
   float h = dht.readHumidity();
   // Lit la temperature en degres Celsius (valeur par defaut
   float t = dht.readTemperature();
   float c = dht.readTemperature(true);

  // Vérifie si toutes les lectures ont échoué et quitte le début (pour réessayer).
  if (isnan(h) || isnan(t) || isnan(c)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }

// FIN

// DATE LCD

    //code pour afficher heure et date de la clock (du RTC) sur l'écran LCD
    DateTime now = RTC.now();
       
    lcd.setCursor(3,0);
    lcd.print(now.day(), DEC);
    lcd.print('/');
    lcd.print(now.month(), DEC);
    lcd.print('/');
    lcd.print(now.year(), DEC);
    lcd.print(' ');
    delay(1000);

// FIN

// Temperature et humidité LCD

  lcd.setCursor(0, 1);
  lcd.print("");
  lcd.print(t);
  lcd.print(" C");
  lcd.setCursor(9, 1);
  lcd.print("");
  lcd.print(h);
  lcd.print(" % ");

  Serial.print("Temperature = ");
  Serial.print(t);
  Serial.print(" *C ");
 
  Serial.print("Humidity = ");
  Serial.print(h);
  Serial.print(" %\t ");
  Serial.println();

  if (h >= 75 && h <= 80) // si hum. est = ou sup. a 75 ET hum infer. ou = a 80 relais ouvert
  {
    digitalWrite(relayPin, HIGH);
  }
  else
  {
    digitalWrite(relayPin, LOW); // Sinon relais fermé
  }
  delay(1000);// Delai d'une seconde entre les mesures
}

// FIN

standardUser:
Merci pour vos réponses constructives.

Bien qu'objet d'un autre post, je reprends ici le code réalisé à partir de vos indications au cas où cette discussion, et surtout la solution complète, intéresserait quelqu'un.

#include <Wire.h>

#include "RTClib.h"
RTC_DS1307 RTC;

const char *tableauDesJours[] = {"Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche"};

void setup ()
{
  Serial.begin(9600);
  Wire.begin();
  RTC.begin();
 
  // 'if' commenté : le RTC est mis à jour après chaque compilation.
  // 'if' non commenté : le RTC n'est PAS mis à jour après chaque compilation.
  //if (! RTC.isrunning())
  {
    RTC.adjust(DateTime(F(DATE), F(TIME)));
    // Ecriture spécifique du dayOfWeek oublié par la library "RTClib".
    Wire.beginTransmission(0x68);
    Wire.write(0x03);            // Pointe sur le registre dayOfWeek #4 d'adresse 0x003.
    Wire.write(decToBcd(1));    // Ecrit le dayOfWeek (ici Lundi = 1).
                              // A modifier manuellement en fonction du jour réel.
    Wire.endTransmission();
  }
}

void loop ()
{
  DateTime now = RTC.now();

//Récupère la valeur du dayOfWeek oubliée par la library 'RTClib'.
  Wire.beginTransmission(0x68);  // Accède au RTC I2C d'adresse 0x68.
  Wire.write(0x03);              // Pointe le registre du dayOfWeek (0x03).
  Wire.endTransmission();
  Wire.requestFrom(0x68, 1);      // Demande de reception d'un octet depuis registre (0x03).
  byte dayOfWeek = Wire.read();  // Stocke la valeur reçue.
  Wire.endTransmission();

Serial.println();
  Serial.print("Numero du jour de la semaine : ");
  Serial.print(dayOfWeek);
  Serial.println();
  Serial.print("Jour de la semaine: ");
  Serial.print(tableauDesJours[dayOfWeek-1]);
  Serial.println();
   
  Serial.print("Heure : ");
  print2digits(now.hour());
  Serial.print(":");
  print2digits(now.minute());
  Serial.print(":");
  print2digits(now.second());
  Serial.println();
   
  Serial.print("Jour : ");
  print2digits(now.day());
  Serial.println();
  Serial.print("Mois : ");
  print2digits(now.month());
  Serial.println();
  Serial.print("Annee : ");
  print2digits(now.year()); 
  Serial.println(); 
  delay(900);
}

void print2digits(int valeur)
{
  if (valeur >= 0 && valeur < 10) {
    Serial.print('0');
  }
  Serial.print(valeur);
}

byte decToBcd(byte valeur)
{
  return ((valeur/10*16) + (valeur%10));
}




Bon codage à tous.

Super code, bravo.
Par contre, nous sommes aujourd'hui un mercredi et ma RTC me remonte une valeur de "1" pour le jour de la semaine… Ce n'est à priori pas lié à ton code, mais je n'arrive pas à comprendre pourquoi.

Voici ce que j'ai dans le moniteur série :

Numero du jour de la semaine : 1
Jour de la semaine: Lundi
Heure : 10:14:43
Jour : 09
Mois : 01
Annee : 2019

J'ai pourtant bien "activé" la ligne de réglage de l'heure et mon pc est bien à l'heure et la date du jour...

Et si tu lis les commentaires dans le code tu vois

    Wire.write(0x03);            // Pointe sur le registre dayOfWeek #4 d'adresse 0x003.
    Wire.write(decToBcd(1));     // Ecrit le dayOfWeek (ici Lundi = 1).
                               // A modifier manuellement en fonction du jour réel.

A modifier manuellement en fonction du jour réel

Autant pour moi, merci !
Désolé de n'avoir pas tout lu. :confused:

Bonjour,

Si on ne veut pas initialiser le jour manuellement voici une petite fonction qui donne le jour de la semaine en fonction de la date:

// retourne le jour de la semaine
// 0: dimanche, 1: Lundi ...
// source: https://fr.wikibooks.org/wiki/Curiosit%C3%A9s_math%C3%A9matiques/Trouver_le_jour_de_la_semaine_avec_une_date_donn%C3%A9e
unsigned jourSemaine(unsigned jour, unsigned mois, unsigned annee)
{
  unsigned c=(14-mois)/12;
  unsigned a=annee-c;
  unsigned m=mois + 12*c - 2;
  unsigned js = (jour + a + a/4 - a/100 + a/400 + (31*m)/12) % 7;

  return js;
}

Excellent !!!

J'ai compris que "js" retournait la valeur/le numéro du jour de la semaine.
J'ai mis ton sketch avant le void setup() mais ça ne fonctionne pas.
Je débute… :confused: