0
\$\begingroup\$

I want to create a real-time clock using ATmega328p microcontroller. The microcontroller's frequency is 1 MHz. So, I think I should use timer interrupts in CTC mode to generate interrupt every second. I have calculated the value for timer CTC mode:

`n = t * f - 1
  • n - number of cycles for CTC mode.
  • t - target time.
  • f - frequency.
  • - 1 because it takes one cycle to reset the counter.

I set the frequency divider by 64 for the timer.

n = 1 s * (10^6 Hz / 64) - 1
n = 1 s * 15625 Hz - 1
n = 15625 - 1
n = 15624

So, I have code:

#include <avr/interrupt.h>
#include <util/delay.h>
#include <time.h>

static unsigned long t = 0;

ISR(TIMER1_COMPA_vect) {
    t++;
}

static void InitializeTimer() {
    cli();

    OCR1A = 15624;
    TCCR1B = (1 << WGM12) | (1 << CS10) | (1 << CS11);
    TIMSK1 = (1 << OCIE1A);

    sei();
}

[[noreturn]] int main() {

    InitializeTimer();

    LCD_SetUp(PC_5, PC_4, PC_3, PD_0, PD_1, PD_2, PD_3, PD_4, PD_5, PD_6, PD_7);
    LCD_Init(2, 16);

    while(true) {
        tm* time = gmtime((time_t*)&t);

        LCD_Clear();
        LCD_Printf("Time: %02d:%02d:%02d", time->tm_hour, time->tm_min, time->tm_sec);

        _delay_ms(100);
    }
}

This code prints number of seconds since the start of the microcontroller to an LCD display. It really does, but since even 3 minutes time error is 2 seconds, since 10 minutes time error is 5 seconds, since 45 minutes time error is 30 seconds. I checked the time error using my phone's stopwatch. Why there is a time error? Error during calculation? What are the reasons for this? Thanks in advance!

\$\endgroup\$
6
  • 2
    \$\begingroup\$ What are you using as the clock source for the AVR? I suspect it's the internal oscillator and if so, that is unsuitable for your purpose. You should switch to an external crystal clock source at least. Better yet would be an RTC chip with a precision crystal oscillator if you need accurate timekeeping. \$\endgroup\$
    – jwh20
    Jan 2, 2021 at 21:42
  • \$\begingroup\$ Incidentally, because it's an 8bit machine, you should be aware of accessing the 16bit value "t" from the main code, as I believe it may be modified by the interrupt in the middle of being read from memory. The safe way to do it is wait until interrupt has just gone off, temporarily disable the interrupt, make a copy of t, and turn the interrupt back on immediately after that. \$\endgroup\$
    – Pete W
    Jan 2, 2021 at 21:45
  • \$\begingroup\$ @jwh20, I'm using an inner crystal clock source by default in AVR microcontrollers. It's not suitable for real time clock? \$\endgroup\$ Jan 2, 2021 at 21:48
  • 1
    \$\begingroup\$ @manueld4722623 the 328P internal clock isn't a crystal. And its accuracy is specified as +/- 10%. You're getting within about 1%, which is about as good as you could expect. \$\endgroup\$
    – hobbs
    Jan 2, 2021 at 21:59
  • 1
    \$\begingroup\$ There is no "internal crystal" in AVR microcontrollers. There is a calibrated oscillator but the datasheet says +/- 2% @ 25C. That's enough for many purposes but not for an RTC in general or for your purpose. See page 260 at: ww1.microchip.com/downloads/en/DeviceDoc/… \$\endgroup\$
    – jwh20
    Jan 2, 2021 at 22:13

1 Answer 1

2
\$\begingroup\$

The AVR's internal oscillator is unsuitable for your purpose. This is from the datasheet:

AVR RC Accuracy

You should switch to an external crystal clock source at least. Better yet would be an RTC chip with a precision crystal oscillator if you need accurate timekeeping.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.