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


von Martin J. (bluematrix) Benutzerseite


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-max1238.html

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.
1
//############ Adresse MAX1238
2
#define Adr_MAX1238  0b01101010
3
4
Data_Array_Messwert[11];
5
6
//############ init MAX1238 via I2C
7
void ADC_MAX1238_init(void)
8
{
9
i2c_start_wait(Adr_MAX1238+I2C_WRITE);   // device address & write mode
10
i2c_write(0b10100010);                   // write Register
11
i2c_write(0b00010111);                   // write Register
12
i2c_stop();                              // stop i2c
13
}
14
15
//############ auslesen MAX1238 via I2C
16
void ADC_MAX1238(void)
17
{
18
uint8_t    hig,low ;                      // hight und Low Byte
19
20
i2c_start_wait(Adr_MAX1238+I2C_READ);     // device address & read mode
21
for (uint8_t i=0; i<=10; i++)             // alle 10 Kanäle auslesen
22
    {
23
    low  = i2c_read(1);    low &= ~((1 << 7) | (1<<6)| (1<<5)| (1<<4) );
24
    hig  = i2c_read(1);    Data_Array_Messwert[i]= ((low << 8)| hig);
25
    }
26
i2c_stop();
27
}

Grüße martin

von Martin J. (bluematrix) Benutzerseite


Angehängte Dateien:

Lesenswert?

noch paar bilder

von Michael (Gast)


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();
}

von Martin J. (bluematrix) Benutzerseite


Lesenswert?

Die fragen beantworten sich mit dem Code-Beispiel weiter oben ...
Das Beispiel funktioniert einwandfrei

von Martin J. (bluematrix) Benutzerseite


Lesenswert?

1
//####################################### I2C  
2
i2c_init();
3
4
//####################################### init MAX1238 via I2C
5
if(i2c_start(Adr_MAX1238+I2C_WRITE))     
6
{
7
i2c_stop();  // failed to issue start condition, possibly no device found
8
}
9
10
else         // issuing start condition ok, device accessible
11
{  
12
i2c_write(0b10100010); // write address = 5
13
i2c_write(0b00010111); // write value 0x75 to EEPROM
14
i2c_stop(); 
15
}
16
17
18
//####################################### messen_adc MAX1238
19
void I2C_ADC_MAX1238(void)
20
{
21
uint8_t   hig,low = 0;  // hight und Low auslese Variable für uniq
22
uint16_t dummy   = 0;   
23
24
//############# I2C  MAX1238 - 12Bit ADC
25
if (i2c_start(Adr_MAX1238+I2C_READ)) 
26
{
27
i2c_stop(); // failed to issue start condition, possibly no device found
28
}
29
30
else       // issuing start condition ok, device accessible
31
{  
32
 for (uint8_t i=0; i<=10;i++)  
33
 {
34
  low  = i2c_read(1);  low &= ~((1 << 7) | (1<<6)| (1<<5)| (1<<4) );
35
  hig  = i2c_read(1);  dummy = ((low << 8)| hig); 
36
37
  //###### umrechnen in mV [ADC*VREF= Vin*Auflösung]
38
  //dummy = dummy*1.221001221;
39
40
  //###### Ausgabe
41
  uart1_puts("Kanal-");            // send string  
42
  if(i<10) uart1_puts(" ");        // send string  
43
44
  itoa( dummy , buffer, 10);       // interger to string & send  
45
  uart1_puts(buffer);              // send
46
  uart1_puts(": ");            // send string  
47
48
  if(dummy<10)   uart1_puts(" "); // send string  
49
  if(dummy<100)   uart1_puts(" "); // send string  
50
  if(dummy<1000)   uart1_puts(" "); // send string  
51
52
  itoa( dummy , buffer, 10);       // interger to string & send  
53
  uart1_puts(buffer);              // send  
54
  uart1_puts(" mV\r");      // send string  
55
 }
56
 i2c_stop();
57
}
58
59
}

von Martin J. (bluematrix) Benutzerseite


Lesenswert?

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

Grüße martin

von Michael (Gast)


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

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.