Forum: Mikrocontroller und Digitale Elektronik DS 1307 via I2C an atmega328-brauche Hilfe


von Jing P. (Gast)


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

von Karl M. (Gast)


Lesenswert?

Hallo,

I2C sollte mit externen Widerständen betrieben werden.
Schau dir bitte die I2C Spezifikation an.

von Stefan A. (ripper121)


Lesenswert?

4.7kOhm Pullup auf beide Leitung

von Joachim B. (jar)


Lesenswert?

benutze als pullup hardware 2x 4,7k

die fleury LIB hilft auch
http://homepage.hispeed.ch/peterfleury/avr-software.html

bist du sicher das deine Adresse stimmt, ich sehe da immer Verwirrung 
zwischen 7-Bit Betrachtung I2C >> 1 und 8-Bitbetrachtung I2C & 0xFE r/w 
Bit ausgeklammert

mit der Fleury LIB und der richtigen Adresse kein Problem, mit Arduino 
auch kein Problem!

von Jing P. (Gast)


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?

von Joachim B. (jar)


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
}

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


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"

: Bearbeitet durch User
von Joachim B. (jar)


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

von Jing P. (Gast)


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

von Marc V. (Firma: Vescomp) (logarithmus)


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

: Bearbeitet durch User
von Jing P. (Gast)


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

von Jobst M. (jobstens-de)


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

von Jobst M. (jobstens-de)


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

: Bearbeitet durch User
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.