mikrocontroller.net

Forum: Compiler & IDEs Port alle 200ms ein-/ausschalten


Autor: C. Schönauer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen!

Ich versuche nun schon seit etwa 3 Stunden den Timer1 meines ATtiny45 (@ 
1Mhz) dazu zu bringen alle 200ms PB0 ein-/auszuschalten. 
Compiler-Fehermeldungen habe ich keine.

#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>

volatile uint8_t i=0;

ISR(TIMER1_OVF_vect) {
  i++;
  if(i>200){
  i=0;
  PORTB ^= (1<<PB0);
  }
}

int main() {
DDRB |= (1<<PB0);

TCCR1 = (1<<CS13)|(1<<CS11)|(1<<CS10);
TIMSK |= (1<<TOIE1);

sei();

while(1);
return 0;
}

Da mein Controller bei 1Mhz werkelt müsste doch ein Prescaler von 1024 
etwa alle 1ms den Interrupt ausführen? Was hab ich faksch gemacht?

Grüsse C. Schönauer

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
C. Schönauer schrieb:

> Da mein Controller bei 1Mhz werkelt müsste doch ein Prescaler von 1024
> etwa alle 1ms den Interrupt ausführen? Was hab ich faksch gemacht?

Rechne nochmal nach. Ich komme auf 13421,7728 Sekunden statt 200ms. Ich 
denke du hast nicht berücksichtigt, dass Timer1 16-Bit breit ist und der 
Interrupt beim Overflow kommt.

> Ich versuche nun schon seit etwa 3 Stunden

Mit etwas mehr Geduld (~3,7h) hätte das Programm etwas ausgegeben!

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Da mein Controller bei 1Mhz werkelt müsste doch ein Prescaler von 1024
>etwa alle 1ms den Interrupt ausführen?

Timer1 läuft mit 1 MHz/1024 = 976 Hz, d. h. er zählt alle 1.024 ms eins 
rauf. Da er das 256 mal machen muss bis es zu einem Overflow Interrupt 
kommt, tritt dieser Interrupt alle 0.262144 s auf. Wegen des 
Softwareteilers (Variable i) von 200 wird Dein Pin alle 52.4288 s seinen 
Zustand ändern.

Fazit: Du bist nur zu ungeduldig.

>Was hab ich faksch gemacht?

Das "k"! :-D Außerdem hast Du auf gut Glück herumprobiert anstatt im 
Datenblatt nachzulesen, wie die Timer funktionieren.

@Stefan: Timer1 beim ATtiny45 ist nur 8 Bit breit.

Autor: gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
am besten gleich CTC modus
und einen timercompareinterrupt bei 200ms  :)

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und das Nonplusultra: CTC-Modus mit Compare-Interrupt bei 10 ms und 
diese 10 ms softwaremäßig auf 200 ms runterteilen. Ein Basistakt von 10 
ms ist noch für viele andere Sachen prima geeignet, z. B. Tasten 
entprellen (200 ms wäre dafür schon zu langsam).

Autor: C. Schönauer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

vielen Dank für die vielen Antworten!
Hab jetzt probiert einen 10ms Interrupt zu programmieren. (Prescaler=64)
OCR1A = 10/(1/1000000*64*1000) => 156

Das gibt mir doch dann folgenden Code:
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>

volatile uint8_t i=0;

ISR(TIMER1_OVF_vect) {
  i++;
  if(i>20){
  i=0;
  PORTB ^= (1<<PB0);
  }
}

int main() {
DDRB |= (1<<PB0);

TCCR1 = (1<<CS12)|(1<<CS11)|(1<<CS10);
OCR1A = 156;
TIMSK |= (1<<OCIE1A);

sei();

while(1);
return 0;
}

Ist das so korrekt?

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
C. Schönauer schrieb:

> Ist das so korrekt?

Nein

== 1 ==
Lies nochmals im Handbuch über den CTC-Mode nach
-- Das CTC-Flag in TCCR1 muss gesetzt werden
-- Der CTC-Wert steht in OCR1C
OCR1A resp. OCR1B kann also immer 0 sein

== 2 ==
Du verwendest den falschen IRQ-Vektor.

== 3 ==
Anstatt der magischen Zahl 156 tut's auch die Rechnung
#define F_CPU 1000000
#define IRQS_PER_SECOND 100
#define PRESCALE 64

OCR1C = (uint32_t) F_CPU / IRQS_PER_SECOND / PRESCALE -1;

Beachte, daß F_CPU modulo (IRQS_PER_SECOND*PRESCALE) nicht 0 ist, d.h. 
die anvisierte Frequenz wird nicht exakt getroffen.

Johann

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Ist das so korrekt?

Ich würde zum Testen in den i-Teiler einfach noch einen weiteren 
Software-Teiler schalten, der durch 5 teilt. Dann Proggi laufen lassen 
und gucken ob ne LED an dem Pin brav mit 1 Hz blinkt (genaugenommen 
ändert sie ihren Zustand jede Sekunde, blinkt also mit der Frequenz 0.5 
Hz). Alternativ: Großer Teilfaktor und mit der Stoppuhr messen.

Dein Interrupt-Intervall ist übrigens nicht genau 10 ms, sondern 9.984 
ms.  Bei einer Uhrenanwendung würdest Du den Fehler schnell spüren. 
Leider lässt sich 10 ms bei 1 Mhz Systemclock mit einem 8-Bit-Timer 
schlecht erzeugen. Aber 8 ms ginge exakt, nämlich mit Prescaler 64 und 
OCR-Wert 125. Aus 8 ms kannst Du ja auch 200 ms problemlos ableiten.

Autor: gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
der richtige irq sollte dann gewählt werden ...

ISR(TIMER1_OVF_vect) {


stimmt dann nicht
es heißt dann

ISR(TIMER1_COMP_vect)

Autor: C. Schönauer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, ich glaube wir kommen dem Ziel näher ;)
Leider blinkt die LED immernoch nicht. Die oben erwähnten Punkte hab ich 
(hoffentlich richtig) korrigiert.
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>

#define IRQS_PER_SECOND 100
#define PRESCALER 64

volatile uint8_t i=0;

ISR(TIMER1_COMPA_vect) {
  i++;
  if(i>20){
  i=0;
  PORTB ^= (1<<PB0);
  }
}

int main() {
DDRB |= (1<<PB0);

TCCR1 = (1<<CTC1)|(1<<CS12)|(1<<CS11)|(1<<CS10);
OCR1A = 0;
OCR1C = (uint32_t)(F_CPU/IRQS_PER_SECOND/PRESCALER-1);
TIMSK |= (1<<OCIE1A);

sei();

while(1);
return 0;
}

* CTC-Flag ist gesetzt
* Prescaler 64 gewählt
* OCR1C berechnet (~156)
* Compare Interrupt aktiviert
* Interrupts allgemein aktiviert
* Auf TIMER1_COMPA_vect wird reagiert

Grüsse
C. Schönauer

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OCR1A = 0;
OCR1C = (uint32_t)(F_CPU/IRQS_PER_SECOND/PRESCALER-1);
> * OCR1C berechnet (~156)

Welche Überlegung steckt denn dahinter, den berechneten Compare-Wert in 
OCR1C zu schreiben?

Edit: Sehe gerade, dass das von Johann L. kommt. Keine Ahnung, was ihn 
da geritten hat.

Autor: C. Schönauer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zum CTC1-Bit steht im Datenblatt:

"When the CTC1 control bit is set (one), Timer/Counter1 is reset to $00 
in the CPU clock cycle
after a compare match with OCR1C register value. If the control bit is 
cleared, Timer/Counter1
continues counting and is unaffected by a compare match."

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also in meinem Datenblatt steht da OCR1A.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan Ernst schrieb:

> Welche Überlegung steckt denn dahinter, den berechneten Compare-Wert in
> OCR1C zu schreiben?
>
> Edit: Sehe gerade, dass das von Johann L. kommt. Keine Ahnung, was ihn
> da geritten hat.

Es ist die Überlegung, das Handbuch zu lesen (ATtiny45, pp. 92):
 12.3.1 TCCR1 – Timer/Counter1 Control Register
 Bit 7- CTC1 : Clear Timer/Counter on Compare Match
 When the CTC1 control bit is set (one), Timer/Counter1 is reset to $00
 in the CPU clock cycle after a compare match with OCR1C register value.
 If the control bit is cleared, Timer/Counter1 continues counting and is
 unaffected by a compare match.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie gesagt, in meinem Datenblatt (2586K–AVR–01/08) steht da OCR1 A.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das da?

http://atmel.com/dyn/resources/prod_documents/doc2586.pdf

Auch da steht OCR1C in 12.3.1, hab eben nochmal extra in die 
Onine-Version geschaut.

Der CTC-Reset geschieht bei == OCR1C.
Der IRQ-Trigger geschieht bei == OCR1A bzw. == OCR1B. Und da beim Reset 
Timer1 auf 0 gesetzt wird, kann man hier einfach OCR1A=0 nehmen.

Hab den Timer auch so am laufen, allerdings mit OCR1B.

Johann

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, ja, ich bin der Idiot hier. :-(

Ich hatte das hier offen:
13. 8-bit Timer/Counter1 in ATtiny15 Mode

@ C. Schönauer:
Dann musst du aber auch TIMER1_COMPC_vect nehmen.

Autor: C. Schönauer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab grad getestet:
Ob OCR1A = 156 und OCR1C = 156, nur OCR1C = 156 oder nur OCR1A = 156, 
macht keinen Unterschied...Muss also was anderes falsch sein.

Die Schaltung stimmt: Wenn ich den uC rausnehme und VCC mit PB0 verbinde 
leuchtet die LED.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan Ernst schrieb:

> @ C. Schönauer:
> Dann musst du aber auch TIMER1_COMPC_vect nehmen.

Ach, den gib es ja anscheinend gar nicht. Am besten halte ich mich aus 
diesem Thread einfach raus. ;-)

Autor: C. Schönauer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Stefan Ernst
TIMER1_COMPC_vect gibts leider nicht bzw. mein AVR-GCC kennt's nicht.

Laut der Header-Datei /usr/avr/include/avr/iotnx5.h gibts nur 
TIMER1_COMPA_vect (Makro auf "_VECTOR(3)")und TIMER1_COMPB_vect.

_VECTOR(3) würde wieder mit dem Datenblatt (zu TIMSK) übereinstimmen:

"OCIE1A: Timer/Counter1 Output Compare Interrupt Enable
[...] The corresponding interrupt at vector $003 is executed if a 
compare matchA occurs. The Compare Flag in Timer/Counter1 is set (one) 
in the Timer/Counter Interrupt Flag Register."

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
C. Schönauer schrieb:
> [...] Muss also was anderes falsch sein.

Möglicherweise hängts auch an den Fuses, zB ein aktivierter WDT der 
immer wieder zu einem Reset führt oder ein falsch eingestellter 
Prescaler per CLKPR.

Den Port kann man übrigens toggeln via
PINB |= (1 << PB0);

was gegenüber dem ^= den Vorteil hat daß es kürzer und vor allem atomar 
ist.

Johann

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ATtiny25/45/85 + Timer1 + CTC-Modus ist in der Tat ein Kapitel für sich.

Such mal über die Suchfunktion nach dem Thread

"ATtiny25, TimerCounter1, CTC-Mode: Bug?"

von 12/2008 und lies ihn genau durch. Da hatte jemand dieselben Probs.
Die schließlich gefundene Lösung steht auch drin.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PS: Dasselbe mit Timer0 ist übrigens ein Klacks.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Beitrag "ATtiny25, TimerCounter1, CTC-Mode: Bug?"

Da geht's allerdings um PWM-Betrieb, also ne was andere Baustelle.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich dachte, es läuft darauf hinaus, das Ding im PWM-Mode betreiben zu 
müssen, um das gewünschte CTC sozusagen als Nebeneffekt zu bekommen (d. 
h. die PWM wird zwar erzeugt, aber nicht auf einen Pin geschaltet).

Oder hab ich das falsch verstanden?

Autor: C. Schönauer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Problem konnte behoben werden in dem der Code anstatt auf einer 
Linux-Maschine auf einer Windows-Maschine mit AVR Studio kompiliert 
wurde. Vielleicht funktionierts auch unter Linux wenn ich die 
AVR-Studio-Compiler-Flags mal identisch übernehme.

Grüsse
C. Schönauer

PS: Sorry das ich den Thread nochmals aufrolle, dachte es sei gut wenn 
später jemand hierrauf zurück kommt

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.