Hilfe bei Timer0 interrupt mit ATMEGA8

Hallo,

auf einem Arduino mit ATMEGA328 funktioniert folgender Code (in Anlehnung an Adafruit) einwandfrei; Im Prinzip wird jede Millisekunde eine ISR aufgerufen die für einen ersten Test einfach einen Pin toggelt.

boolean mark = 0;

void setup() 
{
  OCR0A = 0xAF;
  TIMSK0 |= _BV(OCIE0A);
  pinMode(13, OUTPUT);
}

SIGNAL(TIMER0_COMPA_vect)      // ISR
{
  digitalWrite(13,mark);
  mark =!mark;
}

void loop()
{
 delay (150);                  // Eine langsame main Loop
}

Auf dem ATMEGA8 (Arduino NG,...) kompiliert das aber nicht, dort fehlen offensichtlich die berteffenden Register.

Jetzt kommt meine Frage, wie bringt man so etwas am Mega8 zum laufen, prinzipiell hat der Prozessor ja bereits einen Timer0 Interrupt (z.B. für millis)?? Ich möchte einfach das jede ms zuverlässig bestimter Code ausgeführt wird - auch dann wenn es in der loop() etwas langsamer geht.

Danke, Christian

Wieso schaust du nicht ins Datenblatt? http://www.atmel.com/images/atmel-2486-8-bit-avr-microcontroller-atmega8_l_datasheet.pdf

Seite 72

Der Atmega8 hat keine TIMSKn Register für jeden Timer. Da gibt es ein gemeinsames TIMSK Register für alle Timer.

Wobei Timer0 da auch keine Compare Einheit hat! Also musst du mit dem Overflow Interrupt arbeiten. Das ist aber genau was auch die Arduino Software macht. Da läuft Timer0 mit Prescaler 64. Das heißt er läuft alle 64 * 256 Taktzyklen über. 64 * 256 * 62,5ns = 1,024ms

Eine Alternative wäre Timer1. Mit dem kann man mehr machen

Hallo,

ja, ich habe ins Datenblatt geschaut, das meinte ich mit "...dort fehlen offensichtlich die berteffenden Register." :)

Timer Overflow ist ja prinzipiell auch O.k. Nur sehe ich da Probleme mit der originalen Arduino ISR, also das z.B. die millis() nicht mehr richtig laufen...

Kann man irgendwie den Kompiler anweisen das er in der Arduino 1-ms-ISR noch ein paar Zeilen weiteren Code ausführt?

Christian

Kann man irgendwie den Kompiler anweisen das er in der Arduino 1-ms-ISR noch ein paar Zeilen weiteren Code ausführt?

Schau dir den Prä-Prozessor an. Da kannst du je nach Prozessor andere Dinge kompilieren. z.B.

#if defined(__AVR_ATmega8__)
...
#endif

Oder man fragt ab welche Register definiert sind. Auch per #if defined()

Die Timer0 Initalisierung wird in wiring.c in der init() Funktion unten gemacht. Demnach sollte das für den Atmega8 schon passen:

 // set timer 0 prescale factor to 64
#if defined(__AVR_ATmega128__)
 // CPU specific: different values for the ATmega128
 sbi(TCCR0, CS02);
#elif defined(TCCR0) && defined(CS01) && defined(CS00)
 // this combination is for the standard atmega8
 sbi(TCCR0, CS01);
 sbi(TCCR0, CS00);
#elif defined(TCCR0B) && defined(CS01) && defined(CS00)
 // this combination is for the standard 168/328/1280/2560
 sbi(TCCR0B, CS01);
 sbi(TCCR0B, CS00);
#elif defined(TCCR0A) && defined(CS01) && defined(CS00)
 // this combination is for the __AVR_ATmega645__ series
 sbi(TCCR0A, CS01);
 sbi(TCCR0A, CS00);
#else
 #error Timer 0 prescale factor 64 not set correctly
#endif


    // enable timer 0 overflow interrupt
#if defined(TIMSK) && defined(TOIE0)
    sbi(TIMSK, TOIE0);
#elif defined(TIMSK0) && defined(TOIE0)
    sbi(TIMSK0, TOIE0);
#else
    #error  Timer 0 overflow interrupt not set correctly
#endif

Da wird der Prescaler für den Atmega8 abgehandelt. Und es wird abgefragt ob es TIMSK gibt

Hallo,

hmm, ist ja alles gut und schön, nur etwa in der wiring.c etwas zu verändern / hinzufügen ist überhaupt kein eleganter Programmierstiel. Wenn dann sollte das aus den Sketch heraus gehen..

Gerade nebenbei bemerkt & nachgemessen: Da ist ja noch ein Problem, der Timer0 läuft ja nicht genau bei 1ms über sondern 1.024ms; die millis() werden anscheinend gelegentlich korrigiert (in einer Art und Weise die ich im Moment noch nicht ganz verstehe) :o

Christian