Problem mit Berechnung negativer Zahlen?

OP #2251292
Lesenswert?

Hallo,

ich möchte mit meinem Mega8 eine positive und negative Spannung messen. 
Das ganze muss nicht extrem genau sein, daher hab ich hier aus dem Forum 
einen Vorschlag mit Spannungsteilern gebaut. Das ganze läuft auch, ich 
bekomme ordentliche ADC Werte und die Umrechnung in Volt funktioniert 
auch großteils.

Ich habe allerdings noch ein Problem mit der negativen Berechnung, 
sobald diese >0 wird. Ich bekomme dann immer den Wert -3835.0 
angezeigt...

Hier die wichtigen Auszüge des Codes (AVR-GCC unter Windows):
1
int main( void )
2
{
3
int n_volt0_adc = 513;    // ADC-Wert wenn Messpin für negative Spannung auf GND liegt
4
float n_volt_val = -13.0;  // negative Spannung in V (MIT Vorzeichen)
5
int n_volt_adc = 291;    // ADC-Wert bei negativer Spannung
6

7
float n_volt_div = (n_volt0_adc - n_volt_adc) / n_volt_val;
8
float n_volt;
9

10
 while(1)
11
 {
12
  n_volt = ( n_volt0_adc - ReadChannel(5) ) / n_volt_div;
13
   dtostrf(n_volt, 5, 1, buffer);
14
   lcd_pos( 1, 10 );
15
   lcd_text(buffer);
16
 }
17
}

Folgende Spannungen mit dazugehörigen ADC-Werten hab ich schon gemessen:
--------------------------------
Spannung in V | -13 |  0  | 2,67
--------------------------------
ADC Wert      | 291 | 513 | 559
--------------------------------
Die +2,67 Volt bekomme ich, wenn ich den Messpin nicht angeschlossen 
habe.

Wenn ich das ganze mit meinem Taschenrechner nachrechne, komme ich auf 
die richtigen Ergebnisse, also vermute ich das Problem irgendwo im Code?

Wenn es ein bekanntes Problem ist dann umgeh ich das eben mit einer 
if-Abfrage. Da an diesem Pin eigentlich nie positive Spannungen anliegen 
werden ist das kein Problem. Mich würde nur interessieren, woran das 
liegt?!
#2251314
Lesenswert?

Wenn du den ADC so konfigurierst, dass die 10 Bits linksbündig im 
Ergebnisregister liegen, dann lässt sich der Wert direkt als 16-Bit 
Integer mit Vorzeichen auslesen (int16_t). Zerebrale Knotenbildung durch 
Plus/Minus-Rechnerei entfällt, denn negative Werte sind schon negativ, 
nut eben im Wertebereich +/-32K statt +/-512.
OP #2251441
Lesenswert?

Ja, der µC lebt noch. Die Schaltung die ich verwende um die Spannungen 
zu messen ist diese hier: 
http://www.mikrocontroller.net/attachment/107327/Bild1.png (die untere 
Z-Diode einfach ignorieren, die is falsch eingezeichnet...)

A. K. schrieb:
> Zerebrale Knotenbildung durch Plus/Minus-Rechnerei entfällt
Ansich stört es mich ja nicht, wenn mit den +/- Werten gerechnet wird, 
der Wertebereich ist auch unkritisch, die +/-512 würden ja locker 
reichen.

Die Funktion ReadChannel() liefert mir auch schon einen uint16_t Wert, 
aber ich kann mir trotzdem noch nicht erklären, warum beim Überschreiten 
der 0,0V Grenzen auf einmal ein so seltsamer Wert rauskommt...
#2251494
Lesenswert?

Christian Wächter schrieb:
> Die Funktion ReadChannel() liefert mir auch schon einen uint16_t Wert,
> aber ich kann mir trotzdem noch nicht erklären, warum beim Überschreiten
> der 0,0V Grenzen auf einmal ein so seltsamer Wert rauskommt...

Genau deshalb. Weil ReadChannel ein uint16_t zurück gibt, erfolgt die 
Berechnung in der Klammer als unsigned, und auch das Ergebnis der 
Berechnung in der Klammer wird als unsigned interpretiert.
OP #2251593
Lesenswert?

Stefan Ernst schrieb:
> Weil ReadChannel ein uint16_t zurück gibt, erfolgt die
> Berechnung in der Klammer als unsigned

Ah, verstehe. Was müsste ich dann ändern, damit es korrekt berechnet 
wird? Für float, double etc. kann man ja ein
1
(float)
 davor setzten, um es zu erzwingen. Gibt es das für (un)signed Zahlen 
auch? Oder muss ich das Ergebniss aus (n_volt0_adc - ReadChannel(5)) 
nochmal in eine signed Variable zwischenspeichern?
OP #2253293
Lesenswert?

A. K. schrieb:
> sprintf kann das von Haus aus ("+" Option).

Die Funktion sieht ja gut aus, aber wie bekomme ich der folgendes 
gesagt:

1) Vorzeichen immer anzeigen (+)
2) Insgesamt 6 Stellen : +00.00 (6)
3) 2 Stellen vor dem Komma (automatisch?)
4) 1 Stelle nach dem Komma (1)
5) Vorne evtl. mit einer Leerstelle auffüllen (blank?)
6) Es is ne Float-Zahl (f)

So geht's jedenfalls nicht, ich bekomme nichts angezeigt?!
1
char buffer[10];
2
float n_volt = 55.1;
3
sprintf(buffer, "%+61blankf", n_volt);
#2253296
Lesenswert?

Christian Wächter schrieb:

> 1) Vorzeichen immer anzeigen (+)
> 2) Insgesamt 6 Stellen : +00.00 (6)
> 3) 2 Stellen vor dem Komma (automatisch?)
> 4) 1 Stelle nach dem Komma (1)
> 5) Vorne evtl. mit einer Leerstelle auffüllen (blank?)
> 6) Es is ne Float-Zahl (f)

Also was jetzt? +00.00 sind 2 Stellen nach dem "Komma". +00.0 sind 
insgesamt 5 Zeichen, nicht 6.

"%+5.1f" = immer Vorzeichen, Feldgrösse 5, eine Nachkommastelle, 
Festpunktformat.
OP #2253322
Lesenswert?

A. K. schrieb:
> Also was jetzt? +00.00 sind 2 Stellen nach dem "Komma". +00.0 sind
> insgesamt 5 Zeichen, nicht 6.
Sorry, meinte schon 5 Zeichen

> "%+5.1f" = immer Vorzeichen, Feldgrösse 5, eine Nachkommastelle,
> Festpunktformat.
Perfekt! 1000-Dank, genau so wollte ich es haben. Hätte ich mal lieber 
hier gesucht, Google hat nur Müll gefunden, daher auch der Blödsinn mit 
dem blankf...
#2253326
Lesenswert?

Nils S. schrieb:
>
1
sprintf(buffer, "%+61blankf", n_volt);
> Du braucht ein Komma dazwischen, so wärens 61 Stellen vom Datentyp
> blankf :P
>
> "%+02.04f" gibt dir immer im selben Format

Fast.
Die Zahl vor dem . ist die Gesamtbreite der Ausgabe. Es ist nicht 
sinnvoll, wenn diese Zahl kleiner als die Anzahl der Nachkommastellen 
ist. In diesem Sinne wäre deine Ausgabe

+3.0100

und nicht

+03.0100

wenn du vor dem Komma 2 Stellen haben willst, dann musst du eine 
Feldbreite von 8 anfordern.

"%+08.04f"
#2253327
Lesenswert?

Christian Wächter schrieb:
> A. K. schrieb:
>> Also was jetzt? +00.00 sind 2 Stellen nach dem "Komma". +00.0 sind
>> insgesamt 5 Zeichen, nicht 6.
> Sorry, meinte schon 5 Zeichen
>
>> "%+5.1f" = immer Vorzeichen, Feldgrösse 5, eine Nachkommastelle,
>> Festpunktformat.
> Perfekt! 1000-Dank, genau so wollte ich es haben. Hätte ich mal lieber
> hier gesucht, Google hat nur Müll gefunden, daher auch der Blödsinn mit
> dem blankf...

Jedes C-Buch hätte dir das sauber erklären können. Ziemlich am Anfang, 
wenn es darum geht, den Leser mit printf bekannt zu machen.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren