mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik ATTiny2313 - Timerproblem


Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo liebes Forum.

Ich habe derzeit ein Problem mit einem ATTiny 2313.
Ich habe an den ATTiny extern an XTAL1 und XTAL2 einen Chrystal 
Oszillator 4,096 MHz gehängt.

Die Fusebits für den Chip habe ich so gesetzt :
CKSEL0 = 1
CKSEL1 = 0
CKSEL2 = 1
CKSEL3 = 1
SUT0 = 1
SUT1 = 1
CKOUT = 1
CKDIV = 1

Meine Initialisierung für den Timer0 sieht folgendermaßen aus:
  TIMSK |= (1<<TOIE0);// Timer/Counter0  Overflow Interrupt Enable
  TCCR0B |= (1<<CS02)|(1<<CS00);// Prescaler 1024
  sei();  // Global Interrupt Enable

wenn der Timer0 überläuft soll jeweils dies ausgeführt werden:
ISR (TIMER0_OVF_vect) {
  if (counter == 40) //entspricht 100HZ
  {
    if (counter2 == 100) //entspricht 1HZ
    {
      counter2 = 0;
      if(Zustand == 0)
      {
        PORTB &= ~(1<<Hour);
        Zustand = 1;
      }
      else
      {
        PORTB |= (1<<Hour);
        Zustand = 0;
      }
    }
    else counter2++;
  }
  else counter++;
}

jedoch entspricht die IF Abfrage von Counter2 nicht annähernd 1HZ.

Ist dort irgendetwas Falsch ?

oder an meiner Berechnung für 1 HZ:
4096000HZ / 1024 = 4000
erste If Schleife:  4000/40 = 100
zweite IF Schleife:  100/100 = 1

Ich sehe nirgends einen Fehler. Wäre nett, falls einer den Fehler 
findet.

MFG

Autor: Koko Lores (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
du hast den overflow übersehen!?

timer-takt ist clck/1024. timer 0 ist 10 bit? dann macht er mit dieser 
frequenz 1024 schritte -> overflow alle 3.9s

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Koko Lores wrote:
> du hast den overflow übersehen!?
>
> timer-takt ist clck/1024. timer 0 ist 10 bit? dann macht er mit dieser
> frequenz 1024 schritte -> overflow alle 3.9s

Ich kann zwar verstehen, dass Du auch mal helfen möchtest, aber Du 
solltest da doch vorher mal einen Blick ins Datenblatt des Tiny2313 
werfen. Timer0 und 10 Bit passt irgendwie nicht so recht zusammen...

-------

> Ich habe an den ATTiny extern an XTAL1 und XTAL2 einen Chrystal
> Oszillator 4,096 MHz gehängt.

Diese Info halte ich für falsch, denn ein Quarzoszillator 
(Chrystal-oscillator) braucht nur einen XTAL-Anschluss. Er wird 
Fusebit-mäßig als external clock angesehen. Wenn Du beide XTAL-Pins 
benutzt, dann hast Du vermutlich einen einfachen Quarz, der vom im 
Tiny2313 integrierten Oszillator zum Schwingen gebracht wird.

Aus dem Rest halte ich mich mangels C-Wissen 'raus, ich programmiere 
AVRs nur in ASM.

...

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe den Quarz wie in Figure12 auf Seite 26 des Datenblattes des 
ATTiny2313 angehängt.

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bis auf die falsche Annahme über die Beschaffenheit des Timers hat Koko 
Recht:
Allerdings hat der Timer 8 Bit und dementsprechend bekommst Du bei einem 
Prescaler von 1024 und f_CPU=4,096 MHz eine Overflow-Frequenz von etwas 
mehr als 15 Hz (MAX ist beim 8-Bit-Timer 255). Ein Overflow tritt also 
alle 64 ms auf. Das ist, um genaue Sekunden zu zählen, ein ziemlich 
ungünstiger Wert. Stelle besser den Prescaler auf 8. Dann bekommst Du 
alle 500 µs einen Overflow (also mit einer Frequenz von 2 kHz). Da lässt 
es sich wesentlich leichter zählen. Noch besser gehts i.d.R. mit dem 
CTC-Modus...

> Ich habe den Quarz wie in Figure12 auf Seite 26 des Datenblattes des
> ATTiny2313 angehängt.
Hannes' Beitrag bezog sich darauf, dass Du einen QuarzOSZILLATOR erwähnt 
hast. Und das ist was völlig anderes...

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> erste If Schleife: ...
Es gibt keine "if-Schleifen"! Eine "if"-Anweisung stellt eine 
Entscheidung oder Verzweigung dar, aber keine Schleife...

Autor: Koko Lores (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> ... auch mal helfen ...
Das war kein Schuss ins Blaue.. ;-)

Den Fehler sieht man in dieser Annahme:

>4096000HZ / 1024 = 4000
>erste If Schleife:  _4000_/40 = 100

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sehe ich das Falsch:

4,096 MHz mit einem Prescaler von 8 sind doch 512kHz oder ?

Autor: Koko Lores (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
korrekt

Autor: Joerg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Koko Lores (Gast):
"counter" scheint eine globale Variable zu sein, deren Typ allerdings 
nicht angegeben ist, wenn das mindestens ein "int" ist sollte dieser 
Teil funktionieren. Man sieht aber, dass es besser ist die Formel in den 
Code zu schreiben statt der "magic numbers".

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Gast:
Ich glaube, Dir fehlt ein wenig Grundverständnis zum Thema Timer. Der 
Timer besteht im Prinzip aus einem 8-Bit-Register und ein wenig Hardware 
rundrum. Wenn der Timer eine Taktflanke bekommt, dann wird der 
(Binär-)Wert des Registers (TCNT0 ist das beim AVR) um eins erhöht. Das 
geschieht nun bei jeder entsprechenden Taktflanke. Irgendwann erreicht 
der Wert im Register "11111111" oder in Dezimalschreibweise 255. Das ist 
der höchste mit 8 Bit darstellbare Wert. Wenn jetzt noch eine Taktflanke 
kommt, dann wird der Wert noch mal um eins erhöht. Da 256 aber in 8 Bit 
nicht mehr darstellbar ist, "springt" das Zählregister TCNT0 auf "0", 
d.h. der Timer fängt wieder von vorne an zu zählen. Das passiert bei 
jedem 256. Takt (beim 8-Bit-Timer). Dieses Umspringen vom Maximalwert 
auf 0 nennt man Overflow. Tritt ein Overflow auf, dann wird das 
dazugehörige Interrupt-Flag gesetzt und (wenn doe Interrupt-Bearbeitung 
freigegeben ist) der dazugehörige Interrupt Handler ausgeführt.

Der Takt, mit dem der Timer zählt, wird über einen Vorteiler (den 
Prescaler) aus dem Systemtakt erzeugt. Wenn als Taktquelle für den Timer 
der Prescaler-Ausgang "f_CPU/1024" ausgewählt ist, dann heißt das, dass 
bei jeder 1024. Taktflanke des Prozessortaktes (der bei Dir 4096000 Hz 
beträgt) das Timerregister TCNT0 um eins erhöht wird. Das bedeutet, der 
Timer selbst wird mit 4096000/1024 Hz = 4000 Hz getaktet.

Ein Overflow tritt nun bei jedem 256. Timertakt auf, also mit einer 
"Frequenz" von 4000 Hz/256 = 15,625 Hz. Das macht einen Overflow alle 64 
ms.

Jetzt klar?

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
counter und counter2 sind vom Typ uint8_t die in der Library inttypes.h 
deffiniert sind.

wieso kommt johnny m. denn mit einem Prescaler von 8 auf 500µS ?

wenn ich also einen Prescaler von 1024 wählen würde, müsste ich dann den 
16 Bit Timer nehmen ?

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
und

Autor: Koko Lores (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Joerg X, ich verstehe nicht.. Meinst Du mich?

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sehe ich das jetzt so richtig :

Der Vorteiler teilt mir meine FCPU = 4,096 MHz auf 512 kHz. Mit dieser 
Taktrate wird dann das Register des Timer inkrementiert. Sobald das 
Register denn Wert 255 erreicht hat, wird beim nächsten Takt das 
Register wieder auf 0 gesetzt und ein Interrupt ausgelöst ?

und daher komme ich dann auch auf die 2kHz :)

Autor: Joerg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Koko Lores:
 Sry, Hast recht!
 jetzt seh ich auch, dass da das eigentliche Zählen fehlt (noch mal 
durch TOP +1 teilen)

@Gast
 genau! (und 4000 passen nicht in ein "uint8_t"...)

Autor: Koko Lores (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> (und 4000 passen nicht in ein "uint8_t"...)
Das war wiederum nicht das Problem..

Dann hat Gast ja jetzt bald sein Sekunden-Blinken - Du kannst übrigens 
auch mit einer exklusiv-Oder Verknüpfung den Ausgangspin direkt 
Umschalten. Guck mal in der Artikelsammlung (links 'alle artikel') nach 
bitmanipulation.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich bins mal wieder :(

habe das Programm soweit jetzt geändert :
/* Library´s */
#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>

/* Unterprogramme */
void PORT_INIT (void);
void TIMER_INIT (void);

/* Define´s */
#define Hour PB2
#define Min   PB1
#define Sec  PB0

/* Variabeln */
uint8_t counter = 0;        // counter
uint8_t counter2 = 0;
uint8_t sec_count = 30;
uint8_t min_count = 30;
uint8_t hour_count = 30;
uint8_t Zustand = 0;

int main (void) {
  // Hauptprogramm
  PORT_INIT();
  TIMER_INIT();
  while(1);
  return 1;
}

void PORT_INIT (void) { 
  DDRB = (1<<Sec)|(1<<Min)|(1<<Hour);
  DDRD = 0x3F;
  PORTD = 0x3F;
  PORTB = 0xFF;
}

void TIMER_INIT (void) {
  TIMSK |= (1<<TOIE0);      // Timer/Counter0 Overflow Interrupt Enable
  TCCR0B |= (1<<CS01);      // Prescaler 8
  sei();              // Global Interrupt Enable
}

ISR (TIMER0_OVF_vect) {
  if (counter == 20) // entspricht 100 Hz
  {
    if (counter2 == 100)
    {
      counter2 = 0;
      if(Zustand == 0) 
      {
        PORTB &= ~(1<<Hour);
        Zustand = 1;
      }
      else 
      {
        PORTB |= (1<<Hour);
        Zustand = 0;
      }
    }
    else counter2++;
  }
  else counter++;
}

jedoch wird kein Sekunden Takt erzeugt, ist im Programm ein Fehler oder 
bei den (im ersten Beitrag) Einstellung der Fusebits ?

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde mich echt freuen, wenn einer mir hierbei weiterhelfen kann.

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich denke, Du müsstest, wenn counter 20 ist, diese Variable auch wieder 
auf Null setzen, wie Du es ja auch mit counter2 machst.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
autsch *Kopf => Wand ;)*
danke Johnny (mal wieder :) ).

nochma eine kleine Frage zur Logik, um einen genauen Sekunden Takt zu 
erzeugen, müsste ich doch eigentlich bei den beiden IF-Anweisungen die 
Werte die ich abfrage um 1 verringern. Also bei if(counter==19) und 
if(counter2==99) um einen genauen Sekunde Takt zu erzeugen ?

Da (so wie ich es denke) der Interrupt 20 mal aufgerufen werden muss um 
den Counter auf 20 hochzuzählen. Beim 21.ten Aufruf würde dann erst der 
nächste Zähler hochgezählt wird. Stimmt meine Logik?

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In Deinem Beispiel müsstest Du tatsächlich genaugenommen die Werte um 1 
reduzieren, da Du erst nach der Abfrage die Zähler inkrementierst und 
die Abfrage des inkrementierten Zählers erst im nächsten Zyklus 
geschieht. Ich persönlich bevorzuge die Pre-Increment-Methode, bei der 
der betreffende Zähler erst inkrementiert und dann abgefragt wird.
ISR (TIMER0_OVF_vect) 
{
  if (++counter == 20) // entspricht 100 Hz
  {
  counter = 0;
    if (++counter2 == 100)
    {
       counter2 = 0;
       //Code
    }
  }
}
So ginge es mit 20 und 100 und erspart die else-Anweisungen...

Wenn Du es so lässt wie oben, dann musst Du 19 und 99 nehmen, damit es 
genau stimmt.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke Johnny :)
Die Schreibweise in einer If-Anweisung war mir bisher nicht bekannt.
Aber ma lernt nie aus (wobei ich noch ne "Menge" zu lernen habe).

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.