Forum: Mikrocontroller und Digitale Elektronik ADC Umwandlung mit ATmega8


von Jens S. (derfixej)


Lesenswert?

hallo,

ich will mit dem atmega8 2 analoge signale kontinuierlich umwandeln und
das ergebnis im sram für weitere verarbeitung zur verfügung stellen.
mache sowas zum ersten mal und scheitere schon an der initialisierung.
mit einem kanal ist es klar.

mit ADPS vorteiler einstellen
mit ADEN generell einschalten
in ADMUX kanal wählen
mit ADFR free run wählen
mit ADSC umwandlung starten

aber wie soll ich das machen wenn ich zwei eingänge kontinuierlich
abfragen will?

gruß jens

von Jan M. (mueschel)


Lesenswert?

Gleichzeitig beide Kanäle abzufragen ist nicht möglich.
Die einfachste Lösung ist, bei jedem Auslesen des ADC-Wertes ADMUX neu
zu schreiben. So bekommst du immer abwechselnd die Werte von beiden
Eingängen.

von Rahul (Gast)


Lesenswert?

@Jens:
Der AVR hat nur einen ADC mit einem vorgeschalten 8-kanal-Multiplexer.
So ist es nicht mgöich, mehrere Kanäle gleichzeitig zu messen.
Dafür bräuchte man dann externe Lösungen...

von Jens S. (derfixej)


Lesenswert?

na gut, das konnte ich mir denken, aber wie soll ich es realisieren, die
eingänge hintereinander fortlaufend abzufragen, wenn ich doch immer nur
einen eingang im admux setzen kann, soll ich die allg. einstellungen
enable, vorteiler, free run... separat initialisieren und dann jeweils
vor der abfrage nur admux auf den nächsten eingang umschreiben? mir
fehlt etwas die vorstellungskraft.

gruß jens

von Rahul (Gast)


Lesenswert?

Seite 197 im Datenblatt "Changing Channel or Reference Selection"
Solange eine Messung durchgeführt wird, kann man zwar den Kanal etc.
wechseln, die Änderung wird aber erst aktiv, sobald die Messung beendet
ist.
Du wartest das Ende der Messung ab, und startest eine neue mit
geänderten Einstellungen, nachdem du die ADC-Werte gespeichert hast.
Das kannst du entweder als konstante Abfrage des ADIF-Bit oder in der
Interrupt-Service-Soutine machen.
Beim Auftreten des Interrupts wird im free-running-mode IMHO sofort die
neue Messung gestartet. Sprich, wenn man die Einstellungen in der ISR
ändert, dann wird noch eine Messung mit den alten Einstellungen
durchgeführt. Das ist auch irgendwo im Datenblatt beschrieben...

von Jens S. (derfixej)


Lesenswert?

kann ich das auch ohne interrupt lösen? habe das mit den interrupts noch
nicht so geschnallt. wollte über polling abfragen, aber dann nützt mir
ja das adif bit nichts, oder?

gruß jens

von Rahul (Gast)


Lesenswert?

Das einfachste ist eine Schleife:

{
  ADC-Eingang setzen
  Messung starten
  Ende der Messung abwarten
  Werte sichern
  Parameter ändern (z.B. Feldindex und dergl.)
} wiederholen

von Jens S. (derfixej)


Lesenswert?

also wenn ich das richtig verstanden habe so in etwa:

main:    ldi     r16, lo8(RAMEND)
         out     SPL, r16
         ldi     r16, hi8(RAMEND)
         out     SPH, r16

;Initialisierung ADC
    ldi   r17, 0b10000...  ;ADC enable, vorteiler
    out   ADCSRA, r17
;---------------------------------------------------------------------ma 
inloop:
wdr
          rjmp loop
          rjmp save
          rjmp mainloop
;---------------------------------------------------------------------
;ersten eingang umwandeln und sichern

loop:   ldi  r16, 0     ;auswahl chanel 0
  out  ADMUX, r16                               sbi  ADCSRA, ADSC 
;wandlung
starten
warte1:  sbis   ADCSRA, ADIF  ;abfrage ob umwandlung schon beendet
  rjmp   warte1
  in  r18, ADCL  ;die unteren 8bits in r18 speichern
  in  r19, ADCH  ;die oberen 2bits in r19 speichern

;zweiten eingang umwandeln und sichern

  ldi  r16, 1    ;auswahl chanel 1
  out  ADMUX, r16
  sbi  ADCSRA, ADSC  ;wandlung starten
warte2:  sbis  ADCSRA, ADIF  ;abfrage ob umwandlung schon beendet  rjmp
warte2
  in      r20, ADCL       ;die unteren 8bits in r20 speichern
  in  r21, ADCH  ;die oberen 2bits in r21 speichern
        ret

;gesicherte werte in sram speichern
save:
  ...
  ret

wenn das so stimmt, wie bekomme ich dann die r18-r21 in den sram?
geht das überhaupt so einfach?

gruß jens

von Jens S. (derfixej)


Lesenswert?

also wenn ich das richtig verstanden habe so in etwa:

1
main:    ldi     r16, lo8(RAMEND)
2
         out     SPL, r16
3
         ldi     r16, hi8(RAMEND)
4
         out     SPH, r16
5
         
6
;Initialisierung ADC           
7
    ldi    r17, 0b10000...        ;ADC enable, vorteiler
8
    out    ADCSRA, r17
9
      
10
            
11
;---------------------------------------------------------------------------
12
mainloop: wdr
13
          rjmp loop
14
          rjmp save
15
          rjmp mainloop
16
;---------------------------------------------------------------------------
17
;ersten eingang umwandeln und sichern
18
loop:     ldi    r16, 0           ;auswahl chanel 0
19
      out    ADMUX, r16
20
      sbi    ADCSRA, ADSC       ;wandlung starten
21
warte1:    sbis   ADCSRA, ADIF      ;abfrage ob umwandlung schon beendet ist
22
ADIF=1 
23
      rjmp   warte1
24
      in    r18, ADCL        ;die unteren 8bits in r18 speichern
25
      in    r19, ADCH         ;die oberen 2bits in r19 speichern
26
      
27
;zweiten eingang umwandeln und sichern      
28
      ldi    r16, 1          ;auswahl chanel 1
29
      out    ADMUX, r16
30
      sbi    ADCSRA, ADSC       ;wandlung starten
31
warte2:    sbis  ADCSRA, ADIF      ;abfrage ob umwandlung schon beendet ist
32
ADIF=1  
33
      in    r20, ADCL        ;die unteren 8bits in r20 speichern
34
      in    r21, ADCH        ;die oberen 2bits in r21 speichern
35
      ret
36
;gesicherte werte in sram speichern
37
save:    
38
      ...
39
      ret

wenn das so stimmt, wie bekomme ich dann die r18-r21 in den sram?
geht das überhaupt so einfach?

gruß jens

von Hannes L. (hannes)


Lesenswert?


von Jens S. (derfixej)


Lesenswert?

ich denke das sollte soweit hinkommen, aber warum zeigt mir der compiler
in den zeilen mit dem adsc und adif bit dies an:


constant value required


gruß jens

von Hannes L. (hannes)


Lesenswert?

> aber warum zeigt mir der compiler
> in den zeilen mit dem adsc und adif bit dies an:
>
>
> constant value required

Ich denke mal, dass du hier zwei Programmiersprachen vermischt:

> warte2:    sbis  ADCSRA, ADIF      ;abfrage ob umwandlung schon
> ;beendet
> ;ist
> ADIF=1
>       in    r20, ADCL        ;die unteren 8bits in r20 speichern
>       in    r21, ADCH        ;die oberen 2bits in r21 speichern
>       ret

ADIF=1 passt nicht zu ASM-Syntax.
Das mag in C oder BASIC syntaktisch richtig sein, in ASM versuchst du
damit, den Wert des Bezeichners 'adif' (das ist die Bitnummer, also
eine Konstante, die in der Include-Datei festgeschrieben ist) zu
verändern. Und das darf der Assembler (der kein Compiler ist!) nicht
zulassen...

...

von Hannes L. (hannes)


Lesenswert?

Achja, noch was vergessen...

Ich interpretiere deinen Code so:
- Du stellest in ADMUX die Messquelle (und Referenzquelle) ein,
- du startest die Messung (Wandlung)
- du wartest, bis das adif-Bit gesetzt ist
- du liest die Werte aus...

Also du schaltest dir Messquelle immer erst dann um, wenn du eigentlich
schon gern das Ergebnis hättest.

Ich würde das so machen:
- Ausleseroutine in einen Timer-Interrupt oder den ADC-Complete-
  Interrupt legen. Darin in regelmäßigen Zeitabständen:
- Wert einlesen und sichern
- Messquelle für nächste Messung umschalten
- Messung starten
- fertig, andere Dinge tun, wie Tastenentprellung, Zeit hochzählen,
  LCD-Ausgabe usw.
- zurück zur Mainloop.

Das spart irgendwie Rechenzeit, da nicht auf das Ergebnis der Wandlung
gewartet werden muss, sondern die Wandlung abläuft, während der AVR
noch andere Dinge tut.

Wenn du mit Sleep arbeitest, kannst du sogar die Wandlung automatisch
starten lassen, indem du das Programm nach getaner Arbeit einfach in
den Sleep-Mode schickst. Beim Mega8 geht das glaube sogar im Idle-Mode.
Schau mal im Datenblatt unter SLEEP nach.

...

von Jens S. (derfixej)


Lesenswert?

hallo,
danke für schnelle antwort. das adif=1 gehört nur zum kommentar. da hat
was nicht so hingehauen beim reinkopieren. sollte einfach nur heißen,
dass die umwandlung beendet ist, wenn das adif bit gesetzt ist. (wie
krieg ich das denn beim nächsten mal besser hin? (code) (/code) hat
nicht geklappt)
davon kann die fehlermeldung also nicht kommen. und das mit den
interrupt klingt einleuchtend, ich hab bloß keinen schimmer wie das
funzt. was in dieser interruptroutine drinstehen muss, ist mir klar,
aber nicht wie ich diese einbinde. macht man das über die
interruptvectoren? wie gesagt das mit den interrupts hab ich noch nicht
so begriffen.

gruß jens

von Hannes L. (hannes)


Lesenswert?

Dann schau dir doch einfach mal die Programme (Quelltexte) auf meiner
Seite an: www.hanneslux.de

Am besten das Melodiegenerator-Projekt mit Tiny15, erste Variante, da
ist genau erklärt, wie man ASM-Programme mit Interrupts schreibt.

Auch das Projekt, was ich dir im obigen Link genannt habe, zeigt im
Quelltext recht deutlich, wie das mit den Interrupts geht.

Da ich kein Profi bin, ist das Niveau dieser Programme nicht besonders
hoch (vom mathematischen Anspruch her gesehen), der Code müsste also
nachvollziehbar und verständlich sein.

Aber auch im Datenblatt des Mega8 unter Interrupt-Sources wird erklärt,
wie das gemacht wird. Erwarte aber bitte nicht, dass ich dir das
übersetze, ich habe selbst nie englisch gelernt, ich muss da auch
gelegentlich das Wörterbuch befragen.

In C oder BASIC scheint das mit den Interrupts vielleicht etwas
kryptisch bzw etwas schwerer durchschaubar zu sein, in ASM ist aber
sehr einfach und vor allem sehr transparent.

...

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.