hallo, ich möchte ein 10 Hz Signal erzeugen.Das mache ich mit einem 16 bit Timer. Meine Taktfrequenz ist clk=8Mhz. Um genau auf 10 Hz zu kommen benutze ich Output Compare Match. also: ich initalisiere den Timer wie folgt: mit clk\1024 , die Frequenz des Timers ist also 7812,5 Hz um nun auf 10 Hz zu kommen mache ich: OCR1A = 750; dann kommt SIGNAL(SIG_OUTPUT_COMPARE1A) in 100 ms Abstand (10 Hz) meine Rechnung war wie Folgt: 10Hz entspricht 100 ms; 7812,5 Hz entspricht 128 us; 0.1/0.000128 = 750; also muss der timer bis 750 zäheln , dann SIG_OUTPUT_COMPARE1A) auslösen. Hab ich da nen Denkfehler drinn ? bzw falsch gerechnet ? Danke Chris
Sieht soweit schlüssig aus, aber jetzt hast du 10 Ereignisse pro Sekunde. Wenn du jetzt einen Portpin toggeln läßt, kommst du nur auf 5 Hz. MW
Also ich würde es so machen: DU nimmst nen 8bit Timer mit Prescaler /64 also 8.000.000 / 64 = 125.000 Comparematch bei 125 heißt du kriegst jede ms einen Impuls, nun zählst du ein register in der ISR hoch, un wenn du bei 100 bist, hast du deine 10hz, das hat den Vorteil das du auch andere Frequenzen später benutzen kannst, und das ganze ist ein ganzzahliger teiler deiner Quarzfrequenz.
danke erstmal fürs anschauen. ich hab in SIGNAL() einen Zähler drinn, der wenn er bei 10 ist sekunde = true setzt ; und im Hauptprogramm sthet dann so was: if(sekunde == true ) { printf("test"); sekunde =false; } nur leider kommt das printf nicht im abstand 1 Sekunde deswegen dachte ich ich hab den Timer falsch eingestellt .. chris
Hast Du den Timer auch auf den CTC-Mode (= clear on compare match, d. h.
hardwaregesteuertes Resetten auf Null nach Compare Matsch)
konfiguriert?
>nur leider kommt das printf nicht im abstand 1 Sekunde
Warum schreibst Du nicht dazu, in welchem Abstand es denn dann kommt,
denn daraus kann man u. U. wertvolle Rückschlüsse auf den Fehler
ziehen.
>Oh ja stimmt CTC Mode ist wichtig!
Mann, das laber ich doch hier die ganze Zeit g.
Wie hast du die Zählvariable in Signal() initialisiert? So weit ich weiß musst die ein unsigned volatile char sein. Gruß Daniel
@ Chris > 10Hz entspricht 100 ms; stimmt > 7812,5 Hz entspricht 128 us; stimmt auch > 0.1/0.000128 = 750; hä ?? wie isn das gerechnet? Adam Riese meint = 781,25, was ja auch zu erwarten wäre wenn man sich die Frequenzen ansieht. Nix für ungut Dieter
hab den CTC mode nicht an , aber in SIGNAL(....) steht TCNT1=0; drinn, als manuelles Rücksetzen des Zählerstandes. @dd5 hi, danke hast wohl recht ;-) .... @Daniel: danke den Hinweis werde ich überprüfen @Bolle ich weis jetzt net so recht wie ich die zeit messen soll in der printf gemacht wird, es is aber schneller als 1 Sekunde, kannst mir einen Tipp geben ?
>hab den CTC mode nicht an , aber in SIGNAL(....) >steht TCNT1=0; drinn, als manuelles Rücksetzen des Zählerstandes. Davon ist dringend abzuraten! Es kann sein bzw. ist sehr wahrscheinlich, daß Dein Compiler vor die Zeile "TCNT1=0" noch selbsttätig ein paar Zeilen Code hinknallt (SREG auf dem Stack sichern, dito mit den im Handler verwendeten Registern etc.). Das bedeutet, daß zwischen dem Auftreten des Compare-Matches und dem Nullsetzen des Counters (Ausführen der "TCNT1=0"-Zeile) eine gewisse Zeit liegt, und Du nicht genau weißt, wie groß die ist (es sei denn, Du studierst den erzeugte Assemblercode, und zählst die Instruktionen ab, um daraufhin den Compare-Match-Wert genau daran angepaßt nach unten zu korrigieren). Eben weil das aber ein Riesenkrampf wäre, wurde der CTC-Mode erfunden, bei dem der Counter nach Compare-Matsch AUGENBLICKLICH vollautomatisch durch die Hardware resettet wird. Damit ist das angesprochene Problem aus der Welt. >ich weis jetzt net so recht wie ich die zeit messen soll in der printf >gemacht wird, es is aber schneller als 1 Sekunde, kannst mir einen >Tipp geben ? Ein Frequenzzähler oder ein Oszi wäre Dein Freund. Wenn Du keins hast, bleibt nur rechnen. Wenn Du richtig rechnest, kommst Du auch damit ans Ziel.
Den Timer lässt man möglichst frei durchlaufen. Damit hält man sich andere Timer-Features (ICP, den anderen Comp.) offen. Am besten die Compare-Register einlesen, das Zeitintervall dazuaddieren und zurückschreiben. Damit ist das nächste Vergleichsereignis exakt ein Intervall später. Man kann also durch mehrere Output-Compare-Match eines Timers (falls mehrere vorhanden) mehrere unabhängige Interrupt-Takte (ISR-Aufrufe) erzeugen und quasi gleichzeitig den Input-Capture-Eingang nutzen. ...
@HanneS: Danke für Deine Antwort. Leider ist mir nicht ganz klargeworden, was Du mir sagen willst. Wenn der Timer1 (16 Bit) dazu dienen soll, einen vorgegebenen, konstanten Takt zu generieren, d. h. man möchte einen Interrupt haben, der exakt alle 15.625 ms (Beispielwert) aufgerufen wird, kann ich diese Aufgabe dann lösen, ohne Timer1 im CTC-Mode zu betreiben? (Mit CTC-Mode ist es ja leicht: Bei phi = 4 MHz, kein Prescaler, und Output-Compare-Wert 62500 ergibt sich f[output compare match interrupt] = 4000000 Hz/62500 = 64 Hz, 1/(64 Hz) = 15.625 ms)
Ja sicher doch... Hier z.B. die ISR für einen 100ms-Takt mit Overflow: TIM1_COMPA: ;ISR Timer1-Interrupt (alle 10ms) in srsk,sreg ;SREG sichern (Exklusivregister) push xh ;benutzte Register push xl ;sichern in xl,ocr1al ;Weckzeit in xh,ocr1ah ;holen, subi xl,low(-tim1zu) ;Intervall sbci xh,high(-tim1zu) ;dazu, out ocr1ah,xh ;und wieder out ocr1al,xl ;in den Timer ;xl und xh können jetzt innerhalb dieser ISR frei benutzt werden Tastenabfrage: ;Entprellroutine geklaut bei Peter Dannegger... in xl,tap ;Tastenport einlesen (gedrückt=L) com xl ;invertieren (gedrückt=H) eor xl,tas ;nur Änderungen werden H and tz0,xl ;Prellzähler unveränderter Tasten löschen (Bit0) and tz1,xl ;Prellzähler unveränderter Tasten löschen (Bit1) com tz0 ;L-Bit zählen 0,2,->1, 1,3,->0 eor tz1,tz0 ;H-Bit zählen 0,2,->tz1 toggeln and xl,tz0 ;Änderungen nur dann erhalten, wenn im ;Prellzähler and xl,tz1 ;beide Bits gesetzt sind (Zählerstand 3) eor tas,xl ;erhaltene Änderungen toggeln alten (gültigen) ;Tastenstatus and xl,tas ;nur (neu) gedrückte Tastenbits bleiben erhalten or tfl,xl ;und zugehörige Bits setzen (gelöscht wird nach ;Abarbeitung) ;in "tas" steht jetzt der gültige Tastenzustand, ;in "tfl" die Flags der neu gedrückten, noch nicht abgearbeiteten ;Tasten... ;xl ist jetzt wieder frei für weitere temporäre Zwecke in der ISR sbr flags,1<<hundertstel ;neue hundertstel Sekunde inc teiler ;Sekundenvorteiler hoch cpi teiler,teilfaktor ;Endwert erreicht? brne nixvollsek ;nein... sbr flags,1<<neusek ;ja, Flag setzen, clr teiler ;und Teiler löschen nixvollsek: cpi teiler,teilfaktor/2 ;Halbe Sekunde? brne nixhalbsek ;nein... sbr flags,1<<neuhalb ;ja, Flag setzen nixhalbsek: pop xl ;benutzte Register pop xh ;wiederherstellen out sreg,srsk ;SREG wiederherstellen reti ;fertig... Der Timer läuft dabei frei durch. Daher kann der ICP-Interrupt (hier nicht dargestellt) Timerwerte "fotografieren", ohne dass es Messfehler gibt. Die Arbeitsweise ist so: Bei erfolgreichem Vergleich (Compare-Match-Interrupt) wird NICHT der Timer auf einen definierten Startwert (z.B. Null) gesetzt, sondern der Vergleichswert wird um das gewünschte Intervall erhöht. Da man das 16-Bit-Register OCR1A(H/L) als einen Ringzähler sehen kann, braucht man sich nicht um evtl. Überträge zu kümmern. Bei jeder ISR wird einfach das Intervall hinzuaddiert. Im Gegensatz zur Manipulation des Timerwertes steht der Referenzwert (zählt also nicht hoch). Man hat daher genügend Zeit, den Wert zu ändern, ehe der nächste Vergleich zutreffen könnte. Es ist also relativ egal, ob der Int sofort aufgerufen wurde, oder ob erst noch eine (mehrere) andere ISR fertig abgearbeitet wird. Wichtig ist nur, dass die ISR es schafft, vor dem nächsten Vergleich den Vergleichswert zu ändern. Es ist also absolut nicht zeitkritisch. Allerdings setze ich kurze ISR ohne jegliche Warteschleifen als selbstverständlich voraus. Da viele 16-Bit-Timer mehrere Compare-Match-Ereignisse und das Input-Capture-Ereignis auslösen können, sollte man sich angewöhnen den Timer unbedingt frei durchlaufen zu lassen, denn nur dann lassen sich alle Ressourcen gleichzeitig nutzen. Für den Vergleich sind ja nicht die absoluten Werte von Timer und Referenz wichtig, sondern nur die relative Differenz. Es ist dem (einzelnen) Timer-Int daher egal, ob man den Timer oder die Referenz manipuliert. Allerdings nimmt es jeder Timer-Int übel, wenn ein anderer den Timerstand verfälscht. Also ist der Timerstand tabu und jeder Timer-Int darf nur seine Referenz manipulieren... ...
>Da man das >16-Bit-Register OCR1A(H/L) als einen Ringzähler sehen kann, braucht man >sich nicht um evtl. Überträge zu kümmern. Hallo HanneS, thanks a lot für Deine ausführliche Erklärung! Jetzt habe ich die "Philosophie" dieser Art des Timergebrauchs verstanden (clever, clever...), und die von Dir genannten Vorteile leuchten mir ein. Ich muß gestehen, daß mir der CTC-Mode jetzt geradezu als ein bischen primitiv erscheint. Das ist also der Grund, warum beim Timer1 (z. B. ATmega8) zwei Compare-Match-Einheiten Sinn machen. Ich denke, ich werde zukünftig von dieser Methode Gebrauch machen. Danke nochmals.
CTC ist einfach zu "teuer". Es geht auf Kosten der anderen Timer-Features. Manipulation am (flüchtigen, weglaufenden, sich ständig ändernden) Timerstand sind zusätzlich (zu "zu teuer") zu zeitkritisch und daher oft recht ungenau. Es bleibt also nur das freie Durchlaufen des Timers übrig. Neben den INT-auslösenden Timer-Features (mit eigener I/O-Registern) können auch die externen Interrupts in ihrer ISR den "aktuellen Timerstand" mit eigenen (im Register oder SRAM gehaltenen) Referenzwerten vergleichen. Dies ermöglicht sowas wie "Software-Input-Capture". Den Timerstand TCNT1(H/L) kann man als "Kirchturmuhr" betrachten, jeder richtet sich danach, aber niemand darf sie verstellen, um bequemer ablesen zu können... Bit- & Bytebruch... ...HanneS... P.S.: Diese Timernutzung ist nicht "meine Erfindung". Auch ich habe diese Betrachtungsweise (der Zusammenhänge) erst hier im Forum gelernt, da gab es mal einen humorigen Hinweis, den ich leider nicht wiederfinde...
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.