Forum: Mikrocontroller und Digitale Elektronik Uhr RV3029 programmieren


von Mauer (Gast)


Lesenswert?

HAllo,
ich brauche dringend Hilfe. Ich will die RV3029 Uhr benutzen, dazu 
brauche ich Ansätze.

Ich benutze bereits ein I2C Modul, mit einem EEprom, über den I2C 
ZUgriff, nun befindet sich auch eine RV3029 auf der Platine. fürs erste 
will ich die Uhrzeit setzen und lesen können und das Datum setzen und 
lesen können.

Ich hab gedacht, erst brauche ich folgende funktionen:
1
#define RV3029C2_W_SEC        0x08
2
#define RV3029C2_W_MINUTES    0x09
3
#define RV3029C2_W_HOURS      0x0A
4
#define RV3029C2_W_DATE       0x0B
5
#define RV3029C2_W_DAYS       0x0C
6
#define RV3029C2_W_MONTHS     0x0D
7
#define RV3029C2_W_YEARS      0x0E
8
#define RV3029C2_LEN          0x07
9
10
11
+/* eeprom data section */
12
#define RV3029C2_E2P_EEDATA1  0x28
13
#define RV3029C2_E2P_EEDATA2  0x29
14
15
16
struct time {
17
  int sec;
18
  int min;
19
  int hour;
20
}
21
                       //Adresse sec,min,hour //zugriff sec,min..  //Länge
22
unsigned int time_set(unsigned char Address, struct time *tm, unsigned int RV3029C2_LEN)
23
unsigned int time_read(unsigned char Address, struct time *tm, unsigned int RV3029C2_LEN)

ist der Ansatz schonmal in ordnung, am besten wärs wenn jemand mir 
zeigen könnte wie der zugriff aud die Uhr durchgeführt wird. Danke.

von Mauer (Gast)


Lesenswert?

Hallo
wollt mal fragen ob mir jemand zu meinem Problem helfen kann.
Ich habe zwar das schreiben von sek, min, und das lesen an den Adressen 
anliegenden Daten hinbekommen, jedoch solls ja so sein, dass man eine 
Startaddresse vorgibt z.B. die von der sek, dann pa minuten später erst, 
die Uhr ablesen tut und es muss dir richtige Uhrzeit angegeben werden,
wie genau konfiguriere ich die funktion read:

mein beispiel:
1
//base=base addresse, Address=Addressen der Uhrzeit, Data=Daten, Len=Länge der Daten-Bytes
2
3
nsigned int RV3029_read(unsigned long Base, unsigned short Address, unsigned char *Data, unsigned int Len) {
4
  int i = 0;
5
  int Retry = I2C_MASTER_MAX_RETRIES;
6
  unsigned long j;
7
8
   retry:
9
   
10
  // Start Transmission   
11
  I2C_StartTX(Base, RV3029_EEPROM_SLAVE_write, 0);
12
13
  I2C_Send(Base, Address);
14
 
15
  I2C_StartRX(Base, RV3029_EEPROM_SLAVE_read, Data);
16
  for (i = 1; i < Len; i++) {
17
    Data[i] = I2C_Read(Base);
18
  }
19
20
  UARTprintf("Uhrzeit: %02d:%02d:%02d\n", 0x08, 0x09, 0x0A);  // Send the stop condition
21
  I2C_Stop(Base);^
22
23
if (Retry--)
24
    goto retry;
25
  return i;

Ist das so in orsnung, oder kann man da noch was verbessern.danke.

von Yoghurtmonster (Gast)


Lesenswert?

Das go-Konstrukt kann durch eine einfache while-Schleife ersetzt 
werden...

von Yoghurtmonster (Gast)


Lesenswert?

s/go/goto

von Mauer (Gast)


Lesenswert?

Diese beiden Funktionen waren nur zum lesen und schreiben von rv_3029 
gedacht, der man addresse und daten zuweisen und auskesen kann.
Nun habe ich es erweitert mit den Funktionen um die Zeit zu sétzen und 
lesen.
Nur bin ich mir da nicht so sicher:
1
unsigned int RV3029_set_time() {
2
3
Set_time:
4
  I2C_StartTX(0, RV3029_EEPROM_SLAVE_write, 0);
5
  I2C_StartTX(0, RV3029_SEC, 0);
6
  I2C_StartTX(0, RV3029_MINUTES, 0);
7
  I2C_StartTX(0, RV3029_HOURS, 0);
8
  I2C_Stop();
9
10
}
11
12
unsigned int RV3029_get_time() {
13
14
Get_time:
15
  I2C_StartTX(0, RV3029_EEPROM_SLAVE_write, 0);
16
  I2C_StartTX(0, RV3029_EEPROM_SLAVE_read, 0);
17
18
  I2C_StartRX(0, RV3029_SEC, Data_sec);
19
  I2C_StartRX(0, RV3029_MINUTES, Data_min);
20
  I2C_StartRX(0, RV3029_HOURS, Data_hour);
21
  UARTprintf("Uhrzeit: %02d:%02d:%02d\n", Data_hour, Data_min, Data_sec);
22
  I2C_Stop();
23
24
25
}

Nur zum verständnis. beim setzen der Zeit muss ich doch erst die 
Startbedingung setzen also I2C start mit der write adresse des RV3029, 
hab ich gemacht aber muss dazu auch die Daten setzen oder, für die 
Addresse RV3029_SEC, 0x05 (5 sekunden) ... usw. Meine I2C Funktionen 
enthalten einmal die Base Adresse des I2c, die Adressen und Daten. Bei 
write hab die Daten noch auf 0 gesetzt.

So beim Get_time versteh ich nicht hab üerall gelesen wird erst 
I2C_Start mit der Write Address initialisiert und dann mit der Read 
Address, warum dass denn.

Soll bei Get_Time der PArameter Data übergeben werden oder nciht, bin da 
irgendwie durcheinander.

Wäre für jede Hilfe dankbar.
Soll

von Mauer (Gast)


Lesenswert?

Hallo,
kann mir keiner hier weiterhelfen.Danke.


Gruß

von Peter D. (peda)


Lesenswert?

Mauer schrieb:
> struct time {
>   int sec;
>   int min;
>   int hour;
> }

Das ist Verschwendung (eine Minute hat keine 65536 Sekunden usw.).
Nimm unsigned char oder besser uint8_t.

Viele RTC zählen im veralteten BCD-Format, dann muß man noch nach binär 
umwandeln (C rechnet intern nur binär).

Zeit lesen bzw. setzen muß man in einem I2C-Paket machen.
Sonst kann zwischen den Paketen ein Überlauf erfolgen und man hat halb 
neue und halb alte Daten.

Zu dem Code kann ich nichts sagen, da ich weder die RTC noch Deine 
unbekannte I2C-Lib kenne.

Ich erspare mir den ganzen Schrunz mit externer RTC. Ich zähle ganz 
einfach Zeit und Datum im Timerinterrupt.


Peter

von Mauer (Gast)


Lesenswert?

Danke für deine Hilfe hab, deine ersten beiden Punkte umgesetzt, was ich 
wissen will ist der Ablauf.

Wie ist denn genau die Reihenfolge, als erstes wird ja die slave+write 
Adresse mit dem I2C eingelesen:

i2c_write(slave_address+write

was genau wird danach eingelesen, die Adressen der Zeitparameter oder 
die Daten für die Zeitparameter,

Auf diesem Link Beitrag "Uhr mit RV-3029-C2" hat schonmal 
einer darüber gefragt, nur habe ich nicht ganz die Reihenfolge 
verstanden, wann werden die Addressen eingelesen wann die Daten und wann 
wird die Zeit gelesen, und muss ich die Reg 0 bbis 3 (control) auch 
einbeziehen.

von Mauer (Gast)


Lesenswert?

kurze erläuerung meines I2C Pakets:

I2C_StartTX(unsigned char Slave, unsigned char Data) = Sendet die 
Startkondition, die Slave_address und das erste Datenbyte
I2C_StartRX(unsigned char Slave, unsigned char *Data) = sendet 
Startkondition und Slave_address

I2C_Send(unsigned char Data) = sendet das Daten_byte
I2C_Read(unsigned long Base) = empfängt ein Datenbyte
I2C_Stop(unsigned long Base) = sendet die Stopkondition auf dem Bus


nun meine beiden funktionen sehen so aus, hoffe habe die richtige 
Reihenfolge der Aufrufungen der Funkionen eingehalten.
1
#define RV3029_EEPROM_SLAVE_write 0xAC
2
#define RV3029_EEPROM_SLAVE_read 0xAD
3
4
#define RV3029_SEC        0x08
5
#define RV3029_MINUTES    0x09
6
#define RV3029_HOURS      0x0A
7
8
unsigned long RV3029_set_time(unsigned long Base, unsigned char Data) {
9
 
10
11
  I2C_StartTX(Base, RV3029_EEPROM_SLAVE_write, 0);
12
 
13
  I2C_Send(Base, RV3029_SEC);
14
  I2C_Send(Base, 0x09);
15
  I2C_Send(Base, RV3029_MINUTES);
16
  I2C_Send(Base, 0x05);
17
  I2C_Send(Base, RV3029_HOURS);
18
  I2C_Send(Base, 0x02);
19
20
  
21
  
22
  I2C_Stop(Base);
23
24
}
25
26
unsigned long RV3029_get_time(unsigned long Base, unsigned char *Data) {
27
28
29
  I2C_StartTX(Base, RV3029_EEPROM_SLAVE_write, 0);
30
  I2C_Send(Base, RV3029_SEC);
31
  I2C_StartRX(Base, RV3029_EEPROM_SLAVE_read, Data);
32
33
  Data[0] = I2C_Read(Base);
34
  Data[1] = I2C_Read(Base);
35
  Data[2] = I2C_Read(Base);
36
37
  UARTprintf("Uhrzeit: %02d:%02d:%02d\n", Data[2], Data[1], Data[0]);
38
39
  I2C_Stop();

Ist das so in ordnung, muss nur noch bcd to binary funktion 
hinzufügen.danke

von Mauer (Gast)


Lesenswert?

Kann mir jemand sagen, ob die reihefolge, der Aufrufe der register 
richtig ist, oder habe ich da fehler drin.Danke.

von Gerhard G. (g_g)


Lesenswert?

Hallo,

hier findest du den Einstieg: 
Beitrag "Re: Uhr mit RV-3029-C2"

1. internen Takt im Control-Register aktivieren
2. Sende Daten zum Stellen der Uhr (Register)
3. Auslesen

Gruß xmega

von Mauer (Gast)


Lesenswert?

Muss ich da nicht erst die Write_adresse für die Uhr laden, dann den 
Takt aktivieren, danach die erste Adresse (sekunden) laden und danach 
die Daten für sek, min, und stunde eingeben, laut dem Datenblatt zählt 
er die Adressen ja selber hoch. Nochwas, hab den Beitrag schonmal vorher 
angeschaut den du gelinkt hast, wollt mal fragen, warum hat derjenige 
nicht die daten erst in bcd format umgewandelt, um in die uhr zu laden, 
die uhr kann doch nur das bcd format.Danke.

von Mauer (Gast)


Lesenswert?

Hallo,
wollt mal fragen, ist die Startkondition nicht die, dass die 
Write_address initialisiert wird, oder was genau beinhaltet die 
Startkondition des I2C Moduls.Vor der aktivierung des Taktes wird doch 
die Startkondition gesetzt. oder nicht.

von Gerhard G. (xmega)


Lesenswert?

Hallo,

bei dem Beispiel wird mit der I2C master library  von Peter Fleury
gearbeitet. Die enthält natürlich die einzelnen I2C-Befehle.

i2c_write(0x00);                       // Startaddresse
i2c_write(0xE9);                       // REG0
i2c_write(0x00);                       // REG1
i2c_stop();                            // Bus stop


Wenn du die Funktion i2c_write(0x00) z.B. aufdröselst, wirst du sehen, 
dass hier alle I2C-Standardbefehle angewandt werden. Das komplette 
Protokoll möchte ich hier nicht aufzählen.

Wenn du deine eigene Lib verwendest, musst du natürlich den richtigen 
Protokoll-Fluß beachten!

Ist jetzt dein Problem das I2C-Protokoll oder das Programmieren der RTC?

Stell das Problem BCD/HEX und umgekehrt mal in den Hintergrund, das ist 
dann, wenn dein Code mal funktioniert kein Problem.


Gruß xmega

von Mauer (Gast)


Lesenswert?

Ich denk mal ich habe bisher imm er noch nicht geschafft, die Uhr zu 
aktivieren, bei der Ausgabe, gibt das Programm mir für sekunde, minute 
und stunde den Wert 255 zurück. Ich weiß nicht was ich noch machen soll. 
Brauche dringend Tipps.

Mein Code:
1
typedef struct {
2
  uint8_t sec;
3
  uint8_t min;
4
  uint8_t hour;
5
  } MY_BUFFER;
6
7
static MY_BUFFER rtc;
8
9
unsigned long RV3029_set_time(unsigned long Base) {
10
11
  I2C_StartTX(Base, RV3029_EEPROM_SLAVE_write, 0);
12
  I2C_Send(Base, RV3029_CTRL);
13
  I2C_Send(Base, 0xE9);
14
  I2C_Send(Base, 0x00);
15
  I2C_Stop(Base);
16
17
  I2C_StartTX(Base, RV3029_EEPROM_SLAVE_write, 0);
18
  I2C_Send(Base, RV3029_SEC);
19
  I2C_Send(Base, 0x09);
20
  I2C_Send(Base, 0x05);
21
  I2C_Send(Base, 0x02);
22
  I2C_Stop(Base);
23
24
}
25
26
unsigned long RV3029_get_time(unsigned long Base) {
27
28
  unsigned char Data[3];
29
  I2C_StartTX(Base, RV3029_EEPROM_SLAVE_write, 0);
30
  I2C_Send(Base, RV3029_SEC);
31
  I2C_Stop(Base);
32
33
  I2C_StartRX(Base, RV3029_EEPROM_SLAVE_read, Data);
34
  rtc.sec = I2C_Read(Base);
35
  rtc.min = I2C_Read(Base);
36
  rtc.hour = I2C_Read(Base);
37
38
 UARTprintf("Uhrzeit: %02d:%02d:%02d\n", rtc.hour, rtc.min, rtc.sec);
39
40
  I2C_Stop();
41
}

von Peter D. (peda)


Lesenswert?

Mauer schrieb:
> unsigned long RV3029_set_time(unsigned long Base) {
Mauer schrieb:
> unsigned long RV3029_get_time(unsigned long Base) {

Wo ist der Returnwert dazu?
Du solltest die Compilermeldungen lesen, der meckert bei sowas.

Was ist Base?

Beim Lesen muß der Master ein ACK senden und nach dem letzten Byte ein 
NACK.


Peter

von Mauer (Gast)


Lesenswert?

Was für ein return Wert, im code von Peter Fleury gibt es doch auch 
keinen Rückgabewert in der Funktion.

Base ist die Base Adresse des I2C Bus.

Und wie genau wird ein Acknowledge und Nack gesendet . Kannst du mir das 
am Beispiel von Peter Fleur zeigen.

Habs zwar im Datenblatt vom RV3029 nachgelesen, aber nicht so richtig 
verstanden, wie ich dies zu setzen habe.

Gruß

von Peter D. (peda)


Lesenswert?

Mauer schrieb:
> Was für ein return Wert

Wenn Du eine Funktion als "unsigned long" definierst, dann mußt Du Dir 
doch dabei auch was gedacht haben.
Und der Compiler erwartet dann, daß an Ende ein "return irgendwas;" 
steht.

Mauer schrieb:
> Base ist die Base Adresse des I2C Bus.

D.h. also, Dein unbekannter MC hat mehrere I2C, die Deine unbekannte 
Lib für den unbekannten Compiler auswählt.

Es ist sehr unklug, wichtige Basisinformationen wegzulassen. Wenn keiner 
weiß, worum es überhaupt geht, sinkt die Hilfsbereitschaft rapide.

Grundlegende Informationen zur gesamten Entwicklungsumgebung sind nie 
verkehrt. Auch wenn später herauskommen sollte, daß das Problem ähnlich 
auch auf anderen Architekturen besteht.


Mauer schrieb:
> Und wie genau wird ein Acknowledge und Nack gesendet

Da mußt Du die Doku zu Deiner I2C-Lib lesen.
Die Fleury-Lib benutze ich nicht.

Ich benutze fast immer SW-I2C. Solange man I2C nicht als Interrupt 
macht, ist SW-I2C gleich schnell und gleich groß.


Peter

von Mauer (Gast)


Lesenswert?

Danke für deine Hilfreiche Info, werd mich drum kümmern und meld mich 
wieder.

von Peter D. (peda)


Lesenswert?


von Mauer (Gast)


Lesenswert?

Hallo,
ALso, ich weiß nicht warum aber die Uhr wird übehaupt nicht 
angesprochen, Die Uhr befindet sich auf einem Stellaris Board, hoffe 
dies sat euch etwas und wenn eigentlich sollte die Uhr ja mit dem Befehl

 I2C_StartTX(Base, RV3029_SLAVE_write, 0);

gestartet werden, aber leider passiert da nichts, Peter haste richtig 
erkannt, der Mc soll mehrere I2C haben, deshalb baue ich den so um, 
deshalb auch die Initialisierung mit der Base Adresse. Ich komm da net 
weiter.
Die Uhr wird net initialisiert, hab einbißchen umgebaut, nun sieht die 
Funktion so aus:
1
unsigned int RV3029_write(unsigned long Base, struct tm tm) {
2
    int Err;
3
    
4
    I2C_StartTX(Base, RV3029_SLAVE_write, 0);
5
    I2C_Send(Base, RV3029_CTRL);
6
    Err = I2C_Send(Base, 0xE9);
7
    //I2C_Stop(Base);
8
    if (Err)
9
      goto error;
10
    
11
    Err = I2C_Send(Base, RV3029_SEC);
12
    // If an error occurred, goto error handler
13
    if (Err)
14
      goto error;
15
    
16
      // .. keep transmitting data
17
      Err = I2C_Send(Base, tm.tm_sec);
18
      Err = I2C_Send(Base, tm.tm_min);
19
      Err = I2C_Send(Base, tm.tm_hour);
20
21
      // on error, goto error handler
22
      if (Err)
23
        goto error;
24
      // increment the Index
25
      i++;
26
      
27
      if ((RV3029_SEC + i) % RV3029_EEPROM_PAGE == 0) {
28
        break;
29
      }
30
    }
31
    // Send the stop condition
32
    I2C_Stop(Base);
33
34
    return Err;
35
  }
Wenn er den Err zurückliefert, heißt es, dass er die Uhr nicht 
initialisiert hat. Vielleicht hast du noch ein paar Tipps auf Lager was 
ich noch ausprobieren kann.Danke.

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.