Forum: Mikrocontroller und Digitale Elektronik Auslesen eines ADC7828E per I2C


von Peter (Gast)


Lesenswert?

Hi!

Ich versuche gerade einen ADC7828E auszulesen, jedoch scheint es 
irgendwie nicht sehr genau zu funktionieren, was mich wundert.

Ich habe eine Eingangsspannung von 5.02V. Mit meinem Multimeter messe 
ich am Messeingang 0 des ADC knapp 1.612V.

Ich lese ihn insgesamt zwei mal aus, einmal ohne interne Referenz (dann 
benutzt er die externe Spannung am Ref Pin, welche 5.02V beträgt, und 
einmal mit der internen 2.5V Referenz.
1
#include <Wire.h> 
2
  #define I2C_address 0x48
3
void setup() 
4
{ 
5
  Serial.begin(9600);
6
  Wire.begin();          
7
  delay(1000);
8
} 
9
10
void loop() 
11
{
12
13
const byte DAT[2] = {0x84,0x8C}; //0x84 für externe und 0x8C für interne Referenz
14
  
15
  
16
  byte Adval_High, Adval_Low;
17
  byte i;   
18
19
  delay(1000);
20
  
21
  for (i=0; i<2; i++)
22
  {
23
    Wire.beginTransmission(I2C_address);
24
    Wire.write(DAT[i]);   
25
    Wire.endTransmission(); 
26
    delay(1);
27
    
28
    // Read A/D value
29
    Wire.requestFrom(I2C_address, 2);
30
    while(Wire.available())         
31
    { 
32
      Adval_High = Wire.read();   
33
      Adval_Low = Wire.read();
34
    } 
35
  uint16_t val = 5000/4095*((int)(Adval_High * 256 + Adval_Low));
36
  Serial.print(val);
37
  Serial.println(" mV");
38
  }  
39
}

Als Ausgabe erhalte ich jedoch:

Mit externer Referenz: 1215 mV
Mit interner Referenz: 1504 mV

Wie kann es sein das ich um 0.1V daneben liege? Habe ich etwas falsch 
berechnet/ausgelesen?

Grüße

Peter

von Peter (Gast)


Lesenswert?

Sorry, Ich meinte natürlich den ADS7828E

von Peter (Gast)


Lesenswert?

Habe nochmal etwas weiter experimentiert.
1
uint16_t readADC(char sensor){
2
 const byte DAT[8] = {0x84,0xE4,0xF4,0xD4,0xA4,0xE4,0xB4,0xF4}; // Just using the first byte for the moment
3
 
4
  byte highbyte, lowbyte;   
5
 
6
    Wire.beginTransmission(ADC7828E_I2C_Adress);
7
    Wire.write(DAT[sensor]);       
8
    delay(1);
9
  if (Wire.endTransmission() == 0){
10
   //LOG("ADS7828E recognized");
11
  } else {
12
     ERR("Failed to recognize ADS7828E");
13
  }
14
  delay(1);
15
16
uint16_t value;
17
18
 Wire.requestFrom(ADC7828E_I2C_Adress, 2);
19
    while(Wire.available())       
20
    {
21
     
22
      highbyte = Wire.read();   
23
      lowbyte = Wire.read();   
24
          value= ((int)((highbyte<<8) + lowbyte));
25
     }
26
  return(value);
27
}

ausgelesen wird nur der erste Kanal, mit externer Referenz.

So lese ich ihn aus:
1
uint16_t adcvalue =0;
2
for (int i=0; i<1; i++){
3
    adcvalue +=(readADC(0));
4
  }
5
Serial.print("single read FOR:"); 
6
Serial.println(adcvalue);
7
Serial.print("single read ADC:");
8
Serial.println(readADC(0));

Ich bekomme andere ergebnisse je nachdem, wie ich die funktion aufrufe, 
entweder direkt oder in der FOR schleife (die nur einmal durchläuft)
1
single read ADC:1283
2
single read FOR:1250
3
single read ADC:1283
4
single read FOR:1244
5
single read ADC:1285
6
single read FOR:1255
7
single read ADC:1289
8
single read FOR:1254



mit oversampling sieht es dann jedoch völlig anders aus!
1
uint16_t adcvalue =0;
2
for (int i=0; i<10; i++){
3
    adcvalue +=(readADC(0));
4
  }
5
Serial.print("oversampling read FOR:"); 
6
Serial.println(adcvalue/10);
1
oversampling read FOR:1328
2
single read ADC:1346
3
oversampling read FOR:1329
4
single read ADC:1345
5
oversampling read FOR:1327
6
single read ADC:1342



Das beste ist noch, wenn ich zweimal die selbe FOR Schleife einfach 
untereinander packe, erhalte ich auch unterschiedlich ergebnisse!
1
Serial.print("first oversampling ADC Value: ");
2
uint16_t adcvalue =0;
3
for (int i=0; i<10; i++){
4
    adcvalue +=(readADC(0));
5
  }
6
Serial.println(adcvalue/10);
7
8
9
uint16_t adcvalueuncorr =0;
10
for (int i=0; i<10; i++){
11
    adcvalueuncorr +=(readADC(0));
12
  }
13
Serial.print("second oversampling ADC Value:"); 
14
Serial.println(adcvalueuncorr/10);
1
first oversampling ADC Value: 1319
2
second oversampling ADC Value:1342
3
first oversampling ADC Value: 1319
4
second oversampling ADC Value:1341
5
first oversampling ADC Value: 1318
6
second oversampling ADC Value:1341
7
first oversampling ADC Value: 1319
8
second oversampling ADC Value:1342
9
first oversampling ADC Value: 1319
10
second oversampling ADC Value:1342
11
first oversampling ADC Value: 1319
12
second oversampling ADC Value:1341


Wie kann man dieses (für mich jedenfalls) Phänomen erklären, bzw. wie 
macht man es denn richtig? Es ist immerhin ein IC für knapp 8€... Wenn 
das ganze nichts bringt, werde ich wohl den ADC wechseln müssen.

von Joe F. (easylife)


Lesenswert?

Man kann anhand deines Codes nicht wirklich beurteilen was auf dem I2C 
Bus passiert.
Stelle sicher, dass das Protokoll genau so ist, wie es im Datenblatt 
beschrieben ist (am Besten implementierst du den "HS" mode) mit repeated 
start.

Dein I2C Interface sollte natürlich mit clock stretching seitens des ADC 
klarkommen.

Stelle sicher, dass SDA und SCL mit je 2.2K pullups versehen sind.
Stelle sicher, dass alle Bauteile Blockkondensatoren haben, und die 
Spannungsversorgung stabil und rauscharm ist.
Für die Referenzspannung und den ADC bietet es sich an, einen Filter in 
die Versorgungspannung einzubauen (z.B. 10 Ohm + Kondensator).

Bei 5V Versorgung/Referenz und 12-bit Auflösung ist ein Bit gerade mal 
1.22mV. Spannungsversorgungen rauschen gerne mal mit 50mV oder mehr, 
insofern wären deine Messwerte gar nicht soooo krass krank.

von Peter (Gast)


Lesenswert?

So,

Ich habe nun zwei identische For schleifen, die erste ruft die read 
Funktion 5 mal auf, die zweite 10mal. Hier ist der Output, es sieht so 
aus als würde der Chip erst gewisse Zeit brauchen um die Messungen zu 
machen. Zwischen den einzelnen Messungen, bzw. Funktionsaufrufen, ist 
ein delay von 5ms.
1
Channel 1 First Measurement number 0 : 1268
2
Channel 1 First Measurement number 1 : 1289
3
Channel 1 First Measurement number 2 : 1304
4
Channel 1 First Measurement number 3 : 1312
5
Channel 1 First Measurement number 4 : 1317
6
Channel 1 First average: 1298
7
Channel 1 Second Measurement number 0 : 1319
8
Channel 1 Second Measurement number 1 : 1320
9
Channel 1 Second Measurement number 2 : 1322
10
Channel 1 Second Measurement number 3 : 1325
11
Channel 1 Second Measurement number 4 : 1326
12
Channel 1 Second Measurement number 5 : 1326
13
Channel 1 Second Measurement number 6 : 1327
14
Channel 1 Second Measurement number 7 : 1327
15
Channel 1 Second Measurement number 8 : 1327
16
Channel 1 Second Measurement number 9 : 1326
17
Channel 1 Second average: 1324

Wie man wohl nicht übersehen kann arbeite ich mit Arduino und nutze die 
Wire Library (Arduino Standard).

Hier noch meine überarbeitete Read funktion.
1
  Wire.beginTransmission(ADC7828E_I2C_Adress);
2
  //Wire.write(DAT[sensor]);        // Configure the device to read each CH
3
  Wire.write(DAT[sensor]);
4
  if (Wire.endTransmission() == 0) { //Checking if the MCP9808 is available
5
    //LOG("ADS7828E recognized");
6
  }
7
    else if (Wire.endTransmission() == 2) { //Checking if the MCP9808 is available
8
    LOG("ADS7828E data too long to fit in transmit buffer ");}
9
    else if (Wire.endTransmission() == 2) { //Checking if the MCP9808 is available
10
    LOG("ADS7828E NACK receifed  on transmit of address ");}
11
    else if (Wire.endTransmission() == 3) { //Checking if the MCP9808 is available
12
    LOG("ADS7828E NACK receifed  on transmit of data ");}
13
    else if (Wire.endTransmission() == 2) { //Checking if the MCP9808 is available
14
    ERR("Failed to recognize ADS7828E"); }
15
  uint16_t values;
16
  // Read A/D value
17
  Wire.requestFrom(ADC7828E_I2C_Adress, 2);
18
  byte bytes[2];
19
  int bytesRead;
20
  while (2 > Wire.available()) {}
21
  for (bytesRead = 0;  bytesRead < 2; bytesRead++) {
22
    bytes[bytesRead] = Wire.read();
23
  }
24
  values = (int)((bytes[0]<<8) + bytes[1]);
25
  return (values);

So wie es aussieht scheint der Sensor wirklich zu langsam zu sein um Ihn 
so auszulesen, oder?

Ich verstehe nicht ganz wie ich den HS Modus implementiere, ist dieser 
Pseudocode so richtig?
1
Wire.beginTransmission(ADC7828E_I2C_Adress); //Begin Transmission
2
Wire.write(B00001000); //Send HS Mode Master code
3
if (Wire.endTransmission() == 3){ LOG("Master mode activated");}
4
Wire.beginTransmission(B10010000); //Adress with Write Adressing byte at the end
5
Wire.write(DAT[sensor]); //Sending Command Byte
6
Wire.endTransmission();
7
Wire.requestFrom(B10010001, 2);  //requesting 2 Bytes to the read adresss
8
bytes[0] = Wire.read(); // Read byte 1
9
bytes[1] = Wire.read(); // Read byte 2


Vielen Dank im voraus!

von Joe F. (easylife)


Lesenswert?

Ohne die API im Detail zu kennen, "beginTransmission" und 
"endTransmission" kling für mich nach START und STOP condition auf dem 
Bus.
Beschäftige dich mal mit I2C auf Hardwareebene, damit du verstehst was 
eine START, STOP und REPEATED-START condition ist.
Dann findest du raus, wie du diese Conditions mit deiner I2C Library 
erzeugen kannst. Es hilft, testweise nur einzelne Bytes auf den Bus zu 
schreiben, und das Ergebnis an einem Oszilloskop an SCL und SDA 
nachzuvollziehen.
Im HS Mode verwendet der ADC das sogenannte "Clock-Stretching". Auch 
damit solltest du dich in der Theorie vertraut machen.
Im wesentlichen hält der ADC die CLK Leitung auf low, und signalisiert 
dem Master so, dass er noch Zeit braucht.
Der Master sollte geduldig genug eingestellt werden, um hier kein 
Timeout zu werfen.

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.