Created
January 29, 2012 01:26
-
-
Save dccourt/1696597 to your computer and use it in GitHub Desktop.
Generic timer setup utility
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Setup Timer2. | |
//Configures the 8-Bit Timer2 to generate an interrupt | |
//at the specified frequency. | |
//Returns the timer load value which must be loaded into TCNT2 | |
//inside your ISR routine. | |
//See the example usage below. | |
unsigned char SetupTimer2(float timeoutFrequency){ | |
unsigned char result; //The timer load value. | |
/* We need to work out what divisor of the chip clock can be | |
used to get an 8-bit counter preload value that represents | |
the requested frequency. | |
timer preload_val = scaled_freq / requested_freq | |
=> scaled_freq = clock_freq / scaler | |
=> preload_val = clock_freq / scaler / requested_freq | |
=> 256 > clock_freq / scaler / requested_freq | |
=> clock_freq / scaler < 256 * requested_freq | |
=> 1 / scaler < 256 * requested_freq / clock_freq | |
=> scaler > clock_freq / (256 * requested_freq) | |
*/ | |
Serial.print("clock/requested:"); | |
Serial.println(TIMER_CLOCK_FREQ / timeoutFrequency); | |
int min_scaler = TIMER_CLOCK_FREQ / (256 * timeoutFrequency); | |
Serial.print("Min scaler:"); | |
Serial.println(min_scaler); | |
// Need to convert min_scaler into a power-of-2 value to use. | |
// Allowable values are actually 1, 8, 32, 64, 128, 256, 1024 - | |
// see data sheet, section 18.10. | |
int scaler = 1; | |
while ((scaler < min_scaler) && (scaler < 1024)) | |
{ | |
scaler <<= 1; | |
// skip disallowed values | |
if ((scaler == 2) || (scaler == 4) || (scaler == 16) || (scaler == 512)) | |
{ | |
scaler <<= 1; | |
} | |
} | |
if (scaler < min_scaler) | |
{ | |
// Output a warning. | |
Serial.println("Requested timer frequency too low - unable to find a suitable divider"); | |
} | |
else | |
{ | |
Serial.print("Chosen prescaler:"); | |
Serial.println(scaler); | |
} | |
long scaled_freq = TIMER_CLOCK_FREQ / scaler; | |
// Convert the scaler value into register settings | |
switch (scaler) | |
{ | |
case 1: | |
TCCR2B = 0b00000001; | |
break; | |
case 8: | |
TCCR2B = 0b00000010; | |
break; | |
case 32: | |
TCCR2B = 0b00000011; | |
break; | |
case 64: | |
TCCR2B = 0b00000100; | |
break; | |
case 128: | |
TCCR2B = 0b00000101; | |
break; | |
case 256: | |
TCCR2B = 0b00000110; | |
break; | |
case 1024: | |
TCCR2B = 0b00000111; | |
break; | |
default: | |
Serial.print("Unrecognised scaler: "); | |
Serial.println(scaler); | |
break; | |
} | |
//Calculate the timer load value | |
result=(int)((256.0-(scaled_freq/timeoutFrequency))+0.5); | |
//Timer2 Settings: Timer mode 0 | |
TCCR2A = 0; | |
//Timer2 Overflow Interrupt Enable | |
TIMSK2 = 1<<TOIE2; | |
//load the timer for its first cycle | |
TCNT2=result; | |
Serial.print("Timer2 reload value:"); | |
Serial.println(result); | |
return(result); | |
} | |
// And using this within an ISR to maintain an accurate interval that | |
// takes account of the time spent within the ISR: | |
ISR(TIMER2_OVF_vect) { | |
// ... do some work here ... | |
//Capture the current timer value. This is how much error we | |
//have due to interrupt latency and the work in this function | |
latency=TCNT2; | |
//Reload the timer and correct for latency. | |
TCNT2=latency+timerLoadValue; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment