Forum: Mikrocontroller und Digitale Elektronik Variable in Assembler bearbeiten u. incrementieren


von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Hallo Leute,
bin neu dabei, lerne gerade Assembler und habe, eine für Euch einfache, 
Frage:
Habe eine Veriable mx definiert:
.set mx = 0b00000000
Den Wert der Variabel möchte ich in einer Schleife incrementieren...
Aber wie ?
Wenn ich "inc mx" eingebe kommt ein Fehler dass das Register falsch 
währe...
Ich benutze AVR-Studio im Simulationsmodus und PonyPro2000, habe ein 
Atmel Evaluationboard Vers. 2.0 von der Fa.Pollin und ein mega8 
eingesetzt.
Hat jemand eine einfache Erklärung für mich ?
Vielen Dank

PS:
Lerne/lese gerade das AVR-Tutorial aber es fällt mir alles noch ein 
wenig schwer.... sollte ich was überlesen haben?
Danke

von Spess53 (Gast)


Lesenswert?

Hi

In Assembler gibt es keine Variablen. Alle Operationen werden mit 
Registern gemacht.

z.B.

    ldi r16,0b00000000
    inc r16

Mit '.def' kannst du Registern Namen zuweisen:

    .DEF ior=r16

Dann:

    ldi ior,0b00000000
    inc ior

MfG Spess

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Hallo Spess53,
vielen Dank für die schnelle Antwort.
Habe es genau so gemacht wie Du es zeigst, mein Problem war dass die 
Software (die Demo für ADC im AVR-Tutorial)alle Register von r16 - r31 
belegt hat so dass ich die Register von r1 -r15 benutzen muss.
Dabei kam immerwieder der Fehler das es das falsche Register währe....
Deswegen meine Frage!
Eigentlich will ich versuchen den Demo-Code von der AVR-Tutorial-Seite 
(ADC) zum laufen zu bringen, möchte aber jetzt dass nicht nur ein Kanal 
gelesen wird sondern alle 6(8) Kanäle des mega8 schön nacheinander.
Kannst Du mir da weiterhelfen ?
Vielen Dank

von Uhu U. (uhu)


Lesenswert?

> .set mx = 0b00000000

definiert eine Konstante im Assembler, nicht im Programm. Deswegen kann 
man sie auch nicht mit einem Maschinenbefehl verändern, denn sie 
esistiert zur Laufzeit des Programmes nicht mehr.

@Spess53:
> In Assembler gibt es keine Variablen. Alle Operationen werden mit
> Registern gemacht.

Das stimmt in der Allgemeinheit nicht. Viele Maschinen können z.B. Worte 
im Speicher in-/decrementieren. Der Befehl enthält dann keine 
Registerreferenz; u.U. wird das Statusregister verändert.

von sechszweifuenf (Gast)


Lesenswert?

Die Register 0-15 koennen den Inc befehl nicht, nur die Register 16-31. 
Schmeiss den ADC raus. Der kann eh nicht alle diese register dauernd 
belegen. Hin und wieder muessen Variablen deshlab im RAM lagern.

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Hallo Uhu,
danke für die schnelle Antwort.
Was bedeutet das für mich ?
Wie kann ich es dann schaffen dass ich die MUX-Variabel so umschalte 
dass alle ADCs der Reihe nach abgefragt werden.
Es geht um den Code aus dem AVR-Tutorial (ADC).
Mit diesem Code experimentiere ich rum...

; ADC initialisieren: Single Conversion, Vorteiler 128, ohne 
MUXx-Angaben wird Kanal 0 gesetzt.
    ldi  temp1, (1<<REFS0) | mx; oder (m2<<MUX2) | (m1<<MUX1) | 
(m0<<MUX0) ;Kanal 0, interne Referenzspannung 5V 
(1<<MUX0)|(1<<MUX1)|(1<<MUX2)
    out  ADMUX, temp1
    ldi  temp1, (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0) ; 
Vorteiler = 128
    out  ADCSRA, temp1

Wie Du sehen kannst muss ich in der "temp1" diese Werte für die ADMUX 
eingeben um den Kanal auszuwählen.....
Dachte mir aber ich nehme eine Variable (mx), belege sie mit einem Wert 
den ich dann in einer Schleife incrementiere.
Manuell funktioniert es:

;MUXx-Werte als Variable beim initialisieren einsetzen.
.equ m2    =1  ;Variable
.equ m1    =0
.equ m0    =1
;oder mit .set eine veränderbare Variable
.set mx    =0b00000101 ; ADC-Eingänge binär schalten, 0b00000000= ADC0, 
0b00000001=ADC1 usw. => 0b00000101 = Kanal 6

Also wenn ich dies Variable manuell ändere dann wird auch ein anderer 
ADC-Kanal gelesen.
Aber wie schaffe ich es das ganze in einer Schleife zu zwengen ?

Vielen Dank

von Karl H. (kbuchegg)


Lesenswert?

Robert Breicher wrote:
> Hallo Spess53,
> vielen Dank für die schnelle Antwort.
> Habe es genau so gemacht wie Du es zeigst, mein Problem war dass die
> Software (die Demo für ADC im AVR-Tutorial)alle Register von r16 - r31
> belegt hat so dass ich die Register von r1 -r15 benutzen muss.
> Dabei kam immerwieder der Fehler das es das falsche Register währe....
> Deswegen meine Frage!

Im AVR werden die Regsiter in 'die Oberen' und 'die Unteren'
unterteilt. Der Unterschied, wie du selbst schon festgestellt hast,
zwischen den beiden ist, dass mit den unteren Registern nicht
alle Operationen möglich sind.

Aber: Du kannst dir ja eines der oberen Register temporär
freischaufeln. Du kannst es zb mit einem Push auf den Stack
schieben, dann machst du deine Operationen mit dem Register
und wenn du damit fertig bist, holst du dir den auf dem Stack
zwischengespeicherten alten Registerinhalt mit einem Pop
wieder zurück.

Wahrscheinlicher ist es allerdings, das du mit einer Reorganisation
deines Programmes genügend Register so freibekommst, dass du das
alles gar nicht brauchst. Es ist selten, dass tatsächlich alle
Register ständig gleichzeitig im Einsatz sind. Es spricht nichts
dagegegen, ein Register für mehrere Aufgaben zu benutzen. Solange
es zu keiner zeitlichen Überschniedung kommt, ist das ja auch
kein Problem.

> Eigentlich will ich versuchen den Demo-Code von der AVR-Tutorial-Seite
> (ADC) zum laufen zu bringen, möchte aber jetzt dass nicht nur ein Kanal
> gelesen wird sondern alle 6(8) Kanäle des mega8 schön nacheinander.
> Kannst Du mir da weiterhelfen ?

Wozu brauchst du da so viele Register?
Du kannst die 6 Kanäle ja sowieso nicht alle gleichzeitig
auslesen, sondern nur hintereinander. Und da du mit den Werten
ja irgendetwas machen willst, bietet es sich ja geradezu an,
dieselben Register reihum für die einzelnen Kanäle zu benutzen.

Wenn du diese Woche etwas im Külschrank einlagern musst,
heist das ja nicht, dass du dazu die Tupperdose von letzter Woche
nicht benutzen kannst, wenn deren Inhalt schon längst aufgegessen
wurde.

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Hallo sechzweifuenf,
danke für die schnelle Antwort,
wie gesagt, ich bin ein Neuling, lerne gerade Assembler und den Umgang 
mit den Megaxxx.
Kannst Du mir näher erläutern was Du genau meinst?
Vielen Dank

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Hallo Karl-Heinz,
danke für Deine schnelle Antwort.
Es hört sich sehr vernünftig an was Du sagst, da ich aber noch nicht die 
Routine habe um sowas zu machen, (seh den Wald vor lauter Bäume nicht) 
würde mir jetzt eine Demo sehr viel helfen....
(Ich kann nicht erkennen welche Register gerade nicht benutzt 
werden....!)
Vielen Dank

von Karl H. (kbuchegg)


Lesenswert?

> ; ADC initialisieren: Single Conversion, Vorteiler 128, ohne
> MUXx-Angaben wird Kanal 0 gesetzt.
>    ldi  temp1, (1<<REFS0) | mx; oder (m2<<MUX2) | (m1<<MUX1) |
> (m0<<MUX0) ;Kanal 0, interne Referenzspannung 5V
> (1<<MUX0)|(1<<MUX1)|(1<<MUX2)
>     out  ADMUX, temp1
>    ldi  temp1, (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0) ;
> Vorteiler = 128
>     out  ADCSRA, temp1
>
> Wie Du sehen kannst muss ich in der "temp1" diese Werte für die ADMUX
> eingeben um den Kanal auszuwählen.....

Schon. Aber danach brauchst du temp1 nicht mehr. Es wurde an
dieser Stelle nur dafür benutzt um den Wert für das AMUX
Register bzw. das ADCSRA Register zusammenzustellen. Sobald
dieser Vorgang abgeschlossen ist, kannst du temp1 für irgendwelche
anderen Dinge verwenden.

Dachte mir aber ich nehme eine Variable (mx), belege sie mit einem Wert
den ich dann in einer Schleife incrementiere.
Manuell funktioniert es:

> ;MUXx-Werte als Variable beim initialisieren einsetzen.
> .equ m2    =1  ;Variable
> .equ m1    =0
> .equ m0    =1
> ;oder mit .set eine veränderbare Variable
> .set mx    =0b00000101 ; ADC-Eingänge binär schalten, 0b00000000= ADC0,
> 0b00000001=ADC1 usw. => 0b00000101 = Kanal 6

Das sind keine Variablen.
Das sind Vereinbarungen mit dem Assembler, sodass er im weiteren
Programmtext, wenn auch immer er den Text 'm2' sieht, er diesen
Text 'm2' durch den Text '1' ersetzen soll. Das hat nichts mit
Variablen zu tun, sondern dient einzig und alleine dem Programmierer,
sodass er Zahlenwerten die im Programm auftauchen einen Namen geben
kann um so besser den Überblick zu behalten, was an dieser Stelle
überhaupt passieren soll.

Wenn du beispielsweise irgendwo siehst (das ist jetzt kein
Assmebler, sondern soll das Prinzip verdeutlichen)

     x = 0.19 * y

dann weist du zunächst mal nicht, was diese Berechnung soll.
Mache ich mir aber eine derartiges Defintion

.equ  Mehrwertsteuer  = 0.19

     x = Mehrwertsteuer * y

dann erzählt mir hier der Programmtext schon sehr viel mehr.
Es geht offensichltich um die Berechnung der Steuerhöhe bei
einem vorgegebenem Betrag.

von Karl H. (kbuchegg)


Lesenswert?

Robert Breicher wrote:
> Hallo Karl-Heinz,
> danke für Deine schnelle Antwort.
> Es hört sich sehr vernünftig an was Du sagst, da ich aber noch nicht die
> Routine habe um sowas zu machen, (seh den Wald vor lauter Bäume nicht)
> würde mir jetzt eine Demo sehr viel helfen....
> (Ich kann nicht erkennen welche Register gerade nicht benutzt
> werden....!)

Das ist eines der Probleme im Assembler.

Mach dir einen Ausdruck im Programm, schnapp dir ein paar
Buntstifte und geh dein Programm durch, wo welches Register
benutzt wird. Mit dem Buntstift kannst du dann neben dem
Programmtext eine Linie ziehen, die dir angibt von wo bis
wohin ein bestimmtes Register gebraucht wird. Ausserhalb
dieses Bereichs kannst du dasselbe Register dann logischerweise
für andere Dinge benutzen.

Nehmen wir mal das ADC Beispiel aus dem Tutorial:
Was ist mit dem Register temp5?
Beim Label outp bekommt es zb einen Wert zugewiesen.
Wenn du den Programmtext weiter nach unten durchgehst,
stellst du fest, dass es diesen Wert bis zu der Stelle

    subi adlow,-'0'

;an UART Senden
    mov   temp1, temp5       ; Zehntausender Stelle
    rcall transmit

behalten muss. Damit hast du die Lebensspanne des Registers
festgelegt: Von wo bis wohin darfst du das Register nicht
verändern.
Aber ausserhalb dieses Bereichs kannst du dieses Register für
ganz andere Dinge verwenden. Natürlich unter der Voraussetzung,
dass sich die 'Lebensspannen' dieser Bereiche nicht überlappen.
Das wird ja auch im Demoprogramm gemacht. Für temp5 gibt
es einen zweiten Bereich. Es wird im Abschnitt

Main:
    clr  temp1
    clr  temp2
    clr  temp3
    clr  temp4
    ldi  temp5, 0           ; 256 Schleifendurchläufe

; neuen ADC-Wert lesen  (Schleife - 256 mal)
sample_adc:
    sbi  ADCSRA, ADSC       ; den ADC starten

wait_adc:
    sbic ADCSRA, ADSC       ; wenn der ADC fertig ist, wird dieses Bit 
gelöscht
    rjmp wait_adc

; ADC einlesen:
    in   adlow, ADCL        ; immer zuerst LOW Byte lesen
    in   adhigh, ADCH       ; danach das mittlerweile gesperrte High 
Byte

; alle 256 ADC-Werte addieren
    add  temp2, adlow       ; addieren
    adc  temp3, adhigh      ; addieren über Carry
    adc  temp4, temp1       ; addieren über Carry, temp1 enthält 0
    dec  temp5              ; Schleifenzähler MINUS 1
    brne sample_adc         ; wenn noch

ebenfalls verwendet.
Dort, beim Kommentar ' 256 Schleifendurchläufe' bekommt es den
Wert 0 und ziemlich weit unten in diesem Abschnitt wird es mal
decrementiert. Das ist also der zweite Lebensbereich für
dieses Register. Er kollidiert nicht mit dem andern Abschnitt
und daher ist das auch in Ordnung.

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Hallo Karl-Heinz,
danke noch mal...
Also wenn ich es richtig verstanden habe kann ich "temp1" nach dem der 
Wert für den ADMUX gesetzt wurde wieder mit anderen "Aufgaben" belegen.
Im Abschnitt "Main" wird "temp1" mit clr ja freigemacht, danach kann er 
wie Du meinst auch wieder für andere Zwecke benutzt werden.
Noch einen Tipp ?
Danke

von Karl H. (kbuchegg)


Lesenswert?

Im übrigen:
Im ADC Tutorial sind noch jede Menge Register frei.
Du brauchst nur ein einziges neues Register, welches
den als nächstes auszulesenden Kanal enthält.
Warum nimmst du nicht Register r26 dafür her?

von spess53 (Gast)


Lesenswert?

Hi

Deinen aktuellen Kanal brauchst du nicht in einem Register speichern, 
denn der steht in ADMUX.

Meine Variante (ohne 'temp'-Quatsch):

        in r16,ADMUX
        mov r17,r16
        inc r16                ; Kanal incrementieren
        andi r16,0b00000111    ; Kanalnummer 0..7
        andi r17,0b11111000    ; restliche Bits
        or r16,r17
        out ADMUX,r16

für 6 kanäle
        ....
        andi r16,0b00000111    ; Kanalnummer
        cpi r16,6
        brne abc
        clr r16
abc:    andi r17,0b11111000
        ....

Wenn die benutzten Register belegt sind, dann mit push/pop sichern.

MfG Spess

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Danke Karl-Heinz,
jetzt verstehe ich was Du meinst, jetzt wird es etwas heller :-)
Muss ich das Register zuerst mit "clr" löschen um es benutzen zu können?
Danke

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Karl heinz Buchegger wrote:
> Im übrigen:
> Im ADC Tutorial sind noch jede Menge Register frei.
> Du brauchst nur ein einziges neues Register, welches
> den als nächstes auszulesenden Kanal enthält.
> Warum nimmst du nicht Register r26 dafür her?

Hallo Karl-Heinz,
hatte den selben Fehler mit r26 - r31....
Dachte mir es werden für "wörter" benutzt.....
Gruß

von rene (Gast)


Lesenswert?

Es gibt konstaten :
.equ    default  =4;

Es gibt benamste register

.def  ErrorCode = r15;
.def  Temp      = r16;
.def  U1        = r17;
.def  U2        = r18;

Es gibt benamste variablen

.DSEG    ; im datensegment
.mystate:     .byte  1;   1 byte fuer mystate
.ADCChannel:  .byte  1;   ADC Channel
.ADC1:        .byte  2;   ADC1 word
.ADC2:        .byte  2;   ADC2
.ADC3:        .byte  2;   ADC3
.ADC4:        .byte  2;   ADC4
.ADC5:        .byte  2;   ADC5
.ADC6:        .byte  2;   ADC6
.ADC7:        .byte  2;   ADC7
.ADC8:        .byte  2;   ADC8
.RxBuf:       .byte  64;  Rxbuffer 64 byte

Lade von Variablen ins register

 SetYPtr    Mystate
 ld         temp,Y

zurueckschreiben

 st         Y,temp

Wobei SetYPtr ein Makro ist...

Siehe auch : http://www.ibrtses.com/embedded/avrmacros.html
http://www.ibrtses.com/embedded/avrsmallstuff.html

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Hallo Spess53,
danke für den Demo-Code,
werde es gleich versuchen....
Muss nur gucken wo genau welcher Abschnitt eingebaut werden soll....
Nicht so einfach für mich......
Vielen Dank

von Karl H. (kbuchegg)


Lesenswert?

Robert Breicher wrote:
> Danke Karl-Heinz,
> jetzt verstehe ich was Du meinst, jetzt wird es etwas heller :-)
> Muss ich das Register zuerst mit "clr" löschen um es benutzen zu können?

Nein.
Ein Register behält seinen Wert, bis du einen anderen Wert
hineinschreibst. Wenn du haben möchtest, dass das Register
einen neuen Wert von 0 enthält, dann muss man auch 0 hineinschreiben.
Der 'clr' macht das.

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Hallo rene,
vielen Dank für die schnelle Antwort,
Werde die Links besuchen und weiter studieren....
Danke für die klasse Übersicht und Info...
Gruß

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Danke Karl-Heinz,
kappiert :-)
Also einfach mit einem neuen Wert überschreiben.....
OK.
Danke

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

spess53 wrote:
> Hi
>
> Deinen aktuellen Kanal brauchst du nicht in einem Register speichern,
> denn der steht in ADMUX.
>
> Meine Variante (ohne 'temp'-Quatsch):
>
>         in r16,ADMUX
>         mov r17,r16
>         inc r16                ; Kanal incrementieren
>         andi r16,0b00000111    ; Kanalnummer 0..7
>         andi r17,0b11111000    ; restliche Bits
>         or r16,r17
>         out ADMUX,r16
>
> für 6 kanäle
>         ....
>         andi r16,0b00000111    ; Kanalnummer
>         cpi r16,6
>         brne abc
>         clr r16
> abc:    andi r17,0b11111000
>         ....
>
> Wenn die benutzten Register belegt sind, dann mit push/pop sichern.
>
> MfG Spess

Hallo Spess,
kannst Du mir die Logik Deines Codes erklären?
Ich möchte gerne verstehen wie man denken muss um sowas lösen zu können.
Es ist ja sowas wie ein Algorithmuss, oder ?
Ich möchte nur gerne verstehen was ich da mache, nicht nur einfach "copy 
& past"..
Vielen Dank

von Karl H. (kbuchegg)


Lesenswert?

Robert Breicher wrote:
> spess53 wrote:
>> Hi
>>
>> Deinen aktuellen Kanal brauchst du nicht in einem Register speichern,
>> denn der steht in ADMUX.
>>
>> Meine Variante (ohne 'temp'-Quatsch):
>>
>>         in r16,ADMUX
>>         mov r17,r16
>>         inc r16                ; Kanal incrementieren
>>         andi r16,0b00000111    ; Kanalnummer 0..7
>>         andi r17,0b11111000    ; restliche Bits
>>         or r16,r17
>>         out ADMUX,r16
>>
>> für 6 kanäle
>>         ....
>>         andi r16,0b00000111    ; Kanalnummer
>>         cpi r16,6
>>         brne abc
>>         clr r16
>> abc:    andi r17,0b11111000
>>         ....
>>
>> Wenn die benutzten Register belegt sind, dann mit push/pop sichern.
>>
>> MfG Spess
>
> Hallo Spess,
> kannst Du mir die Logik Deines Codes erklären?
> Ich möchte gerne verstehen wie man denken muss um sowas lösen zu können.
> Es ist ja sowas wie ein Algorithmuss, oder ?
> Ich möchte nur gerne verstehen was ich da mache, nicht nur einfach "copy
> & past"..

Geh davon aus, dass die Kanalnummer um 1 erhöht werden muss.
Das ist dein Ansatzpunkt.
UNd jetzt geh den Code Instruktion für Instruktion durch
und versuch nachzuvollziehen was da passiert. Immer mit
dem Hintergedanken: die Kanalnummer muss um 1 erhöht werden
und die Kanalnummer steht im ADMUX Register. Und innerhalb
dieses Registers sind es nur die untersten 3 Bits, die die
Kanalnummer enthalten.


> Vielen Dank

von spess53 (Gast)


Lesenswert?

Hi


ADMUX hat folgende Belegung:
Bit  7     6      5   4  3    2    1    0
    REFS1 REFS0 ADLAR – MUX3 MUX2 MUX1 MUX0


in r16,ADMUX        ; ADMUX nach r16
mov r17,r16         ; Kopie nach r17,für REFS1,REFS0,ADLAR
inc r16             ; r16=r16+1
andi r16,0b00000111 ; Bit 7..3 werden ausgeblendet, r16= MUX2..MUX0
                    ; Kanal 0..7
andi r17,0b11111000 ; Bit 2..0 werden ausgeblendet, 
r17=REFS1,REFS0,ADLAR
or r16,r17          ; Wert für ADMUX wieder zusammensetzen
out ADMUX,r16       ; neuer Wert nach ADMUX

Bei 6 Kanälen

      cpi r16,6     ; Kanalnummer>5
      brne abc      ; wenn<>6 nach abc springen
      clr r16       ; Kanalnummer auf 0 setzten
abc:  ...           ; weiter im Programm


MfG Spess

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Halloo Spess,
vielen Dank für Deine Hilfe, total willkommen !
Verstehe von Minute zu Minute mehr....
Bin gerade dabei Deinen Code in der Demo anzupassen, habe aber noch das 
Problem mit r16/r17, die muss ich irgendwie mit pop/push bearbeiten denn 
der Code funktioniert nicht einfach so nach dem ich ihn eingefügt 
habe....
Also muss ich etwas graue Zellen bemühen......
Vielen Dank

PS:
Einen Hinweiss wie man sowas am besten macht ?
Gruß

von spess53 (Gast)


Lesenswert?

Hi

Bedanke dich für deine Schwierigkeiten erst mal bei denen, die diesen 
'tempXYZ'-Unsinn eingeführt haben.

Da ich dein Programm nicht kenne, kann ich nur mutmaßen.

Irgendwo steht da:

    in xxx,ADCL
    in yyy,ADCH

danach wird mit xxx,yyy irgendwas gemacht. Und danach wäre die Stelle um 
den Kanal umzuschalten. Als nächstes springst du wieder an die Stelle , 
an der die ADC-Conversation gestartet wird. Dann beginnt das spiel von 
vorn.

MfG Spess

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

spess53 wrote:

>
> Da ich dein Programm nicht kenne, kann ich nur mutmaßen.
>

> MfG Spess

Hallo Spess,
es handelt sich um die Demo in dem AVR-Tutorial (ADC) auf diesen Seiten.
Ich kämpfe gerade mit dem Code, er gibt jetzt nur 1023 aus, egal welchen 
Kanal ich jetzt eingebe....
Zumindest kann ich jetzt in der Software "Terminal" nur eine Zahlenreihe 
mit 01023 sehen....
Bedanke mich für Deine Hilfe...
Eine Idee wie ich dein Code da anpassen könnte?
Ich will jeden Kanal einlesen, also muss ich den ADMUX in einer Schleife 
haben....oder ?
Habe Deinen Code eingefügt und versuche gerade daraus schlau zu werden.
Gruß

von rene (Gast)


Lesenswert?

Der ADC will den Kanal gewaehlt haben, dann startet man eine Wandlung. 
Wenn die Wandlung fertig ist, liest man aus. Und setzt den neuen Kanal. 
usw. Zuerst sollte ein Kanal vernuenftige Werte liefern bevor ich mich 
ums Umschalten kuemmern wuerde.

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

spess53 wrote:
> Hi
>
>
> ADMUX hat folgende Belegung:
> Bit  7     6      5   4  3    2    1    0
>     REFS1 REFS0 ADLAR – MUX3 MUX2 MUX1 MUX0
>
>
> in r16,ADMUX        ; ADMUX nach r16
> mov r17,r16         ; Kopie nach r17,für REFS1,REFS0,ADLAR
> inc r16             ; r16=r16+1
> andi r16,0b00000111 ; Bit 7..3 werden ausgeblendet, r16= MUX2..MUX0
>                     ; Kanal 0..7
> andi r17,0b11111000 ; Bit 2..0 werden ausgeblendet,
> r17=REFS1,REFS0,ADLAR
> or r16,r17          ; Wert für ADMUX wieder zusammensetzen
> out ADMUX,r16       ; neuer Wert nach ADMUX
>

Hi Spess,
habe eine Frage zu Deinem Code:
Warum incrementierst Du da r16 ?
Also:
Du lädst (in) ADMUX nach r16
dann
kopierst r16 nach r17
dann inc r16 ... aber warum ?
andi r16 und andi r17 sind klar
or r16, r17 auch soweit klar wobei r17 anders sein muss da ich RFS0=1 
benötige.
Alles andere soweit klar....
Gruß & danke

von Karl H. (kbuchegg)


Lesenswert?

Robert Breicher wrote:
> habe eine Frage zu Deinem Code:
> Warum incrementierst Du da r16 ?
> Also:
> Du lädst (in) ADMUX nach r16
> dann
> kopierst r16 nach r17
> dann inc r16 ... aber warum ?

Na ja. Du willst doch die um 1 höhere Kanalnummer haben

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

rene wrote:
> Zuerst sollte ein Kanal vernuenftige Werte liefern bevor ich mich
> ums Umschalten kuemmern wuerde.

Hallo Rene,
also der Demo-Code (AVR-Tutorial - ADC) hat bei mir funktioniert, jetzt 
kämpfe ich mit dem Code von Spess, da ich aber am lernen bin sind alle 
Schritte für mich noch sehr schwer/unklar, weiss z.B. nicht genau wie 
ich debn Code implementieren/anpassen muss, versuche jeden Befehl 
nachzuschlagen und zu kappieren, dann versuche ichdie Logik zu 
verstehen.
Mühsam geht es weiter....
Danke Dir

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Hi Karl-Heinz,
ist soweit klar, aber ich will erst mal gucken dass ich einen Kanal 
wieder (mit Deinem Code) richtig lesen kann.
Das macht mir noch Stress...
Dann geht es ans incrementieren :-)
Danke Dir

von spess53 (Gast)


Angehängte Dateien:

Lesenswert?

Hi

Ich habe dir das Programm mal für deine Zwecke zurechtgestutzt.Ohne 
Gewähr.

Ständiger Wert 1023 deutet auf Uin>Uref.

MfG Spess

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Hallo Spess,
vielen dank für Deinen neuen Code.
Habe ihn eingelesen und gestartet und wie gehabt kommen 2 Warnungen für 
r26 und r27:

...\thermo2\thermo2.asm(13): warning: Register r26 already defined by 
the .DEF directive

Eine Idee ?
Danke nochmals !

von Karl H. (kbuchegg)


Lesenswert?

Robert Breicher wrote:
> Hallo Spess,
> vielen dank für Deinen neuen Code.
> Habe ihn eingelesen und gestartet und wie gehabt kommen 2 Warnungen für
> r26 und r27:
>
> ...\thermo2\thermo2.asm(13): warning: Register r26 already defined by
> the .DEF directive

Die kannst du fürs erste ignorieren.

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

spess53 wrote:

>
> Ständiger Wert 1023 deutet auf Uin>Uref.
>
> MfG Spess

Hi Spess,
ich habe ein Poti von ARef des Mega8 an GND, der Schleifer ist am ADC0 
dran.
Mit der Demo funktioniert es gut, habe keine Probs damit.
Wenn ich am Poti drehe dann kann ich den Eingang (ADC0) auf GND legen, 
dann müsste 0000 ausgegeben werden.... tut er aber nicht, das bedeutet 
dass der Eingang nicht richtig funktioniert oder konfiguriert ist..... 
oder ?
Gruß

von spess53 (Gast)


Lesenswert?

Hi

Schon mal direkt am Pin gemessen?

MfG Spess

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Karl heinz Buchegger wrote:

>
> Die kannst du fürs erste ignorieren.

Hi Karl-Heinz,
Warnungen ignorieren ?
Geht das einfachso ?
Danke

PS:
Habe den Code jetzt in den Mega8 übertragen, der funktioniert wirklich 
super, sau schnell...
Habe nur jetzt ein Problem:
Mein Mega ist mit einem externen 16MHz-Quartz bestückt und die Fuse 
eingestellt, jetzt kann ich nicht mehr lesen wenn ich den Code so 
anpasse. Es kommen komische Zeichen raus....
Mit meiner alten Version konnte ich mit 9600 Boud sauebr lesen..
Gibt es eine Möglichkeit nach dem alle 6 Kanäle einmal gelesen wurden 
dass eine leere Zeile ausgegeben wird ?

von Karl H. (kbuchegg)


Lesenswert?

Robert Breicher wrote:
> Karl heinz Buchegger wrote:
>
>>
>> Die kannst du fürs erste ignorieren.
>
> Hi Karl-Heinz,
> Warnungen ignorieren ?
> Geht das einfachso ?

In dem Fall ist das ok.
Die Warnung bezieht sich darauf, dass es eine zweite
.def Anweisung gibt (die im Include File steckt), die
diesem Register bereits einen Namen gegeben hat.

Es handelt sich um das Registerpärchen r26 und r27, das
gemeinsam als das X-Register bekannt ist. Da du aber
keine Operationen mit dem X-Register machst, spielt es
keine Rolle, dass du r26 für andere Zwecke benutzt.

> PS:
> Habe den Code jetzt in den Mega8 übertragen, der funktioniert wirklich
> super, sau schnell...
> Habe nur jetzt ein Problem:
> Mein Mega ist mit einem externen 16MHz-Quartz bestückt und die Fuse
> eingestellt, jetzt kann ich nicht mehr lesen wenn ich den Code so
> anpasse. Es kommen komische Zeichen raus....

Hast du auch nicht vergessen, die Frequenzangabe im Code
anzupassen. Wenn du das nicht gemacht hast, dann werden die
UART Initialisierwerte falsch berechnet.

> Gibt es eine Möglichkeit nach dem alle 6 Kanäle einmal gelesen wurden
> dass eine leere Zeile ausgegeben wird ?

Sicher.
Nach der 6.ten Ausgabe gibst du nochmal ein CR/LF aus.
Im Originalcode sind das die Ausgaben von 10 und 13. Die
beiden sorgen dafür, dass eine neue Zeile angefangen wird.

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Hallo Stefan,
danke für die schnelle Antwort.
Schon komisch.....
Danke

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Karl heinz Buchegger wrote:
> Robert Breicher wrote:
>> Karl heinz Buchegger wrote:

> Hast du auch nicht vergessen, die Frequenzangabe im Code
> anzupassen. Wenn du das nicht gemacht hast, dann werden die
> UART Initialisierwerte falsch berechnet.
>
>> Gibt es eine Möglichkeit nach dem alle 6 Kanäle einmal gelesen wurden
>> dass eine leere Zeile ausgegeben wird ?
>
> Sicher.
> Nach der 6.ten Ausgabe gibst du nochmal ein CR/LF aus.
> Im Originalcode sind das die Ausgaben von 10 und 13. Die
> beiden sorgen dafür, dass eine neue Zeile angefangen wird.

Hi,
nein, habe es gleich gemacht.
Habe auch das Problem dass meine Software (Terminal) nicht immer sauber 
lesen kann, ich muss sie öfters diconnesten/reconnecten um den Wert 
lesen zu können, dazwischen gibt es Hyroglifen aus....
Das macht er jetzt auch bei einer Boudrate von 14400 !

Gibt es da ein Problem was ich anders lösen muss ?
danke

von Karl H. (kbuchegg)


Lesenswert?

Robert Breicher wrote:
>
> Hi,
> nein, habe es gleich gemacht.
> Habe auch das Problem dass meine Software (Terminal) nicht immer sauber
> lesen kann, ich muss sie öfters diconnesten/reconnecten um den Wert
> lesen zu können, dazwischen gibt es Hyroglifen aus....
> Das macht er jetzt auch bei einer Boudrate von 14400 !
>
> Gibt es da ein Problem was ich anders lösen muss ?

Eigentlich nicht.
Wenn die Taktfrquenz stimmt, die Baudrate stimmt, dann
solltest du im HT was sehen.

Nur zur Sicherheit: Die Übertragung hat schon funktioniert?
Du hast nur das neue Programm eingespielt und auch an den
Fusebits nichts verändert?

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Hallo Karl-Heinz,
also die Übertragung hat geklappt, die Fuse-Bits hatte ich schon am 
Anfang angepasst, teste die ganze Sache schon mit dem schnelle Quartz.
Habe nur Deinen Code eingespielt, vorher nur noch den Tackt und Boud 
angepasst...
Es funzt auch, aber wenn ich die Software starte kommt gelegentlich 
Kauderwelsch raus, dann connecte und disconnecte ich einige Male, dann 
klappt es wieder....
Also etwas instabil...
Eine Idee ?
Gruß & Danke

von Karl H. (kbuchegg)


Lesenswert?

Robert Breicher wrote:
> Hallo Karl-Heinz,
> also die Übertragung hat geklappt, die Fuse-Bits hatte ich schon am
> Anfang angepasst, teste die ganze Sache schon mit dem schnelle Quartz.
> Habe nur Deinen Code eingespielt, vorher nur noch den Tackt und Boud
> angepasst...
> Es funzt auch, aber wenn ich die Software starte kommt gelegentlich
> Kauderwelsch raus, dann connecte und disconnecte ich einige Male, dann
> klappt es wieder....
> Also etwas instabil...
> Eine Idee ?

Nicht wirklich.
Du solltest nur darauf achten, dass der Empfänger empfangsbereit
ist, bevor der Sender loslegt. Dies deshalb damit der Empfänger
auch sauber auf das erste Byte synchronisieren kann.

Aber wenn bei dir Hyperterminal sowieso ständig durchläuft,
sollte das eigentlich kein Problem sein.

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Hallo Karl-Heinz,
danke erstmal für Deine Hilfe.

Habe den Code eingegeben, er funzt in soweit dass er den Wert sauber 
ausgibt, das Problem mit gelegentlichen Sonderzeichen liegt 
möglicherwiese an der Anpassung meiner seriellen Schnittstelle.
Das werde ich noch lösen.
Habe da eine andere Frage:
In der Demo (von der Tutorial-Seite) werden die 256 Messungen nochmal 
bearbeitet um den Mittelwert zu errechnen und erst den dann an die UART 
gesendet.
Gibt es einen Grund warum Du diesen Teil einfach entfernt hast?
Zur Zeit werden die Änderungen am Poti erst nach einer Weile angezeigt, 
ich denke es sind die 256 Steps die gelesen werden und wenn die Schleife 
zu ende ist wird der neue Wert ausgegeben....
Kann ich den einfach wieder einfügen ?
Habe den Code eingefügt und Übertragen, jetzt wird etwas ausgegeben aber 
ich kann es mit nichts in Verbindung bringen....
Es hat nichts mit dem Poti zu tun.....
Danke

von Peter D. (peda)


Lesenswert?

Robert Breicher wrote:

> (Ich kann nicht erkennen welche Register gerade nicht benutzt
> werden....!)

Das Problem ist alt, aber lösbar.
Du mußt Dich erstmal hinsetzen und einige Regeln aufschreiben:

1.
Reserviere einige Register (6..16) als Scratchpad. Diese Register kann 
jede Funktion (Unterprogramm) nach belieben benutzen.
D.h. derjenige, der eine Funktion aufruft, geht davon aus, daß nach dem 
Return diese Register nicht mehr ihren alten Wert beinhalten. Werden 
aber Werte noch gebraucht, muß der Aufrufer sie Pushen oder im SRAM 
abspeichern.

R0, R1 sind automatisch Scratchpadregister, da sie von Operationen (LPM, 
MUL) verändert werden.

Benötigt eine Funktion mehr als die Scratchpadregister, muß es diese 
pushen und popen. Sie kann allerdings davon ausgehen, daß sie selber 
Unterfunktionen aufrufen kann und diese dann erhalten bleiben.


2.
Lege Dir Aufrufkonventionen fest, in welchen Registern Funktionen 
Argumente geliefert bekommen, bzw. sie Returnwerte zurückliefern. Es 
reichen in der Regel bis zu 3 16Bit Argumente (6 Register) oder 2 32Bit 
Argumente (8 Register) aus. Vorzugsweise nimmt man dazu welche von den 
Scratchpadregistern.

3.
Reseviere Scratchpadregister (5..10) für Interrupts. Damit muß man nicht 
aufwendig pushen und popen, sondern kann gleich loslegen.
Da sich Interrupts nicht gegenseitig unterbrechen können, kann die jeder 
Interrupt benutzen.
Da man 3 Pointer hat, nehme ich immer einen (X) mit für die Interrupts.
Das Main benutzt dann nur Y und Z.


4.
Alle anderen Variablen legt man im SRAM an.

Häufig benutzte Variablen können auch die restlichen Register benutzen.
Aber Register, die als Variablen verwendet werden, dürfen nicht mehrfach 
verwendet werden!


5.
Oftmals wird auch ein Null-Register reverviert, um schnell mit 0 zu 
rechnen.
Oder sogar 2, um mit MOVW schnell einen 16Bit-Wert zu nullen.
z.B. R2, R3.


6.
Den so festgelegten Registern gibt man mit .def dann aussagekräftige 
Namen.
Man verwendet nie direkt Register, außer R0,R1.


Peter

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Hallo Peter,
vielen Dank für Deine Hilfe,
jetzt kommt Plan in der ganzen Sache.
Vielen Dank.

PS:
Muss in Ruhe alles verdauen was Du mir jetzt vorgelegt hast....
Kämpfe noch mit dem Code von Spess53....
Da gibt es einen Zähler der Schleifen - 256 - aber ich weiss noch nicht 
wie es funktioniert....
Ich bearbeite den Demo-Code aus dem AVR-Tutorial (ADC) und einige Leute 
haben mir da viel geholfen.
Spess53 hat mir was zusammengebaut anhand diesen Demo-Codes, hat aber 
den Teil für das Errechnen des Mittelwertes rausgenommen und ich 
versuche heraus zu finden warum und wie ich es wieder einbauen kann.....
Gruß

von spess53 (Gast)


Lesenswert?

Hi

Von dem Schleifenzähler ist nur noch der Kommentar drin. Mir ging es 
eigentlich darum, dir die Kanalumschaltung zu verdeutlichen. Deshalb 
habe ich die Mittelwertbildung rausgelassen. Du brauchst eigentlich nur 
die Teile aus dem Originalcode wieder reinkopieren.

MfG Spess

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Hi Spess,
vielen Dank noch mal.
Es wurde mir irgendwann klar dass Du es für mich einfacher machen 
wolltest, hat mich am Anfang etwas irritiert :-)
Hatte es wieder drin aber es funzte nicht, es kamen Zahlen raus die aber 
nicht mit meinem Poti was zu tun hatte....
Jetzt ist es wieder draussen, habe dafür die Ausgabe insofern verändert 
dass ich jede Zählung mit Tabs trenne und nach dem alle 6 Kanäle durch 
sind kommt eine neue Zeile....
Bin mächtig stolz :-)

Werde mich jetzt an der Mittelwertberechnung machen.....grübbel...
Warum werden nach der Rechnerei falsche/andere Werte ausgegeben...
Es hat mit der neuen Registerbelegung zu tun...denke ich!
Danke Dir für die enorme Hilfe !
Gruß

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Hallo an alle,
vielen Dank für euere Hilfe....
Es ist unglaublich hilfreich was Ihr da zustande bringt.

Vielen Dank und eine gute Nacht

PS:
Für heute ist Ende, morgen in alles Frische geht es weiter....
Danke an alle
Ciao

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.