Forum: Mikrocontroller und Digitale Elektronik ADC Ergebniss auflösen


von blawa (Gast)


Lesenswert?

Also ich weis nicht genau wie ich folgendes machen soll:
8 Bit ADC ( 0 - 5 V Input )
diese 0-5V will ich in 200 Teilbereiche zerlegen und das Ergebniss dann
in eine Variable abspeichern...
Mein 8 Bit ADC zerlegt aber diesen Berreich in 255 einzelstücke oder?
Bzw wenn ich dann diese Zerlegung habe, ist das dann eine Integer Zahl
die die Volt angibt?

von Rahul (Gast)


Lesenswert?

nö.
Es ist ein Byte, das nur dir eine Relation zwischen der
Referenzspannung und gemessener Spannung angibt.
Die Zahl in Volt bekommst du durch eine Berechnung:

U = 5V*ADC/255

Wenn du nur noch 200 Teilbereiche haben willst, geht das so:

T = 200*ADC/255

Vielleicht siehst du das System...

von ,,,, (Gast)


Lesenswert?

> U = 5V*ADC/255

Eher so:

U = 5V*ADC/256

von Rahul (Gast)


Lesenswert?

nö. Die Diskussion hatten wir schon zur Genüge.
Wieso sollte ich eine Zahl, die mit maximal 8 Bit dargestellt wird,
durch eine mit 9 Bit teilen (Zahlenraum...)?
Ansonsten ist es egal, ob 255 oder 256, da der Fehler unter 1% liegt...

von Rolf Magnus (Gast)


Lesenswert?

Darüber hatten wir schon mal eine Diskussion hier, aber ich kann sie
grad nicht finden.

> Eher so:
>
> U = 5V*ADC/256

Dann bekommst du nie einen Wert von 5V raus, da ADC maximal einen Wert
von 255 haben kann.

von ,,,, (Gast)


Lesenswert?

8 Bit Auflösung, 256 Möglichkeiten; bei Vref=5V hat das LSB die
Wertigkeit 5V/256. Mit 8 Bit kann man maximal 255*LSB darstellen.

von ,,,, (Gast)


Lesenswert?

> Wieso sollte ich eine Zahl, die mit maximal 8 Bit dargestellt
> wird, durch eine mit 9 Bit teilen (Zahlenraum...)?

Weil dies die Grundlagen der digitalen Messtechnik sind.

von johnny.m (Gast)


Lesenswert?

>256 Möglichkeiten

Genau, und eine davon ist 0!

von ,,,, (Gast)


Lesenswert?

> Dann bekommst du nie einen Wert von 5V raus, da ADC maximal einen
> Wert von 255 haben kann.

Ein AD-Wandler, dessen Referenz 5V beträgt, kann halt nicht bis 5V
messen.

LOL

von johnny.m (Gast)


Lesenswert?

Natürlich kann er das! VREF entspricht dem max. Wandlungsergebnis!

Ansonsten:
1 LSB = VREF / ((2^n)-1) mit n als Anzahl der Bits!
2^8 - 1 = 255

Man hat zwar 256 Zustände, aber der erste ist Null, d.h. es gibt nur
255 Intervalle.

Gruß

Johnny

von johnny.m (Gast)


Lesenswert?

@,,,,:
In der Schule nie die berühmte Rechenaufgabe gehabt, wieviele
Zaunpfähle man braucht, um bei einem Pfahl-Abstand von 1 m einen 10 m
langen Zaun zu bauen????

von ,,,, (Gast)


Lesenswert?

> Natürlich kann er das! VREF entspricht dem max.
> Wandlungsergebnis!

Diese Aussage ist definitv falsch.

von blawa (Gast)


Lesenswert?

Also ich habs jezt folgendermasen Probiert, jedoch funktioniert das
nicht ganz:
void ADC()
{
 ADCON0=0x00;            /* AD-Kanal 0 */
 DAPR=0x00;         /* Bereich 0 V - 5 V */
 while((ADCON0&0x10)!=0);    /* Warten bis Wandlung fertig (15us ) */
 DruckSp1=(5*ADDAT)/255;     /* Umrechnen */
 ADCON0=0x01;                /* AD-Kanal 1 */
 DAPR=0x00;                  /* Bereich 0 V - 5 V */
 while((ADCON0&0x10)!=0);    /* Warten bis Wandlung fertig (15us ) */
 DruckSp2=(5*ADDAT)/255;     /* Umrechnen */
 ADCON0=0x02;                /* AD-Kanal 2 */
 DAPR=0x00;                  /* Bereich 0 V - 5 V */
 while((ADCON0&0x10)!=0);    /* Warten bis Wandlung fertig (15us ) */
 DruckSp2=(5*ADDAT)/255;     /* Umrechnen */
 ADCON0=0x04;                /* AD-Kanal 3 */
 DAPR=0x00;                  /* Bereich 0 V - 5 V */
 while((ADCON0&0x10)!=0);    /* Warten bis Wandlung fertig (15us ) */
 DruckSp2=(5*ADDAT)/255;     /* Umrechnen */
 ADCON0=0x08;                /* AD-Kanal 4 */
 DAPR=0x00;                  /* Bereich 0 V - 5 V */
 while((ADCON0&0x10)!=0);    /* Warten bis Wandlung fertig (15us ) */
 DruckSp2=(5*ADDAT)/255;     /* Umrechnen */
}

von Rahul (Gast)


Lesenswert?

Guck dir doch mal die Funktionsweise eines ADC an.
Im Regelfall wird die zu messende Spannung mit einer sich ändernden
Spannung (Rampe) verglichen. Ist die Vergleichsspannung bei einer
steigenden Rampe grösser als die Messspannung, dann hat man den
ADC-Wert.

von Rahul (Gast)


Lesenswert?

ich meinte die Komma-Ansammlung etc...

von Rahul (Gast)


Lesenswert?

@blawa:
Kommt halt darauf an, wie du DruckSp deklariert hast.
Als integer oder char wird da nur 0-5 rauskommen...

von blawa (Gast)


Lesenswert?

Also ich habe es als Integer Deklariert, jedoch krieg ich immer nur 0x00
raus... als was müsste ich es definieren, damit ich meinen Wert kriege?

von johnny.m (Gast)


Lesenswert?

Grundsätzlich hängt das alles vom Typ des A/D-Wandlers ab. Die in uCs
verbauten Wandler sind i.a. Successive-Approximation-Wandler und können
z.T. prinzipbedingt tatsächlich nur VREF-1LSB ausgeben (Bei den AVRs ist
das z.B. so). Da blawa jedoch bis zuletzt hartnäckig verschwiegen hat,
was für ein Teil er da eigentlich benutzt, konnte das alles Mögliche
sein... Irgendwo haben halt alle ein bisschen recht! OK, ADCs mit ein-
oder zwei-Rampen-Verfahren werden aufgrund ihrer Langsamkeit nur noch
in Low-Cost-Anwendungen und da wo's nicht auf Speed ankommt
eingesetzt...

Gruß

Johnny

von blawa (Gast)


Lesenswert?

Ok muss mich entschuldigen dass ich das nicht erwähnt g´habe ^^
Es handelt sich um den internen ADC des SAB80C535.... wir sollen einen
Druck von 0-300 Bar messen und ausgeben... dafür werden wir unsere
Spannung des Drucksensors verstärken, damit wir auf einen Berreich von
0-5V kommen...
Jezt würd ich gerne wissen wollen, wie ich es machen kann, dass ich das
Konvertiere um dann den Druck im µC in einer Integervariable stehn zu
haben... wobei wir 2Bar Einheiten verwenden wollen...

von johnny.m (Gast)


Lesenswert?

Ist ja net schlimm, hat immerhin zu ner netten Diskussion geführt...

Dass ich mit 8051ern (genau genommen mit nem 80C537) gearbeitet habe
ist schon ne Weile her (stehe eher auf AVR:-), aber ein bisschen ist
noch hängengeblieben...

Was Du mit dem ADCON0-Register machst leuchtet mir nicht ein. Beim
80C537 funktioniert die Kanalwahl mit den drei LSB! Du schreibst aber
00000001, 00000010, 00000100, 00001000... Irgendwie kommt mir das
spanisch vor. Ich glaub, beim 535 müsste das ganz ähnlich laufen wie
beim 537. Außerdem brauchste das DAPR nicht jedes Mal neu zu schreiben.


Was noch viel wichtiger ist: Ich fürchte, Du vergisst einfach, die
Wandlung zu starten (80C537: ADCON0 |= 0x20;).

Probiers mal damit!

Gruß

Johnny

von Rahul (Gast)


Lesenswert?

@Jonny: Welcher ADC kann denn bis Vref messen?

@Blawa: 0-300 Bar? Bei 300 Bar möchte ich nicht neben dem Drucksensor
stehen...finde ich zumindest ziemlich viel...
Der Drucksensor wird ja irgendeine elektrische Grösse ausspucken.
Mit Hilfe des Datenblattes oder aus einer Messung/Messreihe heraus kann
man dann feststellen, wie groß die Ausgangssgrösse bei welchem Druck
ist.
Dann baut man einen Wandler (Operationsverstärker) auf, der das Signal
entsprechend an 0-5V anpasst.

[alles für die Katz, was ich bis jetzt geschrieben habe...]

Integer haben keine Nachkommastellen...
Du kannst entweder eine Fließkomma-Zahl benutzen (type-casr...), dir
die Formel so umbauen, dass du keine Nachkommastellen brauchst oder
eine Tabelle anlegen, die die auzugebenen Werte enthält.

von blawa (Gast)


Lesenswert?

@ johnny.m
was bewirkt der Befehl:
>Was noch viel wichtiger ist: Ich fürchte, Du vergisst einfach, die
>Wandlung zu starten (80C537: ADCON0 |= 0x20;).

von johnny.m (Gast)


Lesenswert?

Der bewirkt, dass das Bit ADEX, das den ADC startet, gesetzt wird. Das
Bit steht beim 80C537 an der Stelle 5, also mit 0x20 (00100000b)
verodern, dann wirds gesetzt. Solange es nicht gesetzt ist, wandelt
auch der ADC nix!

von johnny.m (Gast)


Lesenswert?

@Rahul:
Hast natürlich recht. Das eine Inkrement bleibt immer übrig. Also
VMESSMAX = VREF-1LSB oder VLSB = VREF/(2^n), also 256 beim
8-Bit-Wandler.

von blawa (Gast)


Lesenswert?

Hmm habs jezt folgendermasen probiert, aber auf meinem DSP stehen nur
irgendwelche werte...

void ADC()
{
 P6=0x00;
 ADCON0=0x00;                             /* AD-Kanal 0 */
 DAPR=0x00;                              /* Bereich 0 V - 5 V */
 ADCON0=ADCON0|020;
 while((ADCON0&0x10)!=0);                     /* Warten bis Wandlung 
fertig (15us
) */
 DruckSp1=ADDAT*(11764/10000);                    /* Umrechnen */
 DruckSp11=DruckSp1;
 ADCON0=0x01;                             /* AD-Kanal 1 */
 DAPR=0x00;                            /* Bereich 0 V - 5 V */
 ADCON0=ADCON0|0x20;
 while((ADCON0&0x10)!=0);                     /* Warten bis Wandlung 
fertig (15us
) */
 DruckSp2=ADDAT*(11764/10000);                    /* Umrechnen */
 DruckSp22=DruckSp2;
 ADCON0=0x02;                             /* AD-Kanal 2 */
 DAPR=0x00;                              /* Bereich 0 V - 5 V */
 ADCON0=ADCON0|0x20;
 while((ADCON0&0x10)!=0);                     /* Warten bis Wandlung 
fertig (15us
) */
 DruckSp3=ADDAT*(11764/10000);                    /* Umrechnen */
 DruckSp33=DruckSp3;
 ADCON0=0x03;                             /* AD-Kanal 3 */
 DAPR=0x00;                              /* Bereich 0 V - 5 V */
 ADCON0=ADCON0|0x20;
 while((ADCON0&0x10)!=0);                    /* Warten bis Wandlung 
fertig (15us
) */
 DruckK=ADDAT*(11764/10000);                    /* Umrechnen */
 DruckKK=DruckK;
 ADCON0=0x04;                             /* AD-Kanal 4 */
 DAPR=0x00;                              /* Bereich 0 V - 5 V */
 ADCON0=ADCON0|0x20;
 while((ADCON0&0x10)!=0);                    /* Warten bis Wandlung 
fertig (15us
) */
 DruckFl=ADDAT*(11764/10000);                     /* Umrechnen */
 DruckFll=DruckFl;
}

das 11764/10000 habe ich gschrieben, da ich keine floats verwenden
kann...

und ich will meine 300 bar in 150 teile zerlegen -> ADDAT * 1,1764...
Aber wie gesagt ich bekomme nur irgendwelche werte geliefert, obwohl
ich zu testzwecken nur den Port 6.1 angeschlossen habe...

von Rahul (Gast)


Lesenswert?

Guck dir doch die Werte mal ohne Berechnung an. Oder überprüfe die
Funktion des ADC mit einer externen Spannung (einstellbares Netzteil).
Und 11764/10000 ergibt als integer vermutlich 1.
Wenn du 255 mit 11764 multiplizierst, kommt eine Zahl >16bit heraus...

von peter dannegger (Gast)


Lesenswert?

Die alte Integer-Regel:

Erst alles multiplizieren und dann dividieren !!!


Was ne Division einmal abgeschnitten hat, das ist weg und kommt nicht
wieder.


Peter

von johnny.m (Gast)


Lesenswert?

Rahul hat völlig recht! Lass Dir einfach mal den nackten Wert aus ADDAT
anzeigen. Und Deine Divisiongibt natürlich immer ne 1. Kannste Dir also
eh sparen. Du brauchst auch nach wie vor das DAPR nur einmal am Anfang
zu schreiben. Der Rest sieht eigentlich soweit korrekt aus...

von blawa (Gast)


Lesenswert?

Ok habs mal mit dem ADC Simulator vom Keil ausprobiert und etwas
merkwürdiges festgestellt:
ADDAT hat den richtigen wert
DruckSp1 ist 0x0000 egal bei welcher eingangsspannung
DruckSp11 hat immer irgendeinen Wert...

weis jemand woran das liegt, oder muss ich floats verwenden...
bzw hab auch die klammer versezt...

von Rahul (Gast)


Lesenswert?

>DruckSp1 ist 0x0000 egal bei welcher eingangsspannung
>DruckSp11 hat immer irgendeinen Wert...

mit oder ohne Berechnung?

Dann solltest du dir der Übersichtlichkeit eine Funktion definieren:

integer ADC_mess(integer kanal)
{

 P6=0x00;
 ADCON0=kanal;             /* AD-Kanal */
 DAPR=0x00;               /* Bereich 0 V - 5 V */
 ADCON0=ADCON0|020;
 while((ADCON0&0x10)!=0); /* Warten bis Wandlung fertig (15us) */
 return ADDAT;
}

dann rufst du sie wie folgt auf (Kanal 4 als Beispiel):

DruckF1 = ADC_mess(4);

das Erhöht die Übersichtlichkeit ungemein.

Wenn du jetzt noch irgendwelche Berechnungen anstellen willst, solltest
du immer erst die Multiplikation durchführen, und dann dividieren
(Zahlenraum der ganzen Zahlen...)

Ich kenne den Keil jetzt nicht, aber IMHO gibt es in jedem C-Compiler
"char" bzw. "unsigned char". Das ist nur 8 Bit statt 16 Bit
groß...

Warum willst du den Messbereich eigentlich von 255 auf 150 Werte
verringern?

von blawa (Gast)


Lesenswert?

Ich will den Messbereich auf 150 verringern, da wir von 0-300 bar messen
und 2 bar abstände reichen uns völlig....

von Uwe (Gast)


Lesenswert?

Hi!
Mal ne blöde Frage, kommste nicht besser das Sensorsignal extern zu
teilen? Wenn du das sauber machst ist ein LSB=2Bar und fast die ganze
Rechnerei fällt weg.

MFG Uwe

von Rahul (Gast)


Lesenswert?

Wie ist es denn jetzt mit den berechneten Werten? Immer noch 0x0000?

von andi (Gast)


Lesenswert?

Normalerweise ist die Berechnung genauer aber bei 8 Bit sehe ich es auch
so wie Uwe. Schalte vor deinen ADC einen Trimmer und stelle ihn auf 1LSB
= 2Bar.

von blawa (Gast)


Lesenswert?

Habs gelöst... das Problem war, dass eine normale Integer keine so
hochen Werte speichern kann.... Hab aus der Integer Variable eine
long-Integer gemacht und voila es funzt.... nur hab ich das
Integerproblem, da für ihn 59,998 noch immer 59 ist ^^

von Karl H. (kbuchegg)


Lesenswert?

Was ist 59,998?
Eine floating Point Zahl?
Dann gewoehn Dir bitte an, da einen . zu schreiben.
Ist in der EDV nun mal so. ',' schreiben die
Kaufleute und ev. noch Mathematiker. '.' schreiben
die Informatiker.

Da wirst Du wohl runden muessen anstatt nur einfach die
Nachkommastellen abzuschneiden.
Hinweis: Was passiert wenn Du zu einer Gleitkommazahl
zunaechst mal 0.5 addierst und erst dann die Nachkommastellen
abschneidest?

von Rahul (Gast)


Lesenswert?

Bin ich froh, kein Informatiker zu sein...(Bin aber zum Glück auch
keiner der anderen beiden.)

von blawa (Gast)


Lesenswert?

Naja da mir die Vollversion nicht zur verfügung steht, kann ich kein
float verwenden. Ich hatte zwar überlegt, die nachkommastellen mittels
modulo herrauszufinden, aber obs nun 59 oder 60 ist, ist nicht
relevant, dh werd ichs sol lassen wie es ist ^^

von Unbekannter (Gast)


Lesenswert?

> Dann gewoehn Dir bitte an, da einen . zu schreiben.
> Ist in der EDV nun mal so. ',' schreiben die
> Kaufleute und ev. noch Mathematiker. '.' schreiben
> die Informatiker.

So ein Blödsinn.

In Deutschland wird ein Komma zur Abtrennung der Dezimalstellen
geschrieben und die Ziffern werden in Dreier-Gruppen mit einem kleinem
Abstand dazwischen (bzw. nach DIN 5008 ein ganzer Leerschritt)
geschrieben.

  Also:  1 500 234,234

Das Leerzeichen wird oft weg gelassen, gerade bei vierstelligen
Zahlen.

Auf keinem Fall sollte man ein Punkt zur Gliederung der Dreier-Gruppen
verwenden. Dann ist Chaos vorprogrammiert.

Einfach mal einen Blick in den Duden wagen, oder auch die DIN 5008
anschauen.

von Arno H. (Gast)


Lesenswert?

Die Unsitte mit dem Punkt als Dezimalzeichen hat ihren Ursprung auf
einer kleinen unbedeutenden Insel in der westlichen Nordsee. Die
Sprache dieses Volkes hat sich nun mal leider über den Globus
verbreitet.
Da es sich für eine Sprachgruppe von ca 100Mio (Stichwort
Globalisierung) nicht lohnt extra Computerprogramme zu übersetzen,
werden wir damit leben müssen, können das aber durch fehlende Umlaute
gut kompensieren.
Arno

von Karl H. (kbuchegg)


Lesenswert?

> In Deutschland wird ein Komma zur Abtrennung der Dezimalstellen
> geschrieben und die Ziffern werden in Dreier-Gruppen mit einem
> kleinem Abstand dazwischen (bzw. nach DIN 5008 ein ganzer
> Leerschritt) geschrieben.

Erklaer das doch bitte mal den internationelen Gremien
die Programmiersprachen normieren.

von Läubi (Gast)


Lesenswert?

Ein Programmiersprachensyntax hat doch nichts mit einer "richtigen"
Schreibweise zu tun. (Richtig ist sowieso relativ) du hast aber
behauptet es sei generell falsch mit Komma was faktisch nicht stimmt.

von Karl H. (kbuchegg)


Lesenswert?

Wo hab ich behauptet, dass dies falsch waere?
Ich hab ihn lediglich gebeten, sich den ueblichen
Gepflogenheiten zur Schreibweise von Gleitkommazahlen
(im Umfeld von Programmierern, aber das sollte eigentlich
bei so einem Thread implizit vorausgesetzt werden koennen)
anzupassen.

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.