I2C an AT90S8535 in C mit WinAVR

Gast #149280
Lesenswert?
• ▲
▼
Hi Leutz,

ich bin vor einiger Zeit auf den WinAVR umgestiegen (von CodeVision)
und breche mir mit dem I2C-Bus ganz schön einen ab.
Alle Beispiele, die ich bisher gefunden habe, waren nicht umzusetzen
:-(

Hat jemand eine in C geschriebene I2C-Routine (Start, Stop, Write,
Read), die er zur Verfügung stellen könnte ?

Vielen Dank!
Gast #149281
Lesenswert?
• ▲
▼
Vielleicht hilft das, war für ein ATmega161:

#define READ      0x01    // I2C READ bit

#define SCLPORT    PORTE
#define SDAPORT    PORTD

#define SCL      PE2
#define SDA      PD2

#define QDEL    delay(5)
#define HDEL    delay(10)

#define I2C_SDL_LO  cbi( SDAPORT, SDA)
#define I2C_SDL_HI  sbi( SDAPORT, SDA)

#define I2C_SCL_LO  cbi( SCLPORT, SCL);
#define I2C_SCL_HI  sbi( SCLPORT, SCL);


void i2ct(void)
{
  HDEL; I2C_SCL_HI; HDEL; I2C_SCL_LO;
}

void i2cstart(void)
{
  I2C_SDL_LO; QDEL; I2C_SCL_LO;
}

void i2cstop(void)
{
  HDEL; I2C_SCL_HI; QDEL; I2C_SDL_HI; HDEL;
}


#define I2C_SCL_TOGGLE  i2ct();
#define I2C_START       i2cstart();
#define I2C_STOP        i2cstop();



u16 i2c_putbyte(u08 b)
{
    s16 i;

  for (i=7;i>=0;i--)
  {
    if ( b & (1<<i) )
          I2C_SDL_HI;
        else
            I2C_SDL_LO;         // address bit
        I2C_SCL_TOGGLE;         // clock HI, delay, then LO
    }

    I2C_SDL_HI;                  // leave SDL HI

  // added
  cbi(SDAPORT-1, SDA);      // change direction to input on SDA line 
(may
not be needed)
  HDEL;
    I2C_SCL_HI;                     // clock back up
    b = inp(SDAPORT-2) & (1<<SDA);  // get the ACK bit
  HDEL;
    I2C_SCL_LO;            // not really ??
  sbi(SDAPORT-1, SDA);      // change direction back to output
  HDEL;
  //printf("put: %x\r\n",b);

    return (b == 0);              // return ACK value
}

u08 i2c_getbyte(u16 last)
{
    s16 i;
    u08 b = 0;
    u08 c = 0;

    I2C_SDL_HI;                  // make sure pullups are ativated
  cbi(DDRD, SDA);      // change direction to input on SDA line (may not 
be
needed)

    for (i=7;i>=0;i--)
  {
    HDEL;
        I2C_SCL_HI;                // clock HI
    c = bit_is_set(SDAPORT-2, SDA);
        b <<= 1;

        if (c)
            b |= 1;

    HDEL;
      I2C_SCL_LO;               // clock LO
    }
  sbi(DDRD, SDA);      // change direction to output on SDA line

    if (last)
      I2C_SDL_HI;                  // set NAK
    else
      I2C_SDL_LO;                  // set ACK

    I2C_SCL_TOGGLE;                // clock pulse
    I2C_SDL_HI;                  // leave with SDL HI

    return b;                  // return received byte
}
Gast #149284
Lesenswert?
• ▲
▼
Hi,

danke für die Hilfe.

Hatte schon mal ein Beispiel, wo sbi und cbi genutzt wurden, das kann
der WinAVR nicht compilieren.

Warum liegen sda und scl an Port D und E ? Hab nur Port D ;-)

Meine Leitungen liegen an:

 SDA  PORTD.6
 SCL  PORTD.7


------------------
Ein Beispiel habe ich geändert, und es lässt sich auch compilieren.
Leider läufts nicht bzw. bekomme ich es nicht zum laufen.

Vielleicht wird einer draus schlau ? Leider hab ich von I2C nicht
allzuviel Ahnung ;-)

/***************************************************
/ I2C-Library
/
/ Stellt I2C-Routinen für den MSP430F149 bereit. SDA
/ ist an Pin 47 angeschlossen, SCL an Pin 48. Wenn
/ ihr andere Ports benutzt , müsst ihr nur hier in
/ dieser Datei jeweils "P5OUT=..." passend ersetzen.
/ Die delay_ms()-Funktion befindet sich in der Datei
/ http://www.mathar.com/lcd.c.
/***************************************************/

//Pin 47 = SDA = P5.3 (0x08) = PORTD.6 = 0x40 (64)
//Pin 48 = SCL = P5.4 (0x10) = PORTD.7 = 0x80 (128)

//Pin-Table:
//0 1 2 4 8 16 32 64 128 256
//- 0 1 2 3 4  5  6  7    -


void SCL_low(void);
void SCL_high(void);
void SCL_clock(void);
void SDA_low(void);
void SDA_high(void);
void SDA_read(void);
void SDA_write(void);
void SCL_write(void);
void SCL_read(void);
void I2C_start(void);
void I2C_stop();
void I2C_init(char address, char r_w);
int I2C_gotACK(void);
void I2C_sendbyte(char byte);
double I2C_receivebyte(void);
void I2C_sendACK(void);

void SCL_low(void)                     // pin 48 (SCL) auf low setzen
{
  PORTD&=~0x80;
  delay_ms(1);                             // 1ms warten (rise time,
fall time usw.)
}

void SCL_high(void)                    // pin 48 (SCL) auf high setzen
{
  PORTD|=0x80;
  delay_ms(1);
}

void SCL_clock(void)
{
  SCL_high();
  SCL_low();
}

void SDA_low(void)                     // pin 47 (SDA) auf low setzen
{
  PORTD&=~0x40;
  delay_ms(1);
}

void SDA_high(void)                    // pin 47 (SDA) auf high setzen
{
  PORTD|=0x40;
  delay_ms(1);
}

void SDA_write(void)                   // pin 47 (SDA) auf output
setzen
{
  DDRD|=0x40;
}

void SDA_read(void)                    // pin 47 (SDA) auf input
setzen
{
  DDRD&=~0x40;
}

void SCL_write(void)                   // pin 48 (SCL) auf output
setzen
{
  DDRD|=0x80;
}

void SCL_read(void)                    // pin 48 (SCL) auf input
setzen
{
  DDRD&=~0x80;
}

void I2C_start(void)                   // I2C START condition auf den
bus senden
{
  SCL_write(); SDA_write(); SCL_low(); SDA_high(); SCL_high();
SDA_low(); SCL_low();
}

void I2C_init(char address, char r_w)  // I2C-device mit adresse
"address" lesend oder schreibend initialisieren
{
  char i;
  SDA_write();                         // sicherheitshalber erst mal
SDA und SCL auf write setzen
  SCL_write();
  SCL_low();                           // sicherheitshalber erst mal
SCL auf low setzen
  for (i=7; i>0; i--)                  // 7-bit-I2C-adresse senden
  {
    if (address&(1<<(i-1))) SDA_high(); else SDA_low();
    SCL_clock();
  }
  if (r_w=='r') SDA_high(); else SDA_low();
  SCL_clock();                         // 1 oder 0 senden (read oder
write)
}

int I2C_gotACK(void)                   // nachschauen, ob ein ACK vom
bus empfangen wurde
{
  char gotACK;
  SCL_write();
  SCL_low();                           // sicherheitshalber erst mal
SCL auf low setzen
  SDA_read();                          // sicherheitshalber erst mal
SDA auf read und SCL auf write setzen
  SCL_high();                          // jetzt SCL auf high setzen und
damit 9. clockpulse erzeugen
  if (!(PIND & 0x40)) gotACK=1; else gotACK=0;
  SCL_low();                           // jetzt SCL wieder auf low
setzen
  if (gotACK) return 1; else return 0;
}

void I2C_sendbyte(char byte)           // ein komplettes byte auf den
bus schicken
{
  char i;
  SDA_write();                         // sicherheitshalber erst mal
SDA und SCL auf write setzen
  SCL_write();
  SCL_low();                           // sicherheitshalber erst mal
SCL auf low setzen
  for (i=8; i>0; i--)
  {
    if (byte&(1<<(i-1))) SDA_high(); else SDA_low();
    SCL_clock();
  }
}

double I2C_receivebyte(void)           // ein komplettes byte vom bus
empfangen
{
  double byte=0;
  SCL_low();
  SDA_read();                          // sicherheitshalber erst mal
SCL auf low und SDA auf read setzen
  SCL_high(); if ((PIND&0x40)>>3) byte+=128; SCL_low();
  SCL_high(); if ((PIND&0x40)>>3) byte+=64; SCL_low();
  SCL_high(); if ((PIND&0x40)>>3) byte+=32; SCL_low();
  SCL_high(); if ((PIND&0x40)>>3) byte+=16; SCL_low();
  SCL_high(); if ((PIND&0x40)>>3) byte+=8; SCL_low();
  SCL_high(); if ((PIND&0x40)>>3) byte+=4; SCL_low();
  SCL_high(); if ((PIND&0x40)>>3) byte+=2; SCL_low();
  SCL_high(); if ((PIND&0x40)>>3) byte+=1; SCL_low();
  return byte;
}

void I2C_sendACK(void)                 // ACK auf den bus schicken
{
  SDA_low(); SDA_write(); SDA_low(); SCL_clock();
}

void I2C_stop()                        // I2C STOP condition auf den
bus senden
{
  SCL_write(); SCL_low(); SDA_write(); SDA_low(); SCL_high();
SDA_high();
}
Beitrag #5451874 wurde von einem Moderator gelöscht.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren