Forum: Mikrocontroller und Digitale Elektronik I2C mit software


von Schorschi (Gast)


Lesenswert?

Hi,

Ich versuche seit stunden einen I2C - Bus per Software zu emulieren.

Irgendwie klappt es aber nicht. Ich möchte ein I2C EEPROM Lesen und
Schreiben.

Kann mit jemand etwas helfen.


Gruss und Danke,
Schorschi.

von Dom (Gast)


Lesenswert?

Ohne, dass du deinen Code hier postest geht das Helfen wohl schlecht.

Dom

von Stephan Schwarz (Gast)


Lesenswert?

seit Stunden?? also, wenn das dann schon funktionieren würde, könntest
du dich aber auch schon glücklich schätzen.
Wenn du geschreiben hättest "seit Tagen"  dann wäre das was anderes.
Schreibst du die Tools dafür selber?
oder nimmst du fertige?

von edi.edi (Gast)


Lesenswert?

mit einer floete ?,einem pc ?,einem avr ?,einem'51...?

von Ingo Henze (Gast)


Lesenswert?

Flöte ist gar nich mal so abwegig, gibt es zwar nicht mit I2C, aber mit
MIDI, was ja auch ein serielles Protokoll ist.

von Schorschi (Gast)


Lesenswert?

Hi,

klar ich sollte ja natürlich auch etwas info geben.

Ich verwende nen PIC16LF873A  (XTAL 4MHz) und ein 128Bit EEPROM von
Microchip und nen C-Kompiler.

Der PIC hat zwas nen hardware i2c aber da hab ich die SPI schon für was
anderes misbraucht.

zu meinem code.
Ich habe einige funktionen geschrieben mit denen ich mit übergabe von
Adresse und Daten einfach auf das EEprom zugreifen kann. Aber irgendwie
funzt das net.

hie der code:

//------------------------------------------------------------
// pause
//------------------------------------------------------------
void pause(void)
{
  SDA=0;
  SCL=0;
}

//------------------------------------------------------------
// EEPROM STOP Sequenz
//------------------------------------------------------------
void ESTOP(void)
{
  TSCL = 0;
  TSDA = 0;
  TSCL = 1;
  TSDA = 1;
}


//------------------------------------------------------------
// EEPROM START Sequenz
//------------------------------------------------------------
void ESTART(void)
{
  ESTOP(); //Zuerst stop sequenz senden da sonst kein start möglich
  TSCL = 0;
  TSDA = 0;
}

//------------------------------------------------------------
// Schreibe char an EEPROM
//------------------------------------------------------------
void WCHAREE(char var)
{char u, hvar0=0x80;

 for(u=0; u<8; u++)
 {
    if(var&&(hvar0>>u)) //Bit ist High
    {
      TSDA=1;
  }
    else //Bit ist low
    {
      TSDA=0;
    }
     TSCL=1;
     TSCL=0;
     pause();
 }

}

//------------------------------------------------------------
// Liest char aus EEPROM
//------------------------------------------------------------
char RCHAREE(void)
{char o, hvar1=0;
 TSDA = 1; //Auf eingang schalten

 for(o=0; o<8; o++) //holen von 8bit
 {
  TSCL=1;
  if(SDA == 1)
  {
   hvar1|= 0x01;
  }
  TSCL=0;

  hvar1<<1;
  pause();
 }

 TSCL=1;
 TSCL=0;
 return hvar1;

}

//------------------------------------------------------------
// EEPROM schreibbefehl
//------------------------------------------------------------
char EWRITE(void)
{
  WCHAREE(EWR); //Schreibbefehl senden

  //Acknowledge
  TSDA = 1; //Eingang
  TSCL = 1; //Nächster takt

  if (SDA == 1) //kein aknowledge
  {
   return 0;
  }
  else //aknowledge
  {
   return 1;
  }

}

//------------------------------------------------------------
// EEPROM lesebefehl
//------------------------------------------------------------
char EREAD(void)
{
  WCHAREE(ERD); //Schreibbefehl senden

  //Acknowledge
  TSDA = 1; //Eingang
  TSCL = 1; //Nächster takt

  if (SDA == 1) //kein aknowledge
  {
   return 0;
  }
  else //aknowledge
  {
   return 1;
  }

}

//------------------------------------------------------------
// Schreibe EEPROM mit übergabe der Adresse
//------------------------------------------------------------
char WEEPROM(char addr, char data)
{ char ACK=0;

  ESTART(); //Übertragung Starten
  ACK = EWRITE();//Schreibbefehl senden

  if (ACK == 1)//Acknowledge erhalten
  {
   WCHAREE(addr); //Adresse an EEPROM Schreiben

   //Acknowledge
   TSDA = 1; //Eingang
   TSCL = 1; //Nächster takt

   if (SDA == 1) //kein aknowledge
   {
    return 2;
   }
   else //aknowledge sende daten
   {
    WCHAREE(data); //sende daten

    //Acknowledge
    TSDA = 1; //Eingang
    TSCL = 1; //Nächster takt

    //Acknowledge
    if(SDA=1)
    {
     ESTOP(); //Übertragung beenden
     return 3;//Kein ack
    }
    else
    {
     ESTOP(); //Übertragung beenden
     return 1; //Ack
    }
   }

  }
  else
  {
   ESTOP(); //Übertragung beenden
   return 4; //Kein ack
  }

}




//------------------------------------------------------------
// Lese EEPROM mit übergabe der Adresse
//------------------------------------------------------------
char REEPROM(char addr)
{ char ACK, data;

  ESTART(); //Übertragung starten
  ACK=EWRITE();//schreibbefehl

  if (ACK == 1)//Acknowledge erhalten
  {
    WCHAREE(addr+1); //Schreibe zu lesende adresse

   //Acknowledge
   TSDA = 1; //Eingang
   TSCL = 1; //Nächster takt

   if (SDA == 1) //kein aknowledge
   {
    ESTOP();
    return 0;
   }
   else
   {
    ESTART(); //Übertragung starten
    ACK=EREAD(); //Lesebefehl senden

    //Acknowledge
    TSDA = 1; //Eingang
    TSCL = 1; //Nächster takt

    if (SDA == 1) //kein aknowledge
    {
     ESTOP();
     return 0;
    }
    else
    {
      data = RCHAREE();
      ESTOP();
      return data;
    }
   }

  }
  else //keine Acknowledge
  {
   ESTOP(); //Übertragung stoppen
   return 0;
  }


}

Mit den Funktionen REEPROM und WEEPROM möchte ich auf das EEprom
zugreifen.

Danke für eure Hilfe,

Gruss Schorschi.

von Peter D. (peda)


Lesenswert?

Irgendwie vermisse ich sämtliche Wartezeiten in Deinem Code.

Anbei mal meine Routine:

http://www.specs.de/users/danni/appl/soft/c51/eeprom/eeprom.c51

Ist zwar für den 8051, aber da es in C ist, kann man es leicht auf den
PIC anpassen. Der Hauptunterschied ist, daß beim 8051 die
Richtungsumschaltung entfällt, da er bereits open-drain Ausgänge hat.

Ich benutze Page-Write und -Read, d.h. es wird ein ganzer Block an
Bytes geschrieben bzw. gelesen. Und nach dem Schreiben einer Page
erfolgt ein Ready-Polling, um das Schreibende zu erkennen.

Für den 24C128 muß auch noch ein Adreßbyte mehr gesendet werden, als
für den 24C16.


Peter

von Schorschi (Gast)


Lesenswert?

Hi,

danke für eure hilfe aber ich komme da irgendwie nicht weiter.
Habe auch schon dass eeprom gewechselt. Daran kann es nicht liegen.

ich habe jetzt die funktionen vereinfacht. eifach zeile für zeile
programmiert.

aber irgendwie funzt es noch nicht.

sieht einer von euch da nen fehler drin:

//------------------------------------------------------------
// pause
//------------------------------------------------------------
void pause(void)
{
  SDA=0;
  SCK=0;
}

//------------------------------------------------------------
// Schreibe EEPROM mit übergabe der Adresse
//------------------------------------------------------------
void WEEPROM(void)
{
  TSCK=1;    // auf eingang schalten
  TSDA=1;    // auf eingang schalten
  SCK=0;
  SDA=0;

  TSDA=0;    // start signal
  pause();

  TSCK=0;
  pause();
  TSDA=1;    // bit 7  Schreibbefehl
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 6
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=1;    // bit 5
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 4
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 3
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 2
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 1
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 0
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=1;    // release Data line
  pause();
  TSCK=1;
  pause();  // hier kommt acknowledge von EEPROM
  TSCK=0;
  pause();  // ----------------------------------

  TSDA=0;    // bit 7 Adresse
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 6
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 5
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 4
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 3
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 2
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 1
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=1;    // bit 0
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=1;    // release Data line
  pause();
  TSCK=1;
  pause();  // hier kommt acknowledge von EEPROM
  TSCK=0;
  pause();  // ----------------------------------

  TSDA=1;    // bit 7  DAten
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=1;    // bit 6
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 5
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 4
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=1;    // bit 3
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=1;    // bit 2
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 1
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 0
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=1;    // release Data line
  pause();
  TSCK=1;
  pause();  // hier kommt acknowledge von EEPROM
  TSCK=0;
  pause();  // ----------------------------------


  TSDA=0;
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSCK=1;
  pause();
  TSDA=1;    // stop condition!
}




//------------------------------------------------------------
// Lese EEPROM mit übergabe der Adresse
//------------------------------------------------------------
char REEPROM(void)
{
  unsigned char result;
  TSCK=1;    // auf eingang schalten
  TSDA=1;    // auf eingang schalten
  SCK=0;
  SDA=0;

  TSDA=0;    // start signal
  pause();

  TSCK=0;
  pause();
  TSDA=1;    // bit 7  Schreibbefehl
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 6
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=1;    // bit 5
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 4
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 3
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 2
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 1
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 0
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=1;    // release Data line
  pause();
  TSCK=1;
  pause();  // hier kommt acknowledge von EEPROM
  TSCK=0;
  pause();  // ----------------------------------

  TSDA=0;    // bit 7  Adresse
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 6
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 5
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 4
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 3
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 2
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=1;    // bit 1
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 0
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=1;    // release Data line
  pause();
  TSCK=1;
  pause();  // hier kommt acknowledge von EEPROM
  TSCK=0;

  TSCK=1;
  pause();
  TSCK=0;
  pause();

  TSCK=1;
  pause();  // ----------------------------------
  TSDA=0;    // repeated start

  pause();
  TSCK=0;
  pause();
  TSDA=1;    // bit 7 Lesebefehl
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 6
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=1;    // bit 5
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 4
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 3
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 2
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=0;    // bit 1
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=1;    // bit 0
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSDA=1;    // release Data line
  pause();
  TSCK=1;
  pause();  // hier kommt acknowledge von EEPROM
  TSCK=0;
  pause();  // ----------------------------------
  TSCK=1;
  if  (SDA) result=0b10000000; else result=0;
  TSCK=0;
  pause();
  TSCK=1;
  if  (SDA) result=result|0b01000000; else result=result;
  TSCK=0;
  pause();
  TSCK=1;
  if  (SDA) result=result|0b00100000; else result=result;
  TSCK=0;
  pause();
  TSCK=1;
  if  (SDA) result=result|0b00010000; else result=result;
  TSCK=0;
  pause();
  TSCK=1;
  if  (SDA) result=result|0b00001000; else result=result;
  TSCK=0;
  pause();
  TSCK=1;
  if  (SDA) result=result|0b00000100; else result=result;
  TSCK=0;
  pause();
  TSCK=1;
  if  (SDA) result=result|0b00000010; else result=result;
  TSCK=0;
  pause();
  TSCK=1;
  if  (SDA) result=result|0b00000001; else result=result;
  TSCK=0;
  pause();

  TSDA=0;
  pause();
  TSCK=1;
  pause();
  TSCK=0;
  pause();
  TSCK=1;
  pause();
  TSDA=1;    // stop condition!

  return  result;
}


danke und gruss,
schorschi.

von Werner (Gast)


Lesenswert?

Kannst Du Dir bitte mal angewöhnen, den Quelltext als Attachment
anzuhängen und nicht direkt rein zu kopieren.

von Schorschi (Gast)


Lesenswert?

Ohh.

sorry. werde ich in zukunft machen.

danke.

von Schorschi (Gast)


Lesenswert?

Hallo,

hat denn keiner nen tip für mich.

am oszi sehen die signale richtig aus.
soweit ich es interpretieren kann.

bitte helft mit ich weiss nicht mehr weiter.

gruss und danke,
schorschi.

von thkais (Gast)


Lesenswert?

Hast Du schonmal gecheckt, ob nach dem 1. Byte (Adressierung des Chip)
auch schon ein Acknowledge kommt? Falls nicht, dann stimmt schon etwas
mit der Adresse nicht.

von Schorschi (Gast)


Lesenswert?

Hi,

ein aknowledge hab ich.

beim lesen zumidest.

aber das schreiben funzt nicht.

von Schorschi (Gast)


Lesenswert?

Hallo,

jetzt habe ich mal wieder zeit gehabt und hab einfach etwas
rumprobiert.

nun habe ich folgendes problem.

wenn ich den startbefehl und daraufhin den lesebefehl sende,
bekomme ich ein ACK.

wenn ich aber den startbefehl und daraufhin den schreibbefehl sende,

bekomme ich kein ACK.

Ich verstehe nur nicht warum???

Hat einer da einen Tipp für mich??

Gruss georg.

von Schorschi (Gast)


Lesenswert?

Hallo,

jetzt habe ich zwas ACK's aber wenn ich das eeprom auslese kommt immer
noch das gleiche 0xFF raus.

Ich kapier garnichts mehr....

Kann denn keiner mir helfen??

gruss und danke,
Georg

von Stefan Noll (Gast)


Lesenswert?

Hi!

Wenn du einen 4Mhz Controller hast dann dürfte doch deine
Pausenfunktion

void pause(void)
{
  SDA=0;
  SCL=0;
}

nur so zwei bis acht Takte brauchen. Der I2C Bus hat aber glaube ich
eine maximale Taktrate von 100khz, da kommt dein EEProm nicht so ganz
mit. Die beiden Leitungen auf 0 zu setzen brauchst du glaube ich auch
nicht. Wie du am besten eine Pause einfügst kann ich dir leider nicht
sagen, bis jetzt hab ich den I2C Bus nur per PC & CControl gesteuert,
aber so 40-100 nops müssten reichen :-)

Viele Grüße
Stefan Noll

von Schorschi (Gast)


Lesenswert?

hi,

danke für die antwort.

ich habe die pausen auch schon mit ner for - schleife verlängert bringt
auch nichts.

ich habe ja die ack's aber der ausgelesene bzw. geschriebene wert
passt nicht.


gruss und danke,

Georg.

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
Noch kein Account? Hier anmelden.