Forum: Mikrocontroller und Digitale Elektronik PCF8583


von Roland (Gast)


Lesenswert?

Hallo!
wer hat schon mal erfolgreich den Uhrenchip PCF8583 vollständig
programmiert in BASCOM ? d.h. auch mit Datum?
Welcher Tag ist der "Tag 0"? Sonntag oder Montag?
Wie wird das Schaltjahr gesetzt?
Bei mir kommt nach dem 28.02. immer der 29.02 und 30.02!
Irgendwo hab ich sicherlich irgendwo etwas übersehen!
Hat evtl jemand ein Programmlisting greifbar?
Bislang habe ich nur Beispiele gefunden nur mit Uhrzeit also ohne
Datum.
Wäre für jeden Tipp dankbar!
Dank im voraus! Roland.

von Michael (Gast)


Lesenswert?

Hallo Roland,

ich habe vor längerer Zeit 'mal mit dem PCF8583 rumgespielt.
Leider kann ich Dir nicht sagen wie sich die RTC im Februar verhält.

Nachfolgend mein Programmcode.

'
************************************************************************ 
******
' Hardwarebeschreibung
' Hardware STK500
' LCD HD44870-kompatibel
' LCD D7..D4 = P1.7..1.4, P1.3=RS, P3.4 = Enable (Einstellung
Optionen/LCD)
' I2C-Bus RTC Phillips PCF8583P
' I2C-Bus EEPROM 24C64 (
' I2C-Bus: SDA = PortC.6, SCL = PortC.7

'
************************************************************************ 
******
' Konfiguration
$regfile = "8515def.dat"
$crystal = 3690000
$baud = 9600
Config Scl = Portc.7                                        '
I2C-Takt
Config Sda = Portc.6                                        '
I2C-Daten

CONFIG LCDPIN = PIN , DB4 = PORTA.4 , DB5 = PORTA.5 , DB6 = PORTA.6 ,
DB7 = PORTA.7 , E = PORTA.3 , RS = PORTA.2
Config LCD = 16 * 2

Config TIMER0 = timer , PRESCALE = 1024                     ' Timer0
als Timer, Vorteiler=1024

'
************************************************************************ 
******
' Variablendeklaration
Dim ss As Byte , mm As Byte , hh As Byte , day As Byte , month As Byte
Dim Wm As Byte , Yd As Byte
Dim sDatumZeit as String * 16
Dim sStatus as string * 16
'
************************************************************************ 
******
' Konstantendeklaration
Const Rtc_w = &HA2                                          '
RTC-Schreibadresse
Const Rtc_r = &HA3                                          '
RTC-Leseadresse

'
************************************************************************ 
******
' Subroutinendeklaration
' Setzen Uhrzeit/Datum
Declare Sub Settime(ss As Byte , mm As Byte , hh As Byte , day As Byte
, month As Byte)
' Auslesen Uhrzeit/datum
Declare Sub Gettime

'
************************************************************************ 
******
' Hauptprogramm
' Initialisierung
DDRB = &B11111111                                           ' PortB
Ausgänge
PortB = 255                                                 ' Ausgänge
auf High

DDRD = &B00000000                                           ' PortD
Eingänge
PortD = &B11111111                                          ' Pull-Up
Widerstände

month = 1                                                   '
Anfangsdatum
day = 1
hh = 23
mm = 59
ss = 22
Call Settime(ss , mm , hh , day , month)                    ' RTC
setzen

On TIMER0 Timer0_ISR                                        ' bei
Timer0-Interrupt

Enable Interrupts
Enable TIMER0                                               ' Freigabe
Timerinterrupt

CLS
LCD "Start"
wait 2

Do                                                          '
Endlosschleife
   Nop
Loop

End                                                         ' Ende
Programm

'
************************************************************************ 
******
' Subroutinen
' Auslesen Uhrzeit/datum
Sub Gettime

    I2cstart                                                ' Start
    I2cwbyte Rtc_w                                          '
Write-addresse PCF8583
    I2cwbyte 2                                              ' select
second register
    I2cstart                                                ' generate
repeated start
    I2cwbyte Rtc_r                                          ' write
address for reading
    I2crbyte ss , Ack                                       ' read
seconds
    I2crbyte mm , Ack                                       ' read
minuts
    I2crbyte hh , Ack                                       ' read
hours
'    I2crbyte Yd , Ack                                       ' read
year and days
'    I2crbyte Wm , Nack                                      ' read
weekday and month
    I2crbyte Day , Ack                                      ' read
year and days
    I2crbyte Month , Nack                                   ' read
weekday and month
   I2cstop                                                  ' generate
stop

End Sub

' Setzen Uhrzeit/Datum
Sub Settime(ss As Byte , mm As Byte , hh As Byte , day As Byte , month
As Byte)

    ' Werte zu BCD konvertieren
    ss = Makebcd(ss)                                        ' seconds
    mm = Makebcd(mm)                                        ' minuts
    hh = Makebcd(hh)                                        ' hours
    day = Makebcd(day)                                      ' days
    month = Makebcd(month)                                  ' months

    I2cstart                                                ' generate
start
    I2cwbyte Rtc_w                                          ' write
address
    I2cwbyte 0                                              ' select
control register
    I2cwbyte 8                                              ' set year
and day bit for masking
    I2cstop                                                 ' generate
stop

    I2cstart                                                ' generate
start
    I2cwbyte Rtc_w                                          ' write
mode
    I2cwbyte 2                                              ' select
seconds Register
    I2cwbyte ss                                             ' write
seconds
    I2cwbyte mm                                             ' write
minuts
    I2cwbyte hh
    I2cwbyte day                                            ' write
days
    I2cwbyte month
    I2cstop

End Sub

'
************************************************************************ 
******
' Interruptbehandlung
Timer0_ISR:                                                 '
Timer-Interruptroutine
   Call Gettime
   PortB = ss                                               ' Sekunden
an PortB ausgeben
   toggle PortB.7
   sDatumZeit = BCD(Day) + "." + BCD(month) + " - " + bcd(hh) +
":" + bcd(mm) + ":" + bcd(ss)
   Locate 1 , 1
   lcd sDatumZeit
   'locate 1 , 1
Return

von Marcus M. (Gast)


Lesenswert?

Hallo Roland,

mit BASCOM kann ich nciht dienen.
Aber zu der Schaltjahrproblematik folgendes:
Der Chip zählt immer bis zum 29.2., sollange kein Flag gelöscht oder
gesetzt ist. Weiß aber im Moment nicht welches - kein Datenblatt zur
Hand - Du mußt dich aber um den 29.2. selber kümmern. Einen Tag pro
Jahr selbst managen ist doch vertretbar oder?

Gruß Marcus

von Sven (Gast)


Lesenswert?

Wenn Du auf den Alarm-Interupt nicht angewiesen bist, kann ich den
DS1307 von MAXIM/Dallas empfehlen. Hat 100-Jahres-Kalender mit
auto-Schaltjahr, nicht nur 3 Jahre wie der 8583, ist mit Batterie bis
10 Jahre pufferbar.

Sven

von Roland (Gast)


Lesenswert?

Michael:
danke für Dein input!
ich bin der Sache nachgegangen:
- also das "Schaltjahrproblem" existiert m.e. auch in Dein Programm.
- auch die "weekdays" und "Jahreszahl" klappen nicht so recht.
Du hast auch sicherheitshalber die zwei Stellen auskommentiert.
Vermutlich hast Du ähnliche Probleme festgestellt wie ich ??
aber einige "neue features" aus Deinem Listing habe ich mittlerweile
übernommen.

Sven:
danke für den Tipp mit dem DS1307.
ich werde der Sache nachgehen.
scheint mir eine "bessere??" Lösung zu sein.

nochmals Dank an Euch beide,
Roland

von Ratber (Gast)


Lesenswert?

@Sven

>Wenn Du auf den Alarm-Interupt nicht angewiesen bist, kann ich den
>DS1307 von MAXIM/Dallas empfehlen.

Wieso sollte man beim 1307 auf den Alarm verzichten ?

Mit Pin 7 ist das überhaupt kein Akt.
Obendrein bietet er ne menge zusatzfunktionen ;)

von Thomas Fischl (Gast)


Lesenswert?

PCF8583 und Schaltjahr geht schon. Für das Jahr gibt es einen Zähler
(year) von 0 bis 3. Wenn year==0 und month==2, dann läuft date bis 29.
Wenn year!=0 und month==2, dann geht date nur bis 28. Normalerweise ist
alle vier Jahre ein Schaltjahr, so dass das passt. Um die Ausnahme
"Jahr durch 100 teilbar und nicht durch 400 teilbar" müsste man sich
selber kümmern. Das wäre wohl im Jahr 2100 der Fall ;-)

Setzen kann man year übrigens ganz einfach durch:
year = real_year % 4;
Also tatsächliches Jahr modulo 4.

Bei der PCF8583 ist noch einwenig unpraktisch, dass man das Jahr nicht
direkt auslesen kann, sondern nur immer diesen Wert von 0 bis 3
bekommt. Dafür gibt's aber auch einen Trick. Der PCF8583 hat ja ein
paar Bytes RAM. Dort legt man das tatsächliche Jahr ab (z.B. als
16Bit-Wert in 2 Bytes aufgeteilt) und einen Kontrollwert (yearcheck).
Beim Setzten der Uhrzeit macht man dann in etwa folgendes (nur
Pseudocode):
rtc.year = real_year % 4;
rtc.yearcheck = rtc.year;
rtc.real_year_low = (low) real_year;
rtc.real_year_high = (high) real_year;

Beim Auslesen:
real_year = rtc.real_year_high << 8 + rtc.real_year_low
if (rtc.year != rtc.yearcheck) then
  // Der Jahreszaehler hat sich veraendert
  real_year ++;
  rtc.yearcheck = rtc.year
  rtc.real_year_low = (low) real_year;
  rtc.real_year_high = (high) real_year;
fi

Setzt natürlich voraus, dass die Routine zum Auslesen mindestens einmal
im Jahr aufgerufen wird.

Thomas

von Roland (Gast)


Lesenswert?

Hallo Thomas,
Deine Info war schon mal interessant!
Demnach hast Du das Ding richtig zum laufen gebracht ?
Also was ich haben möchte, ist eine Anzeige:
1.Zeile = SS:MM:HH
2.Zeile = WT-TT-MO-JJ
wobei der Wochtentag (WT) nun mal zuerst eine Anzeige 0-6 seinkann.

Ich habe das ganze in bascom-Basic probiert,
aber der Ablauf muss immer derselbe sein.
Also:
zum Datum Eingeben:
Startbefehl
Schreibadresse
Selektiere Control/Statusregister
Schreibe "0" in das controlregister
 (dies um das Mask-Flag nicht zu setzen
  meistens wird hier Bit4 - maskflag- gesetzt
  dann wird aber lt. Datenblatt "read as zero if maskflag is set"
   der Wochentag (0-6) und das Jahr nicht ausgelesen)
 --- oder versteh ich das falsch?
Stoppbefehl
erneuter Startbefehl
schreibadresse
selektiere sekundenregister (location 2)
schreibe sekunden (0-60)
schreibe minuten (0-60)
schreibe stunden (0-24)
schreibe Tag (1-31)
schreibe Wochentag (0-6)
schreibe monat (1-12)
schreibe Jahr (00-99)
stoppbefehl

und zum Auslesen dann analog, aber mit der Leseadresse.

Vielleicht (sicherlich!) mach ich irgendwo einen Gedankenfehler!??
Wo mache ich etwas falsches?
Vielleicht hast Du den entscheidenden Tipp!??

Gruss, Roland

von Thomas Fischl (Gast)


Lesenswert?

Hallo Roland,
ja, bei uns lief der PCF8583 recht gut. Nun verwenden wir zwar auch den
DS1307, aber eigentlich nur wegen dem geringeren Stromverbrauch und
damit längeren Batterie-Pufferzeit.

Hmm.. also das Controlregister haben wir nie gesetzt, sondern einfach
den Resetwert belassen (der ist laut Datenblatt 0).
Die Reihenfolge der Befehle sollte ansonsten so passen. Was genau
funktioniert damit nicht?

Beim Wochentag kannst du dir übrigens selbst aussuchen, ob 0 Sonntag
oder Montag ist... der Echtzeituhr ist das egal.

Thomas

von karl (Gast)


Lesenswert?

freaks!!!

von Sapundzhiev, Iliya (Gast)


Lesenswert?

Hallo Leute,

Ihr habt euch alle mit PCF8583 beschäftigt. Kann jemand von euch mir
helfen? Bei mir funkzioniert alles richtig, nur die Sekunden laufen
einbischen schneller wie normalerweise. Wenn die Uhr aber nur offline
weitertaktet(es wird keine Zeitanzeige an der LCD ausgegeben)
funkzioniert er auch richtig!!! Weiß jemand woran es kiegen kann?

Grüsse,

Iliya

von Michael (Gast)


Lesenswert?

@Iliya

Das Thema gab es hier schon einmal vor ein paar Jahren.
Eine Ursache: zu kleiner Abblockkondensator; 10µF ist gut.
Zweite Möglichkeit: alter Baustein + zu häufiges Abfragen. Warte nach
dem Auslesen 50-100 ms, bevor erneut ausgelesen wird.

Wer sich die Schöpfungsgeschichte ansieht kommt nicht umhin, den Montag
als 1. und den Sonntag als letzten Wochentag zu verwenden :-)

von Sapundzhiev, Iliya (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Mihael,

Vielen Dank für die Hinweise. Nur hoffe ich dass du unter der
Abblockkondensator, der zwischen die Spannungsversorgung und die
"OSCi" Pin meinst. Ich habe so ein Kondensator, der ein Wert zwischen
2,5-5pF entsprechen soll(nach der Grundschaltung aller
PCF8583-Echtzeituhren), aber wegen fehlende pF-Kondensator habe ich
eine von 20 nF genommen. Ich werde vielleicht mit einem grösseren
Kondensator ausprobieren, da sonst fällt mir nichts ein.

Sonst ist die Uhr ganz neu. Ich sende auch mein Sourcecode(Die Uhr habe
ich vorher eingestellt) mit dem ich die Zeit auslese.

Also, für weitere Hinweise bin ich immer offen..

von Michael (Gast)


Lesenswert?

@Iliya

Der Abblockkondensator liegt zwischen Pin 4 und Pin 8; der Kondensator
an OSCI hat einen typ. Wert von 10-15pF. 20nF ist völlig ungeeignet !

von Sapundzhiev, Iliya (Gast)


Lesenswert?

Hallo Mihael,

also das Problem ist jetzt gelöst!!! Der Abblockkondensator, der
gefehlt hat, war die Ursache dafür. Ich danke dir für die Hinweise:-)
Du hast mir wirklich geholfen!!!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.