Forum: Mikrocontroller und Digitale Elektronik 16 Bit Timer mit Atmega 1284p


von Peter (Gast)


Lesenswert?

Hallo Forum
versuche gerade einen 16 Bit Timer mit dem Atmega 1284p zu schreiben. 
Leider will die LED nicht leuchten.
Habe dazu das Stück Code im Programm:
1
#define F_CPU 16000000UL  // Angabe der Quarzfrequenz, wichtig für die Zeit
2
#include <avr/io.h>      // Einbindung Datei Ausgänge
3
#include <avr/interrupt.h>
4
5
void timer1_init()          // Timer 1 konfigurieren
6
  {
7
  TCCR1B |= (1<<WGM12)|(1<<CS11)|(1<<CS10);  // Einstellung CTC Modus, Prescaler 64
8
  TCNT1=0;             // Initialisiert Timer
9
  OCR1A=12499;          // 50ms = 20Hz
10
  TIMSK0|=(1<<OCIE1A);      // Interrupt erlauben
11
  }
12
13
ISR (TIMER1_COMPA_vect)    // ISR
14
  {
15
  PORTC ^= (1<<PC6);    // toggelt PC6
16
  tcount ++; 
17
  }
Wenn ich das richtig verstanden habe, arbeitet mein Prz mit 16MHz, teile 
es mit 64 runter und setze den Wert auf 12499. Damit erreiche ich einen 
Wert von 20 Hz. Mit tcount will ich einen anderen Wert zählen und 
auswerten.
Doch leider klappt es nicht. Kann ich auch 1 ms erreichen? Wie muss sich 
OCR1A verändern um eine höhere Frequen zu erreichen z.B. 124 für 2kHz?
LG Peter

: Verschoben durch Moderator
von STM Apprentice (Gast)


Lesenswert?

1
  sei();

gemacht?

von STM Apprentice (Gast)


Lesenswert?

Peter schrieb:
> TIMSK0|=(1<<OCIE1A);      // Interrupt erlauben

Zu Timer 1 gehört TIMSK1.

von Peter (Gast)


Lesenswert?

Habe es so geändert
1
void timer1_init()          // Timer 1 konfigurieren
2
  {
3
  TCCR1B |= (1<<WGM12)|(1<<CS11)|(1<<CS10);  // Einstellung CTC Modus, Prescaler 64
4
  TCNT1=0;             // Initialisiert Timer
5
  OCR1A=12499;          // 50ms = 20Hz
6
  TIMSK1|=(1<<OCIE1A);      // Interrupt erlauben
7
  sei();
8
  }

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Peter schrieb:
> Habe es so geändert

Und?  Besser jetzt?

>   TCCR1B |= (1<<WGM12)|(1<<CS11)|(1<<CS10);  // Einstellung CTC Modus,

Warum eigentlich "|="?  Du willst doch eh alles in diesem Register 
schreiben, also einfach "=".

>  OCR1A=12499;          // 50ms = 20Hz

Da du F_CPU obendrüber definierst, warum lässt du das nicht den Compiler 
ausrechnen?
1
OCR1A = (F_CPU / 64 /* prescaler */ / 20 /* Hz */) - 1;

Aber meiner Meinung nach ist das "- 1" dort nicht korrekt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Peter schrieb:
> Leider will die LED nicht leuchten.

Leuchtet sie denn (dauerhaft), wenn du den Port initial (vor dem Start 
des Timers) einmal toggelst?

: Bearbeitet durch Moderator
von Peter (Gast)


Lesenswert?

Sie leuchtet dauerhaft. 20 Hz noch zu schnell?

Jörg W. schrieb:
> Da du F_CPU obendrüber definierst, warum lässt du das nicht den Compiler
> ausrechnen?
> OCR1A = (F_CPU / 64 /* prescaler */ / 20 /* Hz */) - 1;
> Aber meiner Meinung nach ist das "- 1" dort nicht korrekt.

Ist die Zeile dann so?

OCR1A = (F_CPU/64/20-1);

Sorry, der Sinn von 20-1 ist mir nicht klar.

von STM Apprentice (Gast)


Lesenswert?

In der Timer-Initialisierung fehlt noch:
1
   TCCR1C   = (1<<FOC1A);     /*  Force Output Compare A   */

von STM Apprentice (Gast)


Lesenswert?

Jörg W. schrieb:
> Aber meiner Meinung nach ist das "- 1" dort nicht korrekt.

Um das +1 oder -1 braucht man sich hier nicht streiten wenn
sonst nichts funktioniert.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Peter schrieb:
> Sie leuchtet dauerhaft. 20 Hz noch zu schnell?

Nein, es sind ja auch 10 Hz.  Die Interruptrate ist 20 Hz, aber mit 
jedem Interrupt toggelst du die LED, sodass sie nur mit 10 Hz 
flimmert. Das sollte man schon gut als Flimmern wahrnehmen.

Wenn das immer noch nicht geht, müsstest du wohl mal mit einem 
vollständigen, compilierbaren Beispiel aufwarten.

>> Aber meiner Meinung nach ist das "- 1" dort nicht korrekt.
>
> Ist die Zeile dann so?
>
> OCR1A = (F_CPU/64/20-1);

Nein, gar kein "-1".  Der Timer zählt von 0 bis OCR-1.  Wenn er auf OCR 
weiterschaltet, wird er sofort auf 0 rückgesetzt, damit taucht der Wert 
OCR in TCNT nie sichtbar auf.

STM Apprentice schrieb:
> Um das +1 oder -1 braucht man sich hier nicht streiten wenn
> sonst nichts funktioniert.

Das ist richtig. Ein Fehler ist es trotzdem, daher war es mir die 
Anmerkung wert.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

STM Apprentice schrieb:
> In der Timer-Initialisierung fehlt noch:
>
>
1
>    TCCR1C   = (1<<FOC1A);     /*  Force Output Compare A   */
2
>

Nö, das würde nur einen ersten compare match erzwingen, statt dass man 
erst 50 ms warten muss.

von Klaus (Gast)


Lesenswert?

Entsprechenden Pin auf Ausgang gesetzt?

von Frank M. (ukw) (Moderator) Benutzerseite


Angehängte Dateien:

Lesenswert?

Peter schrieb:
> Ist die Zeile dann so?
>
> OCR1A = (F_CPU/64/20-1);

Jepp. Klammern sind hier überflüssig, also:
1
OCR1A = F_CPU / 64 / 20 - 1;

Nimm einfach einen Taschenrechner:
1
16000000 / 64 / 20 - 1 = 12499

> Sorry, der Sinn von 20-1 ist mir nicht klar.

Ist nicht 20 minus 1, sondern das Resultat der Division minus 1 wegen 
Punkt-vor-Strich-Rechnung.

Schaue Dir die Formel mal an in obigem Auszug aus dem Datenblatt und 
löse die Gleichung nach OCRnA auf. Dann weisst Du auch, wo die -1 
herkommt. Allerdings sehe ich in der Formel noch einen Faktor 2, den ich 
bei Dir vermisse.

: Bearbeitet durch Moderator
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Klaus schrieb:
> Entsprechenden Pin auf Ausgang gesetzt?

Da die LED immer an ist, sollte das wohl der Fall sein …

Wie geschrieben: ohne vollständigen, compilierbaren Beispielcode kommen 
wir nicht weiter.

von spess53 (Gast)


Lesenswert?

Hi

>In der Timer-Initialisierung fehlt noch:

>   TCCR1C   = (1<<FOC1A);     /*  Force Output Compare A   */

Habe ich bei keiner keiner meiner vielen CTC-Anwendung je benutzt. Was 
soll das machen (was FOCnx bewirkt ist mir bekannt)?

MfG Spess

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Frank M. schrieb:
> Schaue Dir die Formel mal an in obigem Auszug aus dem Datenblatt und
> löse die Gleichung nach OCRnA auf. Dann weisst Du auch, wo die -1
> herkommt.

Gut, das korrigiert meine oben geäußerte Meinung dann, die -1 muss 
bleiben.

> Allerdings sehe ich in der Formel noch einen Faktor 2, den ich
> bei Dir vermisse.

Das ist die Toggle-Frequenz, die sich ergibt. Die LED blinkt halt mit 10 
Hz, wenn die ISR mit 20 Hz getriggert wird.

Im Falle der obigen Formel ergibt sie sich durch das Setzen des "Toggle 
on compare match"-Bits, im Fall des TEs erfolgt das Toggeln explizit 
durch die XOR-Anweisung auf dem Portpin.

: Bearbeitet durch Moderator
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Jörg W. schrieb:
> Das ist die Toggle-Frequenz, die sich ergibt. Die LED blinkt halt mit 10
> Hz, wenn die ISR mit 20 Hz getriggert wird.

Jepp. Das sollte man auch mit bloßem Auge erkennen können.

von Reiner K. (reiner_k)


Lesenswert?

Wie sieht denn das gesamte Programm aus? Bzw. wie ist der Ausgabe PIN 
initialisiert.

Laut Datenblatt findet sich zu Port C:
Port C is an 8-bit bi-directional I/O port with internal pull-up 
resistors (selected for each bit). The Port C output buffers
have symmetrical drive characteristics with both high sink and source 
capability. As inputs, Port C pins that are
externally pulled low will source current if the pull-up resistors are 
activated. The Port C pins are tri-stated when a
reset condition becomes active, even if the clock is not running.

Demnach sollten die Pins von PORTC nach dem Einschalten im Tristate 
Zustand sein, d.h. wohl als INPUT und ohne Pullup Widerstand.

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.