I am using an Atmega328p-pu. I am trying to use the timer 1 for both a 16 bit PWM as well as using the overflow inturrupt to increment a timer. My code is below, I also set the F_CPU to 8000000UL in the make file.
I would like the to have a variable that counts up for a defined amount of time and then resets and continues. so far I would expect it to count up for 7.5 seconds. I believe I should have a clock frequency of 8 MHz, then with fast PWM with a 1 prescaler and ICR1 at 5000 I would expect the inturrupt to happen at 1600 Hz. Then I let it count up for 12000 counts. I would expect this to take 7.5 seconds. but I've measured it at around 57 seconds. I'm not sure what I'm missing, maybe something in the setting of the registers, but I'm not sure where. thanks for your help,
here is what I think is most important,
// values for timer1
// WGM 13 12 11 10 is
// fast PWM 1 1 1 0
TCCR1A |= (1 << 7); // output on A pin (COM1A1)
TCCR1A |= (1 << 1); // WGM 11
TCCR1A &= ~(1 << 0); // WGM 10
TCCR1B |= (1 << 4); // WGM 13
TCCR1B |= (1 << 3); // WGM 12
//for prescaler of 1 set CS12 CS11 CS10
0 0 1
TCCR1B &= ~(1 << 2); // set prescaler to 1x CS12
TCCR1B &= ~(1 << 1); // set prescaler to 1x CS11
TCCR1B |= (1 << 0); // set prescaler to 1x CS10
TIMSK1 = 0; // enable output compare A inturrupt
TIMSK1 |= (1 << 0); // Set the Overflow inturrupt
TCNT1 = 0; // set the counter to zero on startup
ICR1 = 5000; //Set the top of the counter
OCR1A = 0; //set the duty cycle
....
ISR(TIMER1_OVF_vect){
longTimer++;
....
if (longTimer >= 12000){
longTimer = 0;
and here is the entire code
/* Light Control */
// ------- Preamble -------- //
#include <avr/io.h> /* Defines pins, ports, etc */
#include <avr/interrupt.h>
// Global variables
volatile uint8_t tick = 0;
volatile uint8_t fastTimer = 0;
volatile uint16_t longTimer = 0;
volatile uint16_t fader = 0;
volatile uint16_t dayBrightness = 0;
volatile uint8_t nightBrightness = 0;
uint8_t Day = 0;
void init(void) {
// values for push button inturrupt
EIMSK = (1 << 0);
EICRA = (1 << 1) & (1 << 0);
// values for timer1
// WGM 13 12 11 10 is
// fast PWM 1 1 1 0
TCCR1A |= (1 << 7); // output on A pin (COM1A1)
TCCR1A |= (1 << 1); // WGM 11
TCCR1A &= ~(1 << 0); // WGM 10
TCCR1B |= (1 << 4); // WGM 13
TCCR1B |= (1 << 3); // WGM 12
//for prescaler of 1 set CS12 CS11 CS10
0 0 1
TCCR1B &= ~(1 << 2); // set prescaler to 1x CS12
TCCR1B &= ~(1 << 1); // set prescaler to 1x CS11
TCCR1B |= (1 << 0); // set prescaler to 1x CS10
TIMSK1 = 0; // enable output compare A inturrupt
TIMSK1 |= (1 << 0); // Set the Overflow inturrupt
TCNT1 = 0; // set the counter to zero on startup
ICR1 = 5000; //Set the top of the counter
OCR1A = 0; //set the duty cycle
sei();
// values for IO
DDRB |= 0b00000011; /* Data Direction Register B: writing a one to the bit enables output. */
DDRD = 0x00; /* zero sets all as input */
PORTD = 0xff; /* set all inputs as pull ups */
}
ISR(INT0_vect){
//longTimer = 0;
}
ISR(TIMER1_OVF_vect){
longTimer++;
if(Day){
fader++;
}
else{
if(fader > 0){
fader--;
}
}
}
int main(void) {
init();
// ------ Event loop ------ //
while (1) {
if(Day) {
if (fader >= 5000){
OCR1A = 5000;
}
else {
OCR1A = fader;
}
}
else {
OCR1A = fader;
}
if (longTimer >= 12000){
longTimer = 0;
if(Day){
fader = 5000;
}
else{
fader = 0;
}
tick = 1;
}
if (tick == 1){
Day ^= 1;
tick = 0;
}
} /* End event loop */
return 0; /* This line is never reached */
}
Whenever I'm using the internal oscillator and things are running either way (8x) faster, or way (8x) slower, I check the CKDIV8 bit setting. Almost always that's the culprit.
If using an external oscillator or clock, weird timings are often from not switching the the external clock in the fuse settings, or from having F_CPU set differently from actual frequency.
Also, off-topic a bit, but code such as this is redundant:
Those bits are zeroes by default so no reason to clear them unless it's just for clarity as you're learning.