www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik AVR: 2 ADC einlesen


Autor: Johann (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Wie kann ich in AVR Assembler 2 Analogeingänge (PINC 0 und PINC 1) 
"gleichzeitig" einlesen und daraufhin in Register kopieren? Hat jemand 
einen Code in Assembler den er mir freundlicherweise übermitteln kann, 
damit ich es auch lernen kann?

Viiiiiiiiiieln Dank!!

Johann

Autor: Magnus Müller (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die AVRs können die Analogeingänge nur einzeln wandeln. Sind mehrere 
Eingänge zu wandeln, so muss dieses sequenziell geschehen. Gleichzeitig 
is nich.

Gruß,
Magnetus

Autor: Spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Wie kann ich in AVR Assembler 2 Analogeingänge (PINC 0 und PINC 1)
>"gleichzeitig" einlesen und daraufhin in Register ...

Das geht noch nicht mal in Assembler. Der AVR hat nur einen ADC (mit 
mehreren Eingängen über Multiplexer). Also du kannst also immer nur 
Einen Eingang bedienen. Ansonsten einfach: Messung machen, ADMUX 
umschalten, nächste Messung.

MfG Spess

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"gleichzeitig" geht, gleichzeitig geht nicht.

"gleichzeitig" bedeutet, ersten Kanal starten, ADC-Ende abwarten, 
Ergebnis lesen, auf zweiten Kanal umschalten und ADC starten, ADC-Ende 
abwarten, Ergebnis lesen, zurückschalten auf ersten Kanal, usw. Eine 
Wandlung dauert 13 ADC-Zyklen (wenn es nicht die allererste nach 
Aktivierung des ADC ist) , wobei je nach Takteinstellung der ADC-Takt 
100kHz bis 200kHz beträgt. Wenn das nicht "gleichzeitig" genug ist, ist 
der AVR der falsche Prozessor, oder du bauchst einen externen 
2-Kanal-ADC.

Code gibts im Tutorial oben links.

Oliver

Autor: Ahem (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das hatten wir schon mal: Gleichzeitg geht nicht.

Beitrag "2 ADC-Kanäle "gleichzeitig" abtasten - AVR Atmega32"

Autor: Johann (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das mit dem "gleichzeitig" Abtasten war mir bereits bekannt, nur meinte 
ich das gleichzeitige nutzen von 2 Analogeingängen am µC. Das mit dem 
ADMUX umstellen hab ich gemacht nur ohne Erfolg, da die Werte völlig 
unbrauchbar waren. Hat jemand einen Code den er mir evtl. zeigen kann, 
wie dies funktioniert?
Bin sehr dankbar!!!!!

Johann.

Autor: Hannes Lux (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Das mit dem
> ADMUX umstellen hab ich gemacht nur ohne Erfolg, da die Werte völlig
> unbrauchbar waren.

Unter bestimmten Bedingungen ist die erste Messung nach dem Umschalten 
von ADMUX fehlerhaft. Wirf sie weg und miss erneut, die zweite Messung 
(und jede weitere) ist dann ok.

...

Autor: Johann (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!
So sieht mein Erstentwurf aus:
;+------------------------------------------------------------------------------
;| Title    : ADC mit 2 Eingängen
;+------------------------------------------------------------------------------
;| Funktion    : 
;| Schaltung  :
;+------------------------------------------------------------------------------
;| Prozessor  : ATmega8-16PU
;| Takt      : 3686400 Hz
;| Sprache      : Assembler
;| Datum        : 
;| Version      : 001
;| Autor        : Wiethaler Johann
;+------------------------------------------------------------------------------
.include  "m8def.inc"

;-------------------------------------------------------------------------------
; Reset and Interrupt vector             ;VNr.  Beschreibung
;-------------------------------------------------------------------------------
.org 0x000
       rjmp main
.org INT0addr                 ; External Interrupt0 Vector Address
       reti                   
.org INT1addr                 ; External Interrupt1 Vector Address
       reti                   
.org OC2addr                  ; Output Compare2 Interrupt Vector Address
       reti                   
.org OVF2addr                 ; Overflow2 Interrupt Vector Address
       reti                   
.org ICP1addr                 ; Input Capture1 Interrupt Vector Address
       reti                   
.org OC1Aaddr                 ; Output Compare1A Interrupt Vector Address
       reti                   
.org OC1Baddr                 ; Output Compare1B Interrupt Vector Address
       reti                   
.org OVF1addr                 ; Overflow1 Interrupt Vector Address
       reti                   
.org OVF0addr                 ; Overflow0 Interrupt Vector Address
       reti                   
.org SPIaddr                  ; SPI Interrupt Vector Address
       reti                   
.org URXCaddr                 ; USART Receive Complete Interrupt Vector Address
       reti                   
.org UDREaddr                 ; USART Data Register Empty Interrupt Vector Address
       reti                   
.org UTXCaddr                 ; USART Transmit Complete Interrupt Vector Address
       reti                   
.org ADCCaddr                 ; ADC Interrupt Vector Address
       reti                   
.org ERDYaddr                 ; EEPROM Interrupt Vector Address
       reti                   
.org ACIaddr                  ; Analog Comparator Interrupt Vector Address
       reti                   
.org TWIaddr                  ; Irq. vector address for Two-Wire Interface
       reti                   
                 
 
.org INT_VECTORS_SIZE

.def    status1  =  r16
.def    status2  =  r17
.def    temp1  =  r18
.def    temp2  =  r19
.def    temp3  =  r20
.def    temp4  =  r21
.def    temp5  =  r22
.def    temp6  =  r23


main:
          ldi       temp1, LOW(RAMEND)     ; Stackpointer initialisieren
          out       SPL, temp1
          ldi       temp1, HIGH(RAMEND)
          out       SPH, temp1        ;      
      ldi      temp1,0b00111111
      out      DDRB,temp1
      ldi      temp1,0b11111100
      out      DDRD,temp1

mainloop:
      rcall    ADC1
      rcall    ADC2
      ret

ADC1:    ldi      temp1,0b01000000
      out      ADMUX,temp1
      ldi      temp1,0b10111101
      out      ADCSRA,temp1
      in      temp2,ADCL
      out      PORTB,temp2
      ret

ADC2:    ldi      temp1,0b01000001
      out      ADMUX,temp1
      ldi      temp1,0b10111101
      out      ADCSRA,temp1
      in      temp2,ADCL
      out      PORTD,temp2
      ret


Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johann wrote:
> mainloop:
>       rcall    ADC1
>       rcall    ADC2
>       ret
Was hat denn das ret da verloren? Das gibt nen sauberen 
Stack-Underflow. Da die mainloop nicht mit call aufgerufen wird, darf 
da kein ret hin! Schließlich gibt es nichts, wo man von da aus hin 
zurückspringen kann. Wenn überhaupt, dann kommt da ein rjmp mainloop 
hin!

So, wie es da steht, geht das Programm nach dem ersten Durchlauf der 
mainloop ins Nirvana und es gibt einen Reset.

Autor: Martin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
du musst waren, bis die Wandlung fertig ist und nicht gleich das ADC 
Register einlesen

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Martin wrote:
> du musst waren, bis die Wandlung fertig ist und nicht gleich das ADC
> Register einlesen
Das kommt noch dazu. Ein weiteres Zeichen dafür, dass Johann das 
AVR-Tutorial nicht gelesen hat, was dringend zu empfehlen wäre (es 
ist ja weiter oben schon mal angesprochen worden...)

Abgesehen davon liest Du nur ADCL ein, was (abgesehen davon, dass es 
unsinnig ist, nur das Low-Byte zu lesen) aufgrund der 
Registersynchronisation dazu führt, dass nach dem ersten Einlesen ADCL 
und ADCH für jegliche weitere Zugriffe seitens des ADC blockiert sind 
und von da an immer derselbe Wert ausgelesen wird.

Nach einem Lesezugriff auf ADCL muss grundsätzlich auch ADCH gelesen 
werden! Wenn nur 8 Bit Auflösung benötigt werden, dann ADLAR setzen und 
nur ADCH lesen. Das geht.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, ich habe mal einen separaten, allgemeinen Artikel zum Thema [[AVR 
16-Bit-Register]] erstellt. Die Infos standen in der Form bisher nur im 
AVR-GCC-Tutorial...

Autor: Johann (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab´s hinbekommen:
.include "m8def.inc"

.def  temp = r16

main:
        ldi     temp, LOW(RAMEND)     ; Stackpointer initialisieren
        out     SPL, temp
        ldi     temp, HIGH(RAMEND)
        out     SPH, temp
    ldi    temp,0b00111111
    out    DDRB,temp
    ldi    temp,0b11111100
    out    DDRD,temp
    ldi    r16,0b11011101      ;ADC Enable, Vorteiler = 32
    out    ADCSRA,r16        ;Interrupt Enable, single Conv.




;------------------------------------------------------------------------
mainloop:  

    ldi    r16,0          ;Wert ins r16 laden
    out    ADMUX,r16        ;r16 in AD Wandler laden
    in    r26,ADCL        ;Low Teil des AD-Wandler ausl.
    in    r27,ADCH        ;High Teil des AD-Wandler ausl.
    sbi    ADCSRA,6        ;Starte nächste Konvertierung
    asr    r27            ;Schiebe Bit 0 ins C-Flag
    ror    r26            ;Schiebe alle Bit´s nach rechts
    asr    r27            ;Schiebe nächstes Bit ins C-Flag
    ror    r26            ;Schiebe alle Bit´s nach rechts
    out    PORTB,r26
    rcall  wait
    ldi    r16,1          ;Wert ins r16 laden
    out    ADMUX,r16        ;r16 in AD Wandler laden
    in    r26,ADCL        ;Low Teil des AD-Wandler ausl.
    in    r27,ADCH        ;High Teil des AD-Wandler ausl.
    sbi    ADCSRA,6        ;Starte nächste Konvertierung
    asr    r27            ;Schiebe Bit 0 ins C-Flag
    ror    r26            ;Schiebe alle Bit´s nach rechts
    asr    r27            ;Schiebe nächstes Bit ins C-Flag
    ror    r26            ;Schiebe alle Bit´s nach rechts
    out    PORTD,r26
    rcall  wait
    rjmp  mainloop


wait:  inc    r17
    brne  wait
    ret

nur verstehen tu ich´s mit dem wait nicht ganz, wenn ich doch eh einen 
Vorteiler von 32 habe? Mit dem 16Bit Registern hab ich jetzt auch 
verstanden. Daaaanke!

Johann

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johann wrote:
> Ich hab´s hinbekommen:
Nein, hast Du nicht!


>     sbi    ADCSRA,6        ;Starte nächste Konvertierung
>     [...]
>     rcall  wait
>     [...]
>
> wait:  inc    r17
>     brne  wait
>     ret
Das ist völliger Mumpitz! Du musst warten, bis der ADC sich meldet, dass 
er fertig ist. Da gibt es zwei Methoden, das zu tun (bzw. zwei 
Statusbits, die man zu diesem Zweck abfragen kann). Was Du hier machst, 
funktioniert nur dann mit Glück, wenn die Wartezeit wirklich länger ist, 
als der ADC für eine Wandlung benötigt!

> Mit dem 16Bit Registern hab ich jetzt auch
> verstanden. Daaaanke!
Na, wenigstens etwas...

Autor: Johann (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie soll ich denn Abfragen ob er fertig ist?

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Siehe dem Auszug aus dem GCC-Tutorial:

>while ( ADCSRA & (1<<ADSC) ) {
>     ;   // auf Abschluss der Konvertierung warten
>    }

Autor: Εrnst B✶ (ernst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bitte tu dir selbst und uns einen Gefallen, und LIES das 
AVR-Tutorial durch, zumindest den ADC-Abschnitt:
wait_adc:
    sbic    ADCSRA, ADSC        ; wenn der ADC fertig ist, wird dieses Bit gelöscht
    rjmp    wait_adc

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gast wrote:
> Siehe dem Auszug aus dem GCC-Tutorial:
Nützt ihm bei Assembler nicht viel. Aber auf das AVR-Tutorial ist er 
ja auch erst dreimal hingewiesen worden...

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.