Go Down

Topic: Timer2 Frage (Read 515 times) previous topic - next topic

MicroBahner

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

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 )
Gruß, Franz-Peter

beeblebrox

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

TCCR2A = bit (WGM21) ;   // CTC mode


ausgeführt.
Für den Timer 1 muss man folgendens tun
Code: [Select]

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

Doc_Arduino

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.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Doc_Arduino

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.

Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Serenifly

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.

beeblebrox

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

beeblebrox

#36
Apr 22, 2017, 12:17 am Last Edit: Apr 22, 2017, 12:28 am by beeblebrox
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.

Code: [Select]

#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

beeblebrox

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

Doc_Arduino

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: http://www.axtal.com/Deutsch/TechnInfo/Quarzkochbuch
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

uxomm

Näheres dazu findest du hier, ist seit einer Weile frei erhältlich: http://www.axtal.com/Deutsch/TechnInfo/Quarzkochbuch
Danke für den Link!
Always decouple electronic circuitry.

Go Up