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é
> 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.
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.
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
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.
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.
> 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" ???
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?
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.
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.
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?
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
Ja, so verstehe ich das eigentlich auch. Und das ADIF Flag dürfte auch automatisch gelöscht werden, wenn die Interruptroutine aufgerufen wird.
> 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.
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).
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.
>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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.