[Attiny85] Wie messe ich eine genaue Sekunde?

Hallo zusammen,

ich hätte da nochmal eine Frage. Ich habe mich mühsam in Timer- und Interrupt-Programmierung reingefuchst und behaupte jetzt zu verstehen, was da passiert. Ich treibe den ganzen Aufwand, um präzise Sekunden messen zu können. Im Beispiel soll einfach nur eine LED im Sekundentakt blinken. Aber der Takt stimmt nicht - viel zu schnell!!!

Ich habe SO gerechnet:

Prozessortakt / Prescaler / Output Compare Registers = Interrupts pro Sekunde

mit Werten gefüllt:

1.000.000 / 8 / 125 = 1000 Interrupts pro Sekunde

Da nur geschaltet werden soll, wenn der counter == 1000 ist, müsste eigentlich nur einmal pro Sekunde umgeschaltet werden.

Hier mein Minimalbeispiel:

/*
 * Dies ist ein kommentiertes Minimalbeispiel für einen
 * Timer an einem Attiny85, der eine LED blinken lässt.
 * Der uC ist mit 1MHz getaktet.
 */
#include <avr/io.h>
#include <avr/interrupt.h>

volatile int counter;

void setup() {
  /*
   * Port B Data Direction Register – DDRB
   * zuerst den output-Pin für eine LED festlegen (PB3):
   */
  DDRB |= (1 << PB3); 

  /* 
   *  CTC einschalten! Wenn die nächste Zeile 
   *  auskommentiert wird, zählt der Timer immer bis
   *  255 hoch und lässt sich natürlich dementsprechend 
   *  schwer auf genaue Zeiten einstellen. 
   */
  TCCR0A = (1 << WGM01); 

  /*
   * Prescaler auswählen und Einschalten des Timers
   */
//  TCCR0B = (1 << CS00);               // KEIN Prescaler
  TCCR0B = (1 << CS01);               // Prescaler clk/8
//  TCCR0B = (1 << CS01) | (1 << CS00); // Prescaler clk/64
//  TCCR0B = (1 << CS02);               // Prescaler clk/256
//  TCCR0B = (1 << CS02) | (1 << CS00); // Prescaler clk/1024
  

  /*
   * Timer Interrupt Mask: 
   * Einschalten des Interrupts, so dass die Funktion ISR 
   * auch ausgeführt wird.
   */
  TIMSK = (1 << OCIE0A); 
  
   /*
   * Output Compare Registers: 
   * Speicher, in denen eine Zahl drinsteht. 
   * Erreicht der Timer (TCNT0) diese Zahl, 
   * findet der Overflow VOR 255 statt.
   */
  OCR0A = 125;
 
}


ISR (TIM0_COMPA_vect)
{

  counter++;   
  if (counter >= 1000)
  {
    /*
     * Port B Data Register: Verwaltet alle In- und Outputpins (PB0-PB5) 
     * Durch das XOR "^=" wird PB3 umgeschaltet (HIGH wenn LOW und umgekehrt) 
     */
    PORTB ^= (1 << PB3); 
    counter = 0;
  }
}


void loop(){
  // tu nichts!
}

DIESE Seite ist mir bekannt, da wird vorgeschlagen den Timer selbst (TCNT0) zu modifizieren anstatt eine Obergrenze mit OCR0A = 125 zu setzen. Das ist mir unverständlich und es führt vor allem auch nicht zur genauen Sekunde!

Wo liegt mein Fehler?

Danke und Gruß, kuahmelcher

P.S.: Verbesserungsvorschläge zum Minimalbeispiel sind immer willkommen!!

Ich bin zwar kein ATTiny Experte, vermisse aber die Einstellung des Timer-Modus. Je nach Modus wird TOP eine Konstante, OCRA oder ICR. Im falschen Modus läuft der Timer frei, und nur beim TCNT=OCRA wird ggf. ein Interrupt ausgelöst.

Ich bin kein Timer-Experte am ATtiny.
Hab deinen Sketch aber mal auf einen ATtiny85 gespielt und eine LED auf PB3 blinkt etwa im Sekundentakt.
Der ATiny läuft mit internem Takt, 1 MHz.
Mehr als "etwa im Sekundentakte" erwarte ich dabei auch gar nicht.

kuahmelcher:
Ich treibe den ganzen Aufwand, um präzise Sekunden messen zu können.

Nur als Hinweis: präzise Sekunden messen zu wollen ist mit dem internen Takt vergebene Liebesmüh' und selbst mit externem Quarz ist es auf längere Sicht (z.B. über mehrere Tage) wohl zu ungenau. Es braucht vor allem eine Tempereaturkompensation. So etwas kann zum Beispiel eine RTC (Real Time Clock) bieten.
DS3231 schafft das zum Beispiel ausreichend genau um pro Jahr nur wenige Sekunden falsch zu laufen.
Bei diesem Chip gibt es übrigens auch einen Pin mit Sekundentakt.

Edit:
PS: ich verwende diese ATtiny-Core

DrDiettrich:
Ich bin zwar kein ATTiny Experte, vermisse aber die Einstellung des Timer-Modus. Je nach Modus wird TOP eine Konstante, OCRA oder ICR. Im falschen Modus läuft der Timer frei, und nur beim TCNT=OCRA wird ggf. ein Interrupt ausgelöst.

Hallo, das "Problem" ist, dass der Timer-Sketch grundsätzlich funktioniert und alle Größen sich so verhalten, wie ich es erwarte (wenn ich OCR0A, counter oder Prescaler hochsetze dauerts länger). Nur geht der Timer halt (reproduzierbar und zuverlässig) nach dem Mond - das will ich doch gerade vermeiden! :slight_smile:

Ich dachte eigentlich, dass das Einschalten des CTC-Modus reicht (TCCR0A = (1 << WGM01)).

Danke und Gruß, kuahmelcher.

uxomm:
Mehr als "etwa im Sekundentakte" erwarte ich dabei auch gar nicht.

Hallo,

ja, also ich vergleiche das aber mit dem Blink-Sketch aus den Beispielen und da ist ein signifikanter Unterschied. Der müsste ja eigentlich "genauso ungenau" blinken. Ist aber viel genauer. Am Ende geht's auch gar nicht so sehr um die GEnauigkeit (das soll eine Eieruhr für die Küche werden), aber ich möchte es verstehen.

Ich habe außerdem den Betrieb mit einem externen Quarz eingeübt, das funzt mittlerweile auch gut. Es hakt aber noch irgendwo anders ...

Ich verwende auch den gleichen Core wie du! :slight_smile:

Danke und Gruß, kuahmelcher

Ok, für "Eierkochzeitmessung" könnte das wohl gerade noch genau genug sein :slight_smile: vor allem mit externem Quarz.

Nick Gammon (im englischsprachigen Teil dieses Forums kein Unbekannter), hat hier einiges zum Thema Timer zusammengefasst: Gammon Forum : Electronics : Microprocessors : Timers and counters

Und in "Reply #9" gibt es auch ein Beispiel für den ATtiny85.

IDE 1.8.6 mit SpenceKonde, ATtiny85 1 MHz intern:

Ungefähr 1 Sekunde high, eine low, 0,5 Hz, für mich sieht das gut aus.

Hallo,

vielleicht liegt hier genau das Problem. 0,5Hz ist kein Sekundentakt. Die Periodendauer bestimmt den Takt. Wenn der Timer einen Pin aller Sekunde umschaltet, dann hat man eine Periodendauer von 2s. Also 0,5Hz. Ist für mich kein Sekundentakt.

kuahmelcher:
Aber der Takt stimmt nicht - viel zu schnell!!!

Doc_Arduino:
Also 0,5Hz. Ist für mich kein Sekundentakt.

Für mich auch nicht, stimmt aber mit der Fehlerbeschreibung nicht überein, da 0,5 Hz langsamer ist.

Ich tippe zusätzlich auf die Fuses. Beim ATtiny auf 8 MHz, in der IDE auf 1 MHz eingestellt. Dann komme ich auf 4 Hz, was zu schnell wäre.

Hallo,

ja, ich denke auch das sein µC nicht mit 1MHz läuft. Denn wenn alles richtig wäre, würde sein Timer mit 500Hz laufen und er müßte den counter in der ISR auf 500 setzen. Habs auf meinem Mega2560 (16MHz) extra nochmal getestet. Am Rande sei noch erwähnt das OCR0A 124 sein muss und nicht 125.

/*
  Doc_Arduino - german Arduino Forum
  IDE 1.8.7
  Arduino Mega2560
  05.12.2018
  Democode - Timer 0 - CTC - Timer Mode 2  

  Pinouts  >>> http://www.pighixxx.net/pinoutspg/boards/
  Uno      >>> http://www.pighixxx.net/portfolio-items/uno/?portfolioID=314
  Mega2560 >>> http://www.pighixxx.net/portfolio-items/mega/?portfolioID=314
*/
       
const byte Takt_Pin_OC0B = 4;     // Output Pin

void setup()  {
  
  pinMode(Takt_Pin_OC0B, OUTPUT);
  set_Timer0();
}


void loop() {

}   // loop Ende


// ****** Funktionen ******* //
  
void set_Timer0()   //  CTC, Mode 2
{
  cli();         // Interrupts ausschalten
  TCCR0A = 0;    // Reset Register 
  TCCR0B = 0;    // 
  TIMSK0 = 0;    //
  TCNT0  = 0;    // 
  
  TIMSK0 = (1<<OCIE0A);   // Compare Match A
  OCR0A  = 124;           // TOP Wert bestimmt mit Prescaler den Takt, 8kHz
  TCCR0A = (1<<WGM01);    // CTC, Mode 2 
  TCCR0B = (1<<CS01);     // Prescaler 8 
  sei();       
}  

ISR (TIMER0_COMPA_vect)
{
  static unsigned int counter = 0;
  counter++;
  if (counter >= 8000) {
    PORTG ^= (1 << PG5);
    counter = 0;
  } 
}

Doc_Arduino:
ja, ich denke auch das sein µC nicht mit 1MHz läuft.

Richtig - hab's gecheckt. Ich hatte in der Arduino-IDE offensichtlich die 1 MHz eingestellt, aber nicht draufgebrannt. :blush: Ich habe jetzt 1, 8 und 16 MHz ausprobiert und alle funktionieren.

Nebenbei habe ich mir den dritten Attiny verfused, sodass er nix mehr sagt - aber da gibt's ja so eine "Defibrillator"-Anleitung für :slight_smile:

Doc_Arduino:
Am Rande sei noch erwähnt das OCR0A 124 sein muss und nicht 125.

Nur damit ich das verstehe: 124, weil der Interrupt eben erst beim "Overflow" ausgelöst wird und das ist dann eben der 125ste Takt?

Danke und Gruß, kuahmelcher!

agmue:
IDE 1.8.6 mit SpenceKonde, ATtiny85 1 MHz intern:

Hallo, hast richtig vermutet: Der Sketch stimmte, aber mein Bootloader war falsch. :slight_smile:

Verrätst du mir noch mit welchem Programm du dieses phantastische Diagramm erstellt hast? Ich will das auch können!

Danke und Gruß, kuahmelcher

Hallo,

die korrekten Formeln stehen im µC Datenblatt in den Timernkapiteln. Je nach Modus und was man ausrechnen möchte muss man ggf. eins abziehen oder addieren.

Weil ich den auch habe kann ich die zweite Frage ebenfalls beantworten. Viele nutzen den Saleae Nachbau des Dataloggers. Es sind Nachbauten auf dem Markt die Saleae selbst nicht mehr produziert und man nutzt deren Software eigentlich illegal.

Was die Genauigkeit angeht: man kann auch den internen Oszillator trimmen, je nach Anwendung kann das schon reichen. Für ne Eieruhr allemal!

Doc_Arduino:
... eigentlich illegal.

Für einen Hobby-Bastler ist das Preis-Leistungsverhältnis einfach genial. Die Softwareentwicklung kann man leider nicht unterstützen. Mein Gewissen habe ich daher mit einer Spende an Hilfsbedürftige beruhigt.

Um auch analoge Spannungen darstellen zu können, habe ich mir noch ein BitScope zugelegt.

Spannend und sehr hilfreich ist die Interpretation von Dateninhalten bekannter Protokolle wie UART, I2C oder CAN. Die Datenaufbereitung von Saleae gefällt mir besser.

Hallo,

das war nicht wie "verboten" gemeint. Ich nutzte das ja selbst. Im privaten Bereich interessiert das auch niemanden. Ich wollte es dennoch erwähnen nicht das jemand später überrascht ist. Da mir die Saleae Software von allen getesteten am Besten gefällt würde ich auch nichts anderes empfehlen. Ich hatte übrigens die größte Variante von denen original schon bei mir, allerdings wohl zu zeitig gekauft, die Software konnte nicht alles wie versprochen, deshalb zurückgeschickt. Seitdem bin ich mit Oszi und 16 Kanal Nachbau zufrieden.

Doc_Arduino:
Viele nutzen den Saleae Nachbau des Dataloggers.
Es sind Nachbauten auf dem Markt die Saleae selbst nicht mehr produziert und man nutzt deren Software eigentlich illegal.

Es gibt ja auch legale Open Source Alternativen z.B. sigrok.

Whandall:
Es gibt ja auch legale Open Source Alternativen z.B. sigrok.

Bei mir im Einsatz.
Reicht für meine Zwecke voll aus.

Die "echte" Software habe ich nie ausprobiert.
Weiß also nicht, welche besser ist.

Sigrok arbeitet übrigens auch mit dem LA Teil des Hantek6022BL zusammen.
Nicht komplett, aber kann 8 der 16 LA Kanäle bedienen.
Die original LA Software des Hantek6022BL ist unterirdisch.
Die Oszi Software geht.