/***************************************************
/ 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 wait()-Funktion befindet sich in der Datei
/ http://www.mathar.com/lcd.c.
/***************************************************/

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_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
{
  P5OUT&=~0x10;
  wait(1);                             // 1ms warten (rise time, fall time usw.)
}

void SCL_high(void)                    // pin 48 (SCL) auf high setzen
{
  P5OUT|=0x10;
  wait(1);
}

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

void SDA_low(void)                     // pin 47 (SDA) auf low setzen
{
  P5OUT&=~0x08;
  wait(1);
}

void SDA_high(void)                    // pin 47 (SDA) auf high setzen
{
  P5OUT|=0x08;
  wait(1);
}

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

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

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

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

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 (!(P5IN & 0x08)) 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 ((P5IN&0x08)>>3) byte+=128; SCL_low();
  SCL_high(); if ((P5IN&0x08)>>3) byte+=64; SCL_low();
  SCL_high(); if ((P5IN&0x08)>>3) byte+=32; SCL_low();
  SCL_high(); if ((P5IN&0x08)>>3) byte+=16; SCL_low();
  SCL_high(); if ((P5IN&0x08)>>3) byte+=8; SCL_low();
  SCL_high(); if ((P5IN&0x08)>>3) byte+=4; SCL_low();
  SCL_high(); if ((P5IN&0x08)>>3) byte+=2; SCL_low();
  SCL_high(); if ((P5IN&0x08)>>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();
}

