Skip to main content

Salut à tous,

J’espère que vous passez de bonnes vacances et que vous bidouillez bien. Aujourd’hui, je fais un tuto sur l’utilisation du module DS1307 grâce à l’Arduino.

Le module DS1307 est une horloge. En fait, on la programme une fois puis on peut ensuite récupérer l’heure qu’il est puisque le module continue de compter les secondes, minutes, heures, etc… grâce à une petite pile bouton plaquée au dos du module. On communique avec ce module grâce au protocole I2C disponible sur les ports A5 et A4 de l’Arduino UNO.

 

Dans un premier temps, j’ai simplifié le travail puisque j’ai trouvé l’adresse I2C du module grâce au bus pirate. Ce dernier m’a donné ce résultat:  0xD0(0x68 W) 0xD1(0x68 R)

Concrètement, ce résultat signifie: « J’ai trouvé un module sur le premier port avec l’adresse 0x68 et en mode écriture. Ensuite, j’ai continué mes recherches et trouvé un même module sur le second port avec la même adresse mais en mode lecture cette fois-ci »

Je reviendrai sur l’utilisation du bus pirate dans un prochain tutoriel sans doute. On a donc ici connaissance de l’adresse du module (0x68) et on remarque que cette adresse est la même en lecture et en écriture.

Bus Pirate adresse DS1307

 

Lorsque vous aller recevoir votre DS1307, l’heure ne sera pas dessus. Voici un script open-source que j’ai pu récupérer sur internet. Au niveau des branchements, voici comment câbler le module. Les branchements ne changerons pas tout au long du tutoriel :

module —-> Arduino

5V          —-> 5V

GND      —-> GND

SDA      —-> A4

SCL       —-> A5

 

Voici le script permettant d’enregistrer l’heure sur le module:

/* RTC Control v1.00 
 * by <http://www.combustory.com> John Vaughters
 *
 * THIS CODE IS FREE FOR ANYTHING - There is no Rocket Science here. No need to create some long GPL statement.
 *
 * Credit to:
 * Maurice Ribble - http://www.glacialwanderer.com/hobbyrobotics for RTC DS1307 code
 * BB Riley - Underhill Center, VT <[email protected]> For simplification of the Day of Week and month
 * and updating to Arduino 1.0 
 * peep rada - from Arduino Forum - Found that only 32 registers per I2C connection was possible 
 * 
 * With this code you can set the date/time, retreive the date/time and use the extra memory of an RTC DS1307 chip. 
 * The program also sets all the extra memory space to 0xff.
 * Serial Communication method with the Arduino that utilizes a leading CHAR for each command described below. 
 *
 * Commands:
 * T(00-59)(00-59)(00-23)(1-7)(01-31)(01-12)(00-99) - T(sec)(min)(hour)(dayOfWeek)(dayOfMonth)(month)(year) -
 * T - Sets the date of the RTC DS1307 Chip. 
 * Example to set the time for 25-Jan-2012 @ 19:57:11 for the 4 day of the week, use this command - T1157194250112
 * Q(1-2) - (Q1) Memory initialization (Q2) RTC - Memory Dump 
 * R - Read/display the time, day and date
 *
 * ---------------------------------------------------------
 * Notes:
 * Version 1.0
 * Moving this code to Version 1.0 because this code has been updated to Arduino v1.0 and the features have
 * been well tested and improved in a collaborative effort.
 * - Fixed the issue of not being able to access all the registers - JWV
 * - Added initialization for all non-time registers - JWV
 * - Added Dump of all 64 registers - JWV
 * - Some Date/Time reformatting and cleanup of display, added Day/Month texts - BBR
 * - Made compatible with Arduino 1.0 - BBR
 * - Added Rr command for reading date/time - BBR
 * - Made commands case insensitive - BBR
 * - Create #define varibles to support pre Arduino v1.0 - JWV
 * Version 0.01
 * Inital code with basics of setting time and the first 37 registers and dumping the first 32 registers. 
 * The code was based on Maurice Ribble's original code.
 * 
 */
 
#include "Wire.h"
#define DS1307_I2C_ADDRESS 0x68 // This is the I2C address
// Arduino version compatibility Pre-Compiler Directives
#if defined(ARDUINO) && ARDUINO >= 100 // Arduino v1.0 and newer
 #define I2C_WRITE Wire.write 
 #define I2C_READ Wire.read
#else // Arduino Prior to v1.0 
 #define I2C_WRITE Wire.send 
 #define I2C_READ Wire.receive
#endif
// Global Variables
int command = 0; // This is the command char, in ascii form, sent from the serial port 
int i;
long previousMillis = 0; // will store last time Temp was updated
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
byte test;
byte zero;
char *Day[] = {"","Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
char *Mon[] = {"","Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
 
// 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) );
}
 
// 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, Probably need to put in checks for valid numbers.
 
void setDateDs1307() 
{
 
 second = (byte) ((Serial.read() - 48) * 10 + (Serial.read() - 48)); // Use of (byte) type casting and ascii math to achieve result. 
 minute = (byte) ((Serial.read() - 48) *10 + (Serial.read() - 48));
 hour = (byte) ((Serial.read() - 48) *10 + (Serial.read() - 48));
 dayOfWeek = (byte) (Serial.read() - 48);
 dayOfMonth = (byte) ((Serial.read() - 48) *10 + (Serial.read() - 48));
 month = (byte) ((Serial.read() - 48) *10 + (Serial.read() - 48));
 year= (byte) ((Serial.read() - 48) *10 + (Serial.read() - 48));
 Wire.beginTransmission(DS1307_I2C_ADDRESS);
 I2C_WRITE(zero);
 I2C_WRITE(decToBcd(second) & 0x7f); // 0 to bit 7 starts the clock
 I2C_WRITE(decToBcd(minute));
 I2C_WRITE(decToBcd(hour)); // If you want 12 hour am/pm you need to set
 // bit 6 (also need to change readDateDs1307)
 I2C_WRITE(decToBcd(dayOfWeek));
 I2C_WRITE(decToBcd(dayOfMonth));
 I2C_WRITE(decToBcd(month));
 I2C_WRITE(decToBcd(year));
 Wire.endTransmission();
}
 
// Gets the date and time from the ds1307 and prints result
void getDateDs1307()
{
 // Reset the register pointer
 Wire.beginTransmission(DS1307_I2C_ADDRESS);
 I2C_WRITE(zero);
 Wire.endTransmission();
 
 Wire.requestFrom(DS1307_I2C_ADDRESS, 7);
 
 // A few of these need masks because certain bits are control bits
 second = bcdToDec(I2C_READ() & 0x7f);
 minute = bcdToDec(I2C_READ());
 hour = bcdToDec(I2C_READ() & 0x3f); // Need to change this if 12 hour am/pm
 dayOfWeek = bcdToDec(I2C_READ());
 dayOfMonth = bcdToDec(I2C_READ());
 month = bcdToDec(I2C_READ());
 year = bcdToDec(I2C_READ());
 
 if (hour < 10)
 Serial.print("0");
 Serial.print(hour, DEC);
 Serial.print(":");
 if (minute < 10)
 Serial.print("0");
 Serial.print(minute, DEC);
 Serial.print(":");
 if (second < 10)
 Serial.print("0");
 Serial.print(second, DEC);
 Serial.print(" ");
 Serial.print(Day[dayOfWeek]);
 Serial.print(", ");
 Serial.print(dayOfMonth, DEC);
 Serial.print(" ");
 Serial.print(Mon[month]);
 Serial.print(" 20");
 if (year < 10)
 Serial.print("0");
 Serial.println(year, DEC);
 
}
 
 
void setup() {
 Wire.begin();
 Serial.begin(9600); 
 zero=0x00;
}
 
void loop() {
 if (Serial.available()) { // Look for char in serial que and process if found
 command = Serial.read();
 if (command == 84 || command == 116) { //If command = "Tt" Set Date
 setDateDs1307();
 getDateDs1307();
 Serial.println(" ");
 }
 else if (command == 82 || command == 114) { //If command = "Rr" Read Date ... BBR
 getDateDs1307();
 Serial.println(" ");
 }
 else if (command == 81 || command == 113) { //If command = "Qq" RTC1307 Memory Functions
 delay(100); 
 if (Serial.available()) {
 command = Serial.read(); 
 if (command == 49) { //If command = "1" RTC1307 Initialize Memory - All Data will be set to 
 // 255 (0xff). Therefore 255 or 0 will be an invalid value. 
 Wire.beginTransmission(DS1307_I2C_ADDRESS); // 255 will be the init value and 0 will be considered 
 // an error that occurs when the RTC is in Battery mode.
 I2C_WRITE(0x08); // Set the register pointer to be just past the date/time registers.
 for (i = 1; i <= 24; i++) {
 I2C_WRITE(0Xff);
 delay(10);
 } 
 Wire.endTransmission();
 Wire.beginTransmission(DS1307_I2C_ADDRESS); 
 I2C_WRITE(0x21); // Set the register pointer to 33 for second half of registers. Only 32 writes per connection allowed.
 for (i = 1; i <= 33; i++) {
 I2C_WRITE(0Xff);
 delay(10);
 } 
 Wire.endTransmission();
 getDateDs1307();
 Serial.println(": RTC1307 Initialized Memory");
 }
 else if (command == 50) { //If command = "2" RTC1307 Memory Dump
 getDateDs1307();
 Serial.println(": RTC 1307 Dump Begin");
 Wire.beginTransmission(DS1307_I2C_ADDRESS);
 I2C_WRITE(zero);
 Wire.endTransmission();
 Wire.requestFrom(DS1307_I2C_ADDRESS, 32);
 for (i = 0; i <= 31; i++) { //Register 0-31 - only 32 registers allowed per I2C connection
 test = I2C_READ();
 Serial.print(i);
 Serial.print(": ");
 Serial.print(test, DEC);
 Serial.print(" : ");
 Serial.println(test, HEX);
 }
 Wire.beginTransmission(DS1307_I2C_ADDRESS);
 I2C_WRITE(0x20);
 Wire.endTransmission();
 Wire.requestFrom(DS1307_I2C_ADDRESS, 32); 
 for (i = 32; i <= 63; i++) { //Register 32-63 - only 32 registers allowed per I2C connection
 test = I2C_READ();
 Serial.print(i);
 Serial.print(": ");
 Serial.print(test, DEC);
 Serial.print(" : ");
 Serial.println(test, HEX);
 }
 Serial.println(" RTC1307 Dump end");
 } 
 } 
 }
 Serial.print("Command: ");
 Serial.println(command); // Echo command CHAR in ascii that was sent
 }
 command = 0; // reset command 
 delay(100);
 }
//*****************************************************The End***********************

Voilà pour l’écriture sur le module. Le fonctionnement de ce programme est assez simple, ouvrez le port série de l’Arduino, réglez le sur 9600 bauds puis écrivez    T(sec)(min)(hour)(dayOfWeek)(dayOfMonth)(month)(year) en remplaçant par la date que vous souhaitez.

Maintenant, votre module est tout beau avec l’heure entrée dedans. Mais le plus intéressant, c’est surtout de pouvoir récupérer l’heure stockée. Cette opération peut s’effectuer simplement grâce au programme suivant

 

 #include 

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

void loop(){
 
 //Initialisation du pointeur
 Wire.beginTransmission(0x68);
 Wire.write(0);
 Wire.endTransmission();
 
 //Lecture des 7 octets contenant date et heure
 Wire.requestFrom(0x68, 7);  //On demande 7 octets à l'adresse 0x68 (voir plus haut)
 byte secs = Wire.read(); //Chaque octet reçu est stocké dans une variable qui lui est propre
 byte mins = Wire.read(); //Dans l'ordre, on reçoit les secondes, les minutes, les heures, etc...
 byte hrs = Wire.read();
 byte jour = Wire.read();
 byte date = Wire.read();
 byte mois = Wire.read();
 byte annee = Wire.read();
 
 //Affichage des données
 Serial.print("Heure ");
 if(hrs < 10) Serial.print("0");
 Serial.print(hrs,HEX);
 Serial.print(":");
 if(mins < 10) Serial.print("0");
 Serial.print(mins,HEX);
 Serial.print(":");
 if(secs < 10) Serial.print("0");
 Serial.println(secs,HEX);
 
 Serial.print("Date ");
 if(date <10) Serial.print("0");
 Serial.print(date,HEX);
 Serial.print("-");
 if(mois < 10) Serial.print("0");
 Serial.print(mois,HEX);
 Serial.print("-");
 Serial.print("20");
 if(annee < 10) Serial.print("0");
 Serial.println(annee, HEX);
 Serial.println();
 delay(1000);
}

Ce script vous permettra de récupérer les données d’horloge stockées pour les réutiliser dans un programme. Ici, j’ai décidé de les afficher dans le moniteur série.

Je vous donne en prime une idée d’un projet à effectuer avec ce module, la réalisation d’un réveil avec afficheur digital sur des 7 segments ou un écran LCD par exemple.
Les projets sont infinis !

Voilà pour ce tuto sur le DS1307, j’y regroupe deux programmes des plus utiles lorsque l’on débute avec ce type de module.

Fabien Aubret

Co-fondateur SimpleDuino, Co-fondateur SimpleDomo. Ingénieur de l'Ecole Nationale Supérieure des Arts Et Métiers (ENSAM). Passionné d'électronique, d'informatique et des nouvelles technologies en général, j'ai à cœur de transmettre ce que d'autres ont pu m'apprendre.

3 Comments

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.