www.mikrocontroller.net

Forum: Compiler & IDEs suche beispielcode für 16-Bit Timer (Mega 8)


Autor: kranker Jan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moinmoin,

Ich bin auf der suche nach einem möglichst vollständigen Beispielcode 
für einen 16-Bit-Timer im AtMega8.

Also konkret in main() den Timer vorbereiten und dann wie die 
Interruptroutine aussieht. Wie hält man Timer in der Interruptroutine 
wieder an, Wie weist man neuen Zählerwert zu und wie lässt man den dann 
weiterlaufen. Ich möchte zuerst nur eine LED in definierten Abständen 
blinken lassen oder einen Ton an einem Digitalport ausgeben, um die 
Verwendung erstmal besser zu verinnerlichen.


Jan

Autor: irgendwer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guck ins Datenblatt!

Autor: noch wer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
oder ins Tutorium!

Autor: kranker Jan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Im Tutorial steht aber leider kein brauchbarer Beispielcode :(

Jan

Autor: Karl heinz Buchegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da hat er recht :-)

Ist aber trivial. Wenn du den Rest verstanden hast, dann
sollte das kein Problem sein.


Aber was solls.
#define F_CPU 8000000UL

#include <stdio.h>
#include <avr\io.h>
#include <avr\interrupt.h>

ISR( TIMER0_OVF_vect )
{
  PORTB ^= 0xFF;
}

int main()
{
  DDRB = 0xFF;
  PORTB = 0x00;

  TCCR0 = ( 1 << CS01 ) | ( 1 << CS00 );
  TIMSK = ( 1 << TOIE0 ); 
  sei();

  while( 1 ) {
  }
}

Das mag jetzt vielleicht bei dir etwas schnell blinken.
Da musst du dann halt zusätzlich im Interrupt
noch etwas runterteilen.
#define F_CPU 8000000UL

#include <stdio.h>
#include <avr\io.h>
#include <avr\interrupt.h>

int Teiler;

ISR( TIMER0_OVF_vect )
{
  Teiler++;
  if( Teiler == 100 ) {
    Teiler = 0;
    PORTB ^= 0xFF;
  }
}

int main()
{
  DDRB = 0xFF;
  PORTB = 0x00;

  Teiler = 0;

  TCCR0 = ( 1 << CS01 ) | ( 1 << CS00 );
  TIMSK = ( 1 << TOIE0 ); 
  sei();

  while( 1 ) {
  }
}

  

Autor: Luhar (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
  Teiler++;
  if( Teiler >= 100 ) {

Das wäre dann perfekt :-)

Autor: kranker Jan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Karl Heinz,

Vielen Dank für den Code!

1. Leider ist der Code zum Realisieren von einer Melodie an einem Pieper 
über einen Digital-out noch nicht ganz vollständig, deshalb habe ich 
noch eine kleine Nachfrage.

2. Ist der von dir genannte Code nicht ein Beispielcode für den 8-Bit 
Counter oder sehe ich das falsch?

also erstmal zur Nachfrage:
Wie halte ich innerhalb der Serviceroutine den 16-Bit Counter an, weise 
einen neuen Zählerstand zu und lasse den dann weiterlaufen.

Des weiteren muss ich innerhalb der ISR (Interrupt Service Routine) 
zusätzlich die Interrupts deaktivieren, damit kein (wie nennt sich das 
nochmal) overflow stattfindet. (Also kein neuer Interrupt obwohl der 
alte noch nicht abgearbeitet ist.)

Autor: 1001. Rahul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Des weiteren muss ich innerhalb der ISR (Interrupt Service Routine)
>zusätzlich die Interrupts deaktivieren, damit kein (wie nennt sich das
>nochmal) overflow stattfindet. (Also kein neuer Interrupt obwohl der
>alte noch nicht abgearbeitet ist.)

Nein, das macht der AVR für dich.
Dafür gibt es keine Prioritäten zwischen den Interrupts, die dafür 
sorgen könnten, dass ein Interrupt mit höherer Priorität einen mit 
niedriegerer unterbrechen kann (vgl. 8051).

Autor: kranker Jan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ 1001. Rahul

Achso. Naja aber trotzdem muss man wissen, wie man in den 16-Bit-Timer 
innerhalb der 16-Bit-Timer-Interruptroutine eine neue Zählhöhe 
reinschreibt, um wie schon erwähnt z.B. eine Melodie an einem Digitalen 
Portpin auszugeben. Da liegt momentan mein Problem.

Außerdem halte ich es für Sinnvoll, dass dieser Beispielcode, wenn er 
fertig ist und eine Melodie (z.B. Alle meine Entchen) ausgeben kann auch 
in das Tutorial hier reinkommt weil das einfach Basics sind, die da 
stumpf fehlen, obwohl das Tutorial immer so hoch gelobt wird.

Autor: SiO2 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Achso. Naja aber trotzdem muss man wissen, wie man in den 16-Bit-Timer
>innerhalb der 16-Bit-Timer-Interruptroutine eine neue Zählhöhe
>reinschreibt,

So wie du es auch ausserhalb des int machst, vielleicht?

Autor: 1001. Rahul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Naja aber trotzdem muss man wissen

TCNT = neuer Wert; // und fertig.

Für sowas sollte man aber eher einen PWM-Mode benutzen...

Autor: kranker Jan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie sieht das mit den interrupts denn nun eigentlich aus...

Wenn sich dir CPU beispielsweise innerhalt von interrupt vom timer 
befindet, was passiert dann wenn ein Interrupt von einem Digitaleingang 
kommt? Garnicht? Wird der Interrupt komplett ignoriert? Oder wird er in 
eine "warteschleife" gesetzt? Ich habe nur erfahrungen mit einem 8051 
und da ist das offensichtlich komplett anders.

Autor: Rahul, der Trollige (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>da ist das offensichtlich komplett anders.
Da liegst du richtig.

Hier auf der Seite (oben links bei den Links) gibt es den Abschnitt 
"AVR", dort gibt es Tutorien, die sich mit der Einführung zum AVR 
befassen.
Das sollte eine Anlaufstelle für die sein, genauso wie der erste Teil 
des Datenblattes deines Controller.

Autor: kranker Jan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Tutorial ist mir bekannt. Aber ein Beispiel für die benutzung des 
16-Bit Timers gibt es da trotzdem nicht. 8-Bit ist kein Problem. Das 
steht da, aber 16-Bit ebend nicht und da der 16-Bit Timer nen ganzes 
Stück komplizierter ist, ist das Tutorial so wie es jetzt ist für den 
16-Bit Counter völlig unbrauchbar, weil das was bisher zum 16-Bit Timer 
im Tutorial steht deutlich ausführlicher im Datenblatt steht. Aber auch 
das was im Datenblatt steht ist noch kein brauchbares Beispiel. Was 
daher in so ein Tutorial sollte, damit es sich vom Datenblatt 
unterscheidet, ist ein vernünftiges Beispiel für den 16-Bit counter. Und 
genau das versuche ich momentan (leider bisher mit wenig Erfolg) zu 
schreiben.

Autor: Rahul, der Trollige (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>da der 16-Bit Timer nen ganzes Stück komplizierter ist

Wo das denn?

>Was daher in so ein Tutorial sollte, damit es sich vom Datenblatt
>unterscheidet, ist ein vernünftiges Beispiel für den 16-Bit counter.

Dann weisst du ja, was du demnächst machen wirst...

>Und genau das versuche ich momentan (leider bisher mit wenig Erfolg) zu
>schreiben.

Es gibt also schon Code.
Sowas postet man hier und lässt es dann von "uns" und anderen Experten 
zerpflücken bis man keine Lust mehr auf controllern oder dieses Forum 
hat ;-)

Autor: kranker Jan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Rahul

Okay. Dann sei hiermit mein bisheriger Code zur Diskussion freigegeben 
;)

#define F_CPU 8000000UL

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

//#include <util/delay.h>

// ab avr-libc Version 1.2.0 möglich und empfohlen:
#include <stdint.h>
 // veraltet: #include <inttypes.h>


ISR( TIMER1_OVF_vect )
{
  PORTD ^= 0xFF;
}


int main (void) {

  //Portkonfiguration

  DDRD  = 0b11111111; // Datenrichtung des Ports Bit im Register gesetzt
          //76543210  // (1) für Ausgang, Bit gelöscht
            // (0) für Eingang. Als Ausgang 0=GND 1=VCC

  PORTD = 0b11100000; // Ausgang der letzten 5 Bits wird auf Masse 
gezogen (LED's eingeschaltet)

  //16 Bit Timer
  // Die Bits: COM1a1 COM1a0 NA NA NA NA PWM11 PWM10
  TCCR1A = 0b00000000;
  //PWM11  und PWM10  = 0 => PWM-Betriebsart nicht aktiviert - Timer1 
arbeitet als normaler Timer/Zähler
  //COM1a1 und COM1a0 = 0 => OC1 wird nicht angesteuert




  while(1) {
    //Hier in Sleepmodus setzen so dass Interrupts aufwecken
  }

   /* wird nie erreicht */
  return 0;
}

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die AVRs besitzen einen CTC-Modus, bei dem das Nachladen des Timers mit 
einem Startwert entfällt. Der ist für solche Sachen wesentlich besser 
geeignet, als der Overflow...

Autor: Rahul, der Trollige (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und was ist mit TIMSK?
Ein SEI sehe ich auch nirgends...

Autor: Rahul, der Trollige (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und den Timer startest du auch nirgends...
Guck dir am besten mal die Registerbeschreibungen des Timer1 im 
Datenblatt an.

Autor: Rahul, der Trollige (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
TCCR1B...

Autor: Rahul, der Trollige (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Übrigens verhält sich der 16-Bit-Timer bei der Initialisierung (und dem 
Überlauf-Betrieb) meistens genauso wie ein 8-Bit-Timer...

Autor: Rahul, der Trollige (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>kranker Jan

Wenn es eine Grippe ist, solltest du die vielleicht lieber erst mal 
loswerden...

Autor: kranker Jan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was ist SEI ?

Aktuell siehts jetzt so aus:

ISR( TIMER1_OVF_vect )
{
  PORTD ^= 0xFF;
  //PORTD = ~PORTD;
}


int main (void) {

  //Portkonfiguration

  DDRD  = 0b11111111; // Datenrichtung des Ports Bit im Register gesetzt
          //76543210  // (1) für Ausgang, Bit gelöscht
            // (0) für Eingang. Als Ausgang 0=GND 1=VCC

  PORTD = 0b11100000; // Ausgang der letzten 5 Bits wird auf Masse 
gezogen (LED's eingeschaltet)


  //16 Bit Timer
  // Die Bits: COM1a1 COM1a0 NA NA NA NA PWM11 PWM10
  TCCR1A = 0b00000000;
  //PWM11  und PWM10  = 0 => PWM-Betriebsart nicht aktiviert - Timer1 
arbeitet als normaler Timer/Zähler
  //COM1a1 und COM1a0 = 0 => OC1 wird nicht angesteuert

  // Die Bits: ICNC1 ICES1 NA NA CTC1 CS12 CS11 CS10
  // CTC1 CS12 CS11
  // 0    0    0     angehalten
  // 0    0    1     CPU-Takt
  // 0    1    0     1/8
  // 0    1    1     1/64
  // 1    0    0     1/256
  // 1    0    1     1/1024
  TCCR1B = 0b00000011;


  // Die Bits: TOIE1 OCIE1A NA NA TICIE NA TOIE0 NA
  TIMSK = 0b10000000; //TOIE1 = 1 => Timer Overflow 1 Interrupt wird 
ausgelöst


  while(1) {
    //Hier in Sleepmodus setzen so dass Interrupts aufwecken
  }

   /* wird nie erreicht */
  return 0;
}


BTW: Wie postet man Quelltext so schön formatiert wie Heinz das gemacht 
hat?

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das heißt "sei()" und nicht "SEI". Bitte bitte bitte lies das 
Tutorial!!! Da steht wirklich alles drin!

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wie postet man Quelltext so schön formatiert wie Heinz das gemacht
> hat?
OK, das steht nicht im Tutorial. Das geht mit "eckige Klammer auf C 
eckige Klammer zu" und "eckige Klammer auf /C eckige Klammer zu"...

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: kranker Jan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Test
<c>
#define F_CPU 8000000UL

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

//#include <util/delay.h>

// ab avr-libc Version 1.2.0 möglich und empfohlen:
#include <stdint.h>
 // veraltet: #include <inttypes.h>


ISR( TIMER1_OVF_vect )
{
  //PORTD ^= 0xFF;
  PORTD = ~PORTD;
}


int main (void) {

  //Portkonfiguration

  DDRD  = 0b11111111; // Datenrichtung des Ports Bit im Register gesetzt
          //76543210  // (1) für Ausgang, Bit gelöscht
            // (0) für Eingang. Als Ausgang 0=GND 1=VCC

  PORTD = 0b11100000; // Ausgang der letzten 5 Bits wird auf Masse 
gezogen (LED's eingeschaltet)


  //16 Bit Timer
  // Die Bits: COM1a1 COM1a0 NA NA NA NA PWM11 PWM10
  TCCR1A = 0b00000000;
  //PWM11  und PWM10  = 0 => PWM-Betriebsart nicht aktiviert - Timer1 
arbeitet als normaler Timer/Zähler
  //COM1a1 und COM1a0 = 0 => OC1 wird nicht angesteuert

  // Die Bits: ICNC1 ICES1 NA NA CTC1 CS12 CS11 CS10
  // CTC1 CS12 CS11
  // 0    0    0     angehalten
  // 0    0    1     CPU-Takt
  // 0    1    0     1/8
  // 0    1    1     1/64
  // 1    0    0     1/256
  // 1    0    1     1/1024
  TCCR1B = 0b00000011;


  // Die Bits: TOIE1 OCIE1A NA NA TICIE NA TOIE0 NA
  TIMSK = 0b10000000; //TOIE1 = 1 => Timer Overflow 1 Interrupt wird 
ausgelöst

  sei();

  while(1) {
    //Hier in Sleepmodus setzen so dass Interrupts aufwecken
  }

   /* wird nie erreicht */
  return 0;
}
</c>

Autor: kranker Jan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
#define F_CPU 8000000UL

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

//#include <util/delay.h>

// ab avr-libc Version 1.2.0 möglich und empfohlen:
#include <stdint.h>
 // veraltet: #include <inttypes.h> 


ISR( TIMER1_OVF_vect )
{
  //PORTD ^= 0xFF;
  PORTD = ~PORTD;
}


int main (void) {            

  //Portkonfiguration
           
  DDRD  = 0b11111111; // Datenrichtung des Ports Bit im Register gesetzt 
          //76543210  // (1) für Ausgang, Bit gelöscht 
            // (0) für Eingang. Als Ausgang 0=GND 1=VCC

  PORTD = 0b11100000; // Ausgang der letzten 5 Bits wird auf Masse gezogen (LED's eingeschaltet)


  //16 Bit Timer
  // Die Bits: COM1a1 COM1a0 NA NA NA NA PWM11 PWM10
  TCCR1A = 0b00000000;
  //PWM11  und PWM10  = 0 => PWM-Betriebsart nicht aktiviert - Timer1 arbeitet als normaler Timer/Zähler
  //COM1a1 und COM1a0 = 0 => OC1 wird nicht angesteuert

  // Die Bits: ICNC1 ICES1 NA NA CTC1 CS12 CS11 CS10
  // CTC1 CS12 CS11
  // 0    0    0     angehalten
  // 0    0    1     CPU-Takt
  // 0    1    0     1/8
  // 0    1    1     1/64
  // 1    0    0     1/256
  // 1    0    1     1/1024
  TCCR1B = 0b00000011;


  // Die Bits: TOIE1 OCIE1A NA NA TICIE NA TOIE0 NA
  TIMSK = 0b10000000; //TOIE1 = 1 => Timer Overflow 1 Interrupt wird ausgelöst

  sei();

  while(1) {
    //Hier in Sleepmodus setzen so dass Interrupts aufwecken        
  }            
 
   /* wird nie erreicht */
  return 0;                
}

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum ziehst du dann nicht das unnütze Test-Posting zurück?  Du darfst
das nämlich (für deine Postings).  Außerdem hättest du es nach
Feststellung des Nicht-Funktionierens noch passend editieren können,
statt noch eins hinterher zu werfen.

Autor: kranker Jan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich weiß nicht wie man Posts löschen kann.

Autor: Philipp Burch (philipp_burch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Editieren und löschen geht nur nach Anmeldung.

Autor: Karl heinz Buchegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du willst also einen Melodiegenerator bauen. Sag das doch gleich.

Also: Für sowas würde ich 2 Timer benutzen.

Timer1, der 16 Bit Timer, wird im CTC Modus betrieben.
Seine Aufgabe ist es das Tonsignal zu erzeugen, indem ein
Pin getogeglt wird.
CTC: Clear Timer on Compare. Schau dir das unbedingt im
Datenblatt an! Das Prinzip ist Folgendes: Ein Timer zählt
ja durch bis er seinen Endstand erreicht hat. Dann kann er
einen Interrupt auslösen und fängt wieder bei 0 an. Beim
normalen Timerbetrieb ist der Endstand vorgegeben und er
Interrupt ist der 'Overflow-Interrupt'. Im CTC Modus kannst
du aber den gewünschten Endstand vorgeben und der Interrupt
ist auch ein anderer. Steht aber alles im Datenblatt.
Der Rest ist ein bioschen rumrechnerei: Welches muss der
Timer Endstand sein, damit sich am Output Pin die richtige
Frequenz ergibt.

Soweit zum ersten Timer.
Der zweite Timer ist dafür zuständig, dass die Endstände
für den Timer1 in der richgtigen Reihenfolge gesetzt werden.
Der läuft also durch und sorgt mit seinen Overflows für
das Basistiming aus dem dann letztendendes die Länge der
Achtel-, Viertel-, Halbe-, ... Noten und Pausen erzeugt
werden. Im Prinizp kannst du da die Vorlage von oben nehmen
und dich im Overflow Interrupt austoben. Einfach mitzählen
wieviele Overflows das jetzt waren. Die abzuspielende Note
gibt durch ihre Längenangabe vor, wieviele das sein müssen.
Bei erreichen dieser Anzahl, wird die nächste NOte geholt,
der Endstand für den Timer1 neu gesetzt und in einer globalen
Variablen vermerkt wieviele Overflows der Timer0 wieder abwarten
muss, bis die nächste Note drankommt.

Aber erst mal klein anfangen. Ich würde mal damit anfangen,
den Timer1 im CTC Modus zu betreiben und einen Ton hörbar
zu machen. Die Tonhöhe kann durchaus im Programm zunächst mal
ein fixer Wert wein, der inn das Compare-Register des Timer1
geschrieben wird. Alleine mit dem umprogrammieren dieses
Compare-Wertes kann man schon eine Menge Spass haben:
zb. In einer Schleife den Wert erhöhen und eine kurze Zeit
warten; oder andersrum; oder nach einer Wartezeit von vielleicht
500ms Zufallszahlen reinschreiben, oder ...

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.