Forum: Mikrocontroller und Digitale Elektronik ADC - free running Mega8/allgemein


von Thomas (Gast)


Lesenswert?

hallo, habe bisher nicht soviel mit dem adc gemacht ausser mal ne single
conversation.
jetzt habe ich mal probiert das ganze über einen free run zu machen
aber dann kam das entsetzen:
in assembler sieht das so aus:

ldi  temp, 237
out  ADCSRA, temp

also bis auf bit 1 und 4 alle einschalten
das bedeutet:
ADC ENable: set
ADC Start Convers: set
ADC free running: set
die letzen dienen dem prescaler

jetzt zum problem: so wie es da steht wird jetzt nach den 25 zyklen der
interrupt ausgewählt. danach verschwindet jedoch das start conversation
bit. muss man dieses jedesmal beim interrupt wieder neu setezn oder
mach ich gerade irgendwie grundlegend was falsch??
free running hiess für mich bisher das er alls 13 cyklen automatisch
den nexten wert einliest. lag ich da falsch??
grüsse thomas

von ...HanneS... (Gast)


Lesenswert?

Im Free-Run-Mode wird kein Interrupt genutzt. Der ACD "klappert" im
Hintergrund gemütlich vor sich hin und interessiert sich nicht dafür,
ob und wann das Programm den Messwert ausliest...

In einem Programm, das nebenbei die Betriebsspannung (Akku) am Mega8
ermittelt und in % am LCD anzeigt, initialisiere ich den ADC so:

 ldi wl,(1<<adlar)+14       ;linksbündig, Bandgap als Messquelle
 out admux,wl               ;an ADC legen
 ldi wl,(1<<aden)|(1<<adsc)|(1<<adfr)+6 ;ADC freilaufend mit
 out adcsra,wl              ;Vorteiler 64 einschalten

In diesem Fall wird die (konstante) innere Bandgap-Spannung in Bezug
auf die Betriebsspannung gemessen.

Das eigentliche Auslesen geschieht dann als Job in der Mainloop
(niedrige Priorität), über ein Flag synchronisiert von einem
Timer-Interrupt (alle 10ms), der auch noch andere Aufgaben hat
(Tastenentprellung, Zeitzählung, Synchronisierung der LCD-Ausgabe
uvm.):

akkutest:   ;Akku-Zustand messen (Vergleich Vcc mit V_bandgap)
 cbr flags,1<<hundertstel   ;Flag löschen, Job wird erledigt
 ldi wl,80                  ;Basiswert Akkuladezustand
 in wh,adch                 ;ADC einlesen (60...80)
 sub wl,wh                  ;(0...20)
 mov wh,wl                  ;Kopie
 lsl wl                     ;mal
 lsl wl                     ;4,
 add wl,wh                  ;nochmal dazu entspricht mal 5
 lds r0,batt1               ;Mittelwert aus SRAM holen
 lds wh,batt0               ;Nachkommastellen auch
 sub wh,r0                  ;1/256 subtrahieren
 sbc r0,null                ;Übertrag auch
 add wh,wl                  ;Neuwert/256 addieren
 adc r0,null                ;Übertrag auch
 sts batt1,r0               ;zurück
 sts batt0,wh               ;ins SRAM
 rjmp mainloop              ;fertig...

Hierbei wird der Mittelwert über 256 Messungen emittelt. Die Ausgabe an
das LCD geschieht in einem anderen Job alle volle Sekunde, ist also hier
nicht zu sehen.

Beim Auslesen des ADC via Timer-Interrupt ist lediglich abzusichern,
dass zwischen den Auslesezugriffen mindestens eine neue Wandlung
stattgefunden hat. Dies erreicht man aber leicht durch geschicktes
Anpassen von Timer und ADC-Vorteiler.

...

von Thomas (Gast)


Lesenswert?

hallo hannes, init ist die gleiche, nur das ich noch das adie flag
(interrupt enable) setze um bei jeder conversation einen neuen wert zu
lesen...dazu ist der interrupt doch da oder irre ich??
im simulator funzt das auch, nur der chip misst anscheinend nur ein
einziges mal

im programm wird der counter 0 mit prescaler 8 initialisiert
prescaler vom adc ist 32 (bei 2MHz)
nach 25 zyklen ist die erste auswertung des adc abgeschlossen (ca 800
Prozessortakte), die erste conversation ist also schneller
abgeschlossen als der erste timer overflow(255x8 = 2040prozessortakte).
der simulator springt in den adc interrupt, übergibt dort neue werte und
rechnet kurz. im worst case steht der timer dann bei 0xA0 am ende der
adc interrupt routine..also noch weit vor dem overflow. beim timer
overflow will ich den adc dann gleich am anfang wieder starten lassen
(neue messung), also setz ich da bit 6 im adcsra...
schöne theorie, funzt nur nicht real..aber im simulator

 flags sehen dann wie folgt aus
prescaler 0-2: 1, 0, 1
adc enable: 1; der bleibt auch immer an
adsc: 1 ; wird dann bei jeden timer ofl neu gesetzt
adie: 1 ; interrupts enable bleibt auch immer 1

von Thomas (Gast)


Angehängte Dateien:

Lesenswert?

habe mein prog mal zusammengeschnitten und diese version auf den chip
gebrannt. er misst einfach nur einmal den wert...kann mir wer sagen
warum??
egal ob ich free running oder single conversation einstelle..er misst
nur ein einziges mal, ruft die routine aber immer auf
alles was ich will ist die ausgabe der (hier) unteren 8 bit des adc an
port d bei jedem vollständigen (10bit) adc wert. der timer soll dann
eine neue berechnung starten...im simulator klappts, nur auf dem chip
nicht...wieso?!?!?
ich verzweifel noch dran

von ...HanneS... (Gast)


Lesenswert?

Du wirst dich schon entscheiden müssen, ob du free-Run oder Interrupt
willst. Willst du Interrupt, dann wirst du wohl in der ISR die nächste
Conversion starten müssen.

...

von Thomas (Gast)


Lesenswert?

ich möchte einfach das ich bei jeden timer overflow des timer 0 eine
neue conversation starte. wenn die 10bit eingelesen sind im adc dann
will ich diese weiter verarbeiten... ich seh gerade echt nicht das
problem im meiner init des adc...helf mir mal auf die sprünge..falsch
initialisisert für den interrupt oder wie??

von Thomas (Gast)


Angehängte Dateien:

Lesenswert?

habe jetzt mal deine initialisierung versucht und lade beim timer0
überlauf die werte raus...so meintest du das bei nir im 2ten beitrag
oder??
läuft auf meinem chip so auch nur ein einziges mal durch

von Thomas (Gast)


Angehängte Dateien:

Lesenswert?

habe inzwischen leider so den verdacht das mein adc nicht so richtig
funktioniert...
einfache portausgabe über leds an portb hab ich mal getestet:
setze ich das adlar flag und lese das adch aus geht der adc
lösche ich das flag, und lese das adcl aus gehts nicht mehr
extern werden an aref 5V eingespeist und ich werte gerade von 2,4-2,5
volt..also müssten sich allemal irgendwelche bits ändern
msb...also das bit das für 2,5V in meinem fall steht ist das bit 9 wenn
das adlar flag gelöscht ist oder??

von ...HanneS... (Gast)


Lesenswert?

Puhhhh...

Dein ADC ist sicherlich nicht kaputt...

Aber deine Programmbeispiele sind etwas durcheinander.

Free-Run braucht keinen ADC-Interrupt, dafür aber den Timer-Interrupt,
der dafür sorgt, dass der ADC nicht zu oft hintereinander ausgelesen
wird. Du liest den ADC jedoch in der Mainloop alle paar Takte aus.
Rechne doch mal aus, wieviele Takte eine Conversion dauert... Und wenn
du ein vernünftiges Programm schreiben willst, kommst du an einen
Timer-Int sowiso nicht vorbei. Den brauchst du halt für viele Zwecke,
angefangen von der Tastenentprellung über Verzögerungen usw...

Schau dir mal dieses Beispiel an:
http://www.mikrocontroller.net/forum/read-1-140519.html#140585
Da werden 8 ADC-Kanäle per Timer-Int abgefragt. Erst abfragen, dann
Quelle ändern, bis zur nächsten Abfrage (Timer-ISR) vergeht so viel
Zeit, dass bereits einige neue Conversionen stattgefunden haben.

...

von Thomas (Gast)


Lesenswert?

es stimmte schon wie anfangs geschrieben..inzwischen läuft das teil :)

des rätsels lösungwar eigentlich ganz einfach:

beim lesen des ADC's ändert sich die reihenfolge in der man die beiden
regsister auslesen muss...
adlar = 0 muss das lowbyte gelesen und danach muss (!!) das highbyte
gelesen werden...
bei adlar = 1 andersrum
das war das problem, sonst sperrt der controller die nächste auslesung
so long

von ...HanneS... (Gast)


Lesenswert?

Nööö...

ADLAR bestimmt lediglich, ob der 10-Bit-Wert im 16-Bit-Register
linksbündig oder rechtsbündig angeordnet wird. Linksbündig wird
genutzt, wenn man nur 8 Bit Auflösung braucht. Dann kann man nämlich
auf das untere Byte (mit den 2 unteren Bits) verzichten und nur das
obere Byte (mit den oberen 8 Bits) einlesen und verarbeiten.

...

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.