Problem mit ADC an mega128

OP #732922
Lesenswert?

hallo,
bin grad beim probieren des adc vom mega128 den  gemessenen wert wird im 
terminal program ausgegeben,
wenn ich 5volt am adc0 anlege dann ist ja max=1023 sind den 5volt,
wie muss ich das jetzt umändern das er mir nicht 1023 anzeigt sondern 
5volt.

vielleicht könnte mir jemand von euch ein bischen weiterhelfen
danke
mfg kay
Angehängte Dateien:
#732941
Lesenswert?

Kay B. wrote:
> hallo,
> bin grad beim probieren des adc vom mega128 den  gemessenen wert wird im
> terminal program ausgegeben,
> wenn ich 5volt am adc0 anlege dann ist ja max=1023 sind den 5volt,
> wie muss ich das jetzt umändern das er mir nicht 1023 anzeigt sondern
> 5volt.

Leute, das ist aber jetzt übelst. DREISATZ!
OP #733021
Lesenswert?

hallo Alex,
entschuldige vielleicht ne dumme frage, aber wie muss ich das nun in 
mein code umändern,

=> um einen gemessenen Wert A (z.B. 644) in eine Spannung B zu
konvertieren rechnest du
B = A * 5 / 1023





@Falk

Festkommaarithmetik,,, das ist in c geschrieben oder? bin der sprache C 
nicht mächtig
leider kann ich die formeln mit meinen browser nicht lesen


mfg kay
#733023
Lesenswert?

@ Kay B. (newbie)

>=> um einen gemessenen Wert A (z.B. 644) in eine Spannung B zu
>konvertieren rechnest du
>B = A * 5 / 1023

Genau.

>Festkommaarithmetik,,, das ist in c geschrieben oder? bin der sprache C
>nicht mächtig

Und?  Die Rechnung ist unabhängig von der Programmiersprache.

>leider kann ich die formeln mit meinen browser nicht lesen

???

MFG
Falk
Gast #733027
Lesenswert?

Hi

An deiner Stelle würde ich die 2,56V interne Spannungsreferenz benutzen. 
Da hast du erstmal eine Auflösung von 2,5mV/Bit. Die Eingangsspannung 
must du natürlich auf die Hälfte teilen. Damit kommst du auf einen 
ADC-Wert von 1000 bei 5V. Damit wird das Rechnen wesentlich leichter.

MfG Spess
Gast #733031
Lesenswert?

Hm..

Nehmen wir mal an, dein ergebnis steht in ADCH:ADCL (rechtsorientiert)
Also 0..1023

Dann mache folgendes:
Addiere zu der Variablen einfach 1/4 nochmal dazu:
(pseudocode)
temp1 = r17:r16;
temp1 = ADC;
temp1 = temp1 + (temp1>>2);  (evtl runden)

jetz hast du im MSB die Spannungszahl vor dem Komma!
Also wenn ADC=1023 => temp1= 0x04FE (runden)
dieses highbyte von temp1 gibst du aus, anschließend ein Komma.
Dann nimmst du das LSB (also die unteren acht bit von temp1, hier 0xFE)
diesen multiplizerst du mit 10,
im MSB ist jetzt die erste Kommastelle, (MSB=0x09EC) => 9 ausgeben

das LSB wieder mit 10 multiplizieren, (10x 0xEC = 0x0938)
im MSB ist jetzt die zweite Kommastelle.. (MSB=09, ausgeben)
0x38 mal 10 = 0x0x0230,  2 ausgeben,
0x30 mal 10 = 0x01E0,    1 ausgeben,
0xE0 mal 10 = 0x08C0,    8 ausgeben,
0xC0 mal 10 = 0x0780,    7 ausgeben,
0x80 mal 10 = 0x0500,    5 ausgeben,
..
ergibt: 4,9921875    ( ~ 5*1023/1024, Rundung bei *1,25)

Achtung: Die Genauigkeit wird nur vorgegaukelt

das geht super der Algorithmus..

Programmieren kannst dus selbst..
Gast #733043
Lesenswert?

Hi

@Falk
Nicht die Multiplikation, sondern die Division durch 1023. Oder ist es 
für dich illegitim Software durch Nutzung der Hardwareressourcen zu 
vereinfachen.
Diese Referenzspannung ist genau dazu vorhanden.

MfG Spess
#733049
Lesenswert?

@ spess53 (Gast)

>Nicht die Multiplikation, sondern die Division durch 1023. Oder ist es

Auch DU solltest dir den Artikel Festkommaarithmetik mal in Ruhe 
zu Gemüte führen. Speziell

http://www.mikrocontroller.net/articles/Festkommaarithmetik#ADC_allgemein


MfG
Falk

P.S. Und die Referenzspannung ist selten 2,56V, die Toleranzen sind da 
bisweilen erheblich. Und wenn man kalibrieren will, muss man in der 
Software ein wenig rechnen. Tut aber nicht wirklich weh.

MFG
Falk
Gast #733062
Lesenswert?

Hi

Ich gehe davon aus, Kay nicht nur die 5V sondern auch mal eine andere 
Spannung mit einer Auflösung <1V messen will. Zum anderen ist die 
Messung einer Spannung=Referenzspannung sowieso nicht das Grüne vom Ei.

MfG Spess
Gast #733091
Lesenswert?

Hi

@Matthias

Kannst du dein Programm mal etwas erläutern.
Wenn ich das nachvollziehe, machst du erst eine Multiplikation mit 1,25 
und danach eine mit 5. Macht 6,25. Für ADC=1023 ergibt das 6390 ?!?!

MfG spess

P.S.  'clc/ror' lässt sich durch 'lsr' ersetzen
Gast #733107
Lesenswert?

@ spess53 (Gast):

Ich hab mir den Alghorithmus mal in nem Mikroprozessorpraktikum 
ausgdacht, die aufgabe war dort etwa so:
ein ADC-Wert 8bit, soll eine Spannung von 0..5V darstellen. Also wie 
hier, nur nicht 10bit, sondern 8bit.
(auf 8bit bezogen jetzt:)

Ich habe mir da überlegt, dass der maximalwert 255, der ja mit 
1/256mal5V gewichtet ist, ja nur mit fünf multipliziert (skaliert) 
werden muss, um im MSB (8-15.bit) eine Zahl zwischn 0..4 zu 
bekommen.(255*5=1020=0x04FB) somit ist das MSB die Stelle vor dem Komma: 
4,... Volt
da ja jetzt das komplette LSB wohl offensichtlich die Nachkommastelle 
(0..0,99999..V) beinhalten muss, kann ich diese doch einfach mit 
10multiplizieren, es entsteht im MSB eine Zahl 0...9. Das ist die erste 
Nachkommastelle: (10dez* 0xFB=0x09CE) MSB=9, LSB=0xCE => 4,9...V
Das 0xCE wieder mit 10mal nehmen:
(10dez* 0xCE=0x080C) MSB=8, LSB=0x0C                  => 4,98...V
...
(10dez* 0x0C=0x0078) MSB=0, LSB=0x78                  => 4,980...V
...
(10dez* 0x78=0x04B0) MSB=4, LSB=0xB0                  => 4,9804...V
..
(10dez* 0xB0=0x06E0) MSB=6, LSB=0xE0                  => 4,98046..V
...
(sollte irgendwann abgebrochen werden ,-)


PS:  5V*255/256 = 4,98046875V

Da in obigen beispiel der Wertebereich 4mal so groß war (1024statt256), 
dann halt nicht mal5, sondern mal 5/4=1,25....

Noch Fragen?

PS:
>'clc/ror' lässt sich durch 'lsr' ersetzen
lsr ist ohne beachtung des carry-flags, das will ich aber 
'rüber'schieben

>enn ich das nachvollziehe, machst du erst eine Multiplikation mit 1,25
>und danach eine mit 5. Macht 6,25. Für ADC=1023 ergibt das 6390 ?!?!

Nein, nur mit 1,25, im Programm hat sich ein Schusselfehler 
eingeschlichen:
Die Fünf ist hier Unsinn...
1
temp1H = r17
2
temp1L = r16
3
temp2H = r19
4
temp2L = r18
5
faktor = r20
6
counter = r21
7
ascii   = r22
8

9
;------- werte holen
10
mov r17, adch
11
mov r16, adcl
12
;------- temp puffer
13
movw temp2L, temp1L
14
;------- teile durch vier
15
clc                       ; clear carry flag
16
ror temp2H
17
ror temp2L
18
clc
19
ror temp2H
20
ror temp2L
21
;------- zusammenrechnen
22
add temp2L, temp1L
23
adc temp2H, temp1H        ; in temp2 steht jetzt 1,25*adc
24
;------- ausgabe highbyte
25
mov ascii, -0x30          ; ascii für null
26
subi temp2H, ascii
27
UDR = temp2H             ; über uart senden
28
UDR = ','                ; komma senden, warten auf udre einfügen
29
;------- lowbyte mal zehn,
30
ldi faktor, 10
31
ldi counter, 5          ; azahl nachkommastellen
32
loop:
33
mul temp2L, faktor
34
subi r0, ascii
35
UDR = r0                 ; über uart senden, warten auf udre einfügen
36
mov temp2L, r1
37
;------ genug stellen ausgegeben?
38
DEC counter 
39
BRNE loop;
40
;------- nu fertsch ;-)


Was haltet ihr von dem Algorithmus?
Gast #733117
Lesenswert?

Hier ist die Lösung aus besagtem Praktikum:

Siehe pdf Seite 5:
Routine "Analogwert in String umwandeln"
AN_TO_STRING:
...

Die hier gezeigte Lösung hat allerdings noch eine Vornullenunterdrückung 
(fall U<1V), sowie ein Autoranging:
U>=1V => Anzeige: 1.234V
U<1V  => Anzeige: 234mV bzw 98mV, nicht 098mV


Das Programm hier war aber für so nen 80C500 irgendwas ;-/
Angehängte Dateien:
Gast #733144
Lesenswert?

Du solltest das stückweise machen:

erstmal nimmst du den adc wert (den du bisher ausgibst) und tust ihn mit 
1,25 multiplizieren, das gibst du erstmal aus.
Dann machst du schritt für schritt weiter
Gast #733147
Lesenswert?

Hi

So sieht das natürlich besser aus. Allerdings kommst du bei ADC=1023 
nicht auf 5,00.

movw temp2L, temp1L
;------- teile durch vier
adiw temp2L,5             ---->könnte helfen
clc                       ; clear carry flag
ror temp2H

MfG Spess

P.S.  clc - Löscht Carry-Flag (Cy=0)
      ror - Schiebt Register+Bit0=Cy

      lsr - Schiebt Register+Bit0=0

Wo ist da der Unterschied?
Gast #733150
Lesenswert?

>>llerdings kommst du bei ADC=1023 nicht auf 5,00.

Sollst du auch nicht, weil das ja dann nur 1023/1024stel von 5V sind...
der Wertebereich geht ja von 0...5V-1Ulsb

mit Ulsb = 5V/1024..

weil 0..1023 sind 1024 Stufen...

ADC=0        =>   Uadc>= 0,0000000V
ADC=1        =>   Uadc>=     4,8828125mV
ADC=1023     =>   Uadc>= 4,995117188V
Gast #733176
Lesenswert?

@ spess53 (Gast):

Nein. Dann hast du das Prinzip eines ADC nicht (komplett) verstanden:
Ich vereinfache mal:
Referenzspannung: 8V
Auflösung: 8Stufen: (3bit)
Eingangsspannung              ADC-Wert
0,00000000 - 0,9999999...     0
1,00000000 - 1,9999999...     1
2,00000000 - 2,9999999...     2
3,00000000 - 3,9999999...     3
4,00000000 - 4,9999999...     4
5,00000000 - 5,9999999...     5
6,00000000 - 6,9999999...     6
>7,00000000                   7

So arbeitet ein ADC!

Er teilt die Referenzspannung in (hier) 8gleiche Teile, diese beginnen 
IMMER bei Null und enden bei 2^(bit-auflösung)-1

beachte die MINUS EINS!!!

Somit sind die (hier 3bit) Auflösung ausgeschöpft, und mehr kann nicht 
dargestellt werden...
#738140
Lesenswert?

Kay B. wrote:
> hallo,
>
> vielleicht könnte mir nochmal einer weiterhelfen.

Ich versuche es mal...

>
> bei gemessenen 5Volt wird 6.15 angezeigt woran liegt das
> sitze schon tage dran aber bekomme das nicht richtig hin.

Da ich keinen Mega128 habe (meine Projekte arbeiten mit kleineren AVRs, 
ich mag nicht mit Kanonen auf Spatzen schießen), kann ich es natürlich 
nicht testen. Daher keine Gewähr für die Richtigkeit.

Zuerst einige Hinweise, die nichts mit dem Fehler zu tun haben:

- Die von mir genutzten "kleinen AVRs" haben nicht nur 16 Register,
  sondern 32. Ich hoffe, das ist beim Mega128 auch so. Da die meisten
  Registerzugriffe ohne Konstanten erfolgen, lassen sich die unteren
  16 Register auch benutzen. ;-)

- Du definierst 5 Register (r23-r27), die Du gar nicht benutzt.

- Du nutzt eines der tempX-Register für die Addition von 0 mit Carry.
  Dazu reicht ein unteres Register, das man sinnvollerweise auch noch
  "null" nennt, völlig aus. Vorteil: Der Code erklärt sich selbst.

- Du sicherst Register auf Stack, die gar nicht gesichert werden müssen.

- Du nutzt (als temporär gekennzeichnete) Register (temp4, temp3, temp2)
  als globale Variablen zum Aufsummieren der 256 Messwerte. Das ist
  schlechter Stil, wenn man eine Variable "temp" nennt, dann muss sie
  auch temporär verwendbar sein. Sprechende Namen wie "adwh", "adwl"
  oder "adwn" (AD-Wert- High, Low, Nachkomma) verhindern
  Missverständnisse, die aktuell eingelesenen Messwerte jeder Runde sind
  dagegen "temporär" und können in temp-Registern Platz finden.

Den eigentlichen Fehler vermute ich hier:

- Du Summierst 256 ADC-Messungen in den Registern temp2, temp3 und
  temp4. Dabei ist temp4 das hochwertige Byte, temp3 das niederwertige
  Byte und temp2 die (nur für die Rundung berücksichtigte)
  Nachkommastelle. Dein 16-Bit-Ergebnis steht also in temp4:temp3.

- Du zerelegst in "number16:" eine 16-Bit-Zahl und schickst die
  einzelnen Ziffern über UART an den PC. Du zerlegst aber nicht (wie
  gewollt) temp4:temp3, sondern temp3:temp2. Vernünftige Registernamen
  hätten das Missverständnis verhindert. Dazu kommt noch etwas Unsinn
  beim Push und Pop der auszugebenden Register.

- Du erwartest bei 5V angelegter Messspannung Zahlenwerte von etwa 5
  oder 5,00. Ich sehe in Deinem Code aber nirgends eine Skalierung.
  Die Zahlenwerte, die Du bei Beseitigung des anderen Fehlers erwarten
  kannst, sind 00000 bis 01023.

Fazit: Das Abschreiben von Tutorial-Beispiel-Codes bringt nichts, 
solange Du sie nicht verstehst. Mein Vorschlag: Nimm zum Lernen einen 
kleinen AVR wie den Mega8, der ist übersichtlicher und wird von vielen 
Leuten hier verwendet, wodurch sich vermutlich mehr Helfer finden. 
Außerdem sind viele Teile des Tutorials für den Mega8 geschrieben. Falls 
Du ihn dieses Jahr noch brauchst, kannst Du Dir gerne einen oder zwei 
bei mir abholen. Ich hätte auch noch ein funkelniegelnagelneues 
blitzeblaues 4x40-LCD für Dich... ;-)

...
OP #738504
Lesenswert?

hallo,

das erweiterte adc-beispiel habe ich mal ausprobiert das geht allerdings 
sende ich auf uart1.
wenn nun vielleicht andere sachen noch zuerledigen sind (dann sind ja 
nicht mehr genügend register vorhanden) zb. ausgabe auf dem lcd.




hallo hannes,

mega8 habe ich hier auch ein paar rumliegen .

mfg kay
#738606
Lesenswert?

Kay B. wrote:
> wenn nun vielleicht andere sachen noch zuerledigen sind

Dann kommt man mit dem Stil im Tutorial nicht weit, da an allen Ecken 
und Kanten gewartet wird anstatt andere Dinge zu erledigen.

> (dann sind ja
> nicht mehr genügend register vorhanden)

Nööö, es wurde (außer zur Multiplikation r0 und r1) noch kein einziges 
unteres Register verwendet. Und RAM ist auch noch jede Menge frei. Wenn 
man das Beispiel etwas aufräumt, dann sind auch genügend Register frei.

> zb. ausgabe auf dem lcd.

Nööö, auch dazu reichen die Register noch massig.

>
>
>
>
> hallo hannes,
>
> mega8 habe ich hier auch ein paar rumliegen .

Und warum benutzt Du dann für sooo triviale Dinge Deinen Mega128? Lass 
ihn doch liegen bis Du etwas mehr Durchblick hast und mach' die 
Tutorial-Beiträge mit einem Mega8. Es wäre doch schade drum, wenn er bei 
solch trivialen Experimenten durch ein Missgeschick beschädigt würde.

>
> mfg kay

...
#738739
Lesenswert?

Ich habe die Vermutung, dass Kay Probleme hat, die Ressourcen 
eigenständig zu verteilen/verwalten.

Das Tutorial nutzt unbekümmert obere Register, wo auch untere Register 
reichen würden, nun fehlen ihm die Register für die LCD-Routinen.

Vielleicht dringt Kay ja beim "Verstehen" der Zusammenhänge nicht tief 
genug in die Materie ein?

Mein Tip an Kay: Kleiner überschaubarer AVR, kleine überschaubare 
Aufgaben, bei der Lösung der Aufgabe jedes Bit versuchen zu verstehen. 
Das Zusammenkopieren von fremden Quelltexten und Verändern dieser 
Quelltexte nach Versuch und Irrtum führt in eine Sackgasse.

...
#738794
Lesenswert?

@ Hannes Lux (hannes)

>Mein Tip an Kay: Kleiner überschaubarer AVR, kleine überschaubare
>Aufgaben, bei der Lösung der Aufgabe jedes Bit versuchen zu verstehen.
>Das Zusammenkopieren von fremden Quelltexten und Verändern dieser
>Quelltexte nach Versuch und Irrtum führt in eine Sackgasse.

Amen. Das sollte man 1:1 in den noch leeren Artikel Copy&Paste 
Programmierung übernehmen. Ich bin mal so frei.

MFg
Falk

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