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
Hallo, I2C sollte mit externen Widerständen betrieben werden. Schau dir bitte die I2C Spezifikation an.
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!
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?
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
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
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
@ 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
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
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
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.