Forum: Mikrocontroller und Digitale Elektronik Denkfehler ?


von chris (Gast)


Lesenswert?

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

von Michael Wilhelm (Gast)


Lesenswert?

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

von Läubi (Gast)


Lesenswert?

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.

von chris (Gast)


Lesenswert?

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

von Bolle (Gast)


Lesenswert?

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.

von Läubi (Gast)


Lesenswert?

Oh ja stimmt CTC Mode ist wichtig!
Den Fehler hatte ich auch mal ^^

von Bolle (Gast)


Lesenswert?

>Oh ja stimmt CTC Mode ist wichtig!

Mann, das laber ich doch hier die ganze Zeit g.

von Daniel (Gast)


Lesenswert?

Wie hast du die Zählvariable in Signal() initialisiert?
So weit ich weiß musst die ein unsigned volatile char sein.

Gruß Daniel

von dds5 (Gast)


Lesenswert?

@ 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

von chris (Gast)


Lesenswert?

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 ?

von Bolle (Gast)


Lesenswert?

>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.

von Hannes L. (hannes)


Lesenswert?

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.

...

von Bolle (Gast)


Lesenswert?

@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)

von Hannes L. (hannes)


Lesenswert?

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...

...

von Bolle (Gast)


Lesenswert?

>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.

von Hannes L. (hannes)


Lesenswert?

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
Noch kein Account? Hier anmelden.