June 24, 2012
by whitehatyoyoer
|
Hello,
I wrote this clock program to display the time, but there's a problem, it loses time. It loses about 5 second every 10 minutes, which to me isn't good. I've looked over the code multiple times, but can't find anything that would cause the time loss. Here's the code:
// A simple alarm clock, maybe with a few added features.
//written by Tyler Wilber(whitehatyoyoer) for the ATmega168 Nerdkit
//whitehatyoyoer@gmail.com
//This work is licensed under the Creative Commons Attribution 3.0 Unported License.
//To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>
#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"
volatile uint16_t hour=0;
volatile uint16_t min=0;
volatile uint16_t sec=0;
volatile uint16_t mil_sec=0;
volatile uint8_t wait = 0;
void pin_setup()
{
//Pushbutton -- PC0(pin#23) -- input
//Hour switch -- PC1(pin#24) -- input
//Minute switch -- PC2(pin#25) -- input
//Second reset switch -- PC3(pin#26) -- input
//Alarm switch -- PC4(pin#27) -- input
DDRC &= ~(1<<PC0);
PORTC |= (1<<PC0);
DDRC &= ~(1<<PC1);
PORTC |= (1<<PC1);
DDRC &= ~(1<<PC2);
PORTC |= (1<<PC2);
DDRC &= ~(1<<PC3);
PORTC |= (1<<PC3);
}
void update_time()
{
//read the pushbutton/DIP bit 1/DIP bit 3/DIP bit5 states respectively
uint8_t pushbutton = (PINC & (1<<PC0)) >> PC0;
uint8_t hr_bit = (PINC & (1<<PC1)) >> PC1;
uint8_t min_bit = (PINC & (1<<PC2)) >> PC2;
uint8_t sec_bit = (PINC & (1<<PC3)) >> PC3;
//This section changes the time when the button is pressed
if(mil_sec % 50 == 1)
{
wait = 0;
}
if(wait == 0)
{
if(pushbutton == 0)
{
wait = 1;
if(~hr_bit && min_bit && sec_bit)
//if the hour switch is up
{
hour++;
}
if(~min_bit && hr_bit && sec_bit)
//if the min switch is up
{
min++;
}
if(~sec_bit && hr_bit && min_bit)
//if the sec switch is up
{
sec = 0;
}
}
}
//This section update the time when one of the time sections overflow
if(mil_sec / 100 == 1)
{
sec++;
mil_sec = 0;
}
if(sec / 60 == 1)
{
min++;
sec = 0;
}
if(min / 60 == 1)
{
hour++;
min = 0;
}
if(hour / 24 == 1)
{
hour = 0;
}
}
void clock_setup()
{
//WGM0[2:0] = 010 for CTC, TOP = OCRA -- WGM02 in TCCR0B
TCCR0A |= (1 << WGM01);
//CS0[2:0] = 101 for 14.7456Mhz/1024 = 14400hz
TCCR0B |= (1 << CS02) | (1 << CS00);
//set TOP(OCRA) to 144 -- 14400hz/144 = 100hz
OCR0A = 144;
// 8x overclock for testing
// OCR0A = 16;
//OCIE0A timer interrupt on output compare match A
TIMSK0 |= (1 << OCIE0A);
}
ISR(SIG_OUTPUT_COMPARE0A)
{
// sec++;
mil_sec++;
update_time();
}
int main()
{
lcd_init();
pin_setup();
clock_setup();
lcd_home();
FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
sei();
while(1)
{
lcd_home();
fprintf_P(&lcd_stream,PSTR("%2.2d:%2.2d.%2.2d"),hour,min,sec,mil_sec);
}
}
|
June 24, 2012
by esoderberg
|
Whitehat,
Set TOP to 143; because it counts 0, 1, 2,..142,143, 0, 1, 2 ... so 0 through 143 equals 144 events. You're running 144/145 slow, which matches well with what you report 600-5/600 = 595/600.
Eric |
June 24, 2012
by whitehatyoyoer
|
Thanks alot esoderberg, it's been running for over 10 minutes right now and hasn't lost any time. I can't believe I over looked that, I knew that the timer started at 0. It's always simple things that throw you off.
--Whitehat |
June 24, 2012
by whitehatyoyoer
|
So, now after running for over 4 hours it has actually gained 4 seconds. Now I have to figure that out.
--Whitehat |