Hallo Jagdfalke,

da ich nicht weiss was Du genau machen möchtest, lade ich Dir die einzelnen Code-Teile hoch, Du bastelst die dann zusammen. Wenn was net funzt, lade mir bitte deinen kompletten Source-Code hoch.

Die Lösung von Atmel basiert auf der ISR-Routine die aufgerufen wird sobald sich am TWI was getan hat. Hier der Code für die ISR:
Code:
  



ISR(TWI_vect)
{	

	if (i2c_initiated == 0) return;
	switch (TWSR & 0b11111000)
	{
		//Slave
		case TW_SR_GCALL_ACK:   
		case TW_SR_ARB_LOST_GCALL_ACK:
		case TW_SR_SLA_ACK:
		
		case TW_SR_ARB_LOST_SLA_ACK: 
	
			TWI_bufPtr   = 0; 
			TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN) | (1<<TWIE);
                break;  
 		case TW_SR_DATA_ACK: 
  		case TW_SR_GCALL_DATA_ACK:    
 			TWI_buf[TWI_bufPtr++]     = TWDR;
			TWCR = (1<<TWEN)| (1<<TWIE)|(1<<TWINT)| (1<<TWEA);
	
		break;
			case TW_SR_STOP:       
			TWCR = (0<<TWIE);
			

	        break;


		
  		
		//Master Transeiver
      	case TW_START:
	    case TW_REP_START:
	
        	TWI_bufPtr = 0; 		
      	case TW_MT_SLA_ACK:
      	case TW_MT_DATA_ACK:
          	if (TWI_bufPtr <= TWI_msgSize)
          	{	
				TWDR = TWI_buf[TWI_bufPtr++];
				TWCR = (1<<TWINT) | (1<<TWIE) | (1<<TWEN);
 	  		}
	  		else
	  		{
	  	   		TWCR = (1<<TWIE) | (1<<TWEN)|(1<<TWINT)| (1<<TWSTO);
				while(TWCR & (1<<TWSTO));
				TWCR = (1<<TWEN)| (1<<TWIE)|(1<<TWINT)| (1<<TWEA);
	   	  	}
      	break;
		//SR-Error
		case TW_SR_DATA_NACK:      
		case TW_SR_GCALL_DATA_NACK: 
		case TW_ST_LAST_DATA:
		//MT-Error
      	case TW_MT_SLA_NACK:      // SLA+W has been tramsmitted and NACK received
      	case TW_MR_SLA_NACK:      // SLA+R has been tramsmitted and NACK received
      	case TW_MT_DATA_NACK:     // Data byte has been tramsmitted and NACK received
      	case TW_BUS_ERROR:         // Bus error due to an illegal START or STOP condition
      	default:
	 		PORTB |= (1<<PB0);
	 		do{} while(1);												  // Reset TWI Interface
	}

}
Folgende Variablen brauchst Du um die ISR zu betreiben:

static volatile uint8_t TWI_buf[20];
static volatile unsigned char TWI_msgSize = 3;
static volatile unsigned char TWI_bufPtr;
static volatile uint8_t i2c_initiated = 0;

Den Buffer kannst Du an die größe Deiner maximalen Nachrichtengröße einrichten (Da hier auch die Slave-Adresse reinmuss +1). Atmel hat hier einen RingPuffer eingerichtet, den ich aber net brauche(müsste mich auch erstmal damit beschäftigen)

static volatile ist notwendig, damit die Variablen auch in der ISR bekannt sind. Ich glaube static wäre nicht notwendig, hatte aber noch keine Zeit das auszuprobieren.

Der Zeiger auf den Buffer wird benutzt um auf das nächste zu sendende Byte zu zeigen.

Die msgSize ist notwendig damit die ISR weiss wann Stop zu senden ist.

Bei einem Bus-Fehler geht der PortB,Pin0 an, ich nutze das um festzustellen ob auf dem Bus was schiefgelaufen ist, musst Du bestimmt anpassen.


Der Code zum initialisieren des TWI

Code:
void TWI_Initialise(void)
{
TWSR = (1<<TWPS1) | (1<<TWPS0); // Prescaler
TWBR=32;

                                                                                   
TWAR = TW_Slave_Adr;               			//Setzen der TW-Adresse (Slave)
TWCR |= (1<<TWEN) | (1<<TWIE);                              

}
Die Slave-Adresse musst Du natürlich nur einrichten, wenn der AVR auch als Slave fungieren soll. Das TWI wird hier erstmal vorbereitet, und kann dann auch als Master benutzt werden.

Für den Slave-Betrieb muss TWEA=TW Enable Ack gesetzt werden:
TWCR = (1<<TWEN)| (1<<TWIE)|(1<<TWINT)| (1<<TWEA);

Für den Test als Master kannst Du das erstmal rauslassen.

Sobald das TWI eingerichtet ist, kannst Du

i2c_initiated =1;

schreiben. Das ist notwendig, für den Fall das die ISR aufgerufen wird obwohl Sie noch nicht richtig eingerichtet ist.

Wenn Du jetzt was senden willst, musst du den Buffer mit der Nachricht befüllen. Ich mach das so:



Code:
tmp_bufPtr=1;
TWI_msgSize= strlen(Str2Send) ;
do
	TWI_buf[tmp_bufPtr++]=*Str2Send;
while (*Str2Send++);
TWI_buf[0] = recipient;
            
TWCR = (1<<TWEN)| (1<<TWIE)|(1<<TWINT)| (1<<TWSTA);
an die Adresse0 des Puffers muss die Empfänger-Adresse des Slave(bei mir recipient)

wenn Du schreiben möchtest(MT), muss das LSB der Adresse 0 sein, wenn Du vom Slave lesen möchtest(MR) musst Du das LSB auf 1 setzten. Wenn das LSB schon auf 0 steht (bei recipient) reicht es wenn Du 1 dazu addierst.

Mit
TWCR = (1<<TWEN)| (1<<TWIE)|(1<<TWINT)| (1<<TWSTA);

wirfst Du dann die Maschinerie an. (Durch das setzen von TWSTA). Die ISR übernimmt dann den Rest.

Was jetzt aber wichtig ist: Dein Programm sollte jetzt in eine Warteschleife gehen(Zum testen am besten: while(1)). Dadurch das das ganze über eine ISR gelöst ist, läuft dein normales Programm während der Übertragung weiter. Wenn Du jetzt nochmal Anweisung gibst etwas über den TWI-Bus zu senden läuft Du auf einen Bus-fehler, weil mitten in der Übertragung z.B nochmal Start gesendet wird.

Ich muss mich nochmal umschauen, wie man das am besten löst. Irgendwo habe ich was in der Art gesehen, das man solange der Master nichts zu senden hat das TWIE-Flag auf 0 setzt. Zum senden muss es ja auf 1 gesetzt werden. Dann kann man mit TWCR & (1<<TWIE) abfragen ob momentan eine Sendung läuft, und z.B. etwas anderes machen, oder aber warten.

hoffe das hilft

Cu

Martin