problèmes avec RTC DS1307

Bonjour,
voilà mon problème, je tente de programmer une horloge à l'aide d'un RTC DS1307, je débute en programmation sur arduino (mes dernières expériences étaient en BASIC, ça date....) et je pioche à gauche à droite sur le net pour me débrouiller.
Je n'arrive pas à initialiser l'heure, les minutes et les secondes commencent bien à 0 mais l'heure commence à 6 et je ne me l'explique pas.
Si quelqu'un à une idée ça m'avancerai beaucoup, merci.

voici mon code:

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

// Convertion decimal vers BCD
byte decToBcd(byte val)
{
  return ( (val/10*16) + (val%10) );
}

// Convertion BCD vers decimal
byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}

void setDateDs1307(byte second,        // 0-59
                   byte minute,        // 0-59
                   byte hour)          // 0-23
{
   Wire.beginTransmission(DS1307_I2C_ADDRESS);

   Wire.write(decToBcd(second));    
   Wire.write(decToBcd(minute));
   Wire.write(decToBcd(hour));      
   Wire.endTransmission();
}

// obtention de l'heure du ds1307
void getDateDs1307(byte *second,
          byte *minute,
          byte *hour)
{
  // Reset register
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(0);
  Wire.endTransmission();
  
  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

  
  *second     = bcdToDec(Wire.read() & 0x7f);
  *minute     = bcdToDec(Wire.read());
  *hour       = bcdToDec(Wire.read() & 0x3f);  
  }


void setup()
{
  byte second, minute, hour;
  Wire.begin();
  Serial.begin(9600);
  
  second = 0;
  minute = 0;
  hour = 0;
  setDateDs1307(second, minute, hour);
}

void loop()
{
  byte second, minute, hour;

  getDateDs1307(&second, &minute, &hour);
  Serial.print(hour, DEC);
  Serial.print(":");
  Serial.print(minute, DEC);
  Serial.print(":");
  Serial.print(second, DEC);
  Serial.println("  ");
  

  delay(1000);
}

ou est-il possible que le problème vienne de mon horloge et non de mon code?
et comment m'en assurer?

Pourquoi ne pas utiliser une librairie DS1307 déjà faite?

Salut,
je n'ai pas tout regardé en détail mais il y a au minimum une erreur dans ta fonction pour écrire l'heure dans la RTC : avant d'envoyer les données tu dois indiquer l'adresse du premier registre dans lequel tu souhaites écrire (ensuite le pointeur s'incrémente automatiquement).

Donc :

void setDateDs1307(byte second,        // 0-59
                   byte minute,        // 0-59
                   byte hour)          // 0-23
{
   Wire.beginTransmission(DS1307_I2C_ADDRESS);

   Wire.write(0);    // <--------------- Là
   Wire.write(decToBcd(second));    
   Wire.write(decToBcd(minute));
   Wire.write(decToBcd(hour));      
   Wire.endTransmission();
}

De même, dans ta fonction pour lire les données tu demande à récupérer 7 octets via le bus, mais ensuite tu n'en lis que 3. Pas vraiment une bonne idée.

@john_lenfr : je voulais vraiment comprendre ce que je fait, du coup une bibliothèque ça me mâche un peu le travail...

@haifger: merci!!! t'as mit dans le mille, les 7 octets servaient à récupérer le jour/mois/année... :astonished:

Tiens, cadeau :

Bon courage :slight_smile:

Bonjour à tous
J’ai un autre problème avec le ds1307. Je ne sais si je peux le poser à la suite de celui-ci. Bon voilà j’ai un souci d’adressage entre le ds 1307 et un mpu 9150 qui ont la même adresse i2c à savoir 0x68. Comme j’ai besoin des deux je voudrais savoir comment multiplexé les adresses où une autre solution si possible. Il y a la possibilité de passer le mpu 9150 à l’adresse 0x69 moyennant une petite soudure. Ce que je voudrais éviter. Mais bon s’il n’y a pas d’autre solution il faudra faire avec. Merci de partager vos idées sur la question.
Bonne soirée á tous.

Senior01:
Bonjour à tous
J’ai un autre problème avec le ds1307. Je ne sais si je peux le poser à la suite de celui-ci. Bon voilà j’ai un souci d’adressage entre le ds 1307 et un mpu 9150 qui ont la même adresse i2c à savoir 0x68. Comme j’ai besoin des deux je voudrais savoir comment multiplexé les adresses où une autre solution si possible. Il y a la possibilité de passer le mpu 9150 à l’adresse 0x69 moyennant une petite soudure. Ce que je voudrais éviter. Mais bon s’il n’y a pas d’autre solution il faudra faire avec. Merci de partager vos idées sur la question.
Bonne soirée á tous.

si vraiment les 2compos ont la meme adresse et que ton MPU9150 en dispose de plusieurs (par jumper/CC) n'hesite pas à lui en attribuer une autre (un point de soudure ce n'est pas la mort, n'oublie pas de noter ça sur le circuit, dans... 5 ans tu aura oublié la modif :grin: ).
toutes autres solution d'interfaçage va tourner à l'usine à gaz

Merci à toi pour la réponse rapide. Si j’hésite a changer d’adresse c’est parce cette plage d’adresse est très utilisée. Par exemple le giro itg3200 a pour adresse 0x69. Donc si je dois utiliser un deuxième imu par exemple avec un tel gyro me voilà de nouveau avec le problème. C’est un problème qui doit se géré au niveau du Bus i2c et non au niveau du composant. La prise de possession du bus se fait toujours dans l’ordre du composant le plus lent. C’est à dire celui qui envoie le premier un zéro. Bon mais après vient la transmission des données. La est le problème il ne faut pas polluer les donner de celui qui émet sur le bus. Tout est dans la gestion des composants maitres par le bus i2c. Ce dernier est par construction multi-master donc cela devrait pouvoir être faisable. Je cherche encore.
cordialement

Senior01:
Merci à toi pour la réponse rapide. Si j’hésite a changer d’adresse c’est parce cette plage d’adresse est très utilisée. Par exemple le giro itg3200 a pour adresse 0x69. Donc si je dois utiliser un deuxième imu par exemple avec un tel gyro me voilà de nouveau avec le problème. C’est un problème qui doit se géré au niveau du Bus i2c et non au niveau du composant. La prise de possession du bus se fait toujours dans l’ordre du composant le plus lent. C’est à dire celui qui envoie le premier un zéro. Bon mais après vient la transmission des données. La est le problème il ne faut pas polluer les donner de celui qui émet sur le bus. Tout est dans la gestion des composants maitres par le bus i2c. Ce dernier est par construction multi-master donc cela devrait pouvoir être faisable. Je cherche encore.
cordialement

j'ai repondu pragmatiquement
tu a un seul bus I2C
composant lent ou pas , il faut evacuer le conflit d'adresse
tu a un compo adréssé fixe (le DS1307)
tu a un module dont l'adresse peut etre facilement modifiée en petit hard (plage d'adresses ?)
plutot qu'une/des soudures , mettre un/des jumpers ? (je ne connais pas ton IMU pour savoir si c'est simple)

J’avais dans mon post precedent donner le IMU. Il s’agit d’un mpu9150. En fait c’est un 6050 monté avec un hmc5883l sur le meme board. Donc il y a un gyro. et un accel. Ce pmontage elimine les problemes d’ajustement entre le gyro et l’acceleromtre. Cette petite merveille possède également un module DCM (Direction Cosinus matrice) ce qui permettrait de soulager énormément l’arduino. Bon pour être complet il faut dire que le module DCM n’est pas encore totalement au point et je fais encore la correction en externe sur l’arduino. Cette petite merveille sert de noyau central pour beaucoup de pilote automatique inertiel. Moi je l’utilise pour piloter un gyropode. (Pour plus d’info sur la bête c’est par ici http://gyropode.vilain.de.).

Le mpu9150 est adresse 0x68 ou 0x69.
MPU-9150 I²C device address selection pin AD0. When the pin value is low, the device address is 0x68. When the pin value is high, the device address is 0x69. The address value is 7bits.
Donc on peut faire: int MPU9150_I2C_ADDRESS = 0x69;

Je viens de trouver une autre piste. C’est la ligne FSYNC. Je vais explorer la voie et voire ce qu’il y a derriere cette possibilité.

Cordialement

mon code fonctionne, mais maintenant j'ai un autre soucis en utilisant la librairie.
déjà le code fonctionnel si ça peut aider quelqu'un :

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

// Convertion decimal vers BCD
byte decToBcd(byte val)
{
  return ( (val/10*16) + (val%10) );
}

// Convertion BCD vers decimal
byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}

void setDateDs1307(byte second,        // 0-59
                   byte minute,        // 0-59
                   byte hour)          // 0-23
{
   Wire.beginTransmission(DS1307_I2C_ADDRESS);
   Wire.write(0);
   Wire.write(decToBcd(second));    
   Wire.write(decToBcd(minute));
   Wire.write(decToBcd(hour));      
   Wire.endTransmission();
}

// obtention de l'heure du ds1307
void getDateDs1307(byte *second,
          byte *minute,
          byte *hour)
{
  // Reset register
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(0);
  Wire.endTransmission();
  
  Wire.requestFrom(DS1307_I2C_ADDRESS, 3);

  
  *second     = bcdToDec(Wire.read() & 0x7f);
  *minute     = bcdToDec(Wire.read());
  *hour       = bcdToDec(Wire.read() & 0x3f);  
  }


void setup()
{
  byte second, minute, hour;
  Wire.begin();
  Serial.begin(9600);
  
  second = 0;
  minute = 0;
  hour = 0;
  setDateDs1307(second, minute, hour);
}

void loop()
{
  byte second, minute, hour;

  getDateDs1307(&second, &minute, &hour);
  Serial.print(hour, DEC);
  Serial.print(":");
  Serial.print(minute, DEC);
  Serial.print(":");
  Serial.print(second, DEC);
  Serial.println("  ");
  

  delay(1000);
}

maintenant avec la librairie je n'arrive pas à regler la date, j'ai utilisé cette lib : What is an RTC? | DS1307 Real Time Clock Breakout Board Kit | Adafruit Learning System

et le code:

#include <LiquidCrystal.h>

// fonctions Date et heure en utilisant 
// le RTC DS1307 RTC via bus I2C et librairie Wire

#include <Wire.h>
#include "RTClib.h"
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2); //pin utilisés pour le LCD

RTC_DS1307 RTC;

void setup () {
  lcd.begin(20,4);
  lcd.clear();
  lcd.setCursor(0,0);
  Wire.begin();
  RTC.begin();

  if (! RTC.isrunning()) {
    lcd.println("RTC n est pas en cours de fonctionnement!");
    // La ligne suivante fixe la date et l'heure du RTC avec les date et heur de compilation du sketch
  RTC.adjust(DateTime(__DATE__, __TIME__));
  }

}

void loop () {
  DateTime now = RTC.now();
  lcd.clear();
  lcd.print(now.hour(), DEC);
  lcd.print(':');
  lcd.print(now.minute(), DEC);
  lcd.print(':');
  lcd.print(now.second(), DEC);

  delay(3000);
}

malgrès tout mes effort l'heure ne correspond pas du tout à celle de mon système...

du coup pour regler mon horloge je verse ce programme dans l'arduino avec la date rentrée manuellement et en suite grace à la pile l'heure reste en mémoire du DS 1307

#include "Wire.h"
#define DS1307_ADDRESS 0x68
byte zero = 0x00; //workaround for issue #527


void setup(){
  Wire.begin();
  Serial.begin(9600);
  setDateTime(); 
}

void loop(){
  printDate();
  delay(1000);
}

void setDateTime(){

  byte second =      0; //0-59       //données à rentrer manuellement pour régler votre horloge
  byte minute =      9; //0-59
  byte hour =        14; //0-23
  byte weekDay =     2; //1-7
  byte monthDay =    1; //1-31
  byte month =       3; //1-12
  byte year  =       11; //0-99

  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(zero); //stop Oscillator

  Wire.write(decToBcd(second));
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour));
  Wire.write(decToBcd(weekDay));
  Wire.write(decToBcd(monthDay));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));

  Wire.write(zero); //start 

  Wire.endTransmission();

}

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

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

void printDate(){

  // Reset the register pointer
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(zero);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_ADDRESS, 7);

  int second = bcdToDec(Wire.read());
  int minute = bcdToDec(Wire.read());
  int hour = bcdToDec(Wire.read() & 0b111111); //24 hour time
  int weekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
  int monthDay = bcdToDec(Wire.read());
  int month = bcdToDec(Wire.read());
  int year = bcdToDec(Wire.read());

  //print the date EG   3/1/11 23:59:59
  Serial.print(month);
  Serial.print("/");
  Serial.print(monthDay);
  Serial.print("/");
  Serial.print(year);
  Serial.print(" ");
  Serial.print(hour);
  Serial.print(":");
  Serial.print(minute);
  Serial.print(":");
  Serial.println(second);

}