mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik I2C-Anfänger


Autor: Maddin Sche (schrank)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute!

Möchte gerne mittels I2C eine Verbindung zwischen zwei Atmegas (16 und 
32) aufbauen. Leider klappt momentan gar nichts:
Für den Master hab ich die lib von Peter Fleury verwendet. Ich hab daran 
nichts verändern, sollte eigentlich so klappen.
Beim Slave bin ich mir da gar net sicher: Der Quellcode ist von 
Roboternetz (Überschrift: TWI Slave mit avr-gcc). Bin mir net sicher ob 
des so klappt...
Mein Problem besteht momentan einfach darin, dass ich zwei Unbekannte 
habe, was die Fehlersuche recht schwierig für mich gestaltet.


Hat hier irgendjemand eine einfache Routine für mich, mit dem ich zwei 
AVR´s mittels I2C kommunizieren lassen kann?Also eine für Master und 
eine für den Slave.



Vielen Dank!

Autor: Tobias Korrmann (kurzschluss81)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hast du an die Pullupwiderstände gedacht die du zwischen SDA (Daten) und 
VCC und CSL(Clock) und VCC schalten mußt?

Autor: Maddin Sche (schrank)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ja hab ich. wurden zu 2k2 dimensioniert.

Autor: Maddin Sche (schrank)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stelle mal meinen Quellcode online, vllt findet ja jemand den Fehler.
Nochmal ne genau Beschreibung was ich in diesem Testprogramm machen 
will:
Habe zwei PollinFunkBoards, die ich über ein IDE-Kabel 
zusammengeschalten habe. Am 3.Stecker des Kabels hab ich die Pullups 
reingeschalten (jeweils 2k2). Diese Boards haben am PortD Pin6 eine LED. 
Ich möchte jetzt dem Slave ein Byte schicken, welches diese LED 
einschaltet (also 0x01000000). Der Slave soll die Adresse 0x5 haben. Die 
Master Lib ist von peter Fleury. Die Slave lib von 
[[http://www.roboternetz.de/wissen/index.php/TWI_Sla...]] 
rauskopiert. Leider tut sichnach dem Hochladen auf den Controller gar 
nichts.

Hier mein Quellcode für den Master:
#include <avr/io.h>
#include "i2cmaster.h"
#define F_CPU 16000000UL
#include <util/delay.h>





int main(void)
{

     

     i2c_init();                             // initialize I2C library

   while(1)
   {

   i2c_start_wait(0b1010);     /*101 für Adresse 5 und der letzte Nuller für schreiben*/
     i2c_write(0x01);       /*Bufferadresse: möchte in rxbuffer[1] des Slaves schreiben*/
                    
     i2c_write(0b01000000);                        /*Schreibe 0b01000000 in rxbuffer[1],also Pin 6 wird gesetzt*/
     i2c_stop();
    } 

/*Ablauf so korrekt???*/

}

Hier die Routine für den Slave
#include <avr/io.h>
#include "twislave.h" /*Im Beispiel von Roboternetz als "twislave.c" eingebunden, bringt aber Fehler beim Compilieren*/
#define F_CPU 16000000UL
#include <util/delay.h>





int main()
{
DDRD=0b11111111;
init_twi_slave (0b101);/*Slave Adressse soll 0x5 sein*/



while(1)
{

PORTD=rxbuffer[1];/*Soll LED einschalten, die sich am PIND6 befindet*/
}

return 0;

}

Findet hier jemand einen Fehler!
Wäre echt super, wenn mir jemandhelfen würde, bin am verzweifeln!!

Vielen Dank!

Autor: Maddin Sche (schrank)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Keiner der mir weiter helfen kann?
Was ich bis jetzt rausgefunden habe:
Die Interruptroutine des Slaves wird nicht aufgerufen. Hab da einen 
Befehl für ne angeschlossene LED reingetan und LED leuchtet zu keinem 
Zeitpunkt.
Außderdem ist mir ein vermeindlicher Fehler bei der Slave lib 
aufgefallen:
TWAR= adr; laut Datenblatt darf das LSB aber nicht für die Adresse 
benutzt werden. Hab das umgeändert in: TWAR= (adr<<1);
trotzdem kein Erfolg:)

Autor: Otto (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Hier die Routine für den Slave

wenn das alles an Programm ist, kann der Slave nicht funktionieren.....

Wahrscheinlich hast Du zu wenig von der "Slave lib " kopiert.

Otto

Autor: Maddin Sche (schrank)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
da hast du natürlich recht, dass das nicht alles ist:
ich hab beim slave hier eine twislave.h mit eingebunden in die ich den 
Code von roboternetz (siehe link oben) kopiert habe

Autor: Maddin Sche (schrank)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier mal die Routine für den Slave:
#ifndef _TWISLAVE_H
#define _TWISLAVE_H

#include <util/twi.h> //enthält z.B. die Bezeichnungen für die Statuscodes in TWSR
#include <avr/interrupt.h> //dient zur behandlung der Interrupts
#include <stdint.h> //definiert den Datentyp uint8_t
 



//%%%%%%%% von Benutzer konfigurierbare Einstellungen %%%%%%%%

#define buffer_size 8 //Größe der Buffer in Byte (2..254)


//%%%%%%%% 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! %%%%%%%%//
//____________________________________________________________________________________//

#include <util/twi.h> //enthält z.B. die Bezeichnungen für die Statuscodes in TWSR


//Bei zu alten AVR-GCC-Versionen werden die Interrupts anders genutzt, daher in diesem Fall mit Fehlermeldung abbrechen
#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304
  #error "This library requires AVR-GCC 3.4.5 or later, update to newer AVR-GCC compiler !"
#endif

//Schutz vor unsinnigen Buffergrößen
#if (buffer_size > 254)
  #error Buffer zu groß gewählt! Maximal 254 Bytes erlaubt.
#endif

#if (buffer_size < 2)
  #error Buffer muss mindestens zwei Byte groß sein!
#endif


volatile 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. vermeindlicher Bug!!! Bit0 ist nicht Bestandteil der Adresse!!**/
  TWAR= (adr<<1);
  TWCR &= ~(1<<TWSTA)|(1<<TWSTO);
  TWCR|= (1<<TWEA) | (1<<TWEN)|(1<<TWIE);   
  buffer_adr=0xFF;  
  sei();
  
}


//Je nach Statuscode in TWSR müssen verschiedene Bitmuster in TWCR geschreiben werden(siehe Tabellen im Datenblatt!). 
//Makros für die verwendeten Bitmuster:

//ACK nach empfangenen Daten senden/ ACK nach gesendeten Daten erwarten
#define TWCR_ACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|(0<<TWWC);  
//NACK nach empfangenen Daten senden/ NACK nach gesendeten Daten erwarten     
#define TWCR_NACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|(0<<TWWC);
//switched to the non adressed slave mode...
#define TWCR_RESET TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|(0<<TWWC);  

//Die Bitmuster für TWCR_ACK und TWCR_RESET sind gleich. Dies ist kein Fehler und dient nur der Übersicht!


/*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;
PORTD=32;/*Test: rechte LED sollte leuchten*/


switch (TW_STATUS) //TWI-Statusregister prüfen und nötige Aktion bestimmen 
{

case TW_SR_SLA_ACK: // 0x60 Slave Receiver, wurde adressiert  
  TWCR_ACK; // nächstes Datenbyte empfangen, ACK danach
  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
    {
      
      //Kontrolle ob gewünschte Adresse im erlaubten bereich
      if(data<=buffer_size)
        {
          buffer_adr= data; //Bufferposition wie adressiert setzen
        }
      else
        {
        buffer_adr=0; //Adresse auf Null setzen. Ist das sinnvoll?
        }        
      TWCR_ACK;  // nächstes Datenbyte empfangen, ACK danach, um nächstes Byte anzufordern
    }
  else //weiterer Zugriff, Daten empfangen
    {
      rxbuffer[buffer_adr]=data; //Daten in Buffer schreiben
      buffer_adr++; //Buffer-Adresse weiterzählen für nächsten Schreibzugriff
      if(buffer_adr<(buffer_size-1)) //im Buffer ist noch Platz für mehr als ein Byte
        {
          TWCR_ACK;// nächstes Datenbyte empfangen, ACK danach, um nächstes Byte anzufordern
        }
      else   //es kann nur noch ein Byte kommen, dann ist der Buffer voll
        {
          TWCR_NACK;//letztes Byte lesen, dann NACK, um vollen Buffer zu signaliseren
        }
    }
break;

case TW_ST_SLA_ACK: //?!?
case TW_ST_DATA_ACK: //0xB8 Slave Transmitter, weitere Daten wurden angefordert

  if (buffer_adr == 0xFF) //zuvor keine Leseadresse angegeben! 
    {
      buffer_adr=0;
    }  
  TWDR = txbuffer[buffer_adr]; //Datenbyte senden 
  buffer_adr++; //bufferadresse für nächstes Byte weiterzählen
  if(buffer_adr<(buffer_size-1)) //im Buffer ist mehr als ein Byte, das gesendet werden kann
    {
      TWCR_ACK; //nächstes Byte senden, danach ACK erwarten
    }
  else
    {
      TWCR_NACK; //letztes Byte senden, danach NACK erwarten
    }
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:   
    TWCR_RESET; //Übertragung beenden, warten bis zur nächsten Adressierung
break;

  
} //end.switch (TW_STATUS)
} //end.ISR(TWI_vect)


#endif //#ifdef _TWISLAVE_H
////Ende von twislave.c////


Autor: Maddin Sche (schrank)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alles was ich benötige ist eine Funktionierendes Beispiel um 2 uC per 
I2C kommunizieren zu lassen....
Man hört von i2c sehr viel interessante Sachen, gerade im 
Roboterbereich, aber funktionierende Routinen findet man (ich) nicht:(

Autor: Otto (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Doch - in der Codesammlung - das Assemblerbeispiel z. B. funktioniert 
einwandfrei.

Das C-Besipiel: Beitrag "AVR TWI Master und Slave Funtionen in C" habe ich 
nicht getestet.

Evtl. versuchst Du es mal damit.

Gruss Otto

Autor: Maddin Sche (schrank)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Assembler möcht ich nicht nehmen, da ich neben dem Bus noch viele 
weitere Funktionen implemetieren muss.Aber Danke schön!

Im Moment kenn ich mich gar nimmer aus:
Dein vorgeschlagenes Beispiel, löst das den ein Interrupt beim Slave 
aus?





Die Verzweiflung zwingt mich jetzt ins Bett, vllt versteh ich morgen 
früh wieder mehr.

Trotzdem vielen Dank!

Autor: Otto (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du schriebst, dass Du keine Beispiele findest. Daher der Hinweis auf die 
Codesammlung. Evtl. vergleichst Du den anderen Slave mit Deinem, um den 
Fehler einzugrenzen.

Die Slave-Adresse 0x5 ist mir persönlich ein wenig suspekt.

Otto

Autor: Maddin Sche (schrank)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bin jetzt einen kleinen Schritt weitergekommen:
Der Befehl "i2c_start_wait()" wartet ja anscheinend solange, bis sich 
der anzusprechende Slave meldet.
ich hab nach diesem Befehl eine Portausgabe gemacht und eine LED 
angesprochen. Diese leuchtet auch tatsächlich, wenn ich die richtige 
Adresse eingeben (aber auch wenn falsche adresse und sehr oft reset bei 
master und slave, wohl aber eher dann ein zufälliges verhalten).
Das heißt also: Der Slave reagiert schon. Nur die interruptroutine wird 
immer noch nicht aufgerufen...??

Welche Bedingungen müssen eigentlich herrschen, damit diese aufgerufen 
wird? Ausm Datenblatt werd ich momentan net schlau .



Vielen Dank!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.