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.
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:
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.