Erledigt:TCCR0B Prescaler auf 1 setzen micros immer nur gerade Zahlen

Hallo Leute,

ich wollte die Auflösung von micros() vergrößern und habe mir dafür überlegt das ich folgenden Code Eingbe:

TCCR0B = (TCCR0B & 0xF8) | 0x01 ;

dieser Code setzt den Prescaler von Timer0 von 64 auf 1.
Das bedeutet für mich das ich von 4us Auflösung auf 0,0625us kommen müsste oder?

Und ab hier verstehe ich es auch nicht mehr :slight_smile:
0,0625 us sind genau 16MHZ, das bedeutet doch, das der Process immer im ISR für den Timer laufen müsste oder? Tut er aber nicht.

Außerdem habe ich einfach mal über Serial.println die aktuellen micros() ausgegeben.
Das passt soweit auch, ich bekomme nun 64x zu viele "microsekunden" zurück, jedoch erhalte nur gerade Zahlen.

Kann mir einer die zwei Sachen erklären:

  1. Wenn ich den Prescaler auf 1 Setze beudetet es doch, das der Atmega nur in seiner Schleife laufen müsste oder?
  2. Warum erhalte ich immer bei der Rückgabe eine Gerade Zahl?

Vielen Dank

LÖSUNG:

Habe mir nun doch mal den Quellcode angeschaut und Antwort ist wie folgt.
Die Function micros hat folgenden Rückgabewert:

return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());

m gibt den Rückgabewert vom Timer0 overflow an (nachdem TCNTO von 0-255 gezählt hat)
t ist der aktuelle zähler vom Timer0 (TCNT0 zahl zwischen 0 - 255)
clockCyclesPerMicrosecond() rechnet 16000000L(HERZ)/1000000L sind

Und deswegen ergibt sich durch die Multiplikation von "4" ein vielfaches von 4 :slight_smile:

Da es einige Maschienenbefehle braucht um die Zahl zu erhöhen kann es keine Auflösung mit Systemtakt geben.

Grüße Uwe

Das verstehe ich auch ABER:

Wenn ich den folgenden Code laufen lasse, soll er mir auf dem Serialmonitor das Wort "ungerade" ausgeben, wenn die Microsekunden ungerade sind.
Jedoch liefert er nichts.
Um sicher zu stellen, das es nicht durch Zufall durch den Takt immer auf eine gerade Zahl kommt, habe ich den Code um 3 NOP erweitert, sodass etwas passieren sollte.

    unsigned long time1;

void setup() {
  TCCR0B = (TCCR0B & 0xF8) | 0x01 ;
  Serial.begin(115200);
  Serial.println("Start"); 
}

void loop() {
    time1 = micros();
    if(time1 % 2 == 0){
      __asm__("nop\n\t"); 
      __asm__("nop\n\t"); 
      __asm__("nop\n\t"); 
    }
    else{
      Serial.println("ungerade"); 
      
    };
    };

Als zweiten Versuch habe ich einfach folgendes gemacht in der void loop();

Serial.println(micros());
if(micros() > 1920000000){
Serial.println("30 Sekunden sind um.");
}

Nun habe ich einmal die Stoppuhr genommen und geschaut, ob ISR "verloren" gehen.
30 Sekunden* 1000 Millisekunden * 1000 Microsekunden *64, da der Prescaler 64 schneller ist als vorher machen 1920000000

Was soll ich sagen, nach ziemlich genau 30 Sekunden, kommt das Wort auf den Monitor.
Der Original Prescaler ist auf64 eingestellt.

Bedeutet 16MHZ / 64 = 4us genau so wie es in Arduino steht:
On 16 MHz Arduino boards (e.g. Duemilanove and Nano), this function has a resolution of four microseconds

Setze ich nun den Prescaler runter auf 1, also 64 mal schneller, bin ich bei 0,0625us, genau bei dem Systemtackt.

Wie kann es jetzt sein, das der Arduino noch sauber jeden Interrupt zählen kann und parallel die Hauptschleife abarbeiten?

Eigentlich müsste das Controller doch dauerhaft in der Schleife sein und die Zahl nicht immer Gerade..
Ich versteh es nicht

tausday:
Das verstehe ich auch ABER:

Wenn ich den folgenden Code laufen lasse, soll er mir auf dem Serialmonitor das Wort "ungerade" ausgeben, wenn die Microsekunden ungerade sind.

Das ist ja auch kein Wunder, da micros() immer um 4 erhöht wird. Es liefert immer eine durch 4-teilbare und damit eine gerade Zahl. Ungerade wird es höchstens mal beim Timerüberlauf.

Siehe: https://www.arduino.cc/en/Reference/Micros