Bienvenue aux nouveaux arrivants sur FantasPic !

- Pensez à lire les règles durant votre visite, il n'y en a pas beaucoup, mais encore faut-il les respecter .
- N’hésitez pas à faire des remarques et/ou suggestions sur le Forum, dans le but de l'améliorer et de rendre vos prochaines visites plus agréables.
- Vous pouvez regarder votre "panneau de l'utilisateur" afin de configurer vos préférences.
- Un passage par "l'utilisation du forum" est recommandé pour connaître les fonctionnalités du forum.

--- L’équipe FantasPic ---
Commentez, partagez et proposez des Tutos en langage C !
Real Time Clock avec DS1307 (RTC)
Jérémy
Administrateur du site
Administrateur du site
Messages : 2156
Âge : 39
Enregistré en : juillet 2015
Localisation : Dans le sud
Contact :

#1 Message par Jérémy » dim. 1 nov. 2015 17:06

Image

Bonjour à tous,

Aujourd'hui nous allons parlé du module RTC2_click de Mikroelekronika .
Ce module est un calendrier qui permet de connaitre la date et l'heure en temps réel.
Il utilise le driver DS1307 très répandu.
Nous allons voir comment communiquer avec ce driver et dégrossir ses fonctions principales. ( Data-sheet du DS1307 )

Pour faire ce Tuto je me suis inspiré de l'exemple de MikroE, que vous pouvez retrouver ici
Exemple d'utilisation du moduleRTC2_click
Schéma de connexion du module




Image



Configuration :

- PIC18F45K22
- IDE : MikroC Pro for PIC Version 6.6.2
- Compilateur : Mikro prog suite fo PIC V 2.32
- Plaque Easy PIC V7
- RTC2_click en mode I²C
- LCD 16x2 en mode 4bits







1/ Préliminaire

Le module RTC permet d'avoir l'heure et la date n'importe où sur vos projets ! .
Associer à une pile lithium, il sauvegarde la date et l'heure durant plusieurs mois/année même en cas de coupure de courant. Il est cadencé par un quartz externe calé sur une certaine fréquence(32.768KHz).

Durant ce tutoriel nous allons voir comment écrire et lire sur ce module. Nous allons ainsi pouvoir régler le Groupe-Date-Heure (GDH) en écrivant dans les registres du module, et bien évidemment récupérer le GDH fournit par le RTC pour se servir des informations ( afficher l'heure par exemple).

Le DS1307 offre également une sortie qui peut-être configurée en sortie logique ou en sortie de générateur de signal carré(Square-Wave). Cette sortie est relativement peu utilisée. Nous ne verrons pas cette fonction pour le moment.

2/ Initialisation de l'heure

Sans pile de sauvegarde , les registres sont tous à 0 au démarrage . Il conviendra donc de les initialiser.
Cela se fera par l'appui sur un BP (branché sur RA0).
Cette initialisation va simplement injectée dans les registres les valeurs que nous aurons préalablement configurées.

Une fois initialisé et le fonctionnement autorisé, le DS1307 incrémentera les valeurs automatiquement. elle est pas belle la vie ! :D

3/Récupération des infos

Le DS1307 une fois initialisé va nous fournir la date et l'heure ( l'unité la plus petite est la seconde). Il va donc nous falloir lire ses registres où sont stockés les valeurs du GDH , les enregistrées et enfin les affichées ou faire des calculs de durée par exemple.

Dans notre exemple nous afficherons la date et l'heure sur un écran LCD .

Attention!! La seule petite difficulté que j'ai rencontré c'est sur le fait que le module communique avec des valeurs en hexa ( BCD). Il va donc falloir convertir les données de décimal à hexa dans un sens , et de hexa à décimal dans l'autre .

pour ce faire nous utiliserons la bibliothèque conversions et les fonctions qui vont bien :
Bcd2Dec() et Dec2Bcd()

Donc avant chaque écriture et lecture nous devrons convertir les données.

Comme d'habitude , si vous avez des questions, remarques, propositions etc ..... n’hésitez pas à poster a la suite de ce sujet !

Voici le programme commenté ligne par ligne :

Code : Tout sélectionner

/*----------------------------------------------------------------------------------
- Tutoriel Module RTC 2 click sur plaque easyPic 7
- fait par Jérémy le 01/11/2015 sur www.FantasPic.fr
- Pic 18F45K22 avec MikroC 6.6.2
- Fosc : 8Mhz
----------------------------------------------------------------------------------*/

#define RTC_ADDR  0xD0   // Adresse I²C de l'esclave ( DS1307)

// Lcd module connections
sbit LCD_RS at LATB4_bit;
sbit LCD_EN at LATB5_bit;
sbit LCD_D4 at LATB0_bit;
sbit LCD_D5 at LATB1_bit;
sbit LCD_D6 at LATB2_bit;
sbit LCD_D7 at LATB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;

// Constantes
unsigned char txt1[]=" RTC2 click sur ";
unsigned char txt2[]="www.FantasPic.fr";

// Variables
unsigned char heures, minutes, secondes, jour, n_jour, mois, annee,  D_secondes,  U_secondes;
char oldstate = 0;

// Prototypes
unsigned short Bcd2Dec(unsigned short decnum);
unsigned short Dec2Bcd(unsigned short decnum);

/****************************************************************************
* Fonction: Lire les données sur le RTC
* parametre d'entrée : adresse du registre à lire
* parametre de sortie : valeur lue dans le registre
**********************************************************************************/
unsigned char RTC_Read(unsigned char addr){
  unsigned char value; // Déclaration variable temporaire

  I2C1_Start();        // Début de l'I²C
  I2C1_Wr(RTC_ADDR);   // Adresse du RTC ( 0xD0 cf datasheet)
  I2C1_Wr(addr);       // adresse du registre à lire
  I2C1_Start();        // On répète le signal de départ
  I2C1_Wr(RTC_ADDR);   // Adresse du DS1307

  value = I2C1_Rd(0);  // lecture et enregistrement de la valeur le 0=pour no ACK
  I2C1_Stop();         // Arrêt de l'I²C

  return value;        // On retourne la valeur lue
}

/**************************************************************************************************
* Fonction: Ecrire les données sur le DS1307
* parametre d'entrée : adresse du registre à ecrire + valeur à y mettre
**************************************************************************************************/
void RTC_Write(unsigned char addr, unsigned char value){
  I2C1_Start();         // Début de l'I²C
  I2C1_Wr(RTC_ADDR);    // Adresse du RTC ( 0xD0 cf datasheet)
  I2C1_Wr(addr);        // adresse du registre à écrire
  I2C1_Wr(value);       // On écrit la valeur dans le registre
  I2C1_Stop();          // Arrêt de l'I²C
}

/**************************************************************************************************
* Fonction: Ecrire le Groupe Date Heure sur appui du BP
* parametre d'entrée : Les 7 valeurs du GDH à initialiser
**************************************************************************************************/
void Ecrire_GDH (unsigned char heures , unsigned char minutes, unsigned char secondes ,
unsigned char jour,unsigned char n_jour, unsigned char mois,unsigned char annee){

  I2C1_Start();         // Début de l'I²C
  I2C1_Wr(RTC_ADDR);    // Adresse du RTC ( 0xD0 cf datasheet)
  I2C1_Wr(0);           // Met le pointeur à cette adresse ( N° registre)
  
  secondes 
= Dec2Bcd(secondes); // Conversion de décimal en BCD pour le RTC
  I2C1_Wr(secondes);            // On écrit la valeur dans le registre des secondes
  minutes = Dec2Bcd(minutes);   // Après écriture la valeur du pointeur du registre est incrémenter automatiquement
  I2C1_Wr(minutes);             // On peut enchainer directement avec la prochaine valeur
  heures = Dec2Bcd(heures);     // etc ... toutes à la suite.
  I2C1_Wr(heures);
  jour = Dec2Bcd(jour);
  I2C1_Wr(jour);
  n_jour = Dec2Bcd(n_jour);
  I2C1_Wr(n_jour);
  mois = Dec2Bcd(mois);
  I2C1_Wr(mois);
  annee = Dec2Bcd(annee);
  I2C1_Wr(annee);

  I2C1_Stop();                      // Arrêt de l'I²C
}

/**************************************************************************************************
* Fonction: Lit le Groupe Date Heure sur le RTC pour mettre à jour l'affichage
**************************************************************************************************/
void Lecture_GDH(){

  I2C1_Start();                // Début de l'I²C
  I2C1_Wr(RTC_ADDR);           // Adresse du RTC ( 0xD0 cf datasheet)
  I2C1_Wr(0);                  // lecture à cette adresse ( N° registre)
  I2C1_Repeated_Start();       // On répète le signal de départ
  I2C1_Wr(RTC_ADDR+1);         // Adresse du DS1307 (1=lire / 0=ecrire)

  secondes = I2C1_Rd(1);          // Lecture et enregistrement de la valeur
  secondes = Bcd2Dec(secondes);   // Conversion de BCD en décimal pour l'afficheur
  minutes = I2C1_Rd(1);
  minutes = Bcd2Dec(minutes);
  heures = I2C1_Rd(1);
  heures = Bcd2Dec(heures);
  jour = I2C1_Rd(1);
  jour = Bcd2Dec(jour);
  n_jour = I2C1_Rd(1);
  n_jour = Bcd2Dec(n_jour);
  mois = I2C1_Rd(1);
  mois = Bcd2Dec(mois);
  annee = I2C1_Rd(0);
  annee = Bcd2Dec(annee);

  I2C1_Stop();                    // Arrêt de l'I²C
}

/*##################################################################################
##########################    PROGRAMME PRINCIPAL    ###############################
##################################################################################*/
void main(){
  ANSELA = 0;               // Configure le PORTA en digital
  ANSELB = 0;               // Configure le PORTB en digital
  ANSELC = 0;               // Configure le PORTC en digital
  SLRCON = 0;               // ?? Configure all PORTS at the standard Slew

  TRISA0_bit = 1;           // Met RA0 en entrée pour le BP.
                            // Utilisé pour initialisé l'horloge avec une valeur enregistrée

  I2C1_Init(100000);        // Initialise le BUS I2C
  Lcd_Init();               // Initialise le Lcd

  Lcd_Cmd(_LCD_CLEAR);      // Efface écran
  Lcd_Cmd(_LCD_CURSOR_OFF); // Curseur off
  Lcd_Out(1,1,txt1);        // Écrit le texte de présentation 1er ligne
  Lcd_Out(2,1,txt2);        // Écrit le texte de présentation 2iéme ligne

  Delay_ms(3000);           // pause 3 sec

  Lcd_Cmd(_LCD_CLEAR);      // Efface l'écran
  LCD_Chr(1,9,'.');         // On écrit la matrice du texte statique
  LCD_Chr(1,12,'.');
  LCD_Out(2,1,"Heure:");
  LCD_Chr(2,11,':');
  LCD_Chr(2,14,':');
  LCD_Out(1,13,"20");       // le 20 c'est pour l'année 20xx

/*##################################################################################
############################    BOUCLE INFINIE    ##################################
##################################################################################*/
  while(1){
      if (Button(&PORTA, 0, 1, 0))oldstate = 1;  // Anti-rebond
      if (oldstate && Button(&PORTA, 0, 1, 1)) { // Si le BP est appuyé on envoi le GDH suivant
         Ecrire_GDH( 23,  59,  50,    4,  31, 12, 15);  //heure: min: sec: N°jour: jour: mois: année
         oldstate = 0;  // mise à 0 du flag
       }

      Lecture_GDH();     // On va lire notre DS1307

      switch(jour)       // On sélectionne le jour suivant la valeur retournée
        {
          case 1: LCD_Out(1,1, "Lundi"); break;  // Affichage du jour en fonction de la valeur
          case 2: LCD_Out(1,1, "Mardi"); break;
          case 3: LCD_Out(1,1, "Mer. "); break;
          case 4: LCD_Out(1,1, "Jeudi"); break;
          case 5: LCD_Out(1,1, "Ven. "); break;
          case 6: LCD_Out(1,1, "Sam. "); break;
          case 7: LCD_Out(1,1, "Dim. "); break;
        }

      Lcd_Chr(1,7, (n_jour / 10)   + 48);  // Le numéro du jour dizaine
      Lcd_Chr(1,8, (n_jour % 10)   + 48);  // Le numéro du jour unité
      Lcd_Chr(1,10, (mois / 10) + 48);
      Lcd_Chr(1,11, (mois % 10) + 48);
      Lcd_Chr(1,15, (annee / 10)  + 48);
      Lcd_Chr(1,16, (annee % 10)  + 48);

      Lcd_Chr(2,9, (heures / 10)   + 48); // Deuxième lignes 9iéme caractère dizaine des heures
      Lcd_Chr(2,10, (heures % 10)   + 48); // Unité des heures
      Lcd_Chr(2,12, (minutes / 10) + 48);
      Lcd_Chr(2,13, (minutes % 10) + 48);
      Lcd_Chr(2,15, (secondes / 10) + 48);
      Lcd_Chr(2,16, (secondes % 10) + 48);

        Delay_mS(10); // pause de 10ms
   }
}


Sur la vidéo, n'ayant pas de pile, on voit les registres à 0 à l'allumage, puis en appuyant sur le BP en injecte les données . Dans notre exemple nous sommes le Jeudi 31 décembre 2015 et il est 23h59 .
http://www.dailymotion.com/video/x3bxeqz
C'est en faisant des erreurs, que l'on apprend le mieux !!!

Real Time Clock avec DS1307 (RTC)
paulfjujo
Avatar de l’utilisateur
Expert
Expert
Messages : 1087
Âge : 68
Enregistré en : juillet 2015
Localisation : 01800
Contact :

#2 Message par paulfjujo » mar. 3 nov. 2015 16:32

bonjour,


Je ne sais pas si ma remarque suvante est placée au bon endroit
ce serait plutot dans une rubrique du genre "trucs & astuces ,contournement de deboires".. ?


Attention!! ATTENTION :
il est preferable d'utilser la zone programme pour stocker les donnees figées
tel que du texte à afficher, car SINON mikroC les stocke en RAM
Ce n'est pas génant TANT qu'on a sufisament de RAM dispo..
sinon on peut tomber dans le cas où un alarme sibiline apparait à la compilation , tel que " irp bit .."
meme avec une compilation réussie .. NO ERROR.
ou error 102 ...

C'est surtout vrai avec les PIC 16F ... de petite taille RAM .
Ou pire on constate des aleas ou effet de bords par écrasement de données en zone memoire (RAM)
et on tourne en rond pour savoir où est le bug !
voir les nombreux post sur MikroE à ce sujet !

Malheureusement, les exemples MikroC NE SONT PAS toujours à suivre !
Ces exemples suffisamment court arrivent à tourner sans probleme
mais des qu'on étoffe un peu le programme .. les problemes arrivent.

// Constantes en Flash
const unsigned char txt1[]=" RTC2 click sur ";
const unsigned char txt2[]="www.FantasPic.fr";

//declaration en RAM
char TEXTE[17]. // largeur LCD 16 cars + 0=terminateur eventuel de string
// transferer le texte de ROM -> RAM via la librairie "String"
strConstRamCpy( TEXTE,txt1); // copie la chaine "Constante " en "Ram"
LCD_Write_Text(TEXTE);
si on a plusieurs messages , on n'utilise que la RAM tampon de 17 bytes...

Ou utiliser une fonction legerement differente suivant qu'on utilise du TEXTE dans le code
ou du TEXTE dans une variable RAM
exemple avec la fonction MikroC originale :

Code : Tout sélectionner

  void UART_Write_Text(char * UART_text);
strConstRamCpy( TEXTE,txt1);     // copy le string situé en Flash -> RAM
UART_Write_Text(TEXTE)        // envoie le texte situé en RAM sur l'UART (ecran);

nouvelle fonction modifiée en :

Code : Tout sélectionner

void UART1_Write_CText(const char *txt1) 
{
   while (*txt1)
    UART1_Write(*(txt1++));
}

exemple :

Code : Tout sélectionner

UART_Write_CText(" TC2 click sur");   // envoi le Texte ecrit dans le code sur l'UART SANS utiliser la RAM    


on peut faire pareil avec le LCD !
ecrire 2 fonctions distinctes:

Code : Tout sélectionner

void LCD_Write_Text(unsigned int Ligne,char * t1);
void LCD_Write_CText(unsigned int Ligne,unsigned int col,const char * t1);


la seule difference importante est le type de pointeur ! (sur RAM ou ROM.)
On peut donc aussi, tout simplement rajouter un casting sur le type de pointeur !
(casting = modification et forcage de type de variable ou pointeur)
comme dans l'image ci-jointe

3em solution
Message TEXTES fixes stockees en EEPROM ...
serait peut etre le choix le plus judicieux.


un exemple chiffré qui illustre la difference de stockage en RAM
Probleme_102_Finished _with_errors.jpg
Vous n’avez pas les permissions nécessaires pour voir les fichiers joints à ce message.

Real Time Clock avec DS1307 (RTC)
venom
Avatar de l’utilisateur
Passioné
Passioné
Messages : 420
Âge : 33
Enregistré en : avril 2016
Localisation : . <------ ici
Contact :

#3 Message par venom » dim. 2 sept. 2018 14:28

Bonjour,

Je me permet un petit message. Non pas pour apporté une amélioration au tuto, mais je me pose des questions.

Voilà, je commence sérieusement a m’attaquer aux RTC (DS3231). Et je vois dans le code 2 fonctions mais je ne sais pas a quoi servent t'elle ? Sont t'elle utile pour le bon fonctionnement du reste ?

Il s'agit des fonctions
Source du message unsigned char RTC_Read(unsigned char addr)

et
Source du message void RTC_Write(unsigned char addr, unsigned char value)


Car ses fonctions ne sont pas rappeler plus tard dans le code. oops Donc a quoi servent t'elles ?
Désolé, j’essaie de bien comprendre le code pour partir du bon pied dans le fonctionnement des RTC.

Ps: si ma question nécessite un nouveau topic, merci de me le faire savoir.






@++
En fait tout est une question de BIT ? :-D


Retourner vers « Langage C »

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 1 invité