Forum: Mikrocontroller und Digitale Elektronik AVR: 2 ADC einlesen


von Johann (Gast)


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

von Magnus Müller (Gast)


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

von Spess53 (Gast)


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

von Oliver (Gast)


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

von Ahem (Gast)


Lesenswert?

Das hatten wir schon mal: Gleichzeitg geht nicht.

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

von Johann (Gast)


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.

von Hannes Lux (Gast)


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.

...

von Johann (Gast)


Lesenswert?

Hallo!
So sieht mein Erstentwurf aus:
1
;+------------------------------------------------------------------------------
2
;| Title    : ADC mit 2 Eingängen
3
;+------------------------------------------------------------------------------
4
;| Funktion    : 
5
;| Schaltung  :
6
;+------------------------------------------------------------------------------
7
;| Prozessor  : ATmega8-16PU
8
;| Takt      : 3686400 Hz
9
;| Sprache      : Assembler
10
;| Datum        : 
11
;| Version      : 001
12
;| Autor        : Wiethaler Johann
13
;+------------------------------------------------------------------------------
14
.include  "m8def.inc"
15
16
;-------------------------------------------------------------------------------
17
; Reset and Interrupt vector             ;VNr.  Beschreibung
18
;-------------------------------------------------------------------------------
19
.org 0x000
20
       rjmp main
21
.org INT0addr                 ; External Interrupt0 Vector Address
22
       reti                   
23
.org INT1addr                 ; External Interrupt1 Vector Address
24
       reti                   
25
.org OC2addr                  ; Output Compare2 Interrupt Vector Address
26
       reti                   
27
.org OVF2addr                 ; Overflow2 Interrupt Vector Address
28
       reti                   
29
.org ICP1addr                 ; Input Capture1 Interrupt Vector Address
30
       reti                   
31
.org OC1Aaddr                 ; Output Compare1A Interrupt Vector Address
32
       reti                   
33
.org OC1Baddr                 ; Output Compare1B Interrupt Vector Address
34
       reti                   
35
.org OVF1addr                 ; Overflow1 Interrupt Vector Address
36
       reti                   
37
.org OVF0addr                 ; Overflow0 Interrupt Vector Address
38
       reti                   
39
.org SPIaddr                  ; SPI Interrupt Vector Address
40
       reti                   
41
.org URXCaddr                 ; USART Receive Complete Interrupt Vector Address
42
       reti                   
43
.org UDREaddr                 ; USART Data Register Empty Interrupt Vector Address
44
       reti                   
45
.org UTXCaddr                 ; USART Transmit Complete Interrupt Vector Address
46
       reti                   
47
.org ADCCaddr                 ; ADC Interrupt Vector Address
48
       reti                   
49
.org ERDYaddr                 ; EEPROM Interrupt Vector Address
50
       reti                   
51
.org ACIaddr                  ; Analog Comparator Interrupt Vector Address
52
       reti                   
53
.org TWIaddr                  ; Irq. vector address for Two-Wire Interface
54
       reti                   
55
                 
56
 
57
.org INT_VECTORS_SIZE
58
59
.def    status1  =  r16
60
.def    status2  =  r17
61
.def    temp1  =  r18
62
.def    temp2  =  r19
63
.def    temp3  =  r20
64
.def    temp4  =  r21
65
.def    temp5  =  r22
66
.def    temp6  =  r23
67
68
69
main:
70
          ldi       temp1, LOW(RAMEND)     ; Stackpointer initialisieren
71
          out       SPL, temp1
72
          ldi       temp1, HIGH(RAMEND)
73
          out       SPH, temp1        ;      
74
      ldi      temp1,0b00111111
75
      out      DDRB,temp1
76
      ldi      temp1,0b11111100
77
      out      DDRD,temp1
78
79
mainloop:
80
      rcall    ADC1
81
      rcall    ADC2
82
      ret
83
84
ADC1:    ldi      temp1,0b01000000
85
      out      ADMUX,temp1
86
      ldi      temp1,0b10111101
87
      out      ADCSRA,temp1
88
      in      temp2,ADCL
89
      out      PORTB,temp2
90
      ret
91
92
ADC2:    ldi      temp1,0b01000001
93
      out      ADMUX,temp1
94
      ldi      temp1,0b10111101
95
      out      ADCSRA,temp1
96
      in      temp2,ADCL
97
      out      PORTD,temp2
98
      ret

von Johannes M. (johnny-m)


Lesenswert?

Johann wrote:
1
> mainloop:
2
>       rcall    ADC1
3
>       rcall    ADC2
4
>       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.

von Martin (Gast)


Lesenswert?

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

von Johannes M. (johnny-m)


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.

von Johannes M. (johnny-m)


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...

von Johann (Gast)


Lesenswert?

Ich hab´s hinbekommen:
1
.include "m8def.inc"
2
3
.def  temp = r16
4
5
main:
6
        ldi     temp, LOW(RAMEND)     ; Stackpointer initialisieren
7
        out     SPL, temp
8
        ldi     temp, HIGH(RAMEND)
9
        out     SPH, temp
10
    ldi    temp,0b00111111
11
    out    DDRB,temp
12
    ldi    temp,0b11111100
13
    out    DDRD,temp
14
    ldi    r16,0b11011101      ;ADC Enable, Vorteiler = 32
15
    out    ADCSRA,r16        ;Interrupt Enable, single Conv.
16
17
18
19
20
;------------------------------------------------------------------------
21
mainloop:  
22
23
    ldi    r16,0          ;Wert ins r16 laden
24
    out    ADMUX,r16        ;r16 in AD Wandler laden
25
    in    r26,ADCL        ;Low Teil des AD-Wandler ausl.
26
    in    r27,ADCH        ;High Teil des AD-Wandler ausl.
27
    sbi    ADCSRA,6        ;Starte nächste Konvertierung
28
    asr    r27            ;Schiebe Bit 0 ins C-Flag
29
    ror    r26            ;Schiebe alle Bit´s nach rechts
30
    asr    r27            ;Schiebe nächstes Bit ins C-Flag
31
    ror    r26            ;Schiebe alle Bit´s nach rechts
32
    out    PORTB,r26
33
    rcall  wait
34
    ldi    r16,1          ;Wert ins r16 laden
35
    out    ADMUX,r16        ;r16 in AD Wandler laden
36
    in    r26,ADCL        ;Low Teil des AD-Wandler ausl.
37
    in    r27,ADCH        ;High Teil des AD-Wandler ausl.
38
    sbi    ADCSRA,6        ;Starte nächste Konvertierung
39
    asr    r27            ;Schiebe Bit 0 ins C-Flag
40
    ror    r26            ;Schiebe alle Bit´s nach rechts
41
    asr    r27            ;Schiebe nächstes Bit ins C-Flag
42
    ror    r26            ;Schiebe alle Bit´s nach rechts
43
    out    PORTD,r26
44
    rcall  wait
45
    rjmp  mainloop
46
47
48
wait:  inc    r17
49
    brne  wait
50
    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

von Johannes M. (johnny-m)


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...

von Johann (Gast)


Lesenswert?

Wie soll ich denn Abfragen ob er fertig ist?

von Gast (Gast)


Lesenswert?

Siehe dem Auszug aus dem GCC-Tutorial:

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

von Εrnst B. (ernst)


Lesenswert?

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

von Johannes M. (johnny-m)


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...

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.