ich hätte mal eine Frage bezüglich dem Timer0, der ja für millis() und delay() verwendet wird.
In meinem Sketch verwende ich eigentlich keine dieser Funktionen und möchte den Timer0 für andere Aufgaben verwenden. Jedoch lässt sich das OCR0A nicht überschreiben, sodass die Frequenz immer bei 1kHz bleibt. Lässt sich das irgendwie ändern?
Eigentlich bin ich mit der Konfiguration der Register recht vertraut, nur bei Timer0 lässt sich nichts ändern. Eventuell kann mir ja jemand helfen. Mein Sketch ruft im setup() Teil folgende Funktion auf:
Nachtrag: geht um den Atmega2560
void set_timer0_pid_isr(void)
{
cli(); // disable all interrupts
TCCR0A = 0; // set entire TCCR0A register to 0
TCCR0B = 0; // set entire TCCR0B register to 0
switch (PRESCALER_PID_CONTROLLER) // PRESCALER_PID_CONTROLLER = 64
{
case 1: // SET CS02 & CS01 & CS00 bit for prescaler 1
TCCR0B &= ~(1 << CS02);
TCCR0B &= ~(1 << CS01);
TCCR0B |= (1 << CS00);
break;
case 8: // SET CS02 & CS01 & CS00 bit for prescaler 8
TCCR0B &= ~(1 << CS02);
TCCR0B |= (1 << CS01);
TCCR0B &= ~(1 << CS00);
break;
case 64: // SET CS02 & CS01 & CS00 bit for prescaler 64
TCCR0B &= ~(1 << CS02);
TCCR0B |= (1 << CS01);
TCCR0B |= (1 << CS00);
break;
case 256: // SET CS02 & CS01 & CS00 bit for prescaler 256
TCCR0B |= (1 << CS02);
TCCR0B &= ~(1 << CS01);
TCCR0B &= ~(1 << CS00);
break;
case 1024: // SET CS02 & CS01 & CS00 bit for prescaler 1024
TCCR0B |= (1 << CS02);
TCCR0B &= ~(1 << CS01);
TCCR0B |= (1 << CS00);
break;
default: // SET CS02 & CS01 & CS00 bit for prescaler 64
TCCR0B &= ~(1 << CS02);
TCCR0B |= (1 << CS01);
TCCR0B |= (1 << CS00);
break;
}
OCR0A = (CPU_FREQ / (PRESCALER_PID_CONTROLLER * 2000UL)) - 1; // set compare value for 0,5 ms -> 2 kHz
TIMSK0 = (1 << OCIE0A); // enable compare match A interrupt
TCNT0 = 0;
sei(); // enable all interrupts
Serial.print("OCR0A: "); Serial.println(OCR0A);
}
ISR(TIMER0_COMPA_vect)
{
PORTB ^= (1<<7);
//PID_CONTROLLER_SAMPLING_TIME_COUNTER < PID_CONTROLLER_SAMPLING_TIME - 1 ? PID_CONTROLLER_SAMPLING_TIME_COUNTER++ : PID_CONTROLLER_SAMPLING_TIME_COUNTER = 0;
}
Die ISR soll nur mit 2kHz den Pin13 Toggeln. Im OCR0A steht auch der richtige Wert 124, allerdings bleibt die Frequenz am Pin weiterhin bei 1kHz.
Die Timer Stoppfunktion kannste meinetwegen auch in der SetPrescaler Funktion aufrufen. Je nach deinen Anforderungen. Man sollte sich jedoch immer an eine einfache Regel halten. Vor irgendwelchen Änderungen am Timer diesen zuerst stoppen und erst wieder nach allen Änderungen starten. Das heißt zuerst die Prescaler Bits löschen und zum Schluss setzen. Ansonsten kann es passieren das der Timer mit einer falschen bzw. noch unfertigen Konfiguration losläuft und nicht das macht was er sollte.
Kann dann bei dir so aussehen. Damit kann auf cli/sei verzichtet werten, weil sowieso nichts passiert solange der Timer gestoppt ist. Und wenn der Prescaler Parameter falsch ist passiert auch nichts, weil der Timer bleibt gestoppt. Ansonsten müßte man noch die Formel für OCR0A absichern.
void reConfigTimer0(const unsigned int prescaler)
{
stopTimer0();
OCR0A = (CPU_FREQ / (prescaler * 2000UL)) - 1; // set compare value for 0,5 ms -> 2 kHz
TIMSK0 = _BV(OCIE0A); // enable compare match A interrupt
TCNT0 = 0;
setPrescalerTimer0(prescaler);
Serial.print("OCR0A: "); Serial.println(OCR0A);
}
Wenn CPU_FREQ dem tatsächlichen Controllertakt [Hz] entspricht, kannste auch F_CPU einsetzen.
Zum generellen Timer-Mode einstellen würde ich noch eine extra Funktion schreiben, dann kann auch TIMSK0 dort drin einmalig geändert werden usw..
Danke für den ganzen Input. Werde ich definitiv berücksichtigen und den Code nochmal etwas überarbeiten. Muss zugeben mit den Makros (sind doch Makros oder?) wie _BV bin ich nicht wirklich vertraut. Gibt es dazu irgendwo eine Doku? Konnte dazu auf die Schnelle nichts finden.
_BV() ist nur eine noch kürzere Schreibweise fürs Bit schupsen. Beim Lesen wird damit besser deutlich was man hier machen möchte. Noch eine Ergänzung damit erst gar keine Missverständnisse aufkommen. Timer stoppen/starten macht natürlich nur Sinn wenn signifikante Änderungen an der Konfigurationen vorgenommen werden. Also wenn du einmal einen PWM Mode verwendest und den Compare Wert für Duty Cycle ständig änderst, dann macht es natürlich keinen Sinn den Timer ein- und auszuschalten. Ansonsten kommt es wie immer auf die Details an.