Home › Forum › Microcontrôleurs & microprocesseurs › Problème initialisation PCF8583

Forum

Veuillez vous identifier avant de répondre ou pour vous abonner à cette discussion

Sujet: Problème initialisation PCF8583

Auteur Message

Pascal37

36 messages

De passage
De passage

Read post 16-02-2011 21:25

Bonsoir,

Je pilote via un ATmega8 un bus I2C et une horloge PCF8583 qui me déclenche une interruption quand l’alarme programmée est active et cela me fait coller un relais ; cette partie fonctionne correctement,

Je rencontre un problème lors de la première mise sous tension de mon montage car le PCF8583, lorsqu’il n’est pas initialisé (neuf), déclenche sur sa sortie une interruption à 1Hz qui vient donc déclencher mon interruption en permanence…

Mon idée est : au démarrage dévalider l’interruption ensuite faire une lecture du registre mémoire « 00 » sur le bit 2 qui doit être a zéro si j’ai bien compris le fonctionnement (PCF8583 non initialisé)
, mais voila je n’arrive pas à lire ce registre !
Je joins une partie de mon code, la valeur qui m’est retournée est toujours « FF », j’ai fait le test avec un PCF8583 programmé et avec un non initialisé.

IL reste bien sûr la solution de faire une « fenêtre » de lecture sur mon entrée d’interruption sur quelques secondes et de voir si le PCF8583 est initialisé mais je trouve cette méthode moins propre…

C’est un peux long à lire, mais un problème bien formulé aide à trouver la solution...
Merci pour votre aide.
A+
Pascal


'**********************
'Lecture du Registre
'**********************

Call Gettime()
Call Gettime_alarm()

Control_status = 0
I2cstart 'generate start
I2cwbyte &HA0 'write address
I2cwbyte 0 'select control register
I2crbyte Control_status , Nack 'set year and day bit for masking,8 par defaut,4validation alarm
I2cstop

Print "Registre controle"
Print Hex(control_status)

Control_alarm = 0
I2cstart 'generate start
I2cwbyte &HA0 'write address
I2cwbyte 8 'select control register
I2crbyte Control_alarm , Nack 'set year and day bit for masking,8 par defaut,4validation alarm
I2cstop

Print "Registre alarme"
Print Hex(control_alarm)


Enable Int0
Enable Interrupts
On Int0 Int0_isr

Modifié par Pascal37 le 16-02-2011 21:36

Modifié par Pascal37 le 16-02-2011 21:37

jjm

3 messages

De passage
De passage

Read post 17-02-2011 10:07

L'adresse I2C pour la lecture du PCF8583 est 0xA1.
Il faut procéder en deux étapes pour lire un registre :

- D'abord sélectionner le registre (0xA0 , ecr. num. du registre)
- Lire le contenu du registre (0xA1, lecture)

D'aprés un extrait de l'AN#11 de Bascom/AVR , je suppose qu'il faudrait faire :

I2cstart 'start
I2cwbyte &HA0 'PCF8583
I2cwbyte 0 'control
I2cstart 'start
I2cwbyte &HA1 'PCF8583 en lecture
I2crbyte valeur , Nack 'lecture contenu registre
I2cstop 'stop

En espérant avoir aidé,

JJ

gregory_e

1 message

De passage
De passage

Read post 17-02-2011 11:15

Ce programme pourra peut-être vous venir en aide :

'-----------------------------------------------------------------------------
' © 2009 Grégory Ester / www.AdeleK.fr
'-----------------------------------------------------------------------------
' Nom Du Programme : 19_EXERCICE5_POUR_ALLER_PLUS_LOIN_PCF8583.bas
' Date : 2009
' Dernière Modification :
' Nom de la carte utilisée : Atm18 + Extended Card
'-----------------------------------------------------------------------------
' Titre : Configuration et Affichage de Date/Mois - HH:MM:SS - Jour - Variable année bissextile
' Description du fonctionnement :
'
' - Message d'accueil(WORKSHOP 2009/EXTENDED CARD/PCF8583 TEST2)
' - Affichage sur LCD :
' Aujourd'hui : DD/MM
' Il est : HH:MM:SS
' Jour : Jour_de_la_semaine
' ANNEE BISSEXTILE +n
'
' n = 0 : année en cours --> bissextile
' n = 1 : année en cours --> bissextile + 1 an
' n = 2 : année en cours --> bissextile + 2 ans
' n = 3 : année en cours --> bissextile + 3 ans
' 2008 était bissextile
'
' Pour configurer l'heure, la date, le jour et la variable 'année bissextile', modifier les lignes suivantes :
' D_a = Makebcd(31) Or &B01000000 '00XXXXXX(année bissextile:00) +1an=01 +2ans=10 +3ans=11 (2009-->+1an)
' M_j = Makebcd(12) Or Jeudi 'jeudi du mois de décembre
' Call Settime(51 , 59 , 23 , D_a , M_j) 'secondes,minutes,heures,dates_an,mois_jour
' ---> Ce qui signifie : Jeudi 31 décembre, 23h 59mins 51secs (2009 : année bissextile +1an)
'
' puis recompiler et reprogrammer le µC
' Au démarrage suivant, appuyer sur le BP S1, la modification est effective
' dès que le message "MISE A L'HEURE OK" s'affiche.
' Les informations enregistrées dans le PCF8583 sont préservées lors d'une coupure
' secteur si la pile CR2032 3V est présente sur l'Extended Card.
'
' L'adresse est configurable grâce au cavalier suivant, ici :
' - PCF8583P(U1) : JP1 ON --> $A0
'-----------------------------------------------------------------------------
' Ports utilisés et nature des signaux :
' Lcd : PB1 - Clock , PB2 - Data
' I2C : PC2 - Scl / PB0 - Sda 'I2C Soft
' Power + 5v / Gnd : USB --> connecteur K5
'-----------------------------------------------------------------------------

'----------------------- DIRECTIVES DE COMPILATION ---------------------------
$regfile = "M88def.dat" 'Mega88 definition
$crystal = 16000000 'Quartz frequency 16MHz
$baud = 9600
$hwstack = 32 'Hardware stack
$swstack = 16 'Software stack
$framesize = 40 'Frame space

'----------------------- DECLARATIONS ET PARAMETRES --------------------------
'----------------- LIBRAIRIES
'----------------- VARIABLES
Dim Rs As Byte , Mask As Byte , N As Byte , I As Byte , J As Byte , Y As Byte
Dim D As Byte , State As Byte , Low_nibble As Byte , High_nibble As Byte
Dim Text As String * 20 , Char As String * 1
'---
Dim Pcf(5) As Byte
Dim K As Byte , Octet As Byte
Dim Var_str2_lcd As String * 2
Dim M_j As Byte , D_a As Byte
Dim Jours As String * 8
Dim An As String * 20
'----------------- CONSTANTES ET ALIAS
Pe_clock Alias Portb.1 '2-wire_display clock
Pe_data Alias Portb.2 '2-wire_display data
S1 Alias Pinc.3
'---
Const Write_8583 = &HA0 'l'adresse est à changer une seule fois ici
Const Read_8583 = Write_8583 + 1
Const Dimanche = &H00 '000X XXXX
Const Lundi = &H20 '001X XXXX
Const Mardi = &H40 '010X XXXX
Const Mercredi = &H60 '011X XXXX
Const Jeudi = &H80 '100X XXXX
Const Vendredi = &HA0 '101X XXXX
Const Samedi = &HC0 '110X XXXX
'----------------- PROCEDURES ET FONCTIONS
Declare Sub Do1clock
Declare Sub Lcd_write_nibble(byval D As Byte )
Declare Sub Lcd_write_byte(byval D As Byte )
Declare Sub Lcd_pos(byval X As Byte , Byval Z As Byte )
Declare Sub Lcd_text(byval Text As String )
Declare Sub Lcd_init
Declare Sub Lcd_clear
'---
Declare Sub Message_accueil
'---
Declare Sub Settime(byval Secondes As Byte , Byval Minutes As Byte , Byval Heures As Byte , Byval Dates_an As Byte , Byval Mois_jours As Byte)
Declare Sub Gettime()
'----------------- DATA DIRECTION REGISTER (SORTIES)
Config Pe_clock = Output
Config Pe_data = Output
'----------------- DATA DIRECTION REGISTER (ENTREES) ET PULLUP
Config S1 = Input
'----------------- INITIALISATION DES PERIPHERIQUES : LCD CAN RC5 KEYPAD…
Config Scl = Portc.2 'I2C : Clock
Config Sda = Portb.0 'I2C : Data
'----------------- DEFINITION DES ROUTINES D'INTERRUPTION
'----------------- CONFIGURATION DES ROUTINES D'INTERRUPTION
'----------------- CONFIGURATION DES TIMERS
'----------------- AUTORISATION DES INTERRUPTIONS
'----------------- PARAMETRES INHERENTS AU PROGRAMME -------------------------
Lcd_init
'----------------- PROGRAMME PRINCIPAL ---------------------------------------
If S1 = 0 Then
D_a = Makebcd(31) Or &B01000000 '00XXXXXX(année bissextile:00) +1an=01 +2ans=10 +3ans=11 (2009-->+1an)
M_j = Makebcd(12) Or Jeudi 'jeudi du mois de décembre
Call Settime(51 , 59 , 23 , D_a , M_j) 'secondes,minutes,heures,dates_an,mois_jour
Lcd_clear
Lcd_pos 1 , 1
Lcd_text " MISE A L'HEURE OK "
Wait 2
End If
Lcd_clear 'LCD clear
Message_accueil 'message d'accueil
Waitms 2000

Lcd_clear
Lcd_pos 1 , 1
Lcd_text "Aujourd'hui : "
Lcd_pos 1 , 2
Lcd_text "Il est : "
Lcd_pos 1 , 3
Lcd_text "Jour : "
Do
Call Gettime 'récupération des valeurs
Lcd_pos 15 , 1 'Affichage DATE/MOIS/AN/JOUR...
Octet = Pcf(4) And &B00111111 'DATE
Var_str2_lcd = Hex(octet) 'pcf8583 compte en BCD
Lcd_text Var_str2_lcd
Lcd_text "/"
Octet = Pcf(5) And &B00011111 'MOIS
Var_str2_lcd = Hex(octet)
Lcd_text Var_str2_lcd

Octet = Pcf(4) And &B11000000 'AN
Shift Octet , Right , 6
Select Case Octet
Case 0 : An = "ANNEE BISSEXTILE "
Case 1 : An = "ANNEE BISSEXTILE +1 "
Case 2 : An = "ANNEE BISSEXTILE +2 "
Case 3 : An = "ANNEE BISSEXTILE +3 "
End Select
Lcd_pos 1 , 4
Lcd_text An

Octet = Pcf(5) And &B11100000 'JOUR
Select Case Octet
Case Dimanche : Jours = "Dimanche"
Case Lundi : Jours = "Lundi"
Case Mardi : Jours = "Mardi"
Case Mercredi : Jours = "Mercredi"
Case Jeudi : Jours = "Jeudi"
Case Vendredi : Jours = "Vendredi"
Case Samedi : Jours = "Samedi"
End Select
Lcd_pos 8 , 3
Lcd_text Jours

Lcd_pos 10 , 2 'Affichage HH:MM:SS...
Var_str2_lcd = Hex(pcf(3))
Lcd_text Var_str2_lcd
Lcd_text ":"
Var_str2_lcd = Hex(pcf(2))
Lcd_text Var_str2_lcd
Lcd_text ":"
Var_str2_lcd = Hex(pcf(1))
Lcd_text Var_str2_lcd '...sur LCD

Wait 1
Loop
End

'----------------- ROUTINES D'INTERRUPTIONS ----------------------------------
'----------------- FONCTIONS -------------------------------------------------
'----------------- PROCEDURES ------------------------------------------------
Sub Do1clock
Waitus 2
Pe_clock = 1
Waitus 4
Pe_clock = 0
Waitus 2
End Sub
'-------------------------------
Sub Lcd_write_nibble(byval D As Byte )
Pe_clock = 0
Pe_data = 0
'Clear all stages of shift register
For N = 1 To 8
Do1clock
Next N
'Set E-Level for at Q7
Pe_data = 1
Do1clock
'Set level for RS at Q6
Pe_data = Rs
Do1clock
'Shift in 4 bits
Mask = 8
For N = 1 To 4
State = D And Mask
If State = 0 Then
Pe_data = 0
Else
Pe_data = 1
End If
'Clock in data with rising edge
Do1clock
Shift Mask , Right
Next N
'Shift in 0-Bit
Pe_data = 0
Do1clock
'Set E
Pe_data = 1
Waitus 4
Pe_data = 0
Waitus 4
End Sub
'-------------------------------
Sub Lcd_write_byte(byval D As Byte )
Low_nibble = D And 15
High_nibble = D / 16
Lcd_write_nibble High_nibble
Lcd_write_nibble Low_nibble
End Sub
'-------------------------------
Sub Lcd_init
Rs = 0 'command mode
Waitms 100 'Delay for power up time
Lcd_write_nibble &H03
Waitms 10
Lcd_write_nibble &H03
Waitms 10
Lcd_write_nibble &H03
Waitms 10
Lcd_write_nibble &H02
Waitms 10
Lcd_write_byte &H28
Waitms 10
Lcd_write_byte &H0C
Waitms 10
Lcd_write_byte &H01
Waitms 10
Lcd_write_byte &B00101100
Waitms 10
Lcd_write_byte &B00001001
Waitms 10
Lcd_write_byte &B00101000
Waitms 10
Lcd_write_byte &B00000110
Waitms 10
Lcd_write_byte &B00001100
Waitms 20
End Sub
'-------------------------------
Sub Lcd_pos(byval X As Byte , Byval Z As Byte )
Rs = 0 'write CTRL
D = 127 + X
If Z = 1 Then D = D + 0 '127 7F/80
If Z = 2 Then D = D + 64 '191 BF/C0
If Z = 3 Then D = D + 20 '147 93/94
If Z = 4 Then D = D + 84 '212 D3/D4
Lcd_write_byte D
End Sub
'-------------------------------
Sub Lcd_text(byval Text As String )
Rs = 1 'data mode
J = Len(text)
For I = 1 To J
Char = Mid(text , I , 1 )
D = Asc(char)
Lcd_write_byte D
Next I
End Sub
'-------------------------------
Sub Lcd_clear
Rs = 0
D = 1
Lcd_write_byte D
Waitms 20
End Sub
'---------------------- message d'accueil
Sub Message_accueil
Lcd_pos 1 , 1
Lcd_text " * WORKSHOP 2009 *"
Lcd_pos 1 , 2
Lcd_text " * EXTENDED CARD *"
Lcd_pos 1 , 3
Lcd_text " * PCF8583 TEST2 *"
Lcd_pos 1 , 4
Lcd_text " *******************"
End Sub
'-------------------------------
Sub Settime(secondes As Byte , Minutes As Byte , Heures As Byte , Dates_an As Byte , Mois_jours As Byte)
Pcf(1) = Makebcd(secondes)
Pcf(2) = Makebcd(minutes)
Pcf(3) = Makebcd(heures)
Pcf(4) = Dates_an 'déjà formaté
Pcf(5) = Mois_jours 'déjà formaté
I2cstart 'datasheet p16
I2cwbyte Write_8583
I2cwbyte 0 'sélection du registre control/status en $00
I2cwbyte &H00 'read locations 05 to 06 unmasked :
'bit 6 et 7 registre $05 unmasqued
'bit 5,6,7 registre $06 unmasqued
I2cstart 'Start
I2cwbyte Write_8583 'Adresse + Write
I2cwbyte 2 'Sélection du registre 'Secondes'
For K = 1 To 5
I2cwbyte Pcf(k) 'écriture de 5 octets (auto increment cf datasheet)
Next K

I2cstop
End Sub
'-------------------------------
Sub Gettime()
I2cstart
I2cwbyte Write_8583 'Adresse + Write
I2cwbyte 2 'sélection du registre 'Secondes'
I2cstart 'Start
I2cwbyte Read_8583 'Adresse + Read
For K = 1 To 4 'lecture donnée (auto increment cf datasheet)
I2crbyte Pcf(k) , Ack 'Ack envoyé par Atmega88
Next K
I2crbyte Pcf(5) , Nack 'dernier octet reçu suivi de Nack (fin réception)
I2cstop
End Sub


Numériquement,
Grégory Ester

Attachment19_EXERCICE5_POUR_ALLER_PLUS_LOIN_PCF8583.bas

YMasquel

2503 messages

Expert
Expert

Read post 17-02-2011 13:05

Bonjour Pascal,

C'est bien les exemples mais un brin d'explications serait une approche qui fixerait mieux les choses.

En protocole I²C chaque envoi d'adresse qui précède une lecture ou une écriture d'un ou plusieurs caractères doit être précédé d'un START (parfois appelé REPEATED START). C'est pour prévenir le composant SLAVE qu'il doit prendre la donnée comme une adresse et non comme un simple caractère.

Amicalement, Yves.

Pascal37

36 messages

De passage
De passage

Read post 17-02-2011 22:45

Bonsoir,

Merci à tous pour votre aide efficace …
Je compte me replonger dans le code la semaine prochaine, ayant des obligations familiales ce week-end…
Pour Yves, je n’ai pas mis le programme en entier mais j’ai respecté les conditions de start.
Mais il est bon, comme tu le soulignes, de préciser les détails du protocole I2C.
Je vous tiens au courant dans la semaine prochaine de l’avancée de mes tests.
Bon week-end
Amicalement
Pascal

YMasquel

2503 messages

Expert
Expert

Read post 18-02-2011 00:18

Bonjour Pascal,

En regardant le code :
I2cstart 'generate start
I2cwbyte &HA0 'write address
I2cwbyte 0 'select control register
I2crbyte Control_status , Nack 'set year and day bit for masking,8 par defaut,4validation alarm
I2cstop


il manquerait un start (Repeated start) et l'adressage du composant en le prévenant que tu va effectuer maintenant une lecture entre l'émission de l'adresse du registre de contrôle et sa lecture proprement dite.
Tu dois :
- émettre un START pour prendre le contrôle;
- envoyer l'adresse du composant avec le bit WRITE;
- envoyer un ACK (par défaut dans la fonction "I2cwbyte");
- envoyer la donnée qui est l'adresse du registre (un emplacement mémoire) sur lequel tu veux agir;
- envoyer un ACK (par défaut dans la fonction "I2cwbyte");
- envoyer un REPEATED START car tu vas changer de sens de communication;
- envoyer à nouveau l'adresse du composant mais avec le bit READ;
- envoyer un ACK (par défaut dans la fonction "I2crbyte");
- faire la lecture du caractère par envoi des signaux d'horloge;
- envoyer un NACK pour signifier que tu ne veux plus rien (en spécifiant ce paramètre dans la fonction "I2crbyte".

Le code devient :
I2cstart 'Initialiser le protocole (occuper le BUS)
I2cwbyte &HA0 'Adresse du composant + WRITE
I2cwbyte 0 'Le traitement se fera sur le registre de contrôle
I2cstart 'Envoyer un repeated start (changement de sens à suivre)
I2cwbyte &HA1 'Adresse du composant + READ (à effectuer)
I2crbyte Control_status , Nack 'la fonction appelée récupère les données et informe que cela lui suffit
I2cstop 'Libérer le BUS

Le meilleur endroit pour bien suivre le protocole I²C se situe dans les fiches de caractéristiques des composants utilisant ce protocole chez MAXIM. Ses figures "I²C Transactions" sont vraiment très explicites.

Amicalement, Yves.

Pascal37

36 messages

De passage
De passage

Read post 18-02-2011 16:33

Bonjour Yves,

Merci pour ce complément d’information très didactique, je pense que tu mis le doigt sur mon erreur !
Des que mon soft tourne je te tiens au courant.
Merci.
Bon week-end
Pascal

Pascal37

36 messages

De passage
De passage

Read post 25-02-2011 14:17

Bonjour a tous,

Mon programme fonctionne ! Effectivement l’erreur était dans l’incrémentation de mon registre pour la lecture…
Merci pour votre aide
@+
Pascal

Veuillez vous identifier avant de répondre ou pour vous abonner à cette discussion

Elektor 6/2012 en kiosque

Elektor-Hebdo gratuit !

Mon adresse électronique :

Unités de crédit Elektor

Nos blogs-ateliers