Hallo,
ich versuche alle 100 us einen Interrupt mit dem Timer/Counter0 zu
erzeugen und seine Flag zu aktivieren. Es wird der Mikrocontroller
ATTiny25 von Atmel verwendet.
Der Timer/Counter0 wird mit dem CTC-Modus konfiguriert und sollte nach
dem Compare Match mit dem Register A eine Interrupt erzeugen und seine
Flag aktivieren. Der Timer läuft problemlos und die Interrupt-Routine
wird aufgerufen. Trotzdem wird seine Flag nicht aktiviert, sondern nach
dem Interrupt wird sinnlos die Flag für den Compare Match B aufgerufen.
Das verstehe ich überhaupt nicht. Ich habe versucht die gleiche Routine
mit anderem Controller (ATTiny2313 und ATTiny85) zu simulieren, den
Counter zu vergrössern, aber das Problem bleibt.
Ich habe detaliert die C-Datei und das Datenblatt vom ATTiny25 geprüft,
aber ich finde den Fehler leider nicht.
Ich wäre sehr dankbar, wenn jemand mir einen Vorschlag geben könnten.
Hier der C-Code:
Ich glaub ich hab die Frage nicht so ganz verstanden.. erst mal
häppchenweise..
> Der Timer läuft problemlos und die Interrupt-Routine wird aufgerufen.> Trotzdem wird seine Flag nicht aktiviert, sondern nach dem Interrupt> wird sinnlos die Flag für den Compare Match B aufgerufen. Das verstehe> ich überhaupt nicht.
Wie meinen? Wessen Flag wird nicht aktiviert und welches wird nicht
aufgerufen(?)?
Ich hab mir den Code nicht komplett angesehen, ich möchte nur die zwei
Punkte hervorheben:
1. in der ISR: Was soll folgende Zeile erreichen?
> TIFR &= ~(1<<OCF0A);
Alle Timer-Interrupt-Flags löschen ausser OCF0A?
2. In main():
> if (PB0 == 0)
^^^^^^^^
ist immer wahr,
> if (PB0 != 0)
^^^^^^^^
ist immer flasch.
Wozu die Abfragen? Die Konstante wird ihren Wert während der Ausführung
wohl kaum ändern..
HTH
Hallo,
ich meine, dass die Flag für Compare Match A nicht aktiviert wird,
sonder die Flag für Compare Match B. Der Timer wird konfiguriert, um
einen Interrupt mit Compare Match A zu erzeugen. Deswegen versehe ich,
wie die Flag von Compare Match B aktiviert wird.
Mit dem Befehl:
TIFR &= ~(1<<OCF0A);
wollte ich die Flag von Compare Match A ausschalten, damit die Flag für
den nächsten Interrupt wieder aktiviert werden kann.
Die if-Befehle verwende ich für die Prüfung eines Pin-Ausgangs. Mit dem
Programm will ich diesen Ausgang mit dem Lesen einer AD-Wandlung
steuern. Ich benötige den Timer, um den AD-Wandler zu steuern. In diesem
C-Code wollte nur eine Endlosschleife erzeugen. So haben die Befehle im
while keinen Sinn, aber ich werde sie später für mein Programm benutzen.
Darüber hinaus haben diese Befehle keinen Einfluss auf dem
Programmablauf, oder?
Habt ihr das C-Code mit dem AVR Studio 4.18 Build 700 simuliert?
Woran kann das Problem liegen? Warum wird die Flag für COMPARE MATCH B
aktiviert, wenn ich nur den TIMER0 für COMPARE MATCH A konfiguriert
habe.
Vielen Dank.
>Habt ihr das C-Code mit dem AVR Studio 4.18 Build 700 simuliert?
Nein.
Wer traut schon einem Simulator;)
>Woran kann das Problem liegen? Warum wird die Flag für COMPARE MATCH B>aktiviert, wenn ich nur den TIMER0 für COMPARE MATCH A konfiguriert>habe.
Das kann mit deiner Einstellung nicht passieren.
Entweder der Simulator macht Mist oder du benutzt nicht den
Code den du gepostet hast.
> Mit dem Befehl:>> TIFR &= ~(1<<OCF0A);>> wollte ich die Flag von Compare Match A ausschalten, damit die Flag für> den nächsten Interrupt wieder aktiviert werden kann.
Dachte ich mir fast. Das tut er aber nicht. Es müsste heissen
TIFR = (1<<OCF0A);
Die übrigen Einstellungen scheinen korrekt zu sein. Hau das Programm mal
auf einen echten µC und nicht in den Simulator.
HTH
Sebastian O. schrieb:> Flag aktivieren. Der Timer läuft problemlos und die Interrupt-Routine> wird aufgerufen. Trotzdem wird seine Flag nicht aktiviert,
Das Flag wird sehr wohl gesetzt, andernfalls würde die ISR nicht
aufgerufen. Allerdings setzt der AVR die meisten Interrupt-Flags mit
Aufruf der zugehörigen ISR automatisch zurück. Man kriegt da also nicht
lang was zu sehen und das Flag in der ISR explizit zurückzusetzen ist
überflüssig.
> sondern nach> dem Interrupt wird sinnlos die Flag für den Compare Match B aufgerufen.
Wie man ein Flag aufrufen kann ist mir nicht recht klar. Setzen darf er
es, denn das OCRB Register hat auch dann einen Inhalt, wenn du keinen
reinschreibst.
Hallo,
wenn es hilfreich wäre, hänge ich den C-Code nur mit der Inizialisierung
des Timers und die Interrupt-Routine an.
Man kann mit diesem einfachen C-Code, dass die Flag für COMPARE MATCH A
immer "0" bleibt und die Flag für COMPARE MATCH B nach den ersten
Interrupt-Aufruf immer "1" bleibt. Es könnte sein, dass die Flag für
COMPARE MATCH A schon zurückgesetzt wurde, aber die Flag für COMPARE
MATCH B wird aktiviert, wenn ich nur den Register OCR0A geschrieben habe
und den Register OCR0B überhaupt nicht manipuliert habe.
Wäre es möglich, dass der Simulator von AVR Studio Fehlern hätte? Könnte
meiner C-Code auf einer echten uC problemlos funktionieren?
Momentan kann ich leider nicht auf einer echten uC den Code probieren,
weil ich noch nicht die Leiterplatte aufgebaut habe. Ich verwende die
Schnittstelle JTAGICE mkII für die Programmierung des uCs. So muss ich
die Leiterplatte fertig haben, um den Code auf den uC zu prüfen.
Könntet ihr vielleicht den Code simulieren?
Ich verwende die Tools AVR Studio 4.18 Build 700 und WinAVR-20090313, da
ich mit anderen Versionen von WinAVR Probleme hatte, den Code mit dem
ATTiny25 zu debuggen.
#include <avr/io.h>
#include <avr/interrupt.h>
void Initialize(void){
/* Timer 0 configuration*/
TCCR0A |= (1<<WGM01);
// CTC Mode
// Normal port operation, OC0A/OC0B disconnected
TCCR0B |= (1<<CS01) | (1<<CS00);
// Prescaler 64
OCR0A = 11; // // ((8000000/64)/100) = 12-->12-1=11
TIMSK |= (1<<OCIE0A);
// CompareA Interrupt permited
}
/*The Compare Interrupt Handler will be called, if TCNT0 = OCR0A =
12-1=11
is (12 Steps), that is exact every 100us */
ISR (TIMER0_COMPA_vect)
{
}
int main(void)
{
Initialize();
// Global Interrupts enable
sei();
while(1)
{
}
Vielen Dank.
>aber die Flag für COMPARE MATCH B wird aktiviert,>wenn ich nur den Register OCR0A geschrieben habe>und den Register OCR0B überhaupt nicht manipuliert habe.
Natürlich wird das Flag gesetzt. OCR0B = 0. D.h. wenn der Timer 0 ist
wird das Flag gesetzt. Wo ist dabei eigentlich das Problem?
Hi
>Es könnte sein, dass die Flag für>COMPARE MATCH A schon zurückgesetzt wurde, aber die Flag für COMPARE>MATCH B wird aktiviert, wenn ich nur den Register OCR0A geschrieben habe>und den Register OCR0B überhaupt nicht manipuliert habe.
Flags werden gesetzt, wenn das entsprechende Ereignis eintritt. Darauf
hast du keinen Einfluss. Dein Register OCR1B steht nach einem Reset auf
Null. Also wird folgerichtig das OCF1B gesetzt wenn der Timer auf Null
steht. Da es keinen zugehörigen Interrupt gibt, wird es auch nicht
wieder zurückgesetzt. Also ist alles, was du beobachtet hast, normal.
Manuell wird ein Flag zurückgesetzt, indem man eine 1 in das
entsprechende Bit schreibt.
>Haben die Timer im Simulator nicht für einige Typen und Timer-Modes>Bugs?
Ja, für PWM-Modes mit einem Register als Top-Wert. CTC und PWM-Modes mit
fixem Top-Wert werden richtig simuliert.
MfG Spess
Hallo,
danke holger für den Vorschlag
Ich habe probiert, den Register OCR0B mit 0xFF zu schreiben. In diesem
Fall wird die Flag für COMPARE MATCH B nicht mehr gesetzt, aber auch
nicht die Flag für COMPARE MATCH A. Die Flag für COMPARE MATCH A muss
gesetz werden, damit der ADC-Wandler mit der Funktion "Auto-Triggering"
aktiviert werden kann.
Darüber hinaus kapiere ich noch nicht, warum die Flag für COMPARE MATCH
B aktiviert werden kann, obwohl das Bit OCIE0B "0" ist. Bedeutet
OCIE0B=0 nur, dass die Interrupt-Routine für COMPARE MATCH B nie
aufgerufen wird, aber die Flag OCF0B kann gesetzt werden, wenn
TCNT0=OCR0B ist?
Ich habe probiert, die Interrupt-Routine für COMPARE MATCH A
auszuschalten, d.h. OCIE0A=0. In diesem Fall wird natürlich die
Interrupt-Routine nicht aufgerufen, aber die Flag OCF0A bleibt denn
immer gesetzt. Sollte die Interrupt-Routine für COMPARE MATCH A
aufgerufen werden, damit ihre Flag zurückgesetzt werden kann und wieder
gesetzt werden kann?
Danke.
Sebastian O. schrieb:> Die Flag für COMPARE MATCH A muss> gesetz werden, damit der ADC-Wandler mit der Funktion "Auto-Triggering"> aktiviert werden kann.
Nein. In der Beschreibung des ADCs steht klar, dass der ADC vom Compare
Match getriggert wird und nicht vom Interrupt Flag.
Sebastian O. schrieb:> Darüber hinaus kapiere ich noch nicht, warum die Flag für COMPARE MATCH> B aktiviert werden kann, obwohl das Bit OCIE0B "0" ist.
In der Beschreibung von OCIE0B steht nichts davon, dass das Flag nicht
gesetzt wird, wenn OCIE inaktiv ist. Weiters wird die Beschreibung von
OCIE aussagen, dass es bei Compare Match (und nur von dem (ohne weitere
Bedingungen)) gesetzt wird.
Deine ganzen Probleme ließen sich lösen, wenn Du weniger Annahmen
darüber machen würdest, wo Abhängigkeiten sein sollen, und stattdessen
mehr im Datenblatt lesen würdest. Das ist nämlich dazu da, solche
Fragen zu klären.
Hi
>Bedeutet OCIE0B=0 nur, dass die Interrupt-Routine für COMPARE MATCH B nie>aufgerufen wird,
Richtig.
> aber die Flag OCF0B kann gesetzt werden, wenn TCNT0=OCR0B ist?
Nicht 'kann gesetzt werden', sondern es wird gesetzt.
> aber auch nicht die Flag für COMPARE MATCH A.
Doch. Das Flag wird aber beim Anspringen der Interrupt-Routine wieder
gelöscht. Wenn du dein Programm auf Assemblerebene debugst, wirst du
auch das gesetzte Flag sehen.
MfG Spess
Hi
>In der Beschreibung des ADCs steht klar, dass der ADC vom Compare>Match getriggert wird und nicht vom Interrupt Flag.
Nein. Wird vom Interrupt-Flag getriggert.
Aus 17.4 Starting a Conversion
....
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.
...
MfG Spess
Hi,
danke spess53 für die Erklärungen.
Das bedeutet, dass der ADC-Wandler mit der Flage von Compare Match A
aktiviert werden kann, obwohl ich die Flage für Compare Match A nicht
aktiv sehen kann, oder?
Wie könnte ich diesen Code auf der Assemblerebene simulieren, ohne einen
neuen Assemblercode schreiben zu müssen?
Vielen Dank,
sebas
Hi
>Wie könnte ich diesen Code auf der Assemblerebene simulieren, ohne einen>neuen Assemblercode schreiben zu müssen?
Ich programmiere nicht mit C. Aber auch dort sollt es im AVR-Studio über
View->Disassembler oder/und den Button 'Toggle Disassembler Window'
gehen.
MfG Spess
Sebastian O. schrieb:> Das bedeutet, dass der ADC-Wandler mit der Flage von Compare Match A> aktiviert werden kann,
Nein. Der ADC wird bei seinem Auto-Trigger nicht von irgend einem Flag
aktiviert, sondern direkt vom Compare Match. Steht aber weiter oben
schon (und im Datenblatt).
Hi
> sondern direkt vom Compare Match.
Nochmal Nein. Autotrigger-Source ist das Flag. Und das wird auch vom ADC
am Ende der Conversation wieder zurückgesetzt. Siehe Datenblatt S.131.
MfG Spess
spess53 schrieb:> Nochmal Nein. Autotrigger-Source ist das Flag.
Ich habe übersehen, dass Du mir schon einmal widersprochen hast. Ja,
das scheint zu stimmen. Das steht allerdings im Widerspruch zur
Beschreibung der ADTS-Bits, wo das Ereignis "Compare Match" als
Trigger-Quelle gewählt wird und und aufgeführt ist, aber kein Flag.
Daraus bezog ich meine Interpretation.
Hi
In 'Starting a Conversion' wird ausdrücklich von Flags geschrieben.
Allerdings muss ich mich in einem Punkt revidieren: Das Flag muss
manuell
zurück gesetzt werden.
MfG Spess
spess53 schrieb:> In 'Starting a Conversion' wird ausdrücklich von Flags geschrieben.
Ja, das habe ich inzwischen auch entdeckt. Die Tafel ADTS2:0 "ADC Auto
Trigger Source Selections" ist offensichtlich ungenau, indem sie das
Ereignis und nicht das Flag als Triggerquelle nennt. Das hat mich aufs
Glatteis geführt.
Edit: Im Text dazu steht „A conversion will be triggered by the rising
edge of the selected Interrupt Flag.“ Ähem. Mea culpa.
Hi,
denn das bedeutet, dass der ADC-Wandler mit der Aktivierung der Flag für
COMPARE MATCH A aktiviert wird. Müsste ich in diesem Fall manuell die
Flag für COMPARE MATCH A lösen oder wäre es besser die Interrupt-Rutine
für COMPARE MATCH A aufrufen und wird da die Flag gelöst?
Vielen Dank.
Hi
Persönlich würde ich das Einlesen des ADC-Wertes im
ADC-Complete-Interrupt machen. Dort könnte auch das Flag gelöscht
werden.
Noch etwas anderes: So wie es aussieht löst du im Moment alle 100µs
(genau genommen alle 96µs) den Timerinterrupt aus. Der AD-Wandler soll
für maximale Genauigkeit mit einem Takt von 50...200kHz laufen. Bei 8MHz
ist der kleinste, für diesen Bereich, mögliche AD-Prescaler 64. Damit
ergibt sich eine Wandlungszeit von 104µs. Timergesteuerte AD-Wandlung
ist aber nur sinnvoll, wenn das Messintervall (wesentlich) grösser als
die Conversation-Time ist. In deinem Fall wäre der Free Running Mode
angebrachter.
MfG Spess
Hi,
das Ziel meines Programms ist die Messung eines Eingans alle 100us.
Meine Idee war, ein Taktsignal von 1MHz (Prescaler=8) für den AD-Wandler
zu vewerden, da ich nur kennen will, ob der Eingag die Spannungsreferenz
erreicht hat. Deswegen benötige ich keine hohe Genauigkeit. Ich muss nur
prüfen, ob die Konvertierung 0xFF ist. Da mein Einganssignal sehr kurz
ist, muss ich schnell wie möglich messen. Denn die Konvertierung dauert
25us für die erste Konvertierung und 13us ab die zweite Konvertierung.
So habe ich Zeit die Interrupt aufzurufen und dem Main-Programm weiter
zu machen, bevor die neue Konvertierung gestartet wird.
Danke.
Hi
So etwas ähnliches hatte ich geahnt/befürchtet.
>Da mein Einganssignal sehr kurz ist, muss ich schnell wie möglich messen.>Denn die Konvertierung dauert 25us für die erste Konvertierung und 13us ab>die zweite Konvertierung.
Das Eingangssignal des AD-Wandlers wird mit der fallenden Flanke des
2.ADC-Taktes gespeichert. Änderungen des Eingangssignals bis zum Ende
der Wandlung sind irrelevant.
>So habe ich Zeit die Interrupt aufzurufen und ....Du rufst überhaupt keinen Interrupt auf. Der wird automatisch am Ende
der Konvertierung generiert. Das Ergebnis einer Wandlung bleibt in
ADCH/L bis zum Ende der nächsten Wandlung erhalten. Also ist es egal, ob
du aufeinander folgende Wandlungen mit langsamen ADC-Takt oder kurze
Wandlungen mit einem entsprechenden Abstand hast.
>...dem Main-Programm weiter zu machen, bevor die neue Konvertierung>gestartet wird.
Im Hauptprogramm kannst du auch weitermachen während eine
Konvertierung läuft. Die AD-Wandlung blockiert in keiner Weise deinen
Programmablauf.
Vielleicht solltest du dir mal den Analog-Komperator zu Gemüte führen.
Der scheint mir für dein Vorhaben besser geeignet.
MfG Spess
Hi,
leider passt der Analog Comparator nicht zu meiner Applikation, da die
Spannungsreferenz die Spannungsversorgung sein sollte. In diesem fall
könnte nur messen, wann der Eingang des Comparators die
Spannungsversorgung erreicht hat. Sobald das passiert, sind
Spannunsreferenz und Spannungsversorgung gleich, so kann ich nicht mehr
erkennen, ob der Eingang des Analog Comparators niedrig als die
Spannungsreferenz ist, da sie immer gleich sind. Andere Möglichkeit
wäre, 1,1 Volt als Spannungsreferenz zu verwenden, aber diese Referenz
ist zu niedrig für meine Applikation. Deswegen verwende ich den
AD-Wandler mit 2,56 Volts als Spannungsreferenz.
Viele Grüsse,
sebas
Hi,
das löst nicht das Problem, da der Eingang und die Spannungsreferenz das
gleiche Verhältnis folgen. Sobald der Eingang die Spannungsreferenz
erreicht, werden VCC und AIN mit der gleichen Spannung versorgt. Wenn
ich einen Spannungsteiler verwende, wird der Comparator immer gesetzt
(Spannungsteiler für die Spannungsreferenz) oder automatisch gelöst
(Spannungsteiler für Eingang des Comparators), da das Signal für AIN und
VCC gleich ist. So ist das Verhältnis auch gleich. Deswegen kann ich
nach einer gewissen Zeit nicht erkennen, ob der Eingang niedrig als die
Spannungsversorgung ist.
Sorry, aber meine Kenntnisse in diesem Bereich sind nicht so gross. Ich
versuche schnell wie möglich alles zu verstehen und eine geigenete
Applikation zu implementieren.
Viele Grüsse,
Sebas
Hi,
die Möglichkeit mit dem Analog Comparator hatte ich betrachtet. Der uC
muss entsprechend auf dem Messsingal reagieren. Das Messsignal ist misst
die Energieverorgung des Systems. Sobald das Messsignal einen
Spannungspegel erreicht, muss der uC ein Pin aktivieren. Ab diesem
Moment sind Energieversorgung und Messsignal gleich. Sobald das
Messsignal nochmal niedrig als den Spannungspegel ist, muss der uC ein
Pin lösen.