Der Timer von ATtiny13A scheint sehr ungenau zu sein, ist das normal? [geschlossen]

Ich habe dieses Blinkprogramm für meinen ATtiny13A geschrieben und versucht, die Genauigkeit mit einem Arduino Uno zu messen, aber der Timer scheint ziemlich ungenau zu sein. Auf dem ATtiny laufe ich auf der internal 128KHzUhr und benutze Timer, um pin0hoch und niedrig mit einer Frequenz von zu machen 1Hz.

Hier ist der ATtiny-Code:

int main(void){

  DDRB = 0;
  TCCR0A = 0;
  PORTB = 0;

  DDRB |= (1 << DDB0);      // pin0 output

  TCCR0A |= (1 << WGM01);   //CTC mode
  TCCR0A |= (1 << COM0A0);  //toggle OC0A on compare match

  TCCR0B |= (1 << CS02) | (1 << CS00); //1024 prescalar
  OCR0A = 124;              //1Hz @ 128KHz internal clock

  while(1){ 
  }

  return 0;
}

Auf dem Arduino verwende ich Interrupts, um die Zeit zwischen jedem High/Low-Signal zu messen. Es ist ein Standard-Uno mit einem externen 16-MHz-Quarz. Hier ist der Arduino-Code:

unsigned long lastHigh = 0;

void setup() {
  Serial.begin(9600);
  const byte interruptPin = 2;
  attachInterrupt(digitalPinToInterrupt(interruptPin), myISR, CHANGE);
}

void loop() {
}

void myISR(){
  unsigned long temp = micros();    //store it ASAP to minimize delay
  Serial.println(temp - lastHigh);
  lastHigh = temp;
}

Ich habe den pin 2auf dem Arduino mit einem 1K-Widerstand auf Masse gezogen und ihn mit pin 0dem ATtiny13A verbunden.

Ich hatte erwartet, zwischen jedem Blinzeln eine perfekte Eins zu lesen, aber hier sind meine Messwerte (in Mikrosekunden):

1063616 1062696 1063608 1062696 1063636 1062692 1063608 1062680 1063576 1062580 1063512 1062676 1063576 1062660 1063584 1062680 1063580 1062672 1063596 1062700 1063596 1062688 1063604 1062680 1063596 1062612 1063528 1062668 1063580 1062680 1063588 1062684

Wie Sie sehen können, ist der Timer nicht nur ~60 Millisekunden ausgeschaltet, sondern zittert auch stark.

Ich habe im Internet gelesen, dass die interne Uhr ungenau ist, aber ich bin mir nicht sicher, ob ~ 60 ms zu ungenau sind oder nicht.

Abgesehen davon, dass sie ausgeschaltet sind, sind die Timings auch sehr nervös. Sie reichen von so niedrig wie 106 2 580 bis so hoch wie 106 3 680 Mikrosekunden.

Ich bin ziemlich unerfahren und bin wirklich neugierig, ob dieses Maß an Ungenauigkeit als normal angesehen wird oder nicht. Ich fand es seltsam, weil 1000us-Jitter die micros()oder- _delay_us()Funktionen ziemlich nutzlos machen.

Vielleicht verursacht Ihre Debug-Ausgabe diesen Jitter. Serial.println() beinhaltet einen weiteren ISR, der die serielle Kommunikation übernimmt. Speichern Sie den berechneten Differenzwert irgendwo und führen Sie die serielle Kommunikation in der Hauptschleife durch. Auf diese Weise können Sie einige Datenpunkte verlieren, aber die Messung selbst wird nicht durch die serielle Kommunikation beeinflusst.

Antworten (2)

Sie sehen also etwa +6 % Abweichung und ±0,05 % Jitter.

Die Abweichung.

Ich konnte nichts über den internen 128-kHz-Oszillator finden, aber der interne 4,8/9,6-MHz-Oszillator hat eine Standardgenauigkeit von ±10 % bei einer bestimmten Spannung und Temperatur. Siehe Abschnitt 18.4.1 (Seite 119) des Datenblatts :

Tabelle mit Informationen zur Oszillatorkalibrierung

Ich vermute, dass der 128-kHz-Oszillator ähnlich ist, also vermute ich, dass +6% für mich den Spezifikationen entsprechen. Sie können den internen Oszillator kalibrieren, um eine bessere Genauigkeit zu erzielen, siehe Atmel Appnote AVR053: Internal RC Oscillator Calibration for tinyAVR and megaAVR Devices .

Sie sollten sich auch ansehen, wie Sie den Timer verwenden. Sie haben keinen Interrupt-Handler definiert, daher glaube ich, dass Sie einen Soft-Reset des Tiny verursachen, wenn der Timer abläuft. Dies bedeutet, dass jeder avr-glibc-Initialisierungscode erneut ausgeführt wird, ebenso wie Ihr Timer-Setup-Code. Dies dauert einige Zyklen und erhöht Ihre Zykluszeit, was zu einer positiven Abweichung führt.

Versuchen Sie, einen ISR einzurichten, der das Blinken übernimmt, und sehen Sie, ob das einen Unterschied macht. Oder versuchen Sie es sogar mit einer kalibrierten Verzögerungsschleife anstelle des Timers.

Das Zittern.

Was den Jitter betrifft, so klingt für mich ±0,05 % ziemlich viel. Aber um ehrlich zu sein, bin ich mir nicht sicher, wie stabil diese RC-Oszillatoren sind.

Ein bedeutender Verdächtiger ist Ihre println()und serielle Übertragung. println()muss einiges an Arbeit leisten, um Ihre Zahl in die Basis 10 umzuwandeln, und der genaue Arbeitsaufwand hängt von der Zahl ab, die gedruckt wird. Außerdem muss die serielle Übertragung mit Ihrem Computer synchronisiert werden, was zu Verzögerungen führen kann, die für Ihren Arduino halbzufällig sind.

Versuchen Sie, etwa 20 Messungen im Speicher zu speichern und Serial.println()sie erst zu verwenden, nachdem alle Messungen abgeschlossen sind.

Außerdem bin ich mir nicht ganz sicher, wie genau Arduino micros()ist. Vielleicht gibt es da ein Genauigkeitsproblem. Wenn Sie Zugang zu einem Oszilloskop haben, können Sie damit stattdessen die Ausgangsfrequenz des Tiny messen und den Arduino als mögliche Fehlerquelle ausschließen.

Aktualisieren! LED-Leistungsaufnahme beeinflusst RC-Oszillator?

Aha, ich habe ein Muster in deinem Zittern bemerkt! Sie messen abwechselnd 106 3 6xx und 106 2 6xx. Der größte Teil Ihres Jitters ist also eine 1-ms-Variation zwischen geraden und ungeraden Zyklen.

Ich vermute, dass dies daran liegt, dass Sie eine LED einschalten, die Strom zieht, was sich auf die Resonanz im RC-Tank auswirkt, der für den internen Oszillator verwendet wird. Das wäre interessant.

Können Sie versuchen, Ihren ursprünglichen Messlauf noch zweimal zu wiederholen, einmal ohne LED und einmal mit?

Wenn das Entfernen der LED das Problem beseitigt, sollten Sie viel Entkopplung auf dem Tiny verwenden und vermeiden, dass das Tiny-Laufwerk direkt geladen wird, aber Ausgänge immer mit Transistoren puffern. Wenn die Uhrgenauigkeit für die Situation sowieso wichtig genug ist.

Danke @marcelm. Ich habe versucht, eine ISR zu definieren, aber ich hatte das gleiche Ergebnis. Ich habe dieses Beispiel gepostet, weil es die geringste Menge an Code hatte. In Bezug auf das println()Problem läuft der Arduino mit 16 MHz und hat 1 Sekunde zwischen jedem Blinken des ATtiny. Wird die benötigte Zeit println()noch relevant sein?
@PouriaP Überprüfen Sie unbedingt das Update auf meine Antwort (dritter Abschnitt), ich habe das Problem möglicherweise gefunden;)
@PouriaP Das Drucken einer Zahl beinhaltet das Konvertieren in die Basis 10, was wiederholte Divisionen durch 10 erfordert. Da die AVRs keine Hardwareteilung haben, muss dies in der Software mit vielen Anweisungen erfolgen. Es kann relevant sein.
Ja! Ich entfernte die LED und der Jitter ging von ~1000 auf ~100us zurück. Und nach dem Hinzufügen eines Kondensators zwischen VCC und GND ging es weiter auf etwa 50 us (sorry, ich hatte vergessen, es früher hinzuzufügen). Obwohl es immer noch ein Muster gibt, genau wie das, das Sie bemerkt haben, nur kleiner. Es ist auch instabil. Wenn ich das Steckbrett auch nur leicht bewege, wird der Jitter wieder schlecht. Vielleicht ist es einfach extrem empfindlich?

6 % Fehler klingen für einen unkalibrierten On-Chip-Oszillator angemessen.

Tatsächlich zeigen die Abbildungen 19-65 und 19-66 auf Seite 157 des Datenblatts , dass die Frequenz des "128-kHz-Watchdog-Oszillators" tatsächlich nicht annähernd 128 kHz beträgt!

Wenn Sie eine höhere Präzision wünschen, sollten Sie mindestens den 4,8/9,6 "kalibrierten" Oszillator verwenden und möglicherweise Ihre On-Kalibrierung an jedem Gerät durchführen. Einmal kalibriert, bleibt es innerhalb von ±2 % über Temperatur und Spannung (siehe Tabelle 18-2 auf S. 119), und Sie können es viel besser machen, wenn Sie einen oder beide dieser Parameter regulieren können.