RTC problem, input freq??

I'm doing my first application with arduino, and it's a RTC.

I'm using the timer/counter 1 in CTC mode, and I want an interrupt each second, but I can't have it, and I don't undestand why... :cry: :cry:

If I'm not wrong:

Target Timer Count = (1 / Target Frequency) / (Prescale / CPU Frequency) - 1

Target Timer Count = (1/2)/(256/16000000)-1= 31249

but the delay between the led blink is further less than a second

We'd need to see your code. Specifically, the types of variables involved. You may be having problems with integer arithmetic.

Here is my code:

#include <avr/io.h>
#include <avr/interrupt.h>

int main (void)
{
DDRB |= (1 << 4); // Set LED as output

TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode

TIMSK |= (1 << OCIE1A); // Enable CTC interrupt

sei(); // Enable global interrupts

OCR1A = 31249; // CTC compare value at prescaler = 256

TCCR1B |= (1 << CS12); // Start timer at Fcpu/256

while(1);
}

ISR(TIMER1_COMPA_vect)
{
PORTB ^= (1 << 4); // Toggle the LED
}

  TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode

And the other bits? What are their values?

TIMSK |= (1 << OCIE1A); // Enable CTC interrupt

Other bits?

TCCR1B |= (1 << CS12); // Start timer at Fcpu/256

Other bits?

All these registries' initial value is 0x00, so i think that with my code I only set bits that I'm interested in.
Maybe I wrong

Your formula gives an interrupt every half second, not every second. In your program the LED toggles at every interrupt.

To get an interrupt every second, change the count value of 62449 in OCR1A

I changed the formula to show interrupt time rather than frequency. A more sophisticated program might calculate the counter value from a given frequency, automatically adjusting prescale values to get best resolution over some range of frequencies. I usually put comments to show how I arrived at count values in case I want to use the program for some other frequency at a later time.

#include <avr/io.h>
#include <avr/interrupt.h>

// Global variable increments when Timer1 reaches count1
byte timerx;

const int LEDPIN = 13;
const unsigned int intTime = 1;
const unsigned int prescale = 256;
const unsigned long CPU = 16000000L;// F_CPU = 16 MHz

//
// For interrupt time = 1 sec, the LED goes high for one second
// and low for a second. 
//
// For these values, count1 = 62499
//
// That is, the result fits in a 16-bit unsigned int, as it must.
//
// If you want higher frequency (interrupt time less
// than one second), use floating point math and round
// off to the nearest unsigned int.  Also, you can decrease
// the prescale amount, to get better resolution at higher
// frequencies, but you must always keep the size so that
// count1 fits into a 16-bit integer.
//
// If you want a lower frequency, change the prescale
// to 1024 (Set bits CS12 and CS10 in TCCR1B.)
// 
const unsigned int count1 = CPU * intTime / prescale - 1 ;

void setup()
{
    pinMode(LEDPIN, OUTPUT);
    digitalWrite(LEDPIN, HIGH);
    //DDRB = (1 << 5); // Set LED on pin 13 as output

    Serial.begin(9600);
    Serial.print("count1 = ");
    Serial.println(count1);

    // Disable interrupts while setting registers   
    cli();

    // Make sure all is normal in TCCR1A
    TCCR1A = 0;

    // Configure timer 1 for CTC mode, prescale = 256
    TCCR1B = (1 << WGM12) | (1<< CS12);

    // Enable CTC Interrupt
    TIMSK1 = (1 << OCIE1A);

    // This determines output frequency
    OCR1A   = count1;

    // Enable global interrupts
    sei();
}

void loop()
{
    static byte old_count;
    if (timerx != old_count) {
        old_count = timerx;
        Serial.print(millis());
        Serial.print("  ");
        Serial.println(timerx, DEC);
    }
}

ISR(TIMER1_COMPA_vect)
{
    //PORTB ^= (1 << 5); // Toggle the LED
    digitalWrite(LEDPIN, 1-digitalRead(LEDPIN));
    ++timerx;
}

Output shows the millis() times when the loop sees a new value of timerx from the ISR:


count1 = 62499
14  1
1011  2
2012  3
3011  4
4012  5
5011  6
6011  7
7011  8
8011  9
9012  10
.
.
.

Regards,

Dave

Footnote:

All these registries' initial value is 0x00, so i think that with my code...

It may be OK in your code if it is executed directly (without the Arduino initialization stuff), but in Arduino sketches, sometimes we discover that the startup code has, for some reason, put stuff in the registers that we don't want. Personally, I like to make sure that the timer registers contain exactly what I want them to have. I assume nothing.

Thanks davekw7x!
I've tried your code and it work great! Like you said I've got to change the value of the OCR1A register.
I thought that the "target frequency" was the time tha the led would be ON plus the time it would be OFF :-[
Thanks one more time

I thought...

Since your specification was in terms of delay values between output toggle events, I calculated the required count value in terms of the specified delay.

Now...

The period of the output waveform is, indeed, equal to the time it is high plus the time it is low, so in our case, the period is two times the delay value, or two seconds. The frequency is 1 divided by the period, which is 1 / (two times the delay value). So for this case, the desired frequency is equal to 1/2 Hz.

Given all of this, I conclude that, for the RTC timer mode and with the output control in the ISR, your formula for counter value as a function as target frequency is incorrect (even if you had plugged in the correct frequency).

If you really want to calculate in terms of frequency rather than delay, you could try something like the following:


Target Timer Count = (1 / 2 / Target Frequency) / (Prescale / CPU Frequency) - 1


But I, personally, would (probably) do it with the specified delay, as I showed in my example sketch. (See Footnote.)

Regards,

Dave

Footnote:
My problem with formulas like the one with frequency is that I tend to forget where they come from and when I want to use them sometime later I have to derive them all over again. Whereas with count as a function of delay, it's (almost) obvious how to get it.

But maybe that's just me. I'm funny that way.