Logiciels > Programmation PIC > Bases > MP > Lecture / écriture sur bus I2C > PCF8583

Dernière mise à jour : 25/04/2010

Présentation

Les exemples décrits ici montrent comment utiliser l'horloge temps réel (RTC) PCF8583 avec un PIC18F2420, les deux étant intimement liés pr un bus I2C. Bien entendu le procédé peut être utilisé pour d'autres types de microcontrôleurs, moyennant adaptation. Il existe une autre horloge temps réel bien connue qui est le DS1307, le fonctionnement de ce composant n'est pas abordé ici mais il fonctionne de façon fort similaire à celle du PCF8583.

Qu'est-ce qu'une horloge temps réel ?

RTC = Real Time Clock = Horloge temps réel
Une horloge temps réel est un composant de type "oscillateur / base de temps" qui fonctionne de façon autonome, avec un quartz pour une bonne précision de la fréquence d'oscillation. Ce type de composant équipe entre autres les cartes mère des ordinateurs, et permet de disposer à tout instant (et sur requête) des informations Date et Heure. Si l'alimentation du composant est assurée lors des coupures secteur (avec une pile, un accu ou un condensateur de forte valeur), les informations sont conservées et continuent d'être régulièrement mises à jour. C'est grâce à ce genre de composant que votre PC conserve la bonne date et la bonne heure même si vous débranchez son cordon secteur pendant plusieurs jours... à condition bien sûr que la pile de sauvegarde (en général une CR2032) soit en bon état. Ce type de composant peut être utilisé ailleurs que dans un ordinateur, en fait dans tout système où la date et/ou l'heure sont utilisées. Par exemple dans un enregistreur d'évenements avec horodatage, ou encore dans un programmateur journalier. L'horloge temps réel PCF8583 dont il est question ici dispose d'une interface de type I2C, et le dialogue avec elle s'effectue grâce à un microcontrôleur utilisé en maître.

Electronique mise en oeuvre

L'exemple logiciel qui sera présenté un peu plus loin se base sur un circuit électronique simple, qui est le suivant.

pic_tuto_base_i2c_pcf8583_001a

Dans ce montage, le PIC 18F2420 récupère de façon cyclique les informations date et heure contenue dans le PCF8583, et les affiche sur un écran LCD alphanumérique.

Logiciel

Le code ci-dessous correspond au programme complet, qui permet de lire les informations contenues dans l'horloge temps réel, de les décoder (car elles ne sont pas utilisables telles quelles) et de les afficher sur l'écran LCD. Les lignes de code en gras sont celles qui ont un rapport direct avec la liaison I2C.

Remarque : dans ce code, il est fait usage de routines qui ne sont pas contenues dans les bibliothèques de MikroPascal, il s'agit des routines InitRtc et SetRTC. Ces deux routines sont extraites de la librairie PCF8583 de Dany, que vous pouvez trouver sur son site internet.

program electronique_pic_tuto_base_i2c_pcf8583;

var
seconds, minutes, hours: byte;
day, month, year: byte;
LCD_RS : sbit at LATA4_bit;
LCD_EN : sbit at LATA5_bit;
LCD_D4 : sbit at LATA0_bit;
LCD_D5 : sbit at LATA1_bit;
LCD_D6 : sbit at LATA2_bit;
LCD_D7 : sbit at LATA3_bit;
LCD_RS_Direction : sbit at TRISA4_bit;
LCD_EN_Direction : sbit at TRISA5_bit;
LCD_D4_Direction : sbit at TRISA0_bit;
LCD_D5_Direction : sbit at TRISA1_bit;
LCD_D6_Direction : sbit at TRISA2_bit;
LCD_D7_Direction : sbit at TRISA3_bit;

const
cAddrPCF8583W = $A0; // or $A2
cAddrPCF8583R = $A1; // or $A3

procedure Main_Init;
begin
CMCON := $07; // turn off comparators
ADCON1 := ADCON1 or $0F; // turn off analog inputs
TRISA := $00;
TRISB := $FF;
// I2C comm init
I2C1_Init(100000);
// LCD init
Lcd_Init; // Initialize LCD
Lcd_Cmd(_LCD_CLEAR); // Clear LCD display
Lcd_Cmd(_LCD_CURSOR_OFF); // Turn cursor off
LCD_Out(1,1,'Date:'); // output not modified text on LCD
LCD_Chr(1,9,':');
LCD_Chr(1,12,':');
LCD_Out(2,1,'Time:');
LCD_Chr(2,9,':');
LCD_Chr(2,12,':');
LCD_Out(1,13,'200');
end;

procedure PCF8583_Init;
begin
// set time to 12:00:00
hours := Dec2BCD(12);
minutes := Dec2BCD(00);
seconds := Dec2BCD(00);
// set date to 18/04/2010
day := Dec2BCD(18);
month := Dec2BCD(04);
year := Dec2BCD(10);
// Dany's procs
InitRtc($A0);
SetRTC(hours, minutes, seconds, day, month, year);
end;

procedure PCF8583_Read;
begin
I2C1_Start; // start signal
I2C1_Wr($A0); // Address PCF8583, see PCF8583 datasheet
I2C1_Wr(2); // Start from address 2
I2C1_Repeated_Start; // repeated start signal
I2C1_Wr($A1); // Address PCF8583 for reading R/W=1
seconds := I2C1_Rd(1); // Read seconds byte
minutes := I2C1_Rd(1); // Read minutes byte
hours := I2C1_Rd(1); // Read hours byte
day := I2C1_Rd(1); // Read year/day byte
month := I2C1_Rd(0); // Read weekday/month byte
I2C1_Stop; // Issue stop signal
end;

procedure PCF8583_Decode;
begin
seconds := ((seconds and 0xF0) shr 4) * 10 + (seconds and 0x0F);
minutes := ((minutes and 0xF0) shr 4) * 10 + (minutes and 0x0F);
hours := ((hours and 0xF0) shr 4) * 10 + (hours and 0x0F);
// standard year read proc
//year := (day and 0xC0) shr 6;
// corrected year read proc (Dany's proc)
year := Bcd2Dec(ReadRtcYear);
day := ((day and 0x30) shr 4) * 10 + (day and 0x0F);
month := ((month and 0x10) shr 4) * 10 + (month and 0x0F);
end;

procedure Time_Display;
var
day_t, day_o, month_t, month_o, year_t, year_o : char;
sec_t, sec_o, min_t, min_o, hour_t, hour_o : char;
begin
// convert numbers to char
day_t := (day / 10) + 48;
day_o := (day mod 10) + 48;
month_t := (month / 10) + 48;
month_o := (month mod 10) + 48;
// standard year read proc
//year_t := (year / 10) + 48 + 8;
// corrected year read proc (Dany's proc)
year_t := (year / 10) + 48;
year_o := (year mod 10) + 48;
sec_t := (seconds / 10) + 48;
sec_o := (seconds mod 10) + 48;
min_t := (minutes / 10) + 48;
min_o := (minutes mod 10) + 48;
hour_t := (hours / 10) + 48;
hour_o := (hours mod 10) + 48;
// display on LCD, char by char
Lcd_Chr(1, 7, day_t);
Lcd_Chr(1, 8, day_o);
Lcd_Chr(1, 10, month_t);
Lcd_Chr(1, 11, month_o);
// standard year read proc
//Lcd_Chr(1, 16, year_o);
// corrected year read proc (Dany's proc)
Lcd_Chr(1, 15, year_t);
Lcd_Chr(1, 16, year_o);
Lcd_Chr(2, 7, hour_t);
Lcd_Chr(2, 8, hour_o);
Lcd_Chr(2, 10, min_t);
Lcd_Chr(2, 11, min_o);
Lcd_Chr(2, 13, sec_t);
Lcd_Chr(2, 14, sec_o);
end;

//----------------- Main procedure
begin
Delay_ms(500);
Main_Init;
Delay_ms(500);
PCF8583_Init; // set date and time
while true do // Endless loop
begin
PCF8583_Read; // Read time from RTC (PCF8583)
PCF8583_Decode; // Decode (format) date and time
Time_Display; // Display on LCD
delay_ms(100);
end;
end.
end.


Descriptif du logiciel

Procédure Main_Init
Cette routine d'initialisation générale, qui est appelée une seule fois au moment de la mise sous tension du PIC, permet de définir l'orientation des broches des ports A et B, grâce aux lignes TRISA et TRISB. La ligne CMCON = 7 permet de désactiver le fonctionnement des comparateurs du PIC (ce n'est pas obligatoire ici, mais il faut y penser si vous voulez pouvoir exploiter toutes les lignes du ports A, et notament les lignes RA3 et RA4). La ligne de code qui nous intéresse le plus ici est sans doute celle où apparaît la procédure I2C1_Init(100000), qui permet de démarrer dans de bonnes conditions le pilotage du bus I2C.

Procédure PCF8583_Read
C'est dans cette procédure que l'on trouve les lignes de code permettant de récupérer les informations date et jour dans le PCF8583, via la liaison I2C. Ces données sont stockées de façon un peu bizarre, il faut bien le reconnaitre. Leur usage en brut est impossible, il faut les décoder pour connaitre les valeurs en clair.

Procédure PCF8583_Decode
On trouve ici tout ce qu'il faut faire pour rendre digestes les informations brutes récupérées du PCF8583, et pour pouvoir les afficher en clair.

Programme principal
Dans le programme principal se déroule des actions qui se répètent indéfiniment, grace à l'emploi d'une boucle infinie (qui ne s'arrête jamais ca aucune condition n'impose son arrêt). Ici, ces actions répétées sont les suivantes :
- lecture des données contenues dans le PCF8583, grâce à la procédure PCF8583_Read.
- décodage des données lues dans le PCF8583, grâce à la procédure PCF8583_Decode.
- affichage de la date et de l'heure en clair, grâce à la procédure Time_Display.