mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik AVR ADC Resultat von komplementär nach "linear" umformen


Autor: Ben ___ (burning_silicon)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hi!

ich habe hier ein kleines problem mit dem resultat einer ADC unter 
verwendung der differential gain stage. das eigentliche messen ist kein 
problem, nur die umwandlung des resultates in eine brauchbare form. der 
AVR spuckt dabei das resultat als "two's complement" aus. der bereich 
-512 bis null geht dabei von 0x200(-512) bis 0x3FF(0), +512 werden zu 
0x1FF. in dieser form ist das ergebnis für mich unbrauchbar, zumal es 
sich noch über ADCH:ADCL verteilt. ich brauch es als 0..1023 bzw 
0x000..0x3FF. aber irgendwie stell ich mich zu doof an um eine schnelle 
umwandlung hinzubekommen, ich würde mich freuen wenn jemand sowas schon 
mal gemacht hat und mir etwas auf die sprünge helfen kann. dezimal wäre 
es einfach (+1024 und erledigt), aber ich bekomm das mit den geteilten 
bereichen irgendwie nicht gebacken, weil der negative bereich "über" dem 
positiven liegt.

Autor: Tim Seidel (maxxie)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
mach daraus erstmal ein signed short (bitshift nach links um 6, 
aritmetischer shift nach rechts um 6, das zieht dir das Vorzeichen in 
die oberen 6 bits)

dann einfach +512 um -512 bis + 511 auf 0 bis 1023 zu bringen.
signed short val = (((signed short)in << 6) >> 6) + 512 ;

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

In Assembler?

MfG Spess

Autor: Ben ___ (burning_silicon)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
mist, zum zweiten mal vergessen... ja, assembler. entschuldigt bitte!

Autor: Wayne Monga (vibra)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
moin

für 8 Bit hät ich was , war mal für nen Dallas Temp.sensor.

+125    01111101    7Dh
0   00000000   00h
-55   11001001   C9h

das wären die Zahlen -55 bis +125 in einem Byte (8bit)
;*************************Two's complement in ASCII*********************************************** 
; Hexdezi used two highregister And 5 Low registers 
;aa = r16 , r6,r7,r8,r9,r10

;r6-r7 Hex Bcd wandlung

; zu wandelnder Wert in aa


.include "2313def.inc"


 .def  aa  = R16      ;input two's complement
 .def temp  = R17      ; scratch space

; Ergebnis in
 .def  dezv  =R08    ;dezimal ausgabe in ascii
 .def  dezh  =R09    ;
 .def  dezl  =R10    ;
;************************************************************************ 
 rjmp  RESET        ;   Reset Handle
;************************************************************************



RESET: 
  
    ldi    zl,Low(RAMEND)  ;Stack setzen
    out    SPL,zl
    rcall hexdezi
loop:  
    rjmp loop

;*****************************************************************************
; aa = two's complement number

hexdezi:
            ;wenn negativ 2 zahlen + vorz. sonst 3 
  sbrc  aa,7      ;Bit 7 gesetzt dann neg. - test auf negative Zahl
  rjmp negaz
            ;test auf größer 99
bin2bcdh:
    clr  temp    ;Clear result msd
bBCD83:  
    subi  aa,100      ;Input = Input -100
    brcs  bBCD84    ;abort If carry Set
    inc    temp  
    rjmp  bBCD83
bBCD84:  
    subi  aa,-100
    mov    dezv,temp
    rcall   bin2bcd
    rcall   bcdasc
    mov    dezh,r6
    mov   dezl,r7
    mov   aa,dezv
    rcall   bcdasc
    mov   dezv,r7
    ret
;**************************************************************************
negaz:
    neg    aa      ; negative Zahl ist  zweiercomplement
    rcall   bin2bcd
    rcall   bcdasc
    ldi   temp,'-'    ; minus ascii
    mov   dezv,temp
    mov    dezh,r6
    mov   dezl,r7
    ret      

;**************************************************************************
; 8Bit Binär in packed Bcd  -  wert in aa - ergebnis in aa !
bin2bcd:
    clr    temp    ;Clear result msd
bBCD81:
    subi  aa,10    ;Input = Input -10
    brcs  bBCD82    ;abort If carry Set
    subi  temp,-$10  ;für packed Bcd 
    rjmp  bBCD81
bBCD82:
    subi  aa,-10
    add    aa,temp
    ret
;***************************************************************************
; Bcd - zahlen in 2 ASCII char ---   wert in aa - ergebnis in r6 und r7  h/l Byte
;  
bcdasc:
    mov   temp,aa    ; aa aufheben
    lsr  temp
    lsr  temp
    lsr  temp
    lsr  temp    ;Msb ins Lsb schieben
    ori    temp,0x30  ;$30 dazuodern erzeugt ascii 30 -39 da nur zahl 0-9
    mov    r6,temp
    andi  aa,0x0f    ;löschen des Msb
    ori    aa,0x30
    mov    r7,aa
    ret


kann man mit AVRStudio simulieren

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Ohne Gewähr:

Vorsicht Pseudocode!

 in r16,ADCL
 in r17,ADCH

wenn Bit1 von r17=H dann

 com r16                    ; change sign
 com r17
 subi r16,  LOW(-1)
 sbci r17,High(-1)

weiter mit

 add r16, Low($200)
 adc r17, High($200)

MfG Spess

Autor: Anja (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ist doch ganz einfach:
das Höchstwertige Bit enthält Dein Vorzeichen (0 = +, 1 = -)
Damit das Ganze ein "echtes" 2er Komplement gibt könntest Du
das Vorzeichen in alle bits oberhalb des Vorzeichens eintragen
(also wenn Bit9 gesetzt ist dann setze Bit 10-15 ebenfalls).
In Assembler wäre dies eine einfache Oder-Verknüpfung im High-Byte
mit 0xFC falls Bit 9 gesetzt ist.

Danach hast du ein echtes 2er-Komplement. (-512 bis +511)
Wenn Du jetzt 512 addierst (also 0x02 zum High-Byte) dann
erhälst Du den Zahlenbereich 0..1023

Tims Vorschlag in "C" macht im Prinzip auch nichts anderes.

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du kannst auch ADLAR setzen.  Damit erhältst Du vorzeichenbehaftete 
fortlaufende Zahlen und sparst Dir ggfs. die Schieberei.

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Noch mal im Reinformat:

     in r16,ADCL
     in r17,ADCH

     sbrs r17,1
     rjmp aaa

     com r16                    ; change sign of dividend
     com r17
     subi r16, LOW(-1)
     sbci r17,High(-1)

aaa: ldi r18, Low($200)
     ldi r19,High($200)

     add r16,r18
     adc r17,r19

MfG Spess

Autor: Ben ___ (burning_silicon)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
stelle fest ich kriegs heute in meine birne nicht rein. vielleicht schon 
zu lange dran rumprobiert. ich probiers mal mit deinem code spess!

Autor: Ben ___ (burning_silicon)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
gibts eigentlich einen AVR der das auch bei differentiellen inputs als 
"lineares" ergebnis ausgeben kann? das wäre für mich glatt ein grund 
dahin zu wechseln. ich kapier den sinn davon nicht, es macht diese 
differentiellen eingänge unnötig kompliziert.

Autor: Ben ___ (burning_silicon)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
geht leider noch nicht, der code negiert mir das ergebnis. sprich beim 
absenken der zu messenden spannung wird eine steigende "gemessen". 
irgendwas ist da noch murks aber ich hab heute keine lust mehr mich 
weiter mit dem schrott zu befassen.

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>gibts eigentlich einen AVR der das auch bei differentiellen inputs als
>"lineares" ergebnis ausgeben kann? das wäre für mich glatt ein grund
>dahin zu wechseln. ich kapier den sinn davon nicht, es macht diese
>differentiellen eingänge unnötig kompliziert.

Warum?. Das widerspricht für meine Begriffe dem Prinzip der 
differenziellen Messung. Es soll ja bestimmt werden, um welchen Betrag 
eine Spannung grösser oder kleiner als eine andere ist. Möglicherweise 
liegt dein Denkfehler schon etwas weiter davor. Aber da niemand weiss, 
worum es geht...........

MfG Spess

Autor: Ben ___ (burning_silicon)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
es geht um eine möglichst genaue spannungsmessung in einem vorgegebenen 
bereich. mehr nicht. um die auflösung zu verbessern wollte ich den 
vollen messbereich auf den interessanten spannungsbereich bringen, das 
wären 9-16V. die 9V müssen daher irgendwie "weg". mit einem 
differentiellen verstärker und einer 10x gain stage ginge das sooo schön 
wenn man anstelle GND an einen pin eine feste offsetspannung anlegt, 
welche der des spannungsteilers bei 9V entspricht. der 
differentialverstärker würde bei der messung von 12V nun nur noch 3V 
"sehen" und der ADC kann im bereich von 9-16V mit vollen 10bit messen. 
jedenfalls in der theorie.

in der praxis schreibt der atmel kack aber vor, daß die messung nicht 
von 0..1023 sondern von -512..511 zu erfolgen hat. klasse idee, kann mir 
mal einer sagen wieso das sein MUSS?! okay, das bedeutet als erstes, daß 
die referenzspannung zum "wegkompensieren" der unwichtigen 9V um 0.25V 
angehoben werden muß damit man den vollen messbereich bekommt. aber daß 
dieses "+-"-verhalten bis ins programm reingezogen wird ist mir 
unverständlich - ein adc-ergebnis im bereich 0..1023 wäre deutlich 
einfacher zu handhaben. wenn dann jemand positive/negative ausgaben 
braucht wäre das ebenfalls sehr einfach möglich, das höchste bit läßt 
sich immer noch als vorzeichen gebrauchen...

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ben _ schrieb:

> in der praxis schreibt der atmel kack aber vor, daß die messung nicht
> von 0..1023 sondern von -512..511 zu erfolgen hat. klasse idee, kann mir
> mal einer sagen wieso das sein MUSS?!

Weil die Differenz nun mal positiv oder negativ sein kann.
Wo liegt denn da das Problem?
Vorzeichenbit ansehen, erweitern auf 16 Bit und 512 addieren. Das kann 
doch nicht so schwer sein.

> einfacher zu handhaben. wenn dann jemand positive/negative ausgaben
> braucht wäre das ebenfalls sehr einfach möglich,

das ist genauso einfach/schwierig wie der umgekehrte Weg.

Du stellst dich an, wie jemand der sich wundert warum sein OpAmp auch 
negative Differenzen verstärkt.

Autor: Ben ___ (burning_silicon)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
na das problem ist aber auch, daß sich durch den schrott die 10x gain 
stage wie eine 5x gain stage verhält. das ist für eine sinnvolle 
strommessung mit der internen referenz schon wieder die ganz unterste 
grenze. 200x würden sich wie 100x verhalten, das ist aber schon wieder 
zuviel des guten. reale 10x wären schon schick gewesen, so kostet das 
die hälfte der auflösung. zum glück immer noch genug, aber es wäre halt 
mehr drin gewesen.

ich fänds praktischer wenn ich immer einen wert zwischen 0..1023 
bekommen würde, den nullpunkt kann man sich dann mit einfachen ADDs bzw. 
SUBs hinschieben wo man ihn haben will.

habe für das eigentliche problem aber eine supereinfache lösung 
gefunden:
mit einem XOR auf das vorzeichenbit ballern und der spuk ist vorbei!

Autor: Gastjjhjjklji (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und warum nimmst Du nicht die Mitte des interessierenden Bereichs als 
Referenzspannung? Da Du die ja sowieso mit einem einfachen 
Spannungsteiler erzeugen willst ist die dort genauso ungenau.

Gast

Autor: Ben ___ (burning_silicon)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Und warum nimmst Du nicht die Mitte des interessierenden Bereichs als
> Referenzspannung?
hab ich. anders gehts ja auch nicht.

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ben _ schrieb:
> geht leider noch nicht, der code negiert mir das ergebnis. sprich beim
> absenken der zu messenden spannung wird eine steigende "gemessen".

Das Ergebnis darf auch nicht komplementiert werden, es muss das 
Vorzeichen ergänzt (nach oben erweitert) werden.  Code:
     in r16,ADCL
     in r17,ADCH

     sbrs r17,2
     rjmp is_positive

     ori r17,0xFC    // Vorzeichen erweitern

is_positive:

Ergebnis ist eine Zahl zwischen -4096 bis +4095.

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der letzte Satz war nicht ganz richtig:  Das Ergebnis ist eine Zahl 
zwischen -512 und +511.  Wie Du von dort aus auf 0..1023 kommst, bedarf 
wohl keiner Erklärung.

Autor: Michael U. (amiga)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

     in r16,ADCL
     in r17,ADCH

     subi r17,0x02   // add 02 zum H-Teil
     andi r17,0x03   // Überträge ignorieren

sollte passen.

Gruß aus Berlin
Michael

Autor: Ben ___ (burning_silicon)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
IN  R16,ADCL
IN  R17,ADCH
LDI R18,2
EOR R17,R18

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.