NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » Realtime clock interrupt fire one per second

July 07, 2011
by gcharris
gcharris's Avatar

I'm looking to have the realtime clock code fire an interrupt once a second rather than 100 times a second. I am kind of lost and I was wondering if you could give me a bit of help.

Here's the original code:

void realtimeclock_setup() {
  // setup Timer0:
  // CTC (Clear Timer on Compare Match mode)
  // TOP set by OCR0A register
  TCCR0A |= (1<<WGM01);
  // clocked from CLK/1024
  // which is 14745600/1024, or 14400 increments per second
  TCCR0B |= (1<<CS02) | (1<<CS00);
  // set TOP to 143
  // because it counts 0, 1, 2, ... 142, 143, 0, 1, 2 ...
  // so 0 through 143 equals 144 events
  OCR0A = 143;
  // enable interrupt on compare event
  // (14400 / 144 = 100 per second)
  TIMSK0 |= (1<<OCIE0A);
}
July 07, 2011
by rboggs10
rboggs10's Avatar

Just change OCR0A from 143 to 14399. So instead of the code you posted it would be:

void realtimeclock_setup() {   // setup Timer0:   // CTC (Clear Timer on Compare Match mode)   // TOP set by OCR0A register   TCCR0A |= (1<<WGM01);   // clocked from CLK/1024   // which is 14745600/1024, or 14400 increments per second   TCCR0B |= (1<<CS02) | (1<<CS00);   // set TOP to 143   // because it counts 0, 1, 2, ... 142, 143, 0, 1, 2 ...   // so 0 through 143 equals 144 events   OCR0A = 14399;   // enable interrupt on compare event   // (14400 / 14400 = 1 per second)   TIMSK0 |= (1<<OCIE0A); }

This will make it fire once every second. You just have to do the math. Hope this helps.

July 07, 2011
by rboggs10
rboggs10's Avatar

Whoops forgot to indent as code block. Here it is:

void realtimeclock_setup() {
  // setup Timer0:
  // CTC (Clear Timer on Compare Match mode)
  // TOP set by OCR0A register
  TCCR0A |= (1<<WGM01);
  // clocked from CLK/1024
  // which is 14745600/1024, or 14400 increments per second
  TCCR0B |= (1<<CS02) | (1<<CS00);
  // set TOP to 143
  // because it counts 0, 1, 2, ... 142, 143, 0, 1, 2 ...
  // so 0 through 143 equals 144 events
  OCR0A = 143;
  // enable interrupt on compare event
  // (14400 / 144 = 100 per second)
  TIMSK0 |= (1<<OCIE0A);
}
July 07, 2011
by rboggs10
rboggs10's Avatar

Messed up again with my reply but you should hopefully get the point just change the OCR0A value to 14399.

July 07, 2011
by gcharris
gcharris's Avatar

Thanks! It compiled. I'll test it on the mcu later tonight. Just one note; I did have to cast it to an unsigned char otherwise it would throw the following warning "warning: large integer implicitly truncated to unsigned type"

void realtimeclock_setup() {
  // setup Timer0:
  // CTC (Clear Timer on Compare Match mode)
  // TOP set by OCR0A register
  TCCR0A |= (1<<WGM01);
  // clocked from CLK/1024
  // which is 14745600/1024, or 14400 increments per second
  TCCR0B |= (1<<CS02) | (1<<CS00);
  // set TOP to 143
  // because it counts 0, 1, 2, ... 142, 143, 0, 1, 2 ...
  // so 0 through 143 equals 144 events
  OCR0A = (unsigned char) 14399;
  // enable interrupt on compare event
  // (14400 / 14400 = 1 per second)
  TIMSK0 |= (1<<OCIE0A);
}
July 07, 2011
by Noter
Noter's Avatar

Timer 0 is an 8 bit counter which means OCR0A is an 8 bit number and it can't be greater than 255. You'll need to switch to the 16 bit timer 1 if you want a single interrupt per second or you could just count the interrupts you have now and only take whatever action every 100th interrupt.

July 07, 2011
by gcharris
gcharris's Avatar

Hmm... would this be correct then?

void realtimeclock_setup() {
  // setup Timer1:
  // CTC (Clear Timer on Compare Match mode)
  // TOP set by OCR1A register
  TCCR1A |= (1<<WGM01);
  // clocked from CLK/1024
  // which is 14745600/1024, or 14400 increments per second
  TCCR1B |= (1<<CS02) | (1<<CS00);
  // set TOP to 143
  // because it counts 0, 1, 2, ... 142, 143, 0, 1, 2 ...
  // so 0 through 143 equals 144 events
  OCR1A =  14399;
  // enable interrupt on compare event
  // (14400 / 14400 = 1 per second)
  TIMSK1 |= (1<<OCIE1A);
}
July 07, 2011
by rboggs10
rboggs10's Avatar

Oh I see. How would one enable the 16 bit timer?

July 07, 2011
by Noter
Noter's Avatar

I don't remember timer 1 register settings but seems although similar they are a little different - better review the datasheet to be sure. I've got timer 1 code somewhere, I'll find it and post an example.

July 07, 2011
by rboggs10
rboggs10's Avatar

Ok just got back from the datasheet and it seems that changing TCCR0A to TCCR1A and so on sounds right to me.

July 07, 2011
by Noter
Noter's Avatar

Yep, you're on the right track. Here's a sniplet using timer1 for a chip that was using the 8Mhz internal clock -

// setup timer for 1 second interrupts
#define Timer1_div_1024     5
TCCR1B = Timer1_div_1024;
OCR1A = 7812; 
TCCR1B |= _BV(WGM12); // CTC mode
TIMSK1 = _BV(OCIE1A); // interrupt on OCR0A match

Then be sure to use TIMER1_COMPA_vect for the interrupt routine.

July 07, 2011
by gcharris
gcharris's Avatar

Totally got it working. Here's the exact code I used. Thanks rboggs10 and Noter.

void realtimeclock_setup() {
    TCCR1B = 5;
    OCR1A = 14400;
    TCCR1B |= _BV(WGM12); // CTC mode
    TIMSK1 = _BV(OCIE1A); // interrupt on OCR0A match
}

I ended up using for the interrupt

SIGNAL(TIMER1_COMPA_vect) {
  // when Timer0 gets to its Output Compare value,
  // one one-hundredth of a second has elapsed (0.01 seconds).
  the_time++;
}
July 08, 2011
by Rick_S
Rick_S's Avatar

The only thing I would change from there for future compatability would be to change the SIGNAL to ISR. The SIGNAL syntax has been depreciated and my not function in future versions of avr-libc. For now they both work.

Rick

Post a Reply

Please log in to post a reply.

Did you know that reading a double floating point variable with scanf requires "%lf" for "long float"? Learn more...