Uwegw (Diskussion | Beiträge) |
Uwegw (Diskussion | Beiträge) |
||
Zeile 1: | Zeile 1: | ||
− | Programm für einen AVR mit TWI(Hardware-I2C)-Schnittstelle als Slave. | + | Programm für einen AVR mit [[TWI]](Hardware-[[I2C]])-Schnittstelle als Slave. |
− | + | ||
+ | |||
+ | |||
+ | Ein Codeschnipsel für den Master. Es wird die I2C_Master-Bibliothek von Peter Fleury verwendet. | ||
+ | Es wird geprüft, ob der Slave bereit ist, dann werden die ersten drei Btes aus dem txbuffer des Slaves gelegen und in byte0..2 abgespeichert. | ||
+ | <pre> | ||
+ | #include "i2cmaster.h" //I2C-Master-Routinen von Peter Fleury verwenden (siehe www.jump.to/fleury) | ||
+ | #define SLAVE_ADRESSE 0x50 | ||
+ | uint8_t byte0; | ||
+ | uint8_t byte1; | ||
+ | uint8_t byte2; | ||
+ | |||
+ | if(!(i2c_start(SLAVE_ADRESSE+I2C_WRITE))) //Slave bereit zum lesen? | ||
+ | { | ||
+ | i2c_write(0x00); //Buffer Startadresse zum Auslesen | ||
+ | i2c_rep_start(SLAVE_ADRESSE+I2C_READ); //Lesen beginnen | ||
+ | |||
+ | byte0= i2c_readAck(); | ||
+ | byte1= i2c_readAck(); | ||
+ | byte2= i2c_readAck(); | ||
+ | i2c_stop(); | ||
+ | } | ||
+ | </pre> | ||
+ | |||
+ | |||
+ | Die twislave.c für den Slave | ||
<pre> | <pre> | ||
#ifndef _TWISLAVE_H | #ifndef _TWISLAVE_H | ||
Zeile 7: | Zeile 31: | ||
/* | /* | ||
− | Dieses Programm in einer separaten Datei (z.B. twislave.c) abspeichern und in das | + | Dieses Programm in einer separaten Datei (z.B. twislave.c) abspeichern und in das eigene Programm |
einbinden. | einbinden. | ||
Version vom 4. März 2007, 14:11 Uhr
Programm für einen AVR mit TWI(Hardware-I2C)-Schnittstelle als Slave.
Ein Codeschnipsel für den Master. Es wird die I2C_Master-Bibliothek von Peter Fleury verwendet. Es wird geprüft, ob der Slave bereit ist, dann werden die ersten drei Btes aus dem txbuffer des Slaves gelegen und in byte0..2 abgespeichert.
#include "i2cmaster.h" //I2C-Master-Routinen von Peter Fleury verwenden (siehe www.jump.to/fleury) #define SLAVE_ADRESSE 0x50 uint8_t byte0; uint8_t byte1; uint8_t byte2; if(!(i2c_start(SLAVE_ADRESSE+I2C_WRITE))) //Slave bereit zum lesen? { i2c_write(0x00); //Buffer Startadresse zum Auslesen i2c_rep_start(SLAVE_ADRESSE+I2C_READ); //Lesen beginnen byte0= i2c_readAck(); byte1= i2c_readAck(); byte2= i2c_readAck(); i2c_stop(); }
Die twislave.c für den Slave
#ifndef _TWISLAVE_H #define _TWISLAVE_H /* Dieses Programm in einer separaten Datei (z.B. twislave.c) abspeichern und in das eigene Programm einbinden. Betrieb eines AVRs mit Hardware-TWI-Schnittstelle als Slave. Zu Beginn muss init_twi_slave mit der gewünschten Slave-Adresse als Parameter aufgerufen werden. Der Datenaustausch mit dem Master erfolgt über die Buffer rxbuffer und txbuffer, auf die von Master und Slave zugegriffen werden kann. rxbuffer und txbuffer sind globale Variablen (Array aus uint8_t). Die Ansteuerung des rxbuffers, in den der Master schreiben kann, erfolgt ähnlich wie bei einem normalen I2C-EEPROM. Man sendet zunächst die Bufferposition, an die man schreiben will, und dann die Daten. Die Bufferposition wird automatisch hochgezählt, sodass man mehrere Datenbytes hintereinander schreiben kann, ohne jedesmal die Bufferadresse zu schreiben. Um den txbuffer vom Master aus zu lesen, überträgt man zunächst in einem Schreibzugriff die gewünschte Bufferposition und liest dann nach einem repeated start die Daten aus. Die Bufferposition wird automatisch hochgezählt, sodass man mehrere Datenbytes hintereinander lesen kann, ohne jedesmal die Bufferposition zu schreiben. Autor: Uwe Große-Wortmann (uwegw) Status: Testphase, keine Garantie für ordnungsgemäße Funktion! letze Änderungen: Kommentare ergänzt, Schutz gegen mehrfaches einbinden eingebaut. */ #include <util/twi.h> //%%%%%%%% von Benutzer konfigurierbare Einstellungen %%%%%%%% #define buffer_size 8 //Größe der Buffer in Byte (1..255) //%%%%%%%% Globale Variablen, die vom Hauptprogramm genutzt werden %%%%%%%% /*Der Buffer, in dem die empfangenen Daten gespeichert werden. Der Slave funktioniert ähnlich wie ein normales Speicher-IC [I2C-EEPROM], man sendet die Adresse, an die man schreiben will, dann die Daten, die interne Speicher-Adresse wird dabei automatisch hochgezählt*/ volatile uint8_t rxbuffer[buffer_size]; /*Der Sendebuffer, der vom Master ausgelesen werden kann.*/ volatile uint8_t txbuffer[buffer_size]; //%%%%%%%% Funktionen, die vom Hauptprogramm aufgerufen werden können %%%%%%%% /*Initaliserung des TWI-Inteface. Muss zu Beginn aufgerufen werden, sowie bei einem Wechsel der Slave Adresse Parameter: adr: gewünschte Slave-Adresse*/ void init_twi_slave (uint8_t adr); //%%%%%%%% ab hier sind normalerweise keine weiteren Änderungen erforderlich! %%%%%%%% //_____________________________________________________________________________________________ uint8_t buffer_adr; //"Adressregister" für den Buffer /*Initaliserung des TWI-Inteface. Muss zu Beginn aufgerufen werden, sowie bei einem Wechsel der Slave Adresse Parameter: adr: gewünschte Slave-Adresse */ void init_twi_slave (uint8_t adr) { TWAR= adr; //Adresse setzen TWCR|= (1<<TWEA) | (1<<TWEN)|(1<<TWIE); TWCR &= ~(1<<TWSTA)|(1<<TWSTO); buffer_adr=0xFF; sei(); } /*ISR, die bei einem Ereignis auf dem Bus ausgelöst wird. Im Register TWSR befindet sich dann ein Statuscode, anhand dessen die Situation festgestellt werden kann. */ ISR (TWI_vect) { uint8_t data=0; //alte version: switch(TWSR) switch (TW_STATUS) //TWI-Statusregister prüfen und nötige Aktion bestimmen { case TW_SR_SLA_ACK: // 0x60 Slave Receiver, wurde adressiert TWCR = (1<<TWEN)| // TWI Interface enabled (1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to send byte (1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Expect ACK on this transmission (0<<TWWC); // buffer_adr=0xFF; //Bufferposition ist undefiniert break; case TW_SR_DATA_ACK: // 0x80 Slave Receiver,Daten empfangen data=TWDR; //Empfangene Daten auslesen if (buffer_adr == 0xFF) //erster Zugriff, Bufferposition setzen { buffer_adr= data; //Bufferposition wie adressiert setzen TWCR = (1<<TWEN)| // TWI Interface enabled (1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to send byte (1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Send ACK after next reception (0<<TWWC); } else //weiterer Zugriff, Daten empfangen { rxbuffer[buffer_adr]=data; //Daten in Buffer schreiben buffer_adr++; //Buffer-Adresse weiterzählen für nächsten Schtreibzugriff if(buffer_adr<(buffer_size-1)) //im Buffer ist noch Platz für mehr als ein Byte { //nächstes Byte lesen, ACK danach, um nächstes Byte anzufordern TWCR = (1<<TWEN)| // TWI Interface enabled (1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to send byte (1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Send ACK after next reception (0<<TWWC); } else //es kann nur noch ein Byte kommen, dann ist der Buffer voll { //letztes Byte lesen, dann NACK, um vollen Buffer zu signaliseren TWCR = (1<<TWEN)| // TWI Interface enabled (1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to send byte (0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| (0<<TWWC); } } break; case TW_ST_SLA_ACK: case TW_ST_DATA_ACK: //0xB0 Slave Transmitter, weitere Daten wurden angefordert TWDR = txbuffer[buffer_adr]; //Datenbyte senden buffer_adr++; //bhufferadresse für nächstes Byte weiterzählen TWCR = (1<<TWEN)| (1<<TWIE)|(1<<TWINT)| (1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| (0<<TWWC); break; case TW_ST_DATA_NACK: //0xC0 Keine Daten mehr gefordert case TW_SR_DATA_NACK: //0x88 case TW_ST_LAST_DATA: //0xC8 Last data byte in TWDR has been transmitted (TWEA = “0”); ACK has been received case TW_SR_STOP: // 0xA0 STOP empfangen default: //Übertragung beenden TWCR = (1<<TWEN)| (1<<TWIE)|(1<<TWINT)| (1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| (0<<TWWC); //buffer_adr=0xFF; //Bufferposition ist undefiniert break; } //end.switch } //end.ISR(TWI_vect) #endif //#ifdef _TWISLAVE_H ////Ende von twislave.c////