www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik I2C mit PIC18F4680 als Slave


Autor: Philipp H. (phil1403)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute, ich versuche seit einigen Tagen das I2C im Master Slave 
Modus zu betreiben. Master = PIC18F4680 Nr.1 und Slave = PIC18F4680 
Nr.2. Den PIC als Master zu verwenden funktioniert! Aber der PIC als 
Slave -> funktioniert nur ansatzweise. Entweder kommt beim Daten 
einlesen kein BF (Buffer full) oder es wird kein SSPIF (Interrupt flag 
gesetzt) - obwohl meiner Meinung nach alle interrupts "enabled" sind. 
Kann mir da jemand helfen?! Wär echt super.

Hier die gesetzten Bits aus der main.c, auch wenn ich keine Interrupt 
Service Routine verwende. Die Flags müssten ja auch so auslesbar sein.
  RCONbits.IPEN = 1;        // for low and high priority interrupts
  INTCONbits.GIE = 1;       // Enables all high priority peripheral interrupts       
  INTCONbits.PEIE = 1;      // Enables all low priority peripheral interrupts
Hier mal meine I2C init Funktion:
#define SLAVE_ADDR   0x08    // Slave address
#define GENERAL_CALL 0x00    // Master can address all Slaves

void settingsI2C(void)
{
 /** \brief This function configure the I2C modul.                          \n
  *  For initialization of the I2C Port it is usefull to use the C18 Library function "OpenI2C()".   \n
  *  Furthermore you have to <b> pull up </b> the SDA and SCL pin, 2kOhm are sufficient! 
  */
  // Serial-PORTs ////////////////////////////////////////////////////////////////
  // begin: configuration according to Errata sheet ************//
  TRISCbits.TRISC3 = 0;        // set pins as Outputs
  TRISCbits.TRISC4 = 0;
  LATCbits.LATC3 = 0;          // force SDA and SCL low
  LATCbits.LATC4 = 0;
  // end: configuration according to Errata sheet ************//

  TRISCbits.TRISC3 = 1;        // Set SCL as input, the MSSP module will ensure that each pin is configured as an output when needed! (AppNote 989)
  TRISCbits.TRISC4 = 1;        // Set SDA as input  

  sync_mode = SLAVE_7;         // I2C slave mode, 7-bit address
  slew = SLEW_OFF;             // 100kHz 
  SSPADD = SLAVE_ADDR;         // in SLAVE mode = slave_x 7bit-address, x = 1...6 -> here Slave_1    
  OpenI2C(sync_mode,slew);     // initialize slave mode
  SSPCON1bits.SSPEN = 1;       // enables serial port pins SDA und SCL
  SSPCON1bits.CKP = 1;         // release clock
  SSPCON2bits.SEN = 1;         // clock stretch enable for slave transmit and receive mode
  SSPSTATbits.CKE = 0;         // SMBus specific inputs disabled = 0, enabled = 1
  PIE1bits.SSPIE = 1;          // Enable = 1 master synchronous serial port interrupt
  IPR1bits.SSPIP = 1;          // Set priority of interrupt to high = 1, low = 0
  SSPCON2bits.GCEN = 1;        // General call is enabled when = 1
//  IdleI2C();            // the NOTE1 in Datasheet, at page 199 give evidence to set the bus in idle state, but only the master have to do it so
}

Und hier die Funktion für das Einlesen der Daten:
unsigned char get_byte_I2C(void)
{
/** \brief This function read a byte from the I2C bus.            \n
 *  \var uint8 buffer transfer the value of SSPBUF-Register.        \n
 *  \return buffer is the returned value of SSPBUF.
 */
  uint8 buffer = 0;   
      
  if(!PIR1bits.SSPIF)              // When SSPIF = 0, interrupt still not occur
  {
      while (DataRdyI2C() = 0);    // wait until byte received, check the BF-bit (Buffer full),SSPSR is loaded into SSPBUF if BF = 1, receive complete (C18 Library function)
    buffer = SSPBUF;               // buffers the SSPBUF
  }      
return buffer;
}

Danke schon mal für eure Tipps, falls ihr welche habt. Irgendwo ist da 
noch ein Fehler drin.

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
while (DataRdyI2C() == 0);    // wait until byte received, check the

Autor: Philipp H. (phil1403)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke, hab ich glatt übersehen.

Autor: Philipp H. (phil1403)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
So nun hab ich gleich noch ein nächstes Problem nachdem das erste gelöst 
wurde. ;) Ich poste mal den Code hierher, auch wenn es bißchen viel 
wird.
Ich möchte zwischen den beiden besagten PICs eine bidirektionale 
Kommunikation herstellen. Das heißt, der Master sendet dem Slave das 
Start Kommando, dann die Adresse mit WRITE, dann 3Byte und ein Stop 
Signal, Als nächstes wird erneut ein Start Signal gesendet und wieder 
die Adresse, allerdings mit READ, danach hört einfach der Takt auf und 
die angeforderten Daten vom Slave werden nicht übernommen. Dieses 
Phänomen kann ich mir grad nicht erklären. Wie kann ich den Takt des 
Masters wieder aktivieren?
-> Ein Oszibild ist anbei.

Die Hauptfunktionen des Slave: In der main.c wird innerhalb der while 
Schleife die requestI2C() aufgerufen.

void requestI2C(void)
{
 /** \brief This function decide according to its variable status which case receive/transmit will used. \n
  *  \var uint8 status Transfer the value from function scanRWI2C() - check R/W bit.       
  */
  unsigned char status = 0;
  unsigned char read = 0;

  status = scanRWI2C();       // Returns the "mode" - communication Master -> Slave

  switch(status)              // If the slave is selected through "General Call" or "Slave Address" than do ...
  {  // case 1 means Slave is not selected by address
    case 1: 
        break;

    // case 2 means Slave is selected by address and Write Bit is set
    case 2:  while(!SSPSTATbits.P)    // As long as the stop condition for I2C transmission does not occur
        {
          read = getByteI2C();        // Read new byte from bus
          receiveDataI2C(read);       // Read "Identifier" 
        }
        break;

    // case 3 means Slave is selected by address and Read Bit is set
    case 3:  while(!SSPSTATbits.P)    // As long as the stop condition for I2C transmission does not occur
        {
          transmitDataI2C();          // Send the states of "MOSFET-Test" to Master 
        }
        break;
  }
}

void clearFlagsI2C(void)
{
  SSPCON1bits.SSPOV = 0;        // after reading the SSPBUF, the SSPOV bit properly clear an overflow condition
  PIR1bits.SSPIF = 0;           // Clear interrupt flag, to continiue communication
  SSPCON1bits.CKP = 1;          // Release clock, when = 1
}

unsigned char getByteI2C(void)
{
 /** \brief This function read a byte from the I2C bus.              \n
  *  \var uint8 buffer transfer the value of SSPBUF-Register.        \n
  *  \return buffer is the returned value of SSPBUF.
  */  
  uint8 bufSSPBUF = 0;
  
  while (!SSPSTATbits.BF);       // Wait until byte received, returns 1 if the BF bit is set, or 0 if not
     bufSSPBUF = SSPBUF;         // Save incoming byte
    clearFlagsI2C();  
return bufSSPBUF;
}

unsigned char transmitDataI2C(void)
{
 /** \brief This function write a byte to the bus (master).
  */  
   clearFlagsI2C();
   if(WriteI2C(0x33) == 0)        // 0 if acknowledge was received
   {
       clearFlagsI2C();
       return 1;
   }
   else
  return 0;  
}

Die Hauptroutine des Master wird ebenso innerhalb der while Schleife der 
main.c aufgerufen. Die Funktionen getByte und clearFlags sind die 
gleichen wie beim Slave.
So nun liegt der Fehler wahrscheinlich in der folgenden Funktion. Aber 
wo genau?
main()
{
  CloseI2C();                  // close i2c if was operating earlier
  sync_mode = MASTER;          // I2C Master mode, 7-bit address
  slew = SLEW_OFF;             // 100kHz  
  OpenI2C(sync_mode,slew);     // initialize master mode

  SSPADD = 0x60;  //64         // 100kHz Baud clock(3) @20MHz, Fcy=10MHz (0x18 wenn Fosc = 10MHz, 0x64 wenn Fosc = 40MHz)
  slave_adr = 0x10;            // initialize slave address, da /Bit, um eins nach links schieben
  readmode1 = (slave_adr & 0xFE);    // 0x00 = Write
  readmode2 = (slave_adr | 0x01);    // 0x01 = Read

  while(1)
  {  
    IdleI2C();      
    StartI2C();
    IdleI2C();
    if(WriteI2C(readmode1)== 0)    // write SLAVE Adress and write command
    {    
      if(WriteI2C(0x01) == 0)      // Send Identifier 1
      {
      //  clearFlagsI2C();
      } 
      if(WriteI2C(0x11) == 0)      // Send highbyte
      {
      //  clearFlagsI2C();
      }    
      if(WriteI2C(0x11) == 0)      // Send lowbyte
      {
      //  clearFlagsI2C();
      }
    }
    IdleI2C();
    //RestartI2C();
    StopI2C();
    IdleI2C();
    StartI2C();
    IdleI2C();
    if(WriteI2C(readmode2)== 0)    // Write SLAVE Adress and write command
    {  
/* Ab hier steigt der Master aus */
      uint8 bufSSPBUF = 0;
      clearFlagsI2C();
//      SSPCON2bits.RCEN = 1;      // Set master receive enable
//      while(!SSPCON2bits.RCEN)
      bufSSPBUF = ReadI2C();       // Read byte from bus
      clearFlagsI2C();
      AckI2C();                    // Master receive enable = 1 and ACKDT = 0 (acknowledge will be send)
      clearFlagsI2C();
    }
    IdleI2C();
    StopI2C();                     // Send the Stop condition
  } // while_end
}

Danke im voraus für diverse Tipps.

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.