The AVR controlled clock

The AVR controlled clock:

A friend of mine needed a clock into his amplifier as an extra function. So I made him one. It consists only of one AVR processor and one BQ-M512RD (or compatible, with common anodes) LED display. I tried to keep the whole clock as simple as possible, so anyone can build one...

avr_clock1

Here's the schematic (click for a bigger image):

sch_hodiny_avr

And the photo of the device:

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

 #define _s_A 2
 #define _s_B 0
 #define _s_C 6
 #define _s_D 4
 #define _s_E 3
 #define _s_F 1
 #define _s_G 7
 #define _s_dot 5

 const unsigned char segs[] =
 {
  _BV(_s_A) | _BV(_s_B) | _BV(_s_C) | _BV(_s_D) | _BV(_s_E) | _BV(_s_F), //0
  _BV(_s_B) | _BV(_s_C), //1
  _BV(_s_A) | _BV(_s_B) | _BV(_s_D) | _BV(_s_E) | _BV(_s_G), //2
  _BV(_s_A) | _BV(_s_B) | _BV(_s_C) | _BV(_s_D) | _BV(_s_G), //3
  _BV(_s_B) | _BV(_s_C) | _BV(_s_F) | _BV(_s_G), //4
  _BV(_s_A) | _BV(_s_C) | _BV(_s_D) | _BV(_s_F) | _BV(_s_G), //5
  _BV(_s_A) | _BV(_s_C) | _BV(_s_D) | _BV(_s_E) | _BV(_s_F) | _BV(_s_G), //6
  _BV(_s_A) | _BV(_s_B) | _BV(_s_C), //7
  _BV(_s_A) | _BV(_s_B) | _BV(_s_C) | _BV(_s_D) | _BV(_s_E) | _BV(_s_F) | _BV(_s_G),//8
  _BV(_s_A) | _BV(_s_B) | _BV(_s_C) | _BV(_s_F) | _BV(_s_G),//9

  _BV(_s_A) | _BV(_s_B) | _BV(_s_C) | _BV(_s_E) | _BV(_s_F) | _BV(_s_G), //A
  _BV(_s_C) | _BV(_s_D) | _BV(_s_E) | _BV(_s_F) | _BV(_s_G), //B
  _BV(_s_A) | _BV(_s_D) | _BV(_s_E) | _BV(_s_F), //C
  _BV(_s_B) | _BV(_s_C) | _BV(_s_D) | _BV(_s_E) | _BV(_s_G), //D
  _BV(_s_A) | _BV(_s_D) | _BV(_s_E) | _BV(_s_F) | _BV(_s_G), //E
  _BV(_s_A) | _BV(_s_E) | _BV(_s_F) | _BV(_s_G) //F
 };

 #define _ms(n) (17*n)

 void wait(unsigned int a) //basic wait
 { 
  volatile unsigned int b,c;
  for(b=0;b!= a; b++)for(c=0;c!= 50;c++);
  return;
 }

 volatile unsigned char prescale=0;
 volatile unsigned char sec=0;
 volatile unsigned char min_1=0;
 volatile unsigned char min_10=0;
 volatile unsigned char hour_1=0;
 volatile unsigned char hour_10=0;
 volatile unsigned char show_t=0;

 ISR(TIMER1_OVF_vect)
 {
  if(++prescale == 225){prescale = 0;sec++;};
  if(sec>59){min_1++;sec=0;};
  if(min_1>9){min_1=0;min_10++;};
  if(min_10>5){min_10=0;hour_1++;};
  if(hour_1>9){hour_1=0;hour_10++;};
  if(hour_10>1 && hour_1>3){hour_1=0;hour_10=0;};

  if(++show_t==4) show_t=0;
  switch(show_t)
  {
   case 0: //show minutes
    PORTC = 0x04;
    PORTD = (~segs[min_1]);
   break;
   case 1: //show 10 minutes
    PORTC = 0x08;
    PORTD = (~segs[min_10]);
   break;
   case 2: //show hours
    PORTC = 0x10;
    PORTD = (~segs[hour_1]) & ~_BV(_s_dot);
   break;
   case 3: //show 10hours
    PORTC = 0x20;
    PORTD = (~segs[hour_10]);
   break;
   default:
    show_t = 0;
   break;
  } 
  return; 
 }

 #define B1() (bit_is_clear(PINB,3))
 #define B2() (bit_is_clear(PINB,4))
 #define B_WAIT 300

 #define nop() asm volatile ("nop;")

 int main(void)
 {

  TIMSK = 0x04;
  TCCR1B = 0x01;

  DDRD = 0xFF;
  DDRC = 0x3F;
  DDRB = 0x00;
  PORTB = 0xFF;

  sei();
  while(1)
  {
   if(B1())
   {
    wait(_ms(B_WAIT));
    min_1++;
    sec=0;
   }
   if(B2())
   {
    wait(_ms(B_WAIT));
    hour_1++;
    sec=0;
   }
  }
 }

Sorry for the lack of comments. It was a really simple project, so I didn't need em. Enjoy!

Here is the project folder (source, hexfile) and the schematic in Eagle format:

Other implementations

Several people have made this clock or based their designs on my design. Most of them have not shared, but some have.

Radek Stybnar:

avr_clock_radek

OK1KVK implementation:

OLYMPUS DIGITAL CAMERA

MEKWEB also made a clock based on this design, though with a few improvements.

 

This entry was posted in Projects, Simple MCU stuff and tagged . Bookmark the permalink.

24 Responses to The AVR controlled clock

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.