Forum: Mikrocontroller und Digitale Elektronik ADS1112 ADC Wert in Spannung rechnen


von Borsty B. (mantabernd)


Lesenswert?

Guten Abend,

ich habe einen ADS1112 den ich über I2C im Single Ended Modus auslese.

Das Lesen der Register klappt auch.
Ich bekomme für das High Byte z.B.: 0x37 und für das Low Byte: 0xe8.

Lesen des Konfigurationsregisters klappt ebenfalls. Die Werte stimmen 
also.

So, nun muss ich ja das High- und Lowbyte zusammenbringen und wie im 
Datenblatt auf Seite 6 beschrieben umrechnen.


Also die zwei Bytes zusammenfassen erledige ich hiermit:
1
int highbyte = messageBuf[1];
2
int lowbyte = messageBuf[2];
3
4
long t = highbyte << 8 |  lowbyte;

... umrechnen eventuell so?
1
 double v = (double) t * 2.048/32768.0;

Und Ausgabe auf dem Display dann hiermit:
1
itoa( v, ausgabe,10); 
2
lcd_string(ausgabe);

Leider erscheint da nur 0 bzw. 1 auf dem Display :(

Vielleicht kann mir jemand einen Tipp geben und mich auf den richtigen 
Weg schupsen?


Ich arbeite mit AVR Studio und einem Attiny2313. Sprache: C.

Vielen Dank :)

: Bearbeitet durch User
von Dirk K. (dekoepi)


Lesenswert?

Du berechnest so eine float in V, die wiederum in dein double gewandelt 
wird - du wirst also eine Dezimalzahl zwischen -2 und +2 sehen, {-2; -1; 
0; 1; 2;}.
Wenn du mV sehen willst, entferne den Punkt bei der 2.048, fertig.

: Bearbeitet durch User
von Borsty B. (mantabernd)


Lesenswert?

Super, danke hat funktioniert.

Nun muss ich nur noch einen Weg finden die Zahl mit einem Komma aufs 
Display zu bringen...

für 8,50V steht nun nämlich z.B. 85000 auf dem Display.

bei 15V sind es 15000.

von Borsty B. (mantabernd)


Lesenswert?

Jemand eine Idee das ohne sprintf zu machen?

Der Attiny2313 hat leider nicht genug Speicher für solche Spielereien.

von Dirk K. (dekoepi)


Lesenswert?

Das ist doch ab hier trivial?
1
double v = (double) t * 2048/32768.0; 
2
double w = v/1000;
3
itoa( w, ausgabe,2); 
4
lcd_string(ausgabe); 
5
ausgabe="."; 
6
lcd_string(ausgabe);
7
itoa( (v-1000*w), ausgabe,6); 
8
lcd_string(ausgabe);

Je nachdem, wie deine Funktion lcd_string() funktioniert, musst du das 
natürlich etwas anpassen wegen Zeilenumbrüchen und ähnlichem. Ein wenig 
Eigeninitiative würde da tatsächlich nicht schaden.

: Bearbeitet durch User
von Borsty B. (mantabernd)


Lesenswert?

Danke, habe eine Lösung gefunden (wobei deine wohl die schönere ist...). 
Leider passt deine Lösung nicht mehr in den Speicher. 7% zu viel, und 
das schon bei bester Optimierung.

Damit geht's aber gerade so:
1
int Messwert = v;
2
int vorKomma = Messwert / 1000; // zwei Nachkommastellen "abschneiden"
3
int nachKomma = Messwert % 1000; // zwei Nachkommastellen "isolieren"
4
      
5
lcd_string("Solar ");
6
itoa( vorKomma, ausgabe,10);
7
lcd_string(ausgabe);
8
lcd_string(",");
9
itoa( nachKomma, ausgabe,10);
10
lcd_string(ausgabe);
11
lcd_string("  ");

Danke für deine Unterstützung!

von DerDan (Gast)


Lesenswert?

die lösung ist auch noch nicht ganz richtig

für 2.001 V zeigt dein Display 2.1 an !!!

von DerDan (Gast)


Lesenswert?

Borsty B. schrieb:
> int vorKomma = Messwert / 1000; // zwei Nachkommastellen "abschneiden"
> int nachKomma = Messwert % 1000; // zwei Nachkommastellen "isolieren"

und der Typische Fehler das der Kommantar lügt

von Borsty B. (mantabernd)


Lesenswert?

DerDan schrieb:
> die lösung ist auch noch nicht ganz richtig
>
> für 2.001 V zeigt dein Display 2.1 an !!!

Ja, würde es gerne richtig machen. Mein Programm ist nur leider für den 
Controller ohnehin schon zu groß :(

Siehe: Beitrag "C-Code optimieren (passt nicht in Attiny2313) :("

von Karl H. (kbuchegg)


Lesenswert?

Ich denke, die einfachste Variante besteht darin, auf itoa bzw utoa zu 
verzichten und sich selbst eine entsprechende ASCII Konvertierung zu 
schreiben.
Dann ist es nämlich einfach sicherzustellen, dass die führenden 0-en 
auch tatsächlich erscheinen. Ganz im Gegenteil: führende 0-en 
wegzulassen ist Aufwand. Die dann nachträglich wieder zu ergänzen ist 
irgendwie doppelt gemoppelt.

Als Anhaltspunkt kann gleich der erste Punkt in der FAQ
FAQ
dienen. Dort kannst du dir ansehen, wie man so eine Konvertierung macht, 
wenn man sie selbst machen muss/will.

Ich denke allerdings auch:
wenn du die double Rechnerei losgeworden bist, hast du den Speicher um 
sprintf benutzen zu können. Mit den Formatiermöglichkeiten von sprintf 
wirds trivial, auch wenn sprintf etliches zum Code beitragen wird. Aber 
alleine das Ausrichten in einem Feld, so dass die Zahl bei wechselnden 
Vor bzw. Nachkomma Ziffern Anzahlen nicht dauernd hin und her springt, 
ist es schon wert. Denn auch das müsste/sollte man programmieren. Es 
gibt nichts schlimmeres, als wenn einem beim Lesen von Zahlen auf einem 
LCD die Zahl dauern links/rechts hin und herschwimmt, nur weil der 
Zahlenwert von 10.000 auf 9.999 hin und her hüpft.

Im Zweifelsfall lieber die double loswerden und dafür sprintf einsetzen 
können :-)

: Bearbeitet durch User
von Joachim B. (jar)


Lesenswert?

Karl H. schrieb:
> Es
> gibt nichts schlimmeres, als wenn einem beim Lesen von Zahlen auf einem
> LCD die Zahl dauern links/rechts hin und herschwimmt, nur weil der
> Zahlenwert von 10.000 auf 9.999 hin und her hüpft.

denn gibt man ständig
<space>9999 oder 10000 aus und fügt an der 3 Stelle von links das Komma 
ein, reine Stringverarbeitung

von Borsty B. (mantabernd)


Lesenswert?

Also egal wie ich's dreh oder wende, es funktioniert so nicht:
1
long t = highbyte << 8 |  lowbyte;
2
double v = (double) t * 2048/32768.0; 
3
double w = v/1000;
4
itoa( w, ausgabe,2); 
5
lcd_string(ausgabe); 
6
ausgabe="."; 
7
lcd_string(ausgabe);
8
itoa( (v-1000*w), ausgabe,6); 
9
lcd_string(ausgabe);

Mit diesem Code bekomme ich die mV ohne Punkt und Komma aufs Display:
1
t = highbyte << 8 |  lowbyte;
2
v = (double) t * 2048/32768.0;
3
lcd_setcursor( 0, 4 );
4
itoa( v, ausgabe,10);
5
lcd_string(ausgabe);

Allerdings brauch ich die Anzeige ja in Volt mit Zenertrennung...

P.S. jetzt bitte nicht am Long und double aufhängen, ich versuch das 
grad auf einem Controller mit ausreichend Platz und möchte es einfach 
mal zum laufen bringen.

von Borsty B. (mantabernd)


Lesenswert?

Hat denn keiner eine Idee wie ich diesen 16-Bit Hex Wert des AD1112 in 
Volt umrechne?

Millivolt funktioniert ja, brauch also eigentlich nur Millivolt in Volt.

Ich steck im programmieren leider nicht tief genug drin. Auch mit 
Sprintf funktioniert es nicht wie ich es möchte :(

von Bernd N (Gast)


Lesenswert?

Formatiert ausgeben kannst du deine Spannung z.B. so...
1
void AdcValOut (uint16_t AdcValue)
2
{
3
    uint8_t AdcValArray [5];                                      // Integer Array
4
    uint8_t m = 4;                                                // Schleifenzähler für Ausgabe
5
6
    do  {
7
        AdcValArray [m] = '0' + AdcValue %10;                     // Berechnung der einzelnen Stellen sowie
8
        AdcValue /= 10;                                           // Wandlung nach ASCII und abspeichern im
9
    } while (m--);                                                // Array
10
    while (m != 3) {                                              // Anzahl der auszugebenden Stellen = 4
11
        lcd_string (AdcValArray [++m]);                           // ADC Wert ausgeben
12
        if (m == 0) lcd_string ('.');                             // Dezimalpunkt setzen
13
    }
14
}

von Borsty B. (mantabernd)


Lesenswert?

... irgendwie komme ich auch damit nicht klar. :(

Das Display liefert mir dabei nur wirre Zeichen.

... hab's jetzt so gelöst:

1
unsigned char val_array[4];
2
val_array[3] = v / 1000;
3
val_array[2] = v % 1000 / 100;
4
val_array[1] = v % 100 / 10;
5
val_array[0] = v % 10;
6
  
7
sprintf(ausgabe,"%d%d,%d%dV",val_array[3],val_array[2],val_array[1],val_array[0]);
8
lcd_string(ausgabe);

: Bearbeitet durch User
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.