Forum: Mikrocontroller und Digitale Elektronik ADC mit Timer will nicht funktionieren


von Andre H. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!

Ich bin noch relativ neu in der Welt der Mikrocontroller und hänge 
gerade an einem kleinen ASM-Programm, das das Bitmuster eines 
eingelesenen analogen Wertes auf 8 LEDs ausgeben soll.
Bei dem Programm im Anhang bekomme ich beim Kompilieren mit AVR Studio 
immer den Fehler:
D:\Elektronik\ADC\ADC.asm(32): error: Overlap in .cseg: addr=0x20 
conflicts with 0x20:0x21

Das macht der Compiler erst, nachdem ich die Sprungadresse für den 
Timer0 mit .org angegeben habe.

Und nochwas:
Ich lasse ja momentan den ADC im Free Running Mode laufen und ich wollte 
eigentlich, dass bei jedem fertig konvertierten Messwert ein Interrupt 
ausgelöst wird. Ich habe aber hier im Forum gelesen, dass das nicht 
sonderlich optimal wäre, weil ja dann alle paar Zyklen ein Interrupt 
ausgelöst werden würde was bei umfangreichen Programmen zu Problemen 
führen würde. Habe ich das so richtig verstanden?
Dann wäre also die optimale Lösung, den ADC über einen Timer zu 
triggern, der z.B. alle paar ms ein Interrupt auslöst und damit den ADC 
anstößt, oder?

Ich bedanke mich schon mal!

Grüße,
André

von Rolf Magnus (Gast)


Lesenswert?

> D:\Elektronik\ADC\ADC.asm(32): error: Overlap in .cseg: addr=0x20
> conflicts with 0x20:0x21

Das bedeutet, dass du dem Assembler gesagt hast, er soll zwei 
verschiedene Instruktionen an derselben Adresse ablegen.

> .org ADCCAddr
>    rjmp ADC_finished

Das heißt, das rjmp ADC_finished soll an Adresse 0x20 abgelegt werden.

> .org OC0addr
>     rjmp Timer0_Compare

Und rjmp Timer0_Compare kommt an Adresse 0x14

> Timer0_Compare:
>     reti

Dann geht's einfach weiter. Das reti kommt an Adresse 0x15 und so 
weiter. Irgendwann kommst du dann wieder bei 0x20 an, wo ja schon was 
drin steht. Du mußt also am Schluß der Interruptvektortabelle nochmal 
ein .org machen, das dafür sorgt, dass der eigentliche Code erst 
dahinter anfängt.

> Ich lasse ja momentan den ADC im Free Running Mode laufen und ich
> wollte eigentlich, dass bei jedem fertig konvertierten Messwert ein
> Interrupt ausgelöst wird. Ich habe aber hier im Forum gelesen, dass das
> nicht sonderlich optimal wäre, weil ja dann alle paar Zyklen ein
> Interrupt ausgelöst werden würde

Nur, wenn dein Controller mit ziemlich niedrigem Takt läuft. Der ADC ist 
im Normalfall deutlich langsamer.

> Dann wäre also die optimale Lösung, den ADC über einen Timer zu
> triggern, der z.B. alle paar ms ein Interrupt auslöst und damit den ADC
> anstößt, oder?

Es kommt drauf an, wie oft du überhaupt einen ADC-Wert brauchst.

von André H. (andreh)


Lesenswert?

Ok, das Problem mit dem Kompilieren konnte ich jetzt lösen.

Ich habe mal mit AVR Studio ein bisschen simuliert und in der Tat, der 
ADC ist wirklich sehr langsam. Ein Problem, das ich mit dem Programm 
oben im Anhang auch noch habe, ist, dass ein ADC-Interrupt nur 1x 
ausgelöst wird und dann nie wieder. Sowohl im Simulator, als auch in der 
fertigen Schaltung.

Ist das normal?

Naja, eigentlich bräuchte ich einen Messwert nur alle paar ms, von daher 
ist eine Lösung mit einem Timer sicherlich angebrachter. Trotzdem würde 
mich interessieren, warum nur 1x ein Interrupt ausgelöst wird.

von Walter (Gast)


Lesenswert?

Bit 5 – ADFR: ADC Free Running Select
When this bit is set (one) the ADC operates in Free Running mode. In 
this mode, the
ADC samples and updates the Data Registers continuously. Clearing this 
bit (zero) will
terminate Free Running mode.

Grüße
Walter

von André H. (andreh)


Lesenswert?

Dieses Bit gibts beim ATmega32 nur leider nicht (mehr). Stattdessen 
wurde wohl das ADATE Bit und das Register SFIOR eingeführt. Aber das Bit 
habe ich gesetzt und das Register ist so eingestellt, dass der Free 
Running Mode aktiviert ist.

von André H. (andreh)


Angehängte Dateien:

Lesenswert?

Ich habe nun mein Programm mal so umgebaut, dass der ADC auf Timer1 
Overflow triggern soll. Aber auch das klappt nicht. Ein Interrupt wird 
nur 1x aufgerufen, sowohl im Simulator als auch real.

Das Programm ist im Anhang.

Ich habe mir auch mal 
http://www.mikrocontroller.net/attachment/12747/temp3.c angeguckt, aber 
ich kann eigentlich keinen großen Unterschied erkennen.

von Magnus Müller (Gast)


Lesenswert?

> Ich habe nun mein Programm mal so umgebaut, dass der ADC auf Timer1
> Overflow triggern soll. Aber auch das klappt nicht. Ein Interrupt wird
> nur 1x aufgerufen, sowohl im Simulator als auch real.

Hä?
1
Timer1_Overflow:
2
  reti

Wie soll da der ADC auf den TIMER1 OVERFLOW "triggern" ???

von André H. (andreh)


Lesenswert?

Im Datenblatt steht, dass es ein spezielles Register SFIOR gibt, mit dem 
man die "ADC Auto Trigger Source" einstellen kann. Ich habe das Register 
so eingestellt, dass "Trigger Source" auf Timer/Counter1 Overflow steht. 
Also müsste doch eine Konvertierung ausgelöst werden, sobald Timer1 
überläuft, oder?

von Rolf Magnus (Gast)


Lesenswert?

Lass dich nicht beirren, du hast schon recht. Offensichtlich schaut 
sonst keiner ins Datenblatt, bevor er antwortet, oder zumindest nicht 
ins richtige.

Ich denke, folgender Auszug aus dem Datenblatt könnte relevant sein:

"Note that an Interrupt Flag will be set even if the specific interrupt
is disabled or the global interrupt enable bit in SREG is cleared. A
conversion can thus be triggered without causing an interrupt. However,
the Interrupt Flag must be cleared in order to trigger a new conversion
at the next interrupt event."

Zumindest, wenn du den Timer als Triggerquelle nutzt, mußt du also 
dessen Interrupt-Flag löschen, damit eine neue Wandlung angestoßen 
werden kann.

von johnny.m (Gast)


Lesenswert?

Genau, es ist essentiell wichtig, das Flag zu löschen. Achte auch 
darauf, dass der Simulator im AVRStudio anscheinend den ADC-Auto-Trigger 
nicht korrekt simuliert, obwohl alles korrekt eingestellt ist und es 
auch in der Hardware tadellos funktioniert. Das Problem hatte ich mal.

von André H. (andreh)


Angehängte Dateien:

Lesenswert?

Erstmal danke für die Antworten.

Welches Flag muss ich denn genau löschen? Das ADIF Flag? Oder das 
Interrupt Flag vom Timer?
Ich hab jedenfalls gerade so ziemlich alles probiert, aber ich hatte 
bisher immer noch keinen Erfolg.

Mein Programm sieht momentan so aus (siehe Anhang).
Ich habe doch richtig verstanden, dass wenn ich ein Flag löschen will, 
es auf 1 setzen muss, oder?

von Magnus Müller (Gast)


Lesenswert?

Das TOV1 Flag wird aber (laut Datenblatt) beim Aufruf des 
Interrupthandlers automatisch gelöscht, oder?

Das mit dem ADC Auto Trigger war mir bis dato unbekannt... aber man 
lernt ja nie aus ;)

Gruß,
Magnetus

von André H. (andreh)


Lesenswert?

Ja, so verstehe ich das eigentlich auch. Und das ADIF Flag dürfte auch 
automatisch gelöscht werden, wenn die Interruptroutine aufgerufen wird.

von Rolf Magnus (Gast)


Lesenswert?

> Das TOV1 Flag wird aber (laut Datenblatt) beim Aufruf des
> Interrupthandlers automatisch gelöscht, oder?

Ja, beim Aufruf des Timer-Interrupts. Dazu muss der aber auch aktiviert 
sein.

von André H. (andreh)


Lesenswert?

In meinem Programm (siehe oben) habe ich das Timer-Interrupt aber 
aktiviert und entsprechend eine Sprungroutine eingerichtet. Der Timer 
funktioniert auch, aber der ADC will immer noch nicht funktionieren, 
obwohl ich sogar das ADIF Flag gelöscht habe (und auch das TOV1-Flag).

von André H. (andreh)


Lesenswert?

Ok, ich habe nun das Problem gefunden.
In meinem Beispiel habe ich immer nach dem Lesen von ADCH auch noch ADCL 
gelesen. Das darf man scheinbar nicht machen, weil der ADC dann 
"gelockt" wird.

von unsichtbarer WM-Rahul (Gast)


Lesenswert?

>Das darf man scheinbar nicht machen, weil der ADC dann
>"gelockt" wird.

Das steht eigentlich auch im ADC-Abschnitt des Datenblattes ("Handling 
16Bit-Registers" oder so...)
(Nur so als "Nachtret-Anmerkung" ;-)

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.