Wie sieht denn die restliche Beschaltung aus? Ist an SCL/SDA jeweils ein Pullup nach 5V? Wird gern mal vergessen (passiert auch mir immer wieder)
Von der Adresse her schaut 0xA0 aber richtig aus.
Nach längerem hin und her habe ich mich entschieden, das es an der Zeit ist mich mal mit I2C zu befassen und weil ich das Protokoll / den Bus auch verstehen möchte, will ich dies zunächst ohne zusätzliche Bibliotheken ausprobieren. Ich habe im m8 Datenblatt die TWI Kapitel (die Grundlagen) gelesen und daraus folgenden Programmcode erstellt, der eine Verbindung mit einem 24C02 herstellen soll - bis zum ersten ACK des Speichers - dieses kommt jedoch nicht und ich weiss nicht warum.
Mein 24C02 ist wie folgt mit meinem Mega8 verbunden
<pre>GND-|°-- |-VCC
GND-| |-nix
GND-| |-SCK
GND-|----|-SDA</pre>
Folglich müsste die 7bit Adresse des Speichers doch 1010000 sein und das erste zu sendende Byte 10100000 bzw 0xA0 sein. Ein gelungener Schritt wird durch ein Blinken an PB0 signalisiert.
4xBlinken müsste bedeuten, dass alles richtig ist, 5 mal, das kein Ack vom Slave eingegangen ist. Dies ist bei mir immer der Fall und ich kann es mir nicht erklären. Die Adressierung müsste mit 10100000 doch richtig sein für die genannte Beschaltung.Code:#include <avr/io.h> #include <util/delay.h> #define START 0x08 #define SLAVE_OK 0x18 #define F_CPU 8000000UL void blink(){ _delay_ms(300); PORTB |= (1<<PB0); _delay_ms(300); PORTB = 0; } int main(void) { DDRB = 0xFF; PORTB = 0; TWBR = 0x20; TWCR = (1<<TWINT); TWCR |= (1<<TWSTA); TWCR |= (1<<TWEN); while (bit_is_clear(TWCR, TWINT)){ }; blink(); if ((TWSR & 0xF8) == START){ blink(); } TWDR = 0xA0; TWCR = (1<<TWINT) | (1<<TWEN); while (bit_is_clear(TWCR, TWINT)){ }; blink(); if ((TWSR & 0xF8) != SLAVE_OK){ blink(); } else { blink(); blink(); } //hier ginge es dann mit den Daten weiter }
Vielen dank für eure Hilfe[/code]
Wie sieht denn die restliche Beschaltung aus? Ist an SCL/SDA jeweils ein Pullup nach 5V? Wird gern mal vergessen (passiert auch mir immer wieder)
Von der Adresse her schaut 0xA0 aber richtig aus.
#ifndef MfG
#define MfG
[Doppelpost durch Browserfehler]
#ifndef MfG
#define MfG
Das ging ja flott! Pullup10k sind (leider) da. Wär zu schön gewesen
andere Ideen?
Hm... mist... wär der Klassiker gewesen.
Was mir grad im Programm selber auffällt: Während einer I2C-Übertragung sollten keine verzögernden Dinge drin sein wie LCD-Ausgaben, UART-Übertragungen oder eben dieses LED-Blinken. Hier vergeht möglicherweise zu viel Zeit, so dass die TWI-Hardware nen Timeout produziert und den Bus wieder freigibt.
Speicher den Status einfach in ner Variable und werte die aus, wenn STOP gesendet wurde und der Bus wieder frei ist.
#ifndef MfG
#define MfG
Es blinkt trotzdem 5 mal - also war es wohl kein timeout. Danke trotzdem - wir kriegens schon noch ^^Code:int main(void) { DDRB = 0xFF; PORTB = 0; TWBR = 0x20; TWCR = (1<<TWINT); TWCR |= (1<<TWSTA); TWCR |= (1<<TWEN); char temp = 0; while (bit_is_clear(TWCR, TWINT)){ }; temp++; if ((TWSR & 0xF8) == START){ temp++; } TWDR = 0xA0; TWCR = (1<<TWINT) | (1<<TWEN); while (bit_is_clear(TWCR, TWINT)){ }; temp++; if ((TWSR & 0xF8) != SLAVE_OK){ temp++; } else { temp+=2; } for (char i = 0; i < temp; i++){ blink(); } return 0; }
edit: muss jetzt leider schlafen gehen![]()
Also von der Befehlsfolge her siehts eigentlich ziemlich so aus wie bei mir.
Wo was anders ist, ist die Bus-Initialisierung.
Hier mal die Funktionen, die ich verwend. Evtl. hilft dir das weiter.
Damit sollte zumindest mal ein "Bin da!" des EEPROMs kommen.Code:void I2C_Init(ui32_t scl_clock) { // Initializes the I2C/TWI Hardware as Master TWSR = 0; // no prescaler TWBR = ((F_CPU/scl_clock)-16)/2; // must be > 10 for stable operation } e_errors I2C_Start(ui8_t address) { ui8_t twst = 0; ui8_t retval = ERR_OK; TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); // send START condition while(!(TWCR & (1<<TWINT))); // wait until transmission completed twst = TW_STATUS & 0xF8; // check value of TWI Status Register. Mask prescaler bits. if ( (twst != TW_START) && (twst != TW_REP_START)) { retval = ERR_TWI_NO_START; } if (retval == ERR_OK) { // send device address TWDR = address; TWCR = (1<<TWINT) | (1<<TWEN); // wail until transmission completed and ACK/NACK has been received while(!(TWCR & (1<<TWINT))); // check value of TWI Status Register. Mask prescaler bits. twst = TW_STATUS & 0xF8; if ((twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK)) { retval = ERR_TWI_NO_ACK; } } return retval; } void I2C_Stop(void) { TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); // send stop condition while(TWCR & (1<<TWSTO)); // wait until stop condition is executed and bus released }
#ifndef MfG
#define MfG
damit ich den Code ausprobieren kann bräuchte ich glaube ich deine Header Dateien, oder?
danke
->muss jetzt zur Arbeit![]()
Nicht unbedingt, aber wär fast sinnvoller.
Hier mal alle Dateien.
#ifndef MfG
#define MfG
Danke!
Ich hab grad etwas anderes ausprobiert und bin auf einen interessanten Hinweis gestoßen. Offenbar liegt ein Problem mit der Adressierung vor. Wenn ich die Adresse an Chip und im Programm auf 10100100 also 0xA4 ändere bekomme ich das erwünschte ACK. Ich habe im Wiki, sowohl als auch bei Google nach "i2c" AND "10100000" gesucht, aber die Adresse wird nirgendwo als reserviert bezeichnet.
Jedenfalls kann es jetzt erstmal weiter gehen. Melde mich dann wieder
edit: warum lösche ich die TWINT Flag indem ich eine 1 reinschreibe? Das bedeutet doch das durch dass die Hardware den Status dann sofort auf null setzten muss... ist doch paradox...
Lesezeichen