DS 1307 via I2C an atmega328-brauche Hilfe

Gast #4628517
Lesenswert?

Hi Forum,
ich versuche seit einiger Zeit, meine DS 1307 RTC mit einem Amtega 328 
anzusprechen. Dazu wollte ich als ersten Test in eines der RAM-Register 
der RTC einen Wert schreiben (48) (Adresse des Registers ist 0x08) und 
den dann wieder auslesen und via LCD ausgeben (in der Hoffnung das eine 
1 rauskommt).
Verschaltet habe ich das folgendermaßen:
   ____     ______                          _________
  |    1|---|QUARZ |                        |          |
  |R   2|---|______|                        | Atmega   |
  |T   3|---[+3V via Spannungsteiler]       | 328      |   ___
  |C   4|---[GND]                           |          |--|     |
  |    5|-----------------------------------|SDA       |--| LCD |
  |    6|-----------------------------------|SCL       |--| in  |
  |    7|x                                  |          |--| 4bit|
  |    8|---[+5V]                           |          |--|Modus|
  |_____|                                   |__________|--|_____|


CPU-FREQ ist 1mHz
als Programm auf dem avr habe ich zum schreiben der Daten folgendes:
void write_RTC()
{
  power_twi_enable();
  PORTC |= (1<<PORTC5) | (1<<PORTC4);

  TWBR = 2;
  _delay_ms(5);
  TWCR = 0xA4;    //start
   while (!(TWCR & (1<<TWINT)));

  TWDR = 0x08;    //SLA + W
  TWCR = 0x84;
  while (!(TWCR & (1<<TWINT)));

  TWDR = 48;      //data
  TWCR = 0x84;
  while (!(TWCR & (1<<TWINT)));

  TWCR = 0x94;    //stop
  _delay_ms(5);
}
und zum lesen:
void read_RTC()
{
  power_twi_enable();
  PORTC |= (1<<PORTC5) | (1<<PORTC4);

  TWBR = 2;
  _delay_ms(5);
  TWCR = 0xA4;      //start
  while (!(TWCR & (1<<TWINT)));

  TWDR = (0x08 | 0x01);          //SLA + R
  TWCR = 0x84;
  while (!(TWCR & (1<<TWINT)));

  twi_var = TWDR;      //read data

  TWCR = 0x94;      //stop
}


Ich habe, wie es im Datenblatt des AVR auch steht, die internen Pull-Up 
Widerstände aktiviert. Auf dem Oszilloskop kann ich auch sehen, dass auf 
den Leitungen was passiert (hat leider nur einen Kanal, drum kann ich 
nicht genau nachvollziehen was passiert).
Wenn ich das Programm jetzt starte, dann wird mir auf dem LCD ein 
asiatisches Schriftzeichen angezeigt. Wenn ich aber in der Funktion zum 
auslesen statt
TWDR = (0x08 | 0x01);          //SLA + R
TWDR = 48;
setze, dann wird mir auf dem Bildschirm eine 0 angezeigt, bei 49 eine 1 
etc. Drum denke ich, dass das TWDR-Register überhaupt nicht angetastet 
wird vom uC, kann mir aber nicht erklären warum. Ich habe auch schon das 
Datenblatt gewälzt und mir das Tutorial hier im Forum dazu angeschaut, 
konnte aber leider keinen Fehler finden.
Es wäre toll, wenn jemand einen Rat hätte.
vielen Dank schon mal,
Tristan
Gast #4628551
Lesenswert?

also habe jetzt die internen pull-ups abgeschalten und externe 4,7kOhm 
genutzt, was aber auch keine Verbesserung bringt
Ich wollte zum Mindest für den Anfang ohne Lib arbeiten, damit ichs mal 
verstehe.
@joachim B
was meinst du im dritten Absatz? Da werde ich nicht so recht schlau 
draus.
Aber vielen Dank für die schnellen Antworten!

Edit:
hier noch das Datenblatt:
http://cdn-reichelt.de/documents/datenblatt/A200/DS_1307.pdf
Ich habe mich jetzt an der Grafik auf Seite 4 orientiert mit den 
Adressen, allerdings steht auf Seite 2: "Access  is  obtained  by 
implementing  a
START condition and providing a device identification code followed by a 
register address."
Was ist denn da mit "device identification code" gemeint?
#4628561
Lesenswert?

schaust du ins Datenblat hast du für die I2C Adresse ein Byte = 8 Bits, 
aber nur die Bits 7-1 gelten, Bit 0 ist für R/W read write.

Nun gilt aber erst mal es gibt nur 7 Bit 127 I2C Adressen,

redet einer von Adresse 0x20 was meint der ?

ich habe mir angewöhnt die 127 Adressen rechts zu shiften um im 
Datenblatt bei den richtigen Bits zu bleiben
1
#if (ARDUINO>0)
2
  DEBUG_PRINTLN(F(" -> Scanning..."));
3

4
  _i2c_key=0;
5
  byte error, address;
6
  int nDevices=0;
7
  for(address = 1; address < 127; address++ ) 
8
  { // The i2c_scanner uses the return value of
9
    // the Write.endTransmisstion to see if
10
    // a device did acknowledge to the address.
11
    Wire.beginTransmission(address);
12
    error = Wire.endTransmission();
13

14
    if (error == 0)
15
    { DEBUG_PRINT(F("I2C device found at address 0x"));
16
      if (address<16) 
17
        DEBUG_PRINT(F("0"));
18
      DEBUG_PRINT_DEC_HEX(address,HEX);
19
      DEBUG_PRINT(F("; "));
20
      if (address<64) 
21
        DEBUG_PRINT(F("0"));
22
      DEBUG_PRINT_DEC_HEX(address,BIN);
23
      DEBUG_PRINT(F("x; << 0x"));
24
      DEBUG_PRINT_DEC_HEX((address<<1),HEX);
25
      DEBUG_PRINT(F("; "));
26
      if ((address<<1)<128) 
27
        DEBUG_PRINT(F("0"));
28
      DEBUG_PRINT_DEC_HEX((address<<1),BIN);
29
      
30
      switch(address<<1)
31
      { //case 0x40:I2C_TASTATUR_8574);
32
        //case 0x70:I2C_TASTATUR_8574A);
33
        //case 0x78:I2C OLED         "));
34
        //case 0xA0:I2C EEPROM       "));
35
        case 0xD0:
36
          Wire.beginTransmission(DS1307_ID);
37
          printIIC(0x3F);
38
          (Wire.endTransmission()) ? i2c_test_flags|=(1<<I2C_RTC_3231) : i2c_test_flags|=(1<<I2C_RTC_1307);
39
          #ifdef DEBUG
40
          (i2c_test_flags&(1<<I2C_RTC_3231)) ? Serial.println(F(" DS3231 RTC ")) : Serial.println(F(" DS1307 RTC "));
41
          #endif
42
          break;
43
        default:
44
          DEBUG_PRINTLN(F(""));
45
          break;
46
      }
47
      nDevices++;
48
    }
49
    else if (error==4) 
50
    { DEBUG_PRINT(F("Unknow error at address 0x"));
51
      if (address<16) 
52
        DEBUG_PRINT(F("0"));
53
      DEBUG_PRINTLN_DEC_HEX(address,HEX);
54
    }    
55
  }
56
  if (nDevices == 0)
57
    DEBUG_PRINTLN(F("No I2C devices found"));
58
  else
59
    DEBUG_PRINTLN(F("done"));
60
  DEBUG_PRINTLN(F(""));
61
#else
62
  test_i2c_key();
63
#endif
64

65
}
(Firma: Vescomp) #4628669
Lesenswert?

Tristan V. schrieb:
> Adressen, allerdings steht auf Seite 2: "Access  is  obtained  by
> implementing  a
> START condition and providing a device identification code followed by a
> register address."
> Was ist denn da mit "device identification code" gemeint?
 Die Adresse naturlich.
1
 TWDR = 0x08;    //SLA + W
2
 TWDR = (0x08 | 0x01);          //SLA + R
 Wo hast du diese Adressen her ?
 DS1307 hat die Adresse 0xD0 (schreiben) und 0xD1 (lesen).
 Probiere es mal mit richtigen Adressen...  ;-)


Joachim B. schrieb:
> ich habe mir angewöhnt die 127 Adressen rechts zu shiften um im
> Datenblatt bei den richtigen Bits zu bleiben

 Ja, sicher.
 Welches Datenblatt ?

 Hier ist es fur DS1307:
1
  The address byte contains the 7 bit DS1307/DS1308 address, which is
2
  1101000, followed by the *direction bit (R/W )  which, for a write,
3
  is a 0.

 Siehe auch:
 Beitrag "Re: I2C BeginnerFrage"
 und:
 Beitrag "Re: I2C BeginnerFrage"
#4628687
Lesenswert?

Marc V. schrieb:
> Ja, sicher.
>  Welches Datenblatt ?

alle, kein spezielles, ich nutze

DS3231, (DS1307 erst später), PCF8574(a)  und Oled

mit dem PCF8574 habe ich mal angefangen

https://www.nxp.com/documents/data_sheet/PCF8574.pdf
Seite 12 und die ganze shifterei verwirrt doch nur, wenn jedes Bit an 
seinem Platz bleibt dann ergeben sich halt völlig andere 
Betrachtungsweisen der I2C Adresse
Gast #4628743
Lesenswert?

@ Marc Vesely:
diese Adresse ist aus dem Datenblatt zur RTC von Reichelt, in dem steht 
aber auch nichts von der 0xD0 bzw. D1 Adresse drin. Das war eine der 
Sachen, die mich so verwundert hat.
Um das Lesen aus der RTC zu umgehen, habe ich die Funktion mal so 
umgeschrieben, dass sie den SQW-Ausgang auf 1Hz einschaltet und auch 
noch versucht, eine Fehlererkennung zu implementieren.
das kam bei raus (bitte reißt mir nicht den Kopf ab :D)
1
void write_RTC()
2
{
3
  power_twi_enable();
4
  TWBR = 2;
5
  TWSR &= ~(1<<TWPS0) &~(1<<TWPS1);
6
  _delay_ms(5);
7
  
8
  TWCR = (1<<TWEN)|(1<<TWSTA)|(1<<TWINT);    //start
9
   while (!(TWCR & (1<<TWINT)));
10
  if (!((TWSR & 0xF8)== 0x08))
11
    write_data_to_LCD_as_string("start error");
12
  
13
  TWDR = (0xD0);                //SLA + W
14
  TWCR = (1<<TWEN)|(1<<TWINT);
15
  while (!(TWCR & (1<<TWINT)));
16
  if (!((TWSR & 0xF8)==0x40))
17
    write_data_to_LCD_as_string("address error");
18
  
19
  TWDR = (0x07);                //register address
20
  TWCR = (1<<TWEN)|(1<<TWINT);
21
  while (!(TWCR & (1<<TWINT)));
22
  if (!((TWSR & 0xF8)==0x40));
23
  write_data_to_LCD_as_string("address error");
24
  
25
  TWDR = 0x10;    //data
26
  TWCR = (1<<TWEN)|(1<<TWINT);
27
  while (!(TWCR & (1<<TWINT)));
28
  if (!((TWSR & 0xF8)==0x50))
29
    write_data_to_LCD_as_string("data error");
30
  
31
  TWCR = 0x94;    //stop
32
  _delay_ms(5);
33
}

ich bekomme auf dem LCD 2x address error und data error, start scheint 
aber zu funktionieren.
vielen Dank,
Tristan
(Firma: Vescomp) #4628780
Lesenswert?

Tristan V. schrieb:
> ich bekomme auf dem LCD 2x address error und data error, start scheint
> aber zu funktionieren.
1
  TWDR = (0xD0);                //SLA + W
2
  TWCR = (1<<TWEN)|(1<<TWINT);
3
  while (!(TWCR & (1<<TWINT)));
4
//*** Fehler
5
  if (!((TWSR & 0xF8)==0x40)) write_data_to_LCD_as_string("address error");
6
//*** Fehler
 Beim schreiben solltest du auf 0x18 prüfen !!!
 Beim lesen prüfst du auf 0x40.

 P.S.
1
  twi.start
2
  twi.Write 0xD0
3
  twi.Write 0x00   // Sekundenregister auswaehlen
4
  twi.stop
5
  twi.start
6
  twi.Write 0xD1
7
  twi.ReadNack     // Sekunden auslesen
8
  twi.stop
Gast #4628821
Lesenswert?

ok, also ich habe die Tabelle nochmal durchgeguckt und die Werte 
geändert, da habe ich irgendwiegepennt...
Allerdings funktioniert es jetzt immer noch nicht so recht. Ich denke, 
ich belass es erstmal dabei, nächste Woche habe ich die Möglichkeit das 
nochmal persönlich mit jemandem zu besprechen der Ahnung davon hat, das 
dürfte für Alle einfacher sein als die Ferndiagnose durch die Glaskugel 
:D
Aber vielen Dank für die vielen und schnellen Hilfen,
ich melde mich wenn es klappt :)
Tristan
#4628971
Lesenswert?

Tristan V. schrieb:
> CPU-FREQ ist 1mHz

Okay, da kann die Übertragung etwas länger dauern ...


Das hier läuft (Auf m48 und m168):
1
; TWI Init
2

3
TWBR = 85
4
TWSR = 0
5
TWAR = 0
6
TWAMR = 0
7
TWCR = 0    ; <- TWI Reset!
8

9

10
;Schreiben
11

12
TWCR = 0xA4    ; STA senden
13

14
Warte auf TWINT-Flag
15

16
TWSR AND 0xF8 = 0x08 ?  ; Erfolg?
17

18
TWDR = 0xD0     ; DS1307 mit 0 als RW (also schreiben)
19

20
TWCR = 0x84    ; Abschicken
21

22
Warte auf TWINT-Flag
23

24
TWSR AND 0xF8 = 0x18 ?  ; Erfolg?
25

26
TWDR = Registeradresse
27

28
TWCR = 0x84    ; Abschicken
29

30
Warte auf TWINT-Flag
31

32
TWSR AND 0xF8 = 0x28 ?  ; Erfolg?
33

34
TWDR = Daten
35

36
TWCR = 0x84    ; Abschicken
37

38
Warte auf TWINT-Flag
39

40
TWSR AND 0xF8 = 0x28 ?  ; Erfolg?
41

42
TWCR = 0x94    ; STO senden


Gruß

Jobst
#4628994
Lesenswert?

Ach ja ...
1
;Lesen
2

3
; Teil 1 Registeradresse schreiben
4

5
TWCR = 0xA4             ; STA senden
6

7
Warte auf TWINT-Flag
8

9
TWSR AND 0xF8 = 0x08 ?  ; Erfolg?
10

11
TWDR = 0xD0             ; DS1307 mit 0 als RW (also schreiben)
12

13
TWCR = 0x84             ; Abschicken
14

15
Warte auf TWINT-Flag
16

17
TWSR AND 0xF8 = 0x18 ?  ; Erfolg?
18

19
TWDR = Registeradresse
20

21
TWCR = 0x84    ; Abschicken
22

23
Warte auf TWINT-Flag
24

25
TWSR AND 0xF8 = 0x28 ?  ; Erfolg?
26

27
TWCR = 0x94             ; STO senden
28

29

30
; Teil 2 Daten (aus geschriebener Registeradresse) lesen
31

32
TWCR = 0xA4             ; STA senden
33

34
Warte auf TWINT-Flag
35

36
TWSR AND 0xF8 = 0x08 ?  ; Erfolg?
37

38
TWDR = 0xD1             ; DS1307 mit 1 als RW (also lesen)
39

40
TWCR = 0x84             ; Abschicken
41

42
Warte auf TWINT-Flag
43

44
TWSR AND 0xF8 = 0x40 ?  ; Erfolg?
45

46
TWCR = 0x84             ; Daten abholen ohne ACK
47

48
Warte auf TWINT-Flag
49

50
TWSR AND 0xF8 = 0x58 ?  ; Erfolg?
51

52
Daten = TWDR
53

54
TWCR = 0x94             ; STO senden


Gruß

Jobst

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren