Hallo Freaks, ich versuche, die Impulslänge eines Rechtecksignals zu messen.Dazu habe ich den Code im Anhang geschrieben. Ich verwende WinAVR, ATtiny2313, Quarz 11.059. Im main wähle ich in GIMSK zunächst INT1 und konfiguriere INT1 und INT0 für steigende Flanken. Nach sei() ist also zunächt INT1 scharf. Wenn nun eine steigende Flanke vorbeikommt, soll INT1 den Timer1 starten und mit GIMSK=(1<<INT0) sich selbst deaktivieren, dafür den Kollegen INT0 augewecken. Der soll nun auf die nächste Flanke warten und Timer1 stoppen. Danach deaktiviert er sich ebenfalls (GIMSK=0). In main wird derweilen gewartet, bis beide, INT0 und INT1 ihren Job erledigt haben (while(GIMSK);), anschliessend alle Interrupts gesperrt, der Inhalt von Timer1 ausgelesen und über eine kleine Routine (dez2ser) seriell ausgegeben. Nun das merkwürdige: Egal, welche Eingangsfrequenz (950 Hz bis 32 kHz habe ich getestet) ich an INT0 und INT1 lege (sind parallelgeschaltet), ich erhalte immer einen Messwert von 30 (entspricht ca 3us bei 11 MHz). Es scheint fast, ob INT0 nicht auf die nächste Flanke wartet, sondern gleich anspricht. Wie kann das sein? Danke für Eure Antworten! Hannes
Du müsstest zunächst mal vor der Freigabe des Interrupt das Flag löschen. Wenn das noch von einer vorhergehenden Flanke gesetzt ist, wird selbstverständlich sofort nach Beendigung der einen ISR die andere aufgerufen. Abgesehen davon ist das, was Du da machst, eine ziemliche Krücke. Impulslängen misst man nicht mit externen Interrupts (und erst recht nicht mit gleich zweien davon, immerhin sind die Flanken umschaltbar), sondern mit der Input Capture Unit. Zu dem Thema gibt es hier (und im µC-und-Elektronik-Forum) eine ganze Reihe Threads.
Hallo Hannes, Du solltest das Prinzip ändern: Eine Eingangssignalflanke kommt: Timerzähler wird nullgesetzt und Timer gestartet. Eine nächste Eingangssignalflanke kommt und schaut sich den Timerzählerstand an und gibt in aus. Danach das Spielchen von vorne. Ich vermute das macht es wesentlich unkomplizierter als deine bisherige Lösung. Jan
Hi Johnny, Das habe ich schon ausprobiert (EIFR=0). Gleicher Effekt. Ausserdem sollten die Flags nach Verlassen der Routine doch selbstständig gelöscht werden? Dass ich das mit den 2 INT's mache, hat schon seinen Grund. Da kommt später noch mehr dazu, wofür ich das so brauche. 73 Hannes
Hallo Jan, klar, das geht einwandfrei. Aber das blockiert halt alles.
> EIFR=0
Damit löschst Du gar nichts! Interrupt-Flags werden gelöscht, indem man
eine 1 hineinschreibt! Und wenn das Flag vom zweiten Interrupt von einer
vorhergehenden Flanke noch gesetzt ist (was in Deinem Fall sehr
wahrscheinlich ist) und der Interrupt freigegeben wird, dann wird die
ISR sofort nach dem Verlassen der anderen (vom ersten Interrupt)
ausgeführt. Was Du da gemacht hast, ist eine
Interrupt-Bearbeitungszeit-Messung.
>konfiguriere INT1 und INT0 für steigende Flanken
Du willst die Pulslänge messen, und konfigurierst beide auf die gleiche
Flanke? Das ist doch Quatsch.
Du wirst das von JoHnny geschilderte Problem haben: Dein INT1-Flag ist
schon gesetzt, sobald du den Interrupt im GIMSK freischaltest.
Lösch das Interrupt-Flag und gut müsste sein.
Hannes wrote: > Es scheint fast, ob INT0 nicht auf die nächste Flanke wartet, sondern > gleich anspricht. Nö, er wartet schon auf die nächste Flanke. Allerdings auf die nächste überhaupt und nicht erst auf die nach Interruptfreigabe. Falls das nicht gewünscht wird, muß man vor der Freigabe das Interruptbit löschen (also setzen). Aber ne Frage, warum benutzt Du nicht einfach den ICP-Eingang ? Bequemer kann man doch keinen Zeitstempel kriegen. Peter
Hi trolliger Rahul, sorry, habe mich falsch ausgedrückt: Ich will eigentlich die Periodenzeit messen. @ Johnny: tiny 2313 Data Sheet Seite 61: When an edge or logig chage...triggers an IRQ, INTF becomes set (one). ... The flag is cleared when the ISR is executed.
Genau, und deshalb wird die ISR ja auch ausgeführt! Ich glaube, Dir fehlt da gewaltig Grundverständnis. Es wird nur das zu der ISR gehörende Flag gelöscht. wenn also die INT0-ISR ausgeführt wird, dann wird das Flag INTF0 gelöscht. Da aber das INTF1 mit großer Wahrscheinlichkeit noch gesetzt ist (der Interrupt war ja vorher gesperrt und deshalb das Flag natürlich nicht gelöscht), wird eben nach Verlassen der INT0-ISR sofort die INT1-ISR ausgeführt. Du kannst mir das ruhig glauben.
>sorry, habe mich falsch ausgedrückt: Ich will eigentlich die >Periodenzeit messen. Und dafür braucht man 2 Interrupts? Ich bräuchte nur einen: INTx auf steigende Flanke konfigurieren Bei Eintreten des Interrupts Timer auslesen, Wert vom vorhergehenden Interrupt davon abziehen => eine Pulslänge. Für sowas ist die InputCaptureUnit prädestiniert! Falls es aus aus Johnny's Post noch nicht hervorgegangen ist: Das INT1-Interrupt-Flag wird im gleichen Moment gesetzt wie das des INT0. Wenn man dann in der INT0-ISR das INT1IE-Flag setzt, springt der Controller sofort in die INT1-ISR, da dessen Interrupt-Flag ja auch gesetzt ist. Also: Erst löschen, dann freigeben!
> GIMSK=(1<<INT0); //N�chste Flanke soll INT1 ausl�sen
Ich glaub, da ist auch in Deinem Programm generell ein ziemliches
Durcheinander. In der obigen Zeile stimmt schonmal der Kommentar
überhaupt nicht mit dem Code überein. Außerdem hauen dadurch bei der
nächsten positiven Flanke beide Interrupts rein, weil INT1 nirgends
abgeschaltet wird. Da kann dann alles Mögliche passieren. Aber wie
gesagt: Mach es mit Input Capture. Dafür ist das schließlich da!
Hallo Johnny, Du hast recht, ich habe verkehrt herum gedacht. Nun läuft alles wie es soll. Vielen Dank! Danke auch den Anderen. 73 Hannes
Sorry für den Kommentar, INT0 muss es natürlich heissen. INT1 ist aber schon abgeschaltet, weil GIMSK=(1<<INT0); nur INT0 freigibt Danke auch Rahul und Peter.
OK, hast kein "|" drin. Dann gehts. Hatte ich beim überfliegen nicht gesehen.
>OK, hast kein "|" drin. Dann gehts. Hatte ich beim überfliegen nicht >gesehen. Da fällt mir ein, dass das Programm noch erweitert werden soll. Wenn man "GIMSK=(1<<INT0);" schreibt und noch andere Interrupts verwenden will, die nichts mit der Periodenmessung zu tun haben, werden die durch sowas natürlich "gekillt". Besser wäre es, zu beginn der jeweiligen ISR "GIMSK &= ~(1<<INTx);" zu schreiben (x = 0 oder 1). Dann wird nur die jeweilige Frteigabe abgeschaltet. Eigentlich müsste auch "GIMSK ^= ((1<<INT0) | (1<<INT1));" gehen (Hab ich jetzt so aus der Hüfte "konstruiert"...). Damit würde man sich 2 C-Anweisungen sparen.
Naja, ich hoffe, er hat wenigstens verstanden, dass ein einziger Interrupt völlig ausreicht (Wenn er es schon nicht mit Input Capture machen will). Dann kann er sich die Umschalterei ja komplett sparen.
"Naja, ich hoffe, er hat wenigstens verstanden, dass ..." Danke, sehr nett von Anderen in der dritten Person zu sprechen. Andere Interrupts brauch ich nicht, und ich sagte schon, dass es Gründe für diese Konstruktion gibt.
>Danke, sehr nett von Anderen in der dritten Person zu sprechen. Es war halt eine Unterhaltung zwischen Johnny und mir (die dich nichts angeht ;-)... >Andere Interrupts brauch ich nicht, und ich sagte schon, dass es Gründe >für diese Konstruktion gibt. Die Gründe würde mich schon äusserst interessieren, oder sind die geheim?
"Es war halt eine Unterhaltung zwischen Johnny und mir (die dich nichts angeht ;-)..." Sehr witzig. Du bist wohl wirklich trollig unterwegs, was? Ciao Hannes
@Hannes: Mein Posting bezog sich (wie von Rahul ganz richtig erkannt) auf seinen (Shit, schon wieder dritte Person...) Vorschlag, die Umschalterei mit EXOR zu machen. Wenn Du Dich dadurch angepisst fühlst, kann ich da nix dran ändern. Sorry, dass ich helfen wollte...
nochmal @Hannes: BTW: Wie redest Du von anderen? In der vierten Person? Ich glaube, mich zu erinnern, dass gerade dafür die dritte Person erfunden wurde...
Noch einer, der unter Kategorie ";-) <-- das ist ein Smilie!" fällt... Immer wieder interessant, welche Reaktionen Forennamen bei manchen anderen Forenbenutzern sorgen... Iss mir alles zu drittens...
> Die Gründe würde mich schon äusserst interessieren,
Mich allerdings auch. Im Moment kann ich mir keinen
vorstellen, der mich davon abhalten würde ein Input
capturing zu machen (*). Das ist sowas von simpel und
sowas von genau. Das einzige worauf man achten muss,
ist das man alle Timer Overflows mitkriegt. Allerdings
hat man selbst beim kleinsten Vorteiler 65536 Takte Zeit
einen Overflow zu registrieren, so dass das in der Praxis
wohl kein Problem ist. Noch banaler als ICP gehts ja wohl
kaum: Alles einstellen, auf den Interrupt warten und in
aller Gemütsruhe das eingefrorene Zählergebnis abholen.
Da gibts keine Race Conditions, nichts ist zeitkritisch
und sogar die BASCOM Leute kriegen das ohne Probleme hin
(wenn sie mal Handbuch lesen würden :-)
(*) OK. Einen gibt es. Wenn der Pin nicht mehr frei ist.
Wenn es garantiert ist, dass man maximal einen timer overflow während des Messintervalls bekommt, muss man den nicht einmal mitbekommen.
Da spricht er wahr, unser Troll-Rahul: " Immer wieder interessant, welche Reaktionen Forennamen bei manchen anderen Forenbenutzern sorgen..." sein alter Forenname "fieser, klugscheissender Rahul" passt doch besser zu ihm... höhöhöhöhö
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.