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;
}
}
}
#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/.