Digital Stopwatch

Printer-friendly versionPDF version

Digital Stopwatch from Priyank Bolia on Vimeo.

/* Interfacing multiple displays */

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

#define true 1
#define false 0

//Global variable for the clock system
volatile unsigned int   clock_millisecond=0;
volatile unsigned char  clock_second=0;

volatile unsigned char  clock_minute=0;
volatile unsigned char  clock_hour=0;

//Display hiding system
uint8_t hide_display = false;

//Blinking system
uint8_t blink_display = true;

volatile uint8_t digits[4];

void SevenSegment(uint8_t n, uint8_t dp)
{
  uint8_t symbols[]=
  {
    0x3F, 0x06, 0x5B, 0x4F, /* 0,1,2,3 */
    0x66, 0x6D, 0x7D, 0x07, /* 4,5,6,7 */
    0x7F, 0x6F, 0x77, 0x7F, /* 8,9,A,B */
    0x39, 0x3F, 0x79, 0x71, /* C,D,E,F */
    0x00                    /* BLANK   */
  };

  PORTA = symbols[n] | (dp << 7); /* obtain the one's digit and send to display */
}

void Print(uint16_t num)
{
  /*  
    This function breaks apart a given integer into separate digits
    and writes them to the display array i.e. digits[]  
  */


  uint8_t i=0;
  uint8_t j;
  if(num>9999) return;


  while(num)
  {
    digits[i]=num%10;
    i++;

    num=num/10;
  }

  //Fill with leading 0s
  for(j=i;j<4;j++) digits[j]=0;
}

int main()
{
  DDRA = 0xFF; /* Port A to send a symbol code to a display */
  DDRB = 0x0F; /* Port B for deciding which display is active */
  DDRC = 0x00;

  // Prescaler = FCPU/256
  TCCR0|=(1<<CS02)/*|(1<<CS00)*/;

  //Enable Overflow Interrupt Enable
  TIMSK|=(1<<TOIE0);

  //Initialize Counter
  TCNT0=0;

  //initailly stop the timer by setting clock source = 000
  TCCR1B&=(~((1<<CS12)|(1<<CS11)|(1<<CS10)));

  OCR1A=15;

  //Enable the Output Compare A interrupt
  TIMSK|=(1<<OCIE1A);

  sei(); // enable ALL interrupts

  //Stop blinking the display
  blink_display=false;

  //Show the display
  hide_display=false;

  TCCR1B=(1<<WGM12)|(1<<CS11)|(1<<CS10);

  //Continuasly display the time
  while(1)
  {
    int disp;
    disp=(clock_minute*100)+clock_second;
    //disp=(clock_hour*100)+clock_minute;
    if(!(PINC & (1<<PC1)))
    {
      //halt pressed

      //stop the timer
      TCCR1B&=(~((1<<CS12)|(1<<CS11)|(1<<CS10)));

      //Start blinking the display
      blink_display=true;
    }
    Print(disp);
  }
  return 0;
}

ISR(TIMER0_OVF_vect)
{
  /*
    This interrupt service routine (ISR)
    Updates the displays
  */

}

//The output compute interrupt handler
//We set up the timer in such a way that
//this ISR is called exactly at 1ms interval
ISR(TIMER1_COMPA_vect)
{
  clock_millisecond++;
  if(clock_millisecond % 4 == 0)
  {
    static uint8_t i = 0;
    switch(i)
    {
    case 0:
      PORTB = 0x01; /* turn on Display1 */
      SevenSegment(digits[0], 0);
      break;
    case 1:
      PORTB = 0x02; /* turn on Display2 */
      SevenSegment(digits[1], 0);
      break;
    case 2:
      PORTB = 0x04; /* turn on Display3 */
      SevenSegment(digits[2], 1);
      break;
    case 3:
      PORTB = 0x08; /* turn on Display4 */
      SevenSegment(digits[3], 0);
      break;
    };
    i++;
    if(i == 4)
      i = 0;
  }
  if(clock_millisecond==1000)
  {
    clock_second++;
    clock_millisecond=0;
    if(clock_second==60)
    {
      clock_minute++;
      clock_second=0;
    }
    if(clock_minute==60)
    {
      clock_hour++;
      clock_minute=0;
    }
  }
}

The above code sample is heavily based on the example taken from:
http://extremeelectronics.co.in/avr-projects/avr-project-digital-stop-watch-with-atmega8/, with slight modification to make it work on my development board, as the crystal frequency may be different (Guess so). Another interesting article that talks about multiplexed 7 segment displays is: http://extremeelectronics.co.in/avr-tutorials/multiplexed-seven-segment-displays/.

No votes yet