Timer2 Frage

beeblebrox:
Welche Modi gibt es eigentlich noch für die Timer.
PWM ok und dann gibt es ja noch diesen Zählermodus für externe Pinne.
Wenn ich diesen externen Mode richtig verstehe brauche ich dann um Zeiten zu bestimmen einen
zweiten Timer !?
Ulli

Die PWM-Modi kann man aber nicht nur zur Erzeugung von PWM-Signalen verwenden, die kann man z.B. auch für deinen jetzigen Zweck verwenden. Ein wesentlicher Unterschied zum CTC Mode ist das double-Buffering der Compare-Register.
Das man den Takt von extern vorgeben kann, geht grundsätzlich bei allen Modi. Man kann das zum Zählen von Ereignissen nutzen. Oder man hat einen Timertakt, der mit den internen Prescalern nicht einstellbar ist.

beeblebrox:
Gab es nicht auch einen Modus wo der Counter einfach zählt (mit OVs die man mitzählen muss)
und bei einem externen Interrupt stoppt so das man dann den Wert auslesen kann ?

Der Timer 1 hat ein Input-Capture Register. Bei dem entsprechenden Modus stoppt der Zähler bei einer Flanke am Eingang zwar nicht, aber der Zählwert zu dem Zeitpunkt wird in einem eigenen Register gespeichert, das man dann in Ruhe auslesen kann.

Und siehe da, die Compare Variante hat keine Sekundenverluste (sind ja nur Bruchteile von gewesen)
mehr :slight_smile:

Ulli

Der Timer 1 hat ein Input-Capture Register. Bei dem entsprechenden Modus stoppt der Zähler bei einer Flanke am Eingang zwar nicht, aber der Zählwert zu dem Zeitpunkt wird in einem eigenen Register gespeichert, das man dann in Ruhe auslesen kann.

Und der Timer 3 beim 1284 hat den auch. Ich wusste doch das ich mal damit rumgespielt hatte.

Ich hatte ein Beispiel von Nick Gammon gefunden wo er Signale am Timer1 zählt aber
zum Timen Timer2 nimmt. Das wäre dann doch mit Timer1 alleine auch gegangen, oder ?

Noch mal vielen Dank für die vielen Infos.
Ich werde noch ein wenig weiter mit den Timern spielen um ein besseres Gefühl
dafür zu bekommen was wofür am besten ist.

Erstaunlich finde ich es Trotzdem das der Atmega bei 16Mhz Takt bei einem Prelscale von
64 es nicht schafft zuverlässig einen einzigen Wert in ein Register zu schreiben.
Hätte ich jetzt nicht gedacht.

Zählt der bei einem Prescale von 1 eigentlich mit Taktfrequenz ?

Ulli

Hallo,

Ja, die OVF ISR hat 1000Hz und wenn man damit einen Pin Ausgang toggeln lässt hätte dieser nur noch 500Hz. So stimmt das schon. War gestern schon spät.

Erstaunlich finde ich es Trotzdem das der Atmega bei 16Mhz Takt bei einem Prelscale von
64 es nicht schafft zuverlässig einen einzigen Wert in ein Register zu schreiben.
Hätte ich jetzt nicht gedacht.

Wie kommst du darauf? Redest du noch von deinem millis Zähler?

Zählt der bei einem Prescaler von 1 eigentlich mit Taktfrequenz ?

ja, 1 heißt 1:1, keine Unterteilung am Takteingang.

Doc_Arduino:
Wie kommst du darauf? Redest du noch von deinem millis Zähler?

Ich bezog mich da auf Posting 20.

Ulli

beeblebrox:
Erstaunlich finde ich es Trotzdem das der Atmega bei 16Mhz Takt bei einem Prelscale von
64 es nicht schafft zuverlässig einen einzigen Wert in ein Register zu schreiben.
Hätte ich jetzt nicht gedacht.

Ich nehme mal an, Du meinst damit, dass das softwaremäßige Preload nicht zuverlässig funktioniert. Da scheint dir nicht klar zu sein, wie das mit den Interrupts wirklich funktioniert.
Natürlich kann der AtMega zuverlässig einen Wert in ein Register schreiben. Die Frage ist, was zwischen dem Overflow-Ereignis des Timers und deinem Befehl den Preload ins Timerregister zu schreiben alles passiert. Und das kann eine ganze Menge sein - speziell wenn während des Timer Overflows gerade eine andere ISR läuft. Da hast Du gar nicht in der Hand wieviel Zeit die braucht. Und solange muss deine ISR warten, bis sie drankommt und den einen Register-Schreibe-Befehl ausführen kann. Und auch deine ISR hat einen Overhead, den der C-Compiler erzeugt, und von dem Du gar nichts mitbekommst.

Nee, mir ist schon klar das andere Interrupts meine - gewollte - Ausführung verzögern können.

Aber ich glaube ich verstehe jetzt was passiert. Overflow kommt aber bis ich endlich "drannkomme"
hat der schon wieder 2 - 3 Incremente gemacht bis ich meinen Wert schreibe. Und dann
kommt der nächste Overflow-Int genau diese 2 - 3 (oder wahrscheinlich nur ein) Increment
(Tick) zu spät.

Ich habe jetzt mal den unsinniger weise als uint32_t deklarierten Counter auf uint16 geändert.
Und siehe. Auch die Compareversion lief noch einen Hauch zu langsam (obwohl ich das jetzt wieder nicht verstehe). Jetzt nach einer Stunde noch keine Abweichung und die zum Vergleich noch mitlaufende auf Timer 1 mit Overflow ist auch 'ne Ecke besser geworden. Welche Berechtigung hat der Overflow eigentlich dann noch ?
Ich denke alles was ich damit machen kann kann ich mit dem Compare auch. Oder irrt der
Dichter hier ?

Ulli.

beeblebrox:
Aber ich glaube ich verstehe jetzt was passiert. Overflow kommt aber bis ich endlich "drannkomme"
hat der schon wieder 2 - 3 Incremente gemacht bis ich meinen Wert schreibe. Und dann
kommt der nächste Overflow-Int genau diese 2 - 3 (oder wahrscheinlich nur ein) Increment
(Tick) zu spät.

Genau so ist das.
Edit: Was man evtl. noch machen könnte: den Preload-Wert nicht einfach in das Timer-Register schreiben, sondern auf den aktuellen Timerwert draufaddieren. Dann müssten diese bereits ausgeführten Tics berücksichtigt werden, und das ganze genauer werden.

beeblebrox:
Welche Berechtigung hat der Overflow eigentlich dann noch ?
Ich denke alles was ich damit machen kann kann ich mit dem Compare auch. Oder irrt der
Dichter hier ?

Hier irrt der Dichter ;).
In deinem speziellen Fall und den verwendeten Modi macht der CompareA dasselbe wie der Overflow. Das ist aber im Allgemeinen nicht so. Der Overflow bedeutet immer, dass der Timer seinen Endwert erreicht hat, und wieder bei 0 anfängt. Beim CompareA kann das sein, muss aber nicht. Der Compare IRQ kommt, wenn der Zähler den gleichen Wert hat, wie das Compareregister. Es ist aber keineswegs immer der Fall, dass der Zähler dann wieder bei 0 anfängt. Es kann durchaus sein, dass der Zähler einfach weiterläuft, und dann bei 0xFF überläuft ( und dann einen OVF-IRQ erzeugt ). Ausserdem gibt es auch je einen eigenen Compare IRQ für OCRA und OCRB. Da kann man allerhand wilde Dinge mit anstellen. Im Prinzip könnte man bei einem einzigen Zählerdurchlauf 3 verschiedene Interrupts zu unterschiedlichen Zeiten erzeugen ( Gegebenenfalls - je nach Modus - sogar noch mehr, wenn man die OCR-Register während des Timerdurchlaufs verändert ). Der OCRB beeinflusst das Überlaufverhalten des Timers übrigends nie.

Also wenn ich compare Werte für a und b einstelle dann kriege ich den B-Interrupt nur
wenn der Comparewert kleiner als der für a ist. Bei größer kommt er ja nie vorbei
weil a den Counter wieder auf Null stellt ?
Zumindest verhält sich mein Testprogramm gerade so. D.h. der Interrupt für
B tickt aber letztendlich nicht schneller als der für A weil ja an vorgibt wann auf 0
gesetzt wird !?
Ich sehe in dem Programm gleichlaufenden Zähler für B und A.

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <Arduino.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/atomic.h>

#define I2C_ADDRESS 0x20
// LiquidCrystal_I2C lcd(I2C_ADDRESS, 2, 1, 0, 4, 5, 6, 7,3,POSITIVE); // Neuer Adapter
LiquidCrystal_I2C lcd(I2C_ADDRESS, 4, 5, 6, 0, 1, 2, 3, 7, NEGATIVE);

volatile uint32_t intCnt1 = 0;
volatile uint32_t intCnt2 = 0;
volatile uint32_t intCntB = 0;
        uint32_t oldTime1 = 0;

void setup()
{
  Serial.begin(9600);
  lcd.begin(16,2);
  lcd.print("TTEST 1");
  pinMode(7,OUTPUT); 
  digitalWrite(7,LOW);
  cli();
  
  TCCR2A = 0; // RESET TIMER 2 
  TCCR2B = 0;

  // Timer 2 - gives us our 1 ms counting interval
  // 16 MHz clock (62.5 ns per tick) - prescaled by 128
  //  counter increments every 8 µs. 
  // So we count 125 of them, giving exactly 1000 µs (1 ms)

  TCCR2A = bit (WGM21) ;   // CTC mode
  OCR2A  = 24; 
  OCR2B  = 12;
  
  TCCR2B = bit(CS22);          // Prescaler 64
  // TCCR2B = bit(CS21) | bit(CS20); // Prescaler 32
  // TCCR2B = bit(CS21);          // Prescaler  8
  // TCCR2B =  bit (CS20) | bit (CS22) ;  // prescaler of 128
 
  // Overflow Interrupt erlauben

  // TIMSK2= bit(TOIE2);

  // Timer 2 - interrupt on match (ie. every 1 ms)
  
  TIMSK2 = bit (OCIE2A) | bit(OCIE2B);   // enable Timer2 Interrupt A und B
  TCNT2 = 0; // In diesem Modus von null aufwärtz !
  
  // TCNT2 = 231; // Fuer Prescaler 64
  // TCNT2 = 206; // Fuer Prescaler 32
  // TCNT2 = 56;
  
  // Nochmal für Timer 1
 
 
  TCCR1A = 0; // RESET TIMER 1
  TCCR1B = 0;

  TCCR1B = bit(CS11) | bit(CS10);          // Prescaler 64
  // TCCR2B = bit(CS21) | bit(CS20); // Prescaler 32
  // TCCR2B = bit(CS21);          // Prescaler  8

  // Overflow Interrupt erlauben

  TIMSK1= bit(TOIE1);

  TCNT1 = 65511; // Fuer Prescaler 64
  // TCNT2 = 206; // Fuer Prescaler 32
  // TCNT2 = 56;
  
  sei();
  oldTime1 = millis();
}


// ISR (TIMER2_OVF_vect)
ISR (TIMER2_COMPA_vect) // Jetz den COMPARE Vector !!
{
   intCnt2++;
}


ISR (TIMER2_COMPB_vect) // Jetz den COMPARE Vector !!
{
  intCntB++;
}


//------------------------------------------------------------------

ISR (TIMER1_OVF_vect)
{
  TCNT1 = 65511; // Fuer Prescaler 64
  // TCNT2 = 206; // Fuer Prescaler 32
  // TCNT2 = 56;
 
  intCnt1++;
}


uint32_t secs0    = 0;
uint32_t oldSecs0 = 0;
uint32_t secs1    = 0;
uint32_t oldSecs1 = 0;
uint32_t secs2    = 0;
uint32_t oldSecs2 = 0;

uint8_t  Buffer[16];

uint32_t oldCnt1  = 0;
uint32_t oldCnt2  = 0;
uint32_t oldCntB  = 0;
uint32_t var;

void loop()
{
  if ((millis() - oldTime1) >= 1000)
  {
    oldTime1 = oldTime1 + 1000;
    secs0++;
  }  
  if (secs0 != oldSecs0)
  {
    digitalWrite(7,!digitalRead(7));
    oldSecs0 = secs0;
    lcd.setCursor(8,0);
    sprintf((char *) Buffer,"T1:%04ld",secs0);
    lcd.print((char *) Buffer);
  }
  
  if (secs2 != oldSecs2)
  {
    oldSecs2 = secs2;
    lcd.setCursor(0,1);
    sprintf((char *) Buffer,"T2:%04ld",secs2);
    lcd.print((char *) Buffer);
  }
  
  if (secs1 != oldSecs1)
  {
    oldSecs1 = secs1;
    lcd.setCursor(8,1);
    sprintf((char *) Buffer,"T3:%04ld",secs1);
    lcd.print((char *) Buffer);
  }

  ATOMIC_BLOCK (ATOMIC_RESTORESTATE) {    // cli()+sei() mit SREG Sicherung
    var = intCnt2;
  }
  if ((var - oldCnt2) >= 10000) 
  {
    secs2++;
    oldCnt2 = oldCnt2 + 10000;
  }

  ATOMIC_BLOCK (ATOMIC_RESTORESTATE) {    // cli()+sei() mit SREG Sicherung
    var = intCnt1;
  }
 
  if ((var - oldCnt1) >= 10000) 
  {
    secs1++;
    oldCnt1 = oldCnt1 + 10000;
  }
  
    ATOMIC_BLOCK (ATOMIC_RESTORESTATE) {    // cli()+sei() mit SREG Sicherung
    var = intCntB;
  }

  if ((var - oldCntB) >= 10000)
  {
    oldCntB = oldCntB + 10000;
    lcd.setCursor(0,0);
    sprintf((char *) Buffer,"TB:%04ld",var / 10000);
    lcd.print((char *) Buffer);
  } 
}

Ulli

beeblebrox:
Also wenn ich compare Werte für a und b einstelle dann kriege ich den B-Interrupt nur
wenn der Comparewert kleiner als der für a ist. Bei größer kommt er ja nie vorbei
weil a den Counter wieder auf Null stellt ?

Ja, in den Modi 2,5 und 7 ist das so

beeblebrox:
D.h. der Interrupt für
B tickt aber letztendlich nicht schneller als der für A weil ja an vorgibt wann auf 0
gesetzt wird !?
Ich sehe in dem Programm gleichlaufenden Zähler für B und A.

Für deinen Zweck macht der Compare-Irq da auch keinen Sinn.
Das kann man z.B. verwenden um Servo-Impulse per Software zu erzeugen: beim Overflow (Compare a) schaltet man den Ausgang ein, beim Compare b wieder aus. Vorteil gegenüber HW-PWM: man kann auch mehrere Impulse erzeugen, indem man den OCRB im Zyklus 'weiterschiebt' und es geht jeder digitale Ausgang. Nachteil: Die Impulse sind nicht so exakt wie bei HW-PWM. (Wobei man dafür wegen der besseren Auflösung eher Timer 1 nimmt )

AVR gibt sich aber wirklich Mühe einen zu verwirren.
Um Timer2 in den Comparemode zu setzten wird :

TCCR2A = bit (WGM21) ;   // CTC mode

ausgeführt.
Für den Timer 1 muss man folgendens tun

TCCR1B = bit(WGM12) | bit(CS11) | bit(CS10);          // CTC mode und Prescaler 64

Ich hatte natürlich zuerst Codeschnipsel 1 benutzt um auch den Timer 1 in
den Comparemodus zu bringen. Ging natürlich nicht, oder besser gesagt
mit falscher Geschwindigkeit :-(.

Jetzt klappt es und mit den Infos von euch habe ich jetzt auch mal einen
Test gemacht in dem Timer 1 quasi in 2 Timings läuft mit Hilfe von COMPA und COMPB
und nachtriggern.
Klappt super.

Gibt es den nirgendwo eine vernünftige Übersicht der Timer und der Bits.
Ich muss mir jedesmal Brocken aus anderen Beispielen zusammen suchen.
Einfacher Transfer von den Erkenntnissen für Timer X auf Timer Y ist nur bedingt
tauglich.

Ulli

Hallo,

wenn man einmal raus hat welches Register wofür verantwortlich ist, dann ist das alles im nachhinein beherrschbar. Man muss nur eben erstmal die Ausdauer und Geduld haben sich einzuarbeiten. Die beste Übersicht über alles ist immer noch das Datenblatt zum µC. Dort steht wirklich alles drin. Die vielen Anleitungen im Netz sind laut meiner Auffassung eh nur voneinander kopiert und behandeln alle die gleichen Themen. Näher geht niemand drauf ein. Das kann nur der erste Einstieg sein. Alles weitere geht dann nur noch mit Fleiß und Ausdauer mit dem Datenblatt.

Hallo,

übrigens sind die Erkenntnisse schon von einen Timer auf den anderen übertragbar. Die arbeiten alle gleich. Bis auf paar generelle Unterschiede wie 8 oder 16Bit, 2 oder 3 Timerausgänge, andere Prescaler und solche Kleinigkeiten. Aber die Register- und Bitnamen sind alle vergleichbar. Vielleicht springst du auch zu sehr von einem zum anderen. Ich würde dir empfehlen. Suche dir einen Timer aus und gehe diesen komplett durch. Und wenn du irgendwelche Timereinstellungen postest, dann bitte komplett. Solche Einzeiler wie in #31 helfen da nicht weiter, weil aus dem Zusammenhang gerissen. Ich (wir?) können damit nicht erahnen was gemeint ist. Also ich sehe was du da einstellst, ich weiß aber nicht was es am Ende im Gesamten werden soll.

Timer2 ist ein 8 Bit Timer. Timer 1/3/4/5 sind 16 Bit Timer. Und haben auch sonst leicht andere Funktionen. Das geht aus dem Datenblatt deutlich hervor. Dort werden auch die Register und Modi erklärt.

Ok,
genug geraten.
Habe mir gerade mal das "Datenblatt" (241 Seiten) heruntergeladen und mache mich mal schlau.
Eventuell schreibe ich dann mal ein Tutorial.

Ich hatte jetzt in meinem Beispiel 4 Syncron laufenden Timer.
Der eine war auf mit einer Messung via millis und die drei anderen habe ich selber geschrieben.
2 Mit Timer 1 (ist eigentlich 2 mal der Selbe) und einen mit Timer 2.
Nach über 2 Stunden keine Abweichung.

Dann habe ich mal einen kleinen WS2811 Strip dran gehängt und alle 300ms den Stripe
farblich geändert. Wie man ja weiß blockiert die FAST_SPI Lib die Interrupts um ihr Timing
hinzukriegen.
Jetzt laufen die Time wieder auseinander. Der "millis" Timer gewinnt wieder Zeit.
Wie ist die millis-Messung gemacht das die gesperrten Interrupts der gar nicht oder doch
deutlich weniger weh tun ?

Ulli

Jetzt habe ich in der Version mit häufig gesperrten Interrupts mal eine Korrektur eingebaut.
Und zwar sehe ich normalerweise (freie Interrupts) das das TCNT1 Register in der
Interruptroutine schon wieder 1 oder 2 enthält. Ok der Zähler rennt ja weiter.

Habe ich die FAST-Led laufen kommen auch schon mal höhere Werte vor.
Diese Werte >2 summiere ich auf und immer wenn ich mehr als 24 gesammelt habe (das ist
der Comparewert für 0.1 Millisekunden) korrigiere ich meinen 1/10 Millisekundenzähler.
Das klappt wunderbar un der korrigierte Zähler läuft nach Stunden synchron mit dem "millis" counter.

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <Arduino.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/atomic.h>
#include <WS2812.h>

#define I2C_ADDRESS 0x27
LiquidCrystal_I2C lcd(I2C_ADDRESS, 2, 1, 0, 4, 5, 6, 7,3,POSITIVE); // Neuer Adapter
// LiquidCrystal_I2C lcd(I2C_ADDRESS, 4, 5, 6, 0, 1, 2, 3, 7, NEGATIVE);

volatile uint32_t intCnt1 = 0;
volatile uint32_t intCnt2 = 0;
volatile uint32_t intCntB = 0;
         uint32_t oldTime1 = 0;


#define NUM_LEDS 5
#define NUM_COLORS 7

struct cRGB Cols[NUM_COLORS] =
{
  {0x00,0x00,0x10},
  {0x00,0x10,0x00},
  {0x10,0x00,0x00},
  {0x10,0x10,0x00},
  {0x10,0x00,0x10},
  {0x00,0x10,0x10},
  {0x10,0x10,0x10},
};

WS2812 LED(NUM_LEDS);

cRGB rgb;


void setup()
{
  Serial.begin(9600);
  lcd.begin(16,2);
  lcd.print("TTEST 1");
  pinMode(7,OUTPUT); 
  digitalWrite(7,LOW);
  pinMode(13,OUTPUT); 
  digitalWrite(13,LOW);
  LED.setOutput(8); // Digital Pin 7

  cli();
  
  TCCR2A = 0; // RESET TIMER 2 
  TCCR2B = 0;
  TCCR2A = bit (WGM21) ;   // CTC mode
  OCR2A  = 24; 
  OCR2B  = 12;
  
  TCCR2B = bit(CS22);          // Prescaler 64
  // TCCR2B = bit(CS21) | bit(CS20); // Prescaler 32
  // TCCR2B = bit(CS21);          // Prescaler  8
  // TCCR2B =  bit (CS20) | bit (CS22) ;  // prescaler of 128
 
  // Overflow Interrupt erlauben

  // TIMSK2= bit(TOIE2);

  // Timer 2 - interrupt on match (ie. every 1 ms)
  
  TIMSK2 = bit (OCIE2A); // | bit(OCIE2B);   // enable Timer2 Interrupt
  TCNT2 = 0; // In diesem Modus von null aufwärtz !
  
  // TCNT2 = 231; // Fuer Prescaler 64
  // TCNT2 = 206; // Fuer Prescaler 32
  // TCNT2 = 56;
  
  // Nochmal für Timer 1
 
 
  TCCR1A = 0; // RESET TIMER 1
  TCCR1B = 0;


  // TCCR1A = bit (WGM11);
  TCCR1B = bit(WGM12) | bit(CS11) | bit(CS10);          // Prescaler 64
  // TCCR2B = bit(CS21) | bit(CS20); // Prescaler 32
  // TCCR2B = bit(CS21);          // Prescaler  8

  TCNT1 = 0;
  OCR1A  = 24;
  OCR1B  = 24;

  // Overflow Interrupt erlauben
  // TIMSK1= bit(TOIE1);
  TIMSK1 |= bit (OCIE1A) | bit(OCIE1B);
  

  
  // TCNT1 = 0; // Fuer Prescaler 64
  // TCNT2 = 206; // Fuer Prescaler 32
  // TCNT2 = 56;
  
  sei();
  oldTime1 = millis();
}


ISR (TIMER2_COMPA_vect) // Jetz den COMPARE Vector !!
{
   intCnt2++;
}

uint8_t val_t;
volatile uint16_t ovCnt;

ISR (TIMER1_COMPB_vect) // Jetz den COMPARE Vector !!
{
  intCntB++;
}


//------------------------------------------------------------------

ISR(TIMER1_COMPA_vect)
{
  val_t = TCNT1;
  if (val_t > 2)
  {
    ovCnt += (val_t - 2)  ;
  }

  while (ovCnt >= 24)
  {
    intCnt1++;
    ovCnt = ovCnt - 24;
  }
  intCnt1++;
}


uint32_t secs0    = 0;
uint32_t oldSecs0 = 0;
uint32_t secs1    = 0;
uint32_t oldSecs1 = 0;
uint32_t secs2    = 0;
uint32_t oldSecs2 = 0;

uint8_t  Buffer[16];

uint32_t oldCnt1  = 0;
uint32_t oldCnt2  = 0;
uint32_t oldCntB  = 0;
uint32_t var;
uint32_t ledTime = 0;
uint8_t  col     = 0;
uint8_t  run;

void loop()
{
  if ((millis() - oldTime1) >= 1000)
  {
    oldTime1 = oldTime1 + 1000;
    secs0++;
  }  
  if (secs0 != oldSecs0)
  {
    digitalWrite( 7,!digitalRead( 7));
    oldSecs0 = secs0;
    lcd.setCursor(8,0);
    sprintf((char *) Buffer,"T1:%04ld",secs0);
    lcd.print((char *) Buffer);
  }
  
  if (secs2 != oldSecs2)
  {
    oldSecs2 = secs2;
    lcd.setCursor(0,1);
    sprintf((char *) Buffer,"T2:%04ld",secs2);
    lcd.print((char *) Buffer);
  }
  
  if (secs1 != oldSecs1)
  {
    oldSecs1 = secs1;
    lcd.setCursor(8,1);
    sprintf((char *) Buffer,"T3:%04ld",secs1);
    lcd.print((char *) Buffer);
  }

  ATOMIC_BLOCK (ATOMIC_RESTORESTATE) {    // cli()+sei() mit SREG Sicherung
    var = intCnt2;
  }
  if ((var - oldCnt2) >= 10000) 
  {
    secs2++;
    oldCnt2 = oldCnt2 + 10000;
  }

  ATOMIC_BLOCK (ATOMIC_RESTORESTATE) {    // cli()+sei() mit SREG Sicherung
    var = intCnt1;
  }
 
  if ((var - oldCnt1) >= 10000) 
  {
    secs1++;
    oldCnt1 = oldCnt1 + 10000;
  }
 
   ATOMIC_BLOCK (ATOMIC_RESTORESTATE) {    // cli()+sei() mit SREG Sicherung
    var = intCntB;
  }

  if ((var - oldCntB) >= 10000)
  {
    oldCntB = oldCntB + 10000;
    lcd.setCursor(0,0);
    sprintf((char *) Buffer,"TB:%04ld",var / 10000);
    lcd.print((char *) Buffer);
  } 
 
  // Hier mal ein wenig LED Gezappel mit gesperrten INTs

  if ((millis() - ledTime) >= 600)
  {
    ledTime = ledTime + 600;
    for (run = 0 ; run < NUM_LEDS ; run++)
    {
      LED.set_crgb_at(run,Cols[col]);
    }
    LED.sync();
    if (col == 6) col = 0; else col++;
  }
}

Ok das klappt.
Ich verstehe nur nicht warum.
TCNT1 hat einen höheren Wert wenn der Interrupt "zu spät" kommt.
Interrupts gehen ja wohl nicht verloren sondern werden ich denke in einem FlipFlop
gespeichert und kommen dann wenn sie wieder frei sind.
Der Zähler tickt aber doch unbeirrt weiter. D.h. der nächste "freie" Interrupt kommt doch
wieder "pünklich". Warum muss ich überhaupt korrigieren, respektive warum klappt das
mit meiner Korrektur überhaupt ?

Ich hoffe das war verständlich. Der Korrektur-Code steht im ISR(TIMER1_COMPA_vect).

Ulli

Nur noch einmal eine Info.
Ich habe heute einige "Pro Minis" mit Quartz bekommen.
Ich hätte ja gedacht das die Resonatoren nur Schwankungen erzeugen.
Aber in der Tat gehen die Pro Minis ohne Quartz nach knapp 5000 Sekunden
schon 2 Sekunden nach. Hätte ich jetzt nicht gedacht.

Ulli

Hallo,

grundsätzlich laufen Resonatoren auch stabil. Sie laufen aber nie genau mit dem angegeben Takt und können je nach Umgebungstemperatur den Takt nicht stabil halten. Du kannst 2 gleiche Resonatoren haben die leicht verschieden takten unter gleichen Bedingungen. Das alles kümmert einen Quarz ganz wenig bis gar nicht.

Näheres dazu findest du hier, ist seit einer Weile frei erhältlich: Axtal

Doc_Arduino:
Näheres dazu findest du hier, ist seit einer Weile frei erhältlich: Axtal

Danke für den Link!