www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik 12 Bit ADC Board - I2C TWI


Autor: Martin J. (bluematrix) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
12Bit ADC Board - MAX1238

Hab mir vor einiger Zeit einen ADC benötigt, den man relativ schnell 
über I2C abfragen kann. Außerdem sollte dieser eine Auflösung von 
mindestens 10 bis 12 Bit besitzen. Dabei bin ich auf den MAX1238 (12Bit) 
und MAX1138 (10Bit)gestoßen. Zum Testen hab ich mir kleine Boards für 
die Chips gebaut.

Das Entwicklungs Board besteht aus dem analog digital Converter Chip 
MAX1238 der Firma Maxim 
(http://www.maxim-ic.com/datasheet/index.mvp/id/3271)

* 12Bit ADC
* 12-Channel Single-Ended or 6-Channel Fully Differential
* High-Speed I²C-Compatible Serial Interface
    o 400kHz Fast Mode
    o 1.7MHz High-Speed Mode
* Internal Reference 4.096V
* External Reference: 1V to VDD
* Low Power
    o 670µA at 94.4ksps
    o 230µA at 40ksps
    o 60µA at 10ksps
    o 6µA at 1ksps
    o 0.5µA in Power-Down Mode

Der Chip ist sehr einfach anzusteuern und besitzt verschiedene 
Betriebsmodi (Single-Ended und Fully Differential).

mehr Infos 
hier:http://www.jtronics.de/elektronik-boards/adc-12bit...

Beispiel für die Ansteuerung im Modus Single-Ended und externer 
Referenzspannung an Pin Ref.
Benutzt wurde die I2C/TWI Lib von peter fleury

Der 12Bit Wert wird vom Max1238 über mit 2 Nachrichten zu je 1 Byte 
gesendet. Nachteilig hierbei ist, dass der Max1238 die ungenutzen Bit 
Stellen mit 1 auffüllt.

//############ Adresse MAX1238
#define Adr_MAX1238  0b01101010

Data_Array_Messwert[11];

//############ init MAX1238 via I2C
void ADC_MAX1238_init(void)
{
i2c_start_wait(Adr_MAX1238+I2C_WRITE);   // device address & write mode
i2c_write(0b10100010);                   // write Register
i2c_write(0b00010111);                   // write Register
i2c_stop();                              // stop i2c
}

//############ auslesen MAX1238 via I2C
void ADC_MAX1238(void)
{
uint8_t    hig,low ;                      // hight und Low Byte

i2c_start_wait(Adr_MAX1238+I2C_READ);     // device address & read mode
for (uint8_t i=0; i<=10; i++)             // alle 10 Kanäle auslesen
    {
    low  = i2c_read(1);    low &= ~((1 << 7) | (1<<6)| (1<<5)| (1<<4) );
    hig  = i2c_read(1);    Data_Array_Messwert[i]= ((low << 8)| hig);
    }
i2c_stop();
}


Grüße martin

Autor: Martin J. (bluematrix) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
noch paar bilder

Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich versuche mich gerade an dem Max1238. Leider bekomme ich beim 
auslesen immer für das Highbyte 15 und für das Lowbyte 255 übermittelt.
Andere I2C Bausteine wie z.B. PCF8574 oder 24LC512 funktionieren 
einwandfrei.
Ich kann mir nicht erklären, warum der hier nicht so will wie ich es 
gerne hätte. Hat da jemand evtl. eine Idee?

Ich hänge mal die Routine an:

//***Aufruf der Funktion in main.c****
//**Konfiguration
Max1238out(0B10100010);
Max1238out(0B00000111);

//lesen des Istwert in main.c
ADWandler[i] = Max1238in();

//Max1238 schreiben
unsigned char Max1238out (unsigned char adr){

  starti2c();
  sendbytei2c(0b01101000);
  sendbytei2c(adr);  //Configuration Byte
  stopi2c();
}

//Max1238 lesen
unsigned char Max1238in (void){
  unsigned char daten, daten2;

  starti2c();
  sendbytei2c(0b01101101);

  for (i=0; i<=10; i++){

  daten = readbyteI2C(1);  //Lowbyte

  daten &= ~((1 << 7) | (1<<6)| (1<<5)| (1<<4) );

  daten2 = readbyteI2C(1);  //Highbyte

  ADWandler[i]= ((daten << 8)| daten2);
  }

  stopi2c();
}

Autor: Martin J. (bluematrix) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die fragen beantworten sich mit dem Code-Beispiel weiter oben ...
Das Beispiel funktioniert einwandfrei

Autor: Martin J. (bluematrix) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
//####################################### I2C  
i2c_init();

//####################################### init MAX1238 via I2C
if(i2c_start(Adr_MAX1238+I2C_WRITE))     
{
i2c_stop();  // failed to issue start condition, possibly no device found
}

else         // issuing start condition ok, device accessible
{  
i2c_write(0b10100010); // write address = 5
i2c_write(0b00010111); // write value 0x75 to EEPROM
i2c_stop(); 
}


//####################################### messen_adc MAX1238
void I2C_ADC_MAX1238(void)
{
uint8_t   hig,low = 0;  // hight und Low auslese Variable für uniq
uint16_t dummy   = 0;   

//############# I2C  MAX1238 - 12Bit ADC
if (i2c_start(Adr_MAX1238+I2C_READ)) 
{
i2c_stop(); // failed to issue start condition, possibly no device found
}

else       // issuing start condition ok, device accessible
{  
 for (uint8_t i=0; i<=10;i++)  
 {
  low  = i2c_read(1);  low &= ~((1 << 7) | (1<<6)| (1<<5)| (1<<4) );
  hig  = i2c_read(1);  dummy = ((low << 8)| hig); 

  //###### umrechnen in mV [ADC*VREF= Vin*Auflösung]
  //dummy = dummy*1.221001221;

  //###### Ausgabe
  uart1_puts("Kanal-");            // send string  
  if(i<10) uart1_puts(" ");        // send string  

  itoa( dummy , buffer, 10);       // interger to string & send  
  uart1_puts(buffer);              // send
  uart1_puts(": ");            // send string  

  if(dummy<10)   uart1_puts(" "); // send string  
  if(dummy<100)   uart1_puts(" "); // send string  
  if(dummy<1000)   uart1_puts(" "); // send string  

  itoa( dummy , buffer, 10);       // interger to string & send  
  uart1_puts(buffer);              // send  
  uart1_puts(" mV\r");      // send string  
 }
 i2c_stop();
}

}


Autor: Martin J. (bluematrix) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
den code hab ich grad aus einem laufenden Programm genommen.
Der I2C Bus wird mit der fleury i2C lib betrieben.

Grüße martin

Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

meine Routine funktioniert ja auch, allerdings nur mit all den anderen 
I2C Bausteinen. Der AD Wandler will allerdings nicht und ich habe keine 
Idee warum nicht.

Wäre also ein feiner Zug, wenn sich das mal jemand anschauen könnte und 
mir sagen an was es liegen könnte.

Ich füge einfach noch mal die eigentliche I2C Routine ein.

#define iic_sda_d pd3_0   /* 1=Ausgang, 0=Eingang */
#define iic_sda   p3_0
#define iic_scl_d pd3_3
#define iic_scl   p3_3

#define TRUE 1
#define FALSE 0

void sdah(void)       { iic_sda = 1;  }
void sdal(void)       { iic_sda = 0;  }
void sclh(void)       { iic_scl = 1;  }
void scll(void)       { iic_scl = 0;  }
void starti2c(void)   { sdal(); scll(); }
void stopi2c(void)    {  sdal(); sclh(); sdah(); }
void restarti2c(void) { sdah(); sclh(); starti2c(); }
void I2C_init(void)   { prc2=1;
                        iic_sda_d = 1;
                        prc2=1;
                        iic_scl_d = 1;
                        starti2c();
                        stopi2c(); }

unsigned char sdain(void)
{ unsigned char dummy=0;

   //prc2=1;
   iic_sda_d=0;
   dummy = iic_sda;
   //prc2=1;
   iic_sda_d=1;
   return(dummy);
}

/* Ab hier sind die Funktionen nicht mehr Hardwareabhaengig! */

/* Gibt ein Byte ber den I2C-Bus aus, war das erfolgreich, wurde */
/* dieses Byte also von einem der ICs am Bus akzeptiert, dann     */
/* liefert diese Funktion ein TRUE zurck.                        */

unsigned char sendbytei2c(unsigned char daten)
{
  short x;  unsigned char dummy;


  for (x=7;x>=0;x--)
   {
    if (daten & 0x80)    /* Die acht Datenbits ausgeben */
    sdah();
      else   sdal();
    daten =  daten  << 1  ;     /* Ein Bit nach links schieben */
   sclh(); scll();      /* Zum n„chsten Bit takten */
   }
   sdah();      /* SDA zum Eingang umschalten */
   sclh();      /* Ack aus Slave takten */
   dummy=sdain();    /* ACK lesen */
   scll();
   if (dummy==FALSE) return (TRUE); else return (FALSE);
}

/* Liesst ein Byte vom I2C-Bus, es wird ausserdem das ack-bit erwartet 
*/
/* Diese ACK-Bit muss immer TRUE sein, es sei denn es wird das letzte 
*/
/* Datenwort von einem Device gelesen, dann muss es FALSE sein. 
*/

unsigned char readbyteI2C(unsigned char ack)
{ short x;  unsigned char dummy;

  dummy=0;
  sdah();
  for (x=7;x>=0;x--)
   { sclh();
     dummy=dummy << 1;
     if (sdain()==TRUE) dummy=dummy|(unsigned char)0x01;
     scll();
   }
  if (ack==TRUE) sdal(); else sdah();
  sclh();
  scll();
  return(dummy);
}

//Max1238 schreiben
unsigned char Max1238out (void){

  starti2c();
  sendbytei2c(0b01101010);  //Adresse
  sendbytei2c(0b10100010);  //Configuration Byte
  sendbytei2c(0b00010111);  //Configuration Byte
  stopi2c();
}

//Max1238 lesen
unsigned char Max1238in (void){
  unsigned char daten, daten2;

  starti2c();
  sendbytei2c(0b01101011);  //Adresse

  for (i=0; i<=10; i++){
    daten = readbyteI2C(1);  //Lowbyte
    daten &= ~((1 << 7) | (1<<6)| (1<<5)| (1<<4) );
    daten2 = readbyteI2C(1);  //Highbyte
    ADWandler[i]= ((daten << 8)| daten2);
  }

  stopi2c();
  return (daten);
}

Am AIN0 liegen ca. 3,5V an. Sollte doch funktionieren, oder?

Nur warum nicht...

DANKE

Michael

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.