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
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.
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.
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?
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.