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
.
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.
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.
L'exemple logiciel qui sera présenté un peu plus loin se base sur un circuit électronique simple, qui est le suivant.
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.
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.
: 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
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.
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.
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.
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.
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.