Hallo, kann mir jemand helfen ? ich möchte empfangene messewerte in ein serielles EEPROM reinschreiben und diese dann später über die serielle Schnittstelle an ein PC-Programm übermitteln. Mein primäres Problem ist die empfangene Messwerte in ein serielles EEPROM zu schreiben und zu lesen. Nicht in das interne EEPROM des Prozessors. Ich weis nur soviel das es mit dem I2C Bus funktioniert muss. Gehe ich richtig in der Annahme das ich 2 Portpins (freiwählbar)benötige für SDA und SCL ? Wie realisiere ich das in einem C programm ? Kann mir jemand bei meinem problem helfen. Im voraus besten Dank
siehe FAQ: Gibt es irgendwo I2C-Funktionen für avr-gcc? Fertige I2C-Routinen findet man z.B. auf http://www.mysunrise.ch/users/pfleury/avr-software.html.
Moin moin! Ich grabe mal diesen alten Beitrag aus, anstatt einen neuen zu eröffnen. Nachdem ich an der I2C Ansteuerung der Chipkarte von Reichelt gescheitert bin, habe ich mir erstmal EEPROM im DIP8 Gehäuse vorgenommen. Leider ebenfalls ohne Erfolg. Ich habe breits eine selbstgeschriebene Routine, die Atmel Aplication Note (avr300.asm) und die im Anhang befindliche Datei i2c.inc getestet. Ich glaub, die kam auch aus diesem Forum. Habe die Übersicht inzwischen verloren. Als Controller nutze ich einen Mega8 (interner Oszi 1Mhz), der eeprom ist ein M24C64. Im Anhang ist ebenfalls ein Schaltplan, wie das Ding am Mega8 dran hängt. Allerdings nutze ich PIN 4 und 5 vom Port B. An Port D hängen ein paar LEDs. Das soll passieren: LEDs immer abwechselnd schalten (1: ein, 2: aus, 3: ein ...) Daten in den EEPROM schreiben (neues "LED-Muster") Daten aus EEPROM lesen LEDs schalten. Das passiert: LEDs blitzen kurz auf, gehen aus, bleiben aus. Die Routine "i2cread" gibt für SRAMDAT immer 0x00 zurück. es wird, wie es scheint, nichts gelesen. Oder zuvor nichts geschrieben, das kann ich leider nicht feststellen. Alle Verdindungen und Kontakte wurden geprüft. Wenn ich das Lesen aus dem Speicher und Ausgeben an Port D in die Schleife verlege, zeigt das Oszilloskop am SDA Pin am Speicher lustiges Gewackel, was bestimmt Daten sind ;-) Der SCL Pin liegt dauerhaft auf low. Vielleicht hat ja jemand ein funktionierendes Programm in asm (oder auch schon hex) das ich ausprobieren kann oder entsprechend anpassen kann. Ich hoffe, ihr könnt mir weiterhelfen. Schonmal vielen Dank im Voraus.
> Als Controller nutze ich einen Mega8 (interner Oszi 1Mhz), der eeprom > ist ein M24C64. Im Anhang ist ebenfalls ein Schaltplan, wie das Ding am > Mega8 dran hängt. Allerdings nutze ich PIN 4 und 5 vom Port B. Der Mega8 hat eine Hardware TWI(I2C) die an den Pins PC4(SDA) und PC5(SCL) angeschlassen ist. Wenn Du andere Portpins verwendest, mußt Du das gesammte I2C Protokoll selbst programmieren (Software I2C). Einfach ist es aber den eingebauten (und bezahlten) Hardware I2C des Mega8 zu verwenden.
Das Hardware TWI hab ich schon getestet... Leider auch ohne Erfolg. Hast du da Code für, den ich verwenden kann? Dann würd ich das nochmal testen. In der i2c.inc sind die entsprechenden Software I2C Routinen drin.
Wenn Du den Hardware TWI verwendest, kannst Du so vorgehen. Die Leitungen SDA und SCL müssen über je einen Widerstand von ca. 4,7KOhm an die Versorgungsspannung gelegt werden. Zuerst mußt Du die Baudrate einstellen:
1 | TWBR = (F_CPU / 100000UL - 16) / 2; // TWI Baudrate 100KHz |
F_CPU sollte im makefile eingetragen sein. Jede Übertragung beginnt mit einer Startcondition und endet mit einer Stopcondition. Dafür machst Du zwei Funktionen. Etwa so:
1 | void TwiStart(void) { |
2 | TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); // send start condition |
3 | while ((TWCR & _BV(TWINT)) == 0) ; // wait for transmission |
4 | }
|
5 | |
6 | void TwiStop(void { |
7 | TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); |
8 | }
|
Außerdem brauchst Du noch eine Funktion zum Senden und eine zum Emfangen:
1 | void TwiSend(uint8_t DataByte, uint8_t ackno) { |
2 | TWDR = DataByte; |
3 | if(ackno == 1) TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN); |
4 | else TWCR = _BV(TWINT) | _BV(TWEN); // clear interrupt to start transmission |
5 | while ((TWCR & _BV(TWINT)) == 0) ; // wait for transmission |
6 | }
|
7 | |
8 | uint8_t TwiReceive(uint8_t ackno) { |
9 | uint8_t DataByte; |
10 | if(ackno == 1) TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN); |
11 | else TWCR = _BV(TWINT) | _BV(TWEN); // clear interrupt to start transmission |
12 | while ((TWCR & _BV(TWINT)) == 0) ; // wait for transmission |
13 | DataByte = TWDR; |
14 | return DataByte; |
15 | }
|
Mit dem Parameter ackno steuerst Du ob ein Acknowledge erwartet wird oder nicht. Bei nur einem Byte und beim letzten emfangenen oder gesendeten Byte ist ackno 0(Null). Jeder I2C Chip hat eine Basisadresse welche Du im Datenblatt findest. Mein 24C256 hat 0xA0 und er braucht eine 16Bit Adresse.
1 | #define TWI_SLA_EE 0xA0
|
Um nun auf den Speicher zu schreiben oder zu lesen kombinierst Du die obigen Funktionen wie erforderlich:
1 | void MemByteWrite(uint16_t addr, uint8_t wert) { |
2 | TwiStart(); |
3 | TwiSend(TWI_SLA_EE | TW_WRITE, 0); |
4 | TwiSend(addr >> 8, 0); |
5 | TwiSend(addr, 0); |
6 | TwiSend(wert, 0); |
7 | TwiStop(); |
8 | }
|
9 | |
10 | uint8_t MemByteRead(uint16_t addr) { |
11 | TwiStart(); |
12 | TwiSend(TWI_SLA_EE | TW_WRITE, 0); |
13 | TwiSend(addr >> 8, 0); |
14 | TwiSend(addr, 0); |
15 | TwiStart(); |
16 | TwiSend(TWI_SLA_EE | TW_READ ,0); |
17 | uint8_t wert = TwiReceive(0); |
18 | TwiStop(); |
19 | return wert; |
20 | }
|
Um zugriff auf die Symbole TW_WRITE und TW_READ zu erhalten mußt Du die twi.h aus dem compat Verzeichnis includieren:
1 | #include <compat/twi.h> |
Nun zu ackno. Wen mehr als ein Byte gelesen oder geschrieben werden sollen geht das etwa so:
1 | uint16_t MemWordRead(uint16_t addr) { |
2 | TwiStart(); |
3 | TwiSend(TWI_SLA_EE | TW_WRITE, 0); |
4 | TwiSend(addr >> 8, 0); |
5 | TwiSend(addr, 0); |
6 | TwiStart(); |
7 | TwiSend(TWI_SLA_EE | TW_READ ,0); |
8 | uint16_t wert = TwiReceive(1); |
9 | wert <<= 8; |
10 | wert += TwiReceive(0); |
11 | TwiStop(); |
12 | return wert; |
13 | }
|
Hoffe das hilft etwas. Achtung! Es wird hier keine Fehlerbehandlung vorgenommen. Nach jeder Operation kannst Du den Erfolg oder Misserfolg durch zuweisen von TW_STATUS auswerten:
1 | uint8_t twst = TW_STATUS; |
Gruß Frank.
Falls Dein Speicher einen WP(write protect) Anschluss hat, muss der an Masse. Ebenso die drei(?) Adressleitungen.
Oh, sehe gerade das die twi.h nun im util Verzeichnis liegt. Also richtig:
1 | #include <util/twi.h> |
muss mich erstmal in C für avr einarbeiten und gucken wie ich das auf meiner linux maschine zum laufen bekomme... vielen dank schonmal!
hallo, habe was ähnliches damit gemacht: http://www.myavr.de/shop/artikel.php?artID=65 ... also die I2C leitungen sind am m8 festgelegt C6 und C7 für hardware-TWI frei wählbar wirds nur wenn du mit soft-TWI arbeitest, das twi-protokoll ist aber nicht so simpel wie uart oder spi ob die win-avr bibliotheken soft-TWI her geben bezweifle ich... Wenn du aber das hardware-TWI nimmst solltes du es mit den TWI-bibliotheken hin bekommmen... habs sie selber aber noch nicht benutzt, ich habs mit dem code-wizard vom myavr-workpad gemacht. J.
magst du mir die TWI-bibliotheken mal schicken? mit der software kann ich leider nichts anfangen... bin linux 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.