www.mikrocontroller.net

Forum: Compiler & IDEs mega8515 Timer-> Anfänger


Autor: JannikS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Ich habe jetzt mehrere Themen gelesen, jedoch ist keines auf meinem 
"Niveau" :/
Habe hier einen mega8515. Ich kann bislang lediglich mit dem Controler 
Ein- und Ausgänge und einfach Schleifen realisieren.

Ich würde gernen eine LED einfach nur blinken lassen im Takt von vll. 
einer Sek.
Kann mir wer detailliert erklären wie ich welches Timer register zu 
setzten habe? Darüber würde ich mich wirklich sehr freuen.

Gruß
Jannik

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schreib doch schon mal die Source soweit hin, wie du kommst.

Und vergiss nicht anzugeben, mit welchem Takt dein Atmega8515 in deiner 
Schaltung betrieben wird.

Autor: JannikS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Stefan,

Leider bin ich noch garnicht weit, da ich hier im gcc Tut einfach nicht 
durchblicke welche Register ich jetzt wirklich brauche. Quasi als 
Minimalkonfiguration!

Das einzige was ich jetzt einigermaßen verstehe, ist das ich nach jedem 
überlaufen von meinem 16Bit Register einen Interrupt hervorrufe, mit dem 
ich dann z.B. auch einen Ausgang setzten kann?!
Damit dies nicht zu schnell geschieht setzte ich z.B. TCCR1B = 
0b00000101 womit ich dann die F_CPU / 1024 teilen würde?! und mit sei() 
aktiviere ich meine Interrupts.

Das sind wie du merkst alles nur Bruchteile. Ich finde auch kein 
vernünftiges Beispiel wo es wirklich für Anfänger kommentiert ist.

Meine F_CPU ist bei 8 Mhz.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schreib ein Gerüst ohne das ganze Timer-Gedöns. Also ein einfaches 
Beispiel wie du es zum LED-Blinken brauchst. Du kannst auch schon deine 
Überlegungen zum Timer einfügen und mit Kommentar // Unfertig markieren.

Autor: Michael U. (amiga)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

was Du außer dem Tutorial immer zur Hand haben mußt, ist das komplette 
Datenblatt des jeweiligen AVR.

Dort dann eben nach 16 Bit Timer schauen, interessiere Dich für Dein 
Vorhaben vorrangig für die Betriebsart CTC (Clear Timer on Compare 
Match). Such die nötigen Register und Werte zusammen und versuch Dein 
Glück.

Das Programm kannst Du dann ja gern hier zur Diskussion und 
Fehlersuchhilfe hier reinstellen.

Gruß aus Berlin
Michael

Autor: JannikS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
#include <avr/io.h>
 
int main(void)
{
    DDRA = 0xff; //Ausgang LCD
  DDRB = 0xff; //Ausgang LED
  DDRC = 0x00; //Eingang DIP
  DDRD = 0x00; //Eingang DIP
  
    //Vermutlich hier die ungewisse Konfiguration der Timer-Register
  
  if (bit_is_set(PINC, 2)) {
    PORTB = 0xff; //PortB soll im Takt von etwa 1ner Sek blinken
  }
/*
Das wars zunächst. Das dient für mich erstmal nur zum reinen Verständnis

*/
    
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
JannikS wrote:
>
> Das einzige was ich jetzt einigermaßen verstehe, ist das ich nach jedem
> überlaufen von meinem 16Bit Register einen Interrupt hervorrufe, mit dem
> ich dann z.B. auch einen Ausgang setzten kann?!
> Damit dies nicht zu schnell geschieht setzte ich z.B. TCCR1B =
> 0b00000101 womit ich dann die F_CPU / 1024 teilen würde?! und mit sei()
> aktiviere ich meine Interrupts.
>
> Das sind wie du merkst alles nur Bruchteile.

Nö, das ist eigentlich schon fast alles, was es über Timer
in dieser Betriebsart zu sagen gibt.

Also: schnapp dir das Datenblatt. Such dir die Register
raus. Such dir die Bits in den Registern raus, die du setzen
musst und das wars dann auch schon fast.

> Meine F_CPU ist bei 8 Mhz.

OK. Ist schon mal was.
Zur Rumrechnerei mit dem Vorteiler kannst du dir ja mal das
hier reinziehen:

http://www.mikrocontroller.net/articles/AVR-Tutorial:_Timer

Tja. Und dann heist es: Einfach mal ein Programm schreiben.
Im Simulator durchprobieren, ob alle Registerwerte so gesetzt
sind, wie sie es sein sollen und ob deine ISR auch wirklich
aufgerufen wird.

Hilft alles nichts. Da musst du durch und ins kalte Wasser
springen. Aber keine Angst, das ist keine Raketentechnik
und im Grunde genommen ziemlich simpel.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
1/ Wieviele LEDs hast du an PORTB, weil du den kompletten Port 
veränderst? Es würde bei einer LED reichen, einen Pin vom Port zu 
verändern.

2/ Bedeutet PORTB = 0xff; die LEDs sind AN oder sind AUS?
Wenn es eine Schaltung nach STK500 Muster ist, wären mit dieser 
Anweisung die LED(s) alle AUS, weil diese aktiv-low beschaltet sind. 
Hier ist ein Kommentar im Sourcecode hilfreich.

3/ So könnte es aussehen:

//
// Demo Timer - JannikS
// uC     = Atmega8515
// F_CPU   = 8 MHz
// 

#include <avr/io.h>
#include <avr/interrupt.h>  // Hilfsdefintionen für Interrupts

int main(void)
{
  DDRB = 0xff; // Ausgang LED
  
  /**
  Datenblatt: http://www.atmel.com/dyn/resources/prod_documents/doc2512.pdf
  Ab Seite 80: Timer0

  Als am einfachsten verstehbarer Modus wird der Normal Mode (Seite 85) 
  von Timer0 gewählt:
  
  Ein 8-Bit Register zahlt von einem Anfangswert (Voreinstelltung 0) 
  bis 0xFF hoch. Wenn 0xFF erreicht ist, führt die nächste Erhöhung um 
  Eins zu einem Ergebnis von 0 (neuer Startwert zum Hochzählen) und zu 
  dem gewünschten Overflow-Interrupt
  
  Wie das Register TCCR0 (Timer/Counter Control Register) zu setzen ist, 
  um den Normal Mode einzustellen steht in Table 44 bei den Bits WGM01 
  und WGM02

  Eine weitere Einstellmöglichkeit ist, wie schnell hochgezählt werden
  soll. Das kann mit der vollen Taktrate F_CPU geschehen oder indem man
  die Taktrate durch einen Vorteiler (Prescaler) teilt. Die möglichen 
  Prescaler 1, 8, 64, 256, 1024 sind in Table 48 angegeben.
  
  Berechnung der Zeit bis zum Overflow bei verschiedenen Prescaler 
  Einstellungen
  
  Overflow = 1/F_CPU * 256
  
  Prescaler   Overflow
  1             32 us
  8            256 us
  64          2048 us
  256         8192 us
  1024       32768 us = 32,768 ms
  
  1s sind aber 1000 ms bzw. 1000000 us... 
  d.h. man braucht mehrere Overflow Interrupts in denen die nur Anzahl 
  der Interrupts gezählt wird und erst wenn die Anzahl mal die Dauer 
  die gewünschte Sekunde ergibt, wird die LED umgeschaltet.

  Wieviele Overflows braucht man für eine Sekunde bei verschiedenen 
  Prescaler Werten?
 
  Anzahl_Overflows = 1s / Zeit_für_einen_Overflow

  Prescaler   Overflow  Anzahl_Overflows    
  1             32 us    31250
  8            256 us    3906,25
  64          2048 us    488,28125
  256         8192 us    122,0703125
  1024       32768 us    30,517578125
  
  Bzw. die Gesamtrechnung ist:

  Anzahl_Overflows = 1 * F_CPU / 256

  Hier ist der Wert bei Prescaler 1 interessant: Die Anzahl der nötigen 
  ist Overflows ist nämlich eine ganze Zahl und das vereinfacht das 
  Programmieren!

  Dieser Wert wird im Timer0-Interrupt verwendet.
  */

  // 8-Bit TIMER0 Normal Mode, Prescaler 1
  TCCR0 = (0 << WGM01) | (0 << WGM00) 
          | (0 << CS02) | (0 << CS01) | (1 << CS00) ; 
  
  // Und den spezellen Timer0 Overflow Interrupt nicht nur konfigurieren, 
  // sondern auch zulassen (enablen) d.h. das Timer/Counter Interrupt Mask 
  // Register setzen (Seite 93)

  TIMSK = (1 << TOIE0);

  // Alle zugelassenen Interrupts einschalten
  sei();

  // Endlosschleife
  // 1. main() nie verlassen
  // 2. wird vom Timer0 Overflow Interrupt unterbrochen
  while(1)
  {
  }
}

/**
  Dies ist die Interruptroutine, die aufgerufen wird, 
  wenn der eingestellte Timer einen Überlauf hat.

  Der Name ist aus Datenblatt und aus avr/iom8515.h 
  ersichtlich. avr/iom8515.h ist die genaue Beschreibung
  deines µC und wird über avr/io.h eingebunden.

  Ein möglicher Interruptvektor steht dort im Abschnitt:

  // Timer/Counter0 Overflow
  #define TIMER0_OVF_vect      _VECTOR(7)

  Timer0 ist ein 8-Bit-Timer mit Overflow Modus 
*/

unsigned int Anzahl_Overflows;

ISR(TIMER0_OVF_vect)
{
  Anzahl_Overflows++;

  // Prüfen ob 1s voll
  if (Anzahl_Overflows == 1 * F_CPU / 256)
  {
    // LOW/HIGH mit Hilfe der XOR Bitmanipulation umschalten
    // das schaltet die LED(s) AN/AUS

    // In der Simulation auf die nächste Zeile einen Breakpoint setzen (F9)
    // und das Programm voll laufen lassen (F5). 
    // Dann mit Hilfe der Stop Watch im I/O View die Zeit bis zum 
    // nächsten Erreichen des Breakpoints messen.
    // (Nicht ungeduldig werden. Das dauert auf meinem Rechner ca. 65 s)
    PORTB ^= 0xFF; 

    // Zurücksetzen für nächste 1s Wartezeit
    Anzahl_Overflows = 0;
  }
}


Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 3/ So könnte es aussehen:

Der Code ist bei weitem nicht optimal, sondern soll nur eine erste Idee 
geben (die Scheu vor Interrupts nehmen).

Die Nachteile sind u.a. das grobe Missverhältnis von Arbeitszeit in dem 
Hauptprogramm (zu wenig, hier stört es zum Glück nicht) zur Arbeitszeit 
in der Interruptroutine (zu viel). Sowie die Platzverschwendung mit der 
Hilfsvariable Anzahl_Overflows. Beides kann man geschickter (aber 
vielleicht weniger einsichtig) machen.

Autor: JannikS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wow, vielen Dank Stefan für diese ausführliche Erklärung.
Ich werde mich dann mal im detail damit beschäftigen!

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.