pasanlaksiri
03-03-2007, 08:45 PM
Dual Time Digital Alarm Clock
Features at a glance
Dual time (Standard time + another time - GMT)
Counts seconds, minutes, hours, day, date, month and year
Alarm
12 hour / 24 hour time format
Leap year correction valid up to 2100
http://aycu40.webshots.com/image/10439/2002595822128202705_rs.jpg
http://aycu13.webshots.com/image/10452/2002587071453083354_rs.jpg
http://aycu27.webshots.com/image/11386/2002596448896926065_rs.jpg
http://aycu01.webshots.com/image/11720/2002557608678829086_rs.jpg
http://aycu01.webshots.com/image/11720/2002504982648704595_rs.jpg
http://aycu38.webshots.com/image/11277/2002576489732961578_rs.jpg
http://aycu37.webshots.com/image/12436/2002542608981005265_rs.jpg
http://aycu09.webshots.com/image/10248/2002580657785029848_rs.jpg
http://aycu39.webshots.com/image/12878/2002584967172313425_rs.jpg
http://aycu24.webshots.com/image/10023/2002554831463919052_rs.jpg
http://aycu16.webshots.com/image/9775/2001821195554321427_rs.jpg
http://aycu16.webshots.com/image/9775/2001829545827807916_rs.jpg
This is the Program
#include <pic.h>
__CONFIG(WDTDIS & XT & UNPROTECT & PWRTEN & LVPDIS & BORDIS);
unsigned char check_key(volatile unsigned char *key);
void bin_to_bcd(unsigned char binary, unsigned char *bcd);
void set_time();
void show_alarm_time();
void start_beep();
void inc_day_date();
void time_to_24H();
void time_to_12H();
#define MIN_ON 12
#define MAX_ON 72
#define false 0
#define true 1
#define SW_COM RA5
#define ADJ_TIME 10 // Time out in sec for settings
#define COM_0 RA0
#define COM_1 RA1
#define COM_2 RA2
#define COM_3 RA3
#define COM_4 RA4
#define COM_5 RA5
#define ADJ_KEY sw_0_cnt
#define MODE_KEY sw_1_cnt
#define BEEP_COUNT 4 // PWM duty cycle value for "beep"
#define ALPHA_A 3
#define ALPHA_L 10
#define BLANK 11
#define ALPHA_H 12
#define HIPHON 13
static const unsigned char display_L[14] = {0x00, 0x09, 0x04, 0x00, 0x09, 0x02, 0x02, 0x08, 0x00, 0x00, 0x07, 0x0F, 0x09, 0x0F};
static const unsigned char display_H[14] = {0x80, 0xE0, 0x40, 0x60, 0x20, 0x20, 0x00, 0xE0, 0x00, 0x20, 0x80, 0xE0, 0x00, 0x60};
static const unsigned char day_display_L[7] = {0x01, 0x02, 0x04, 0x08, 0x00, 0x00, 0x00};
static const unsigned char day_display_H[7] = {0x00, 0x00, 0x00, 0x00, 0x20, 0x40, 0x80};
/* End of months Null,JAN,FEB,MAR,APR,MAY,JUN,JLY,AUG,SEP,OCT,NOV,D EC*/
static const unsigned char month_end[13] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static const unsigned char blink[3] = { 0xFE, 0xFD, 0xF3};
static const unsigned char digit3_L[4] = {0x0F, 0x09, 0x04, 0x08};
static const unsigned char digit3_H[4] = {0xE0, 0xE0, 0x40, 0x00};
static unsigned char digit[4];
static unsigned char count, i, j;
static volatile unsigned char sw_0_cnt[2], sw_1_cnt[2];
static unsigned char mode, cursor_digit, timer;
union{
unsigned char FLAG_C;
struct{
unsigned AM:1;
unsigned PM:1;
unsigned AL1:1;
unsigned AL2:1;
unsigned DO_NOT_USE:1;
unsigned COLON:1;
unsigned ST:1;
unsigned FREE_1:1;
}s_flag;
}u_flag;
// DO_NOT_USE because RC4 not connected to anywhere; it will make problems when flag load to PORTC
// AL2 is not implemented
#define flag u_flag.FLAG_C
#define FLAG u_flag.s_flag
static volatile unsigned char seconds, minutes, d_minutes, hours, d_hours, ticks, al_minutes, al_hours;
static volatile unsigned char year, month, date, day, end_of_month;
volatile bit hr_24, bit_24, setup, one_time, pm, d_pm, update, AL_ON, AL_START, SLEEP_STATE, al_pm, show_al;
main()
{
TRISB = 0xF0;
TRISA = 0x00; // RA0 - RA4 are O/Ps, RA5 - RA7 are I/Ps
TRISC = 0b00011011; // RC<0:1> used for Timer1 external crystal
CMCON = 0x07;
ADCON1 = 0x06; // All are digital I/P in PORTA
OPTION = 0b10000011; // Disable PORTB pull ups, set prescalaer to 1:16
T1CON = 0b00001111; // Timer1 1:1 prescale, Osc enabled, no sync,
// external clock source, Timer1 on
TMR1IF = 0; // Clear Timer1 Overflow interrupt flag
TMR1IE = 1; // Enable Timer1 Overflow interrupt
PORTA = 0x00;
PORTB = 0;
PORTC = 0;
TMR1H = 0x80; // Initialize Timer1 to 0x8000
TMR1L = 0x00;
INTCON = 0x68; // Pheripheral, TMR0, RB port change interrupts enabled
GIE = 1;
mode = 0;
setup = 0;
day = 0;
hr_24 = 0;
year = 5;
month = 1;
day = 1;
date = 1;
hours = 1;
d_hours = 1;
al_hours = 1;
pm = 0;
start_beep();
if(! (RB4 & RB5))
{
setup = 1;
cursor_digit = 0;
digit[2] = BLANK;
digit[3] = 0;
bin_to_bcd(year, digit);
while(setup)
{
if(check_key(ADJ_KEY))
digit[cursor_digit]++;
if(digit[0] > 9)
digit[0] = 0;
if(digit[1] > 9)
digit[1] = 0;
if(check_key(MODE_KEY))
cursor_digit ++;
if(cursor_digit > 1 || ticks > ADJ_TIME)
setup = 0;
}
year = digit[1] * 10 + digit[0];
}
while(1)
{
if((al_pm == pm) && (al_hours == hours) && (al_minutes == minutes))
{
if(AL_ON & FLAG.AL1)
{
AL_START = 1;
SLEEP_STATE = 0;
}
}
else
{
AL_ON = 1;
AL_START = 0;
}
if(!RB7)
{
if (SLEEP_STATE)
{
PORTA = 0x30;
RBIE = 1;
TRISB = TRISB = TRISC = 0xFF; //
SLEEP();
continue;
}
}
TRISB = 0xF0;
TRISA = 0x00; // RA0 - RA4 are O/Ps, RA5 - RA7 are I/Ps
TRISC = 0b00011011; // RC<0:1> used for Timer1 external crystal
if(ticks > 9)
{
SLEEP_STATE = 1;
}
if (update)
{
update = 0; // update in every seconds only or for a Mode key press
if(!show_al)
{
switch(mode)
{
case 0:
if(hr_24)
{
FLAG.PM = 0;
FLAG.AM = 0;
}
else
{
FLAG.PM = pm;
FLAG.AM = !pm;
}
FLAG.ST = 1; // we are now in standard time
bin_to_bcd (minutes, digit);
bin_to_bcd(hours, &digit[2]);
one_time = 1;
timer = 0;
break;
case 1:
FLAG.COLON = 1;
show_alarm_time();
break;
case 2:
FLAG.COLON = 1;
bin_to_bcd(date, digit);
bin_to_bcd(month, &digit[2]);
break;
case 3:
FLAG.ST = 0; // We are now in second time
if(hr_24)
{
FLAG.PM = 0;
FLAG.AM = 0;
}
else
{
FLAG.PM = d_pm;
FLAG.AM = ! d_pm;
}
bin_to_bcd(d_minutes, digit);
bin_to_bcd(d_hours, &digit[2]);
break;
case 4:
FLAG.COLON = 1;
digit[2] = BLANK;
digit[3] = 0;
bin_to_bcd(seconds, digit);
}
}
}
/************************************************** **************************************/
/* Setup Routines */
/* */
/************************************************** **************************************/
if(setup)
{
switch(mode)
{
case 0:
/* setting time */
set_time();
minutes = digit[1] * 10 + digit[0];
hours = digit[3] * 10 + digit[2];
pm = FLAG.PM;
/* Set time format 24 Hr of 12 Hr */
setup = 1;
cursor_digit = 4;
digit[0] = ALPHA_H;
digit[1] = BLANK;
while(setup)
{
if(check_key(ADJ_KEY))
{
if(hr_24)
{
hr_24 = 0;
time_to_12H();
}
else
{
hr_24 = 1;
time_to_24H();
pm = 0;
al_pm = 0;
}
}
if(hr_24)
{
digit[2] = 4;
digit[3] = 2;
}
else
{
digit[2] = 2;
digit[3] = 1;
}
if(check_key(MODE_KEY))
setup = 0;
}
break;
case 1:
/* set alarm time */
set_time();
al_minutes = digit[1] * 10 + digit[0];
al_hours = digit[3] * 10 + digit[2];
al_pm = FLAG.PM;
FLAG.COLON = 1;
break;
case 2:
/* set day, date and month */
FLAG.COLON = 1;
end_of_month = month_end[month];
if( (month == 2) && (year & 0x03))
end_of_month --; // Not a leap year (untill 2100, this calc will be true)
while(setup)
{
FLAG.COLON = 1;
if(check_key(MODE_KEY))
cursor_digit ++;
if(check_key(ADJ_KEY))
digit[cursor_digit]++;
date = digit[1] * 10 + digit[0];
if (date > end_of_month)
date = 1;
month = digit[3] *10 + digit[2];
if(month > 12)
month = 1;
bin_to_bcd(date, digit);
bin_to_bcd(month, &digit[2]);
if(cursor_digit > 2 || ticks > ADJ_TIME)
setup = 0;
}
setup = 1;
while(setup)
{
FLAG.COLON = 1;
if(check_key(ADJ_KEY))
day++;
if(day >6)
day = 0;
if(check_key(MODE_KEY) || ticks > ADJ_TIME)
setup = 0;
}
break;
case 3:
/* setting the second time*/
set_time();
d_minutes = digit[1] * 10 + digit[0];
d_hours = digit[3] * 10 + digit[2];
d_pm = FLAG.PM;
break;
case 4:
/* set seconds */
digit[2] = BLANK;
digit[3] = 0;
while(setup)
{
FLAG.COLON = 1;
bin_to_bcd(seconds, digit);
if(check_key(ADJ_KEY))
{
if(seconds > 29)
minutes++;
seconds = 0;
if(minutes > 59)
minutes = 0;
}
if(check_key(MODE_KEY) || ticks > 60)
setup = 0;
}
break;
}// End of setup
}
if(AL_START)
{
if(j < 4)
{
if (i & 0x20)
{
start_beep();
i = 0;
j++;
}
}
else
{
if(i > (32*6))
j = 0;
}
if(check_key(ADJ_KEY) | check_key(MODE_KEY))
{
AL_ON = 0;
AL_START = 0;
}
}
else if(!SLEEP_STATE)
{
if(MODE_KEY[0] & 0x80)
{
setup = 1;
start_beep();
cursor_digit = 0;
ticks = 0;
while(MODE_KEY[0] & 0x80);
}
if(check_key(MODE_KEY))
{
show_al = 0;
mode ++;
update = 1;
if (mode > 4)
mode = 0;
}
/* A short press of ADJ key will show alarm 01's set time */
if(check_key(ADJ_KEY))
{
one_time = 1;
timer = 0;
show_alarm_time();
show_al = 1;
}
if(timer & 0x80)
show_al = 0;
if(show_al)
show_alarm_time();
/* End of showing alarm time */
if(ADJ_KEY[0] & 0x80)
{
FLAG.AL1 = ! FLAG.AL1;
start_beep();
while(ADJ_KEY[0] & 0x80);
}
RC2 = 0;
}
}
}
void start_beep()
{
SLEEP_STATE = 0; // Don't let the PIC go to sleep
ticks = 0;
count = BEEP_COUNT *2; // Set count for length of beep
CCP1CON = 0x0F; // Set the CCP module to PWM
PR2 = 122; // Set the period to 2048Hz
// CCPR1L = 3; // Set the duty cycle very low
CCPR1L = 48;
T2CON = 0b01111101; // Enable Timer2
TMR2IF = 0; // Clear the Timer2 Interrupt flag
TMR2IE = 1; // Enable the Timer2 Interrupt
}
void time_to_24H()
{
/* Change format of time from 12 hr to 24 hour */
/* First standard time */
if(pm)
{
if (hours !=12)
{
hours = hours + 12;
}
}
else if(hours == 12)
{
hours = 0;
}
/* Now do it for the d time */
if(d_pm)
{
if (d_hours !=12)
{
d_hours = d_hours + 12;
}
}
else if(d_hours == 12)
{
d_hours = 0;
}
/* change format of Alarm time */
if(al_pm)
{
if (al_hours !=12)
{
al_hours = al_hours + 12;
}
}
else if(al_hours == 12)
{
al_hours = 0;
}
}
void time_to_12H()
{
/* Change format of time from 24 hours to 12 Hours */
/* first standard time */
if(hours > 12)
{
hours = hours - 12;
pm = 1;
}
if(hours == 12)
{
pm = 1;
}
if (hours == 0)
{
hours = 1;
}
/* Do the same for d time */
if(d_hours > 12)
{
d_hours = d_hours - 12;
d_pm = 1;
}
if(d_hours == 12)
{
d_pm = 1;
}
if (d_hours == 0)
{
d_hours = 1;
}
/* Alarm time */
if(al_hours > 12)
{
al_hours = al_hours - 12;
al_pm = 1;
}
if(al_hours == 12)
{
al_pm = 1;
}
if (al_hours == 0)
{
al_hours = 1;
}
}
void set_time()
{
while(setup)
{
if(check_key(MODE_KEY))
cursor_digit++;
if(check_key(ADJ_KEY))
{
digit[cursor_digit]++;
if(digit[0] > 9)
digit[0] = 0;
if(digit[1] > 5)
digit[1] = 0;
if(digit[2] > 9)
{
digit[2] = 0;
digit[3] ++;
}
if( hr_24)
{
if(digit[3] > 1)
{
if(digit[2] > 3)
{
digit[3] = digit[2] = 0;
}
}
}
else
{
if(digit[3] > 0)
{
if(digit[2] > 2)
{
digit[2] = 1;
digit[3] = 0;
}
if(digit[2] == 2)
{
FLAG.AM = FLAG.PM;
FLAG.PM = !FLAG.PM;
}
}
}
}
if(cursor_digit > 2 || ticks > ADJ_TIME)
setup = 0;
}
}
void bin_to_bcd(unsigned char binary, unsigned char *bcd)
{
unsigned char count = 0;
for( ;binary > 9; binary = binary - 10)
{
count ++;
}
bcd[0] = binary;
bcd[1] = count;
}
void show_alarm_time()
{
if(hr_24)
{
FLAG.PM = FLAG.AM = 0;
}
else
{
FLAG.PM = al_pm;
FLAG.AM = !al_pm;
}
if(one_time)
{
update = 1;
digit[0] = digit[1] = BLANK;
digit[2] = ALPHA_L;
digit[3] = ALPHA_A;
if(timer & 0x40)
one_time = 0;
}
else
{
bin_to_bcd(al_minutes, digit);
bin_to_bcd(al_hours, &digit[2]);
}
}
unsigned char check_key(volatile unsigned char *key)
{
//key[0] = current, key[1] = old
static unsigned char temp;
temp = key[1];
// key[1] = key[0]; // Copy current --> Old
if ( key[0] < key[1])
{
key[1] = key[0];
if (temp < MIN_ON)
{
// key pressed less than MIN_ON time
return false;
}
else if (temp > MAX_ON)
{
return false;
}
else
{
ticks = 0;
start_beep();
return true;
}
}
key[1] = key[0];
return false;
}
void inc_day_date()
{
end_of_month = month_end[month];
if( (month == 2) && (year & 0x03))
end_of_month --; // Not a leap year
day++;
date++;
if(day >6)
day = 0;
if(date > end_of_month)
{
date = 1;
month ++;
}
if(month > 12)
{
month = 1;
year ++;
}
}
void interrupt disp()
{
static unsigned char digit_count, temp;
if(T0IF) // Interrupts on every 4.096 mS
{
i ++;
digit_count ++;
if(digit_count > 5)
{
digit_count = 0;
}
PORTB &= 0xF0;
PORTC &= PORTC & 0x1F;
/* Scan keys */
if(sw_0_cnt[0] < 0xFF)
sw_0_cnt[0] ++;
if(RB4)
sw_0_cnt[0] = 0;
if(sw_1_cnt[0] < 0xFF)
sw_1_cnt[0] ++;
if(RB5)
sw_1_cnt[0] = 0;
switch(digit_count)
{
case 0:
COM_5 = 1; // Disable COM 5
PORTB |= display_L[digit[0]];
PORTC |= display_H[digit[0]];
COM_0 = 1; // Enable COM_0
break;
case 1:
COM_0 = 0;
PORTB |= display_L[digit[1]];
PORTC |= display_H[digit[1]];
COM_1 = 1;
break;
case 2:
COM_1 = 0;
PORTB |= display_L[digit[2]];
PORTC |= display_H[digit[2]];
COM_2 = 1;
break;
case 3:
COM_2 = 0;
PORTB |= digit3_L[digit[3]];
PORTC |= PORTC | digit3_H[digit[3]];
COM_3 = 1;
break;
case 4:
/* COM_4 and COM_5 wired as commom cathode */
COM_3 = 0; // Disable COM_3
PORTB |= day_display_L[day];
PORTC |= day_display_H[day];
COM_4 = 0; // Enable COM_4
timer ++;
break;
case 5:
/* COM_4 and COM_5 wired as commom cathode */
COM_4 = 1; // Disable COM_4
PORTB |= flag;
PORTC |= flag;
COM_5 = 0; // Enable COM_5
}
if (setup && (timer &0x10))
{
/* in setup blink the correspondig digit */
if(cursor_digit == 3)
COM_4 = 1;
else if(cursor_digit == 4)
COM_5 = 1;
else
PORTA &= blink[cursor_digit];
}
T0IF = 0; // Enable TMR0 interrupt
}
if(RBIF) // Port change interrupt
{
SLEEP_STATE = 0;
ticks = 0;
temp = PORTB;
RBIF = 0;
}
if(TMR2IF && TMR2IE) // Timer2 Overflow used for beep
{
if(TMR2IE) // If Timer2 interrupt is enabled
{
count--; // Decrement count
if(!count) // If count has reached zero
{
CCP1CON = 0; // Disable CCP module
T2CON = 0; // Disable Timer2
CCPR1L = 0; // Clear the Duty Cycle
TMR2IE = 0; // Disable Timer2 Interrupt
// SLEEP_STATE = 1; // Enable PIC to SLEEP
}
}
TMR2IF = 0; // Clear Timer2 interrupt flag
}
if(TMR1IF) // Timer1 Overflow, once every sec
{
seconds++; // Increment seconds
if(seconds > 59) // check for seconds overflow
{
seconds = 0;
minutes++;
d_minutes ++; // inc the d time minutes
if(minutes > 59) // check for hours overflow
{
minutes = 0;
hours ++; // increment hours
if(hr_24)
{
if(hours >23)
{
hours = 0;
inc_day_date();
}
}
else
{
if(hours == 12)
{
if(pm)
{
inc_day_date();
}
pm = ! pm;
}
if(hours > 12)
{
hours = 1;
}
}
}
// Next, update the d time
if(d_minutes > 59) // check for d_hours overflow
{
d_minutes = 0;
d_hours ++; // increment d_hours
if(hr_24)
{
if(d_hours >23)
{
d_hours = 0;
}
}
else
{
if(d_hours == 12)
{
d_pm = ! d_pm;
}
if(d_hours > 12)
{
d_hours = 1;
}
}
}// end of updating d time
}
TMR1H |= 0x80; // Set Timer1 to 0x8000 + current time
FLAG.COLON = !FLAG.COLON; // Toggle the colon
ticks++; // increment ticks, used for timeout
TMR1IF = 0; // Clear Timer1 interrupt flag
update = 1;
}
}
Features at a glance
Dual time (Standard time + another time - GMT)
Counts seconds, minutes, hours, day, date, month and year
Alarm
12 hour / 24 hour time format
Leap year correction valid up to 2100
http://aycu40.webshots.com/image/10439/2002595822128202705_rs.jpg
http://aycu13.webshots.com/image/10452/2002587071453083354_rs.jpg
http://aycu27.webshots.com/image/11386/2002596448896926065_rs.jpg
http://aycu01.webshots.com/image/11720/2002557608678829086_rs.jpg
http://aycu01.webshots.com/image/11720/2002504982648704595_rs.jpg
http://aycu38.webshots.com/image/11277/2002576489732961578_rs.jpg
http://aycu37.webshots.com/image/12436/2002542608981005265_rs.jpg
http://aycu09.webshots.com/image/10248/2002580657785029848_rs.jpg
http://aycu39.webshots.com/image/12878/2002584967172313425_rs.jpg
http://aycu24.webshots.com/image/10023/2002554831463919052_rs.jpg
http://aycu16.webshots.com/image/9775/2001821195554321427_rs.jpg
http://aycu16.webshots.com/image/9775/2001829545827807916_rs.jpg
This is the Program
#include <pic.h>
__CONFIG(WDTDIS & XT & UNPROTECT & PWRTEN & LVPDIS & BORDIS);
unsigned char check_key(volatile unsigned char *key);
void bin_to_bcd(unsigned char binary, unsigned char *bcd);
void set_time();
void show_alarm_time();
void start_beep();
void inc_day_date();
void time_to_24H();
void time_to_12H();
#define MIN_ON 12
#define MAX_ON 72
#define false 0
#define true 1
#define SW_COM RA5
#define ADJ_TIME 10 // Time out in sec for settings
#define COM_0 RA0
#define COM_1 RA1
#define COM_2 RA2
#define COM_3 RA3
#define COM_4 RA4
#define COM_5 RA5
#define ADJ_KEY sw_0_cnt
#define MODE_KEY sw_1_cnt
#define BEEP_COUNT 4 // PWM duty cycle value for "beep"
#define ALPHA_A 3
#define ALPHA_L 10
#define BLANK 11
#define ALPHA_H 12
#define HIPHON 13
static const unsigned char display_L[14] = {0x00, 0x09, 0x04, 0x00, 0x09, 0x02, 0x02, 0x08, 0x00, 0x00, 0x07, 0x0F, 0x09, 0x0F};
static const unsigned char display_H[14] = {0x80, 0xE0, 0x40, 0x60, 0x20, 0x20, 0x00, 0xE0, 0x00, 0x20, 0x80, 0xE0, 0x00, 0x60};
static const unsigned char day_display_L[7] = {0x01, 0x02, 0x04, 0x08, 0x00, 0x00, 0x00};
static const unsigned char day_display_H[7] = {0x00, 0x00, 0x00, 0x00, 0x20, 0x40, 0x80};
/* End of months Null,JAN,FEB,MAR,APR,MAY,JUN,JLY,AUG,SEP,OCT,NOV,D EC*/
static const unsigned char month_end[13] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static const unsigned char blink[3] = { 0xFE, 0xFD, 0xF3};
static const unsigned char digit3_L[4] = {0x0F, 0x09, 0x04, 0x08};
static const unsigned char digit3_H[4] = {0xE0, 0xE0, 0x40, 0x00};
static unsigned char digit[4];
static unsigned char count, i, j;
static volatile unsigned char sw_0_cnt[2], sw_1_cnt[2];
static unsigned char mode, cursor_digit, timer;
union{
unsigned char FLAG_C;
struct{
unsigned AM:1;
unsigned PM:1;
unsigned AL1:1;
unsigned AL2:1;
unsigned DO_NOT_USE:1;
unsigned COLON:1;
unsigned ST:1;
unsigned FREE_1:1;
}s_flag;
}u_flag;
// DO_NOT_USE because RC4 not connected to anywhere; it will make problems when flag load to PORTC
// AL2 is not implemented
#define flag u_flag.FLAG_C
#define FLAG u_flag.s_flag
static volatile unsigned char seconds, minutes, d_minutes, hours, d_hours, ticks, al_minutes, al_hours;
static volatile unsigned char year, month, date, day, end_of_month;
volatile bit hr_24, bit_24, setup, one_time, pm, d_pm, update, AL_ON, AL_START, SLEEP_STATE, al_pm, show_al;
main()
{
TRISB = 0xF0;
TRISA = 0x00; // RA0 - RA4 are O/Ps, RA5 - RA7 are I/Ps
TRISC = 0b00011011; // RC<0:1> used for Timer1 external crystal
CMCON = 0x07;
ADCON1 = 0x06; // All are digital I/P in PORTA
OPTION = 0b10000011; // Disable PORTB pull ups, set prescalaer to 1:16
T1CON = 0b00001111; // Timer1 1:1 prescale, Osc enabled, no sync,
// external clock source, Timer1 on
TMR1IF = 0; // Clear Timer1 Overflow interrupt flag
TMR1IE = 1; // Enable Timer1 Overflow interrupt
PORTA = 0x00;
PORTB = 0;
PORTC = 0;
TMR1H = 0x80; // Initialize Timer1 to 0x8000
TMR1L = 0x00;
INTCON = 0x68; // Pheripheral, TMR0, RB port change interrupts enabled
GIE = 1;
mode = 0;
setup = 0;
day = 0;
hr_24 = 0;
year = 5;
month = 1;
day = 1;
date = 1;
hours = 1;
d_hours = 1;
al_hours = 1;
pm = 0;
start_beep();
if(! (RB4 & RB5))
{
setup = 1;
cursor_digit = 0;
digit[2] = BLANK;
digit[3] = 0;
bin_to_bcd(year, digit);
while(setup)
{
if(check_key(ADJ_KEY))
digit[cursor_digit]++;
if(digit[0] > 9)
digit[0] = 0;
if(digit[1] > 9)
digit[1] = 0;
if(check_key(MODE_KEY))
cursor_digit ++;
if(cursor_digit > 1 || ticks > ADJ_TIME)
setup = 0;
}
year = digit[1] * 10 + digit[0];
}
while(1)
{
if((al_pm == pm) && (al_hours == hours) && (al_minutes == minutes))
{
if(AL_ON & FLAG.AL1)
{
AL_START = 1;
SLEEP_STATE = 0;
}
}
else
{
AL_ON = 1;
AL_START = 0;
}
if(!RB7)
{
if (SLEEP_STATE)
{
PORTA = 0x30;
RBIE = 1;
TRISB = TRISB = TRISC = 0xFF; //
SLEEP();
continue;
}
}
TRISB = 0xF0;
TRISA = 0x00; // RA0 - RA4 are O/Ps, RA5 - RA7 are I/Ps
TRISC = 0b00011011; // RC<0:1> used for Timer1 external crystal
if(ticks > 9)
{
SLEEP_STATE = 1;
}
if (update)
{
update = 0; // update in every seconds only or for a Mode key press
if(!show_al)
{
switch(mode)
{
case 0:
if(hr_24)
{
FLAG.PM = 0;
FLAG.AM = 0;
}
else
{
FLAG.PM = pm;
FLAG.AM = !pm;
}
FLAG.ST = 1; // we are now in standard time
bin_to_bcd (minutes, digit);
bin_to_bcd(hours, &digit[2]);
one_time = 1;
timer = 0;
break;
case 1:
FLAG.COLON = 1;
show_alarm_time();
break;
case 2:
FLAG.COLON = 1;
bin_to_bcd(date, digit);
bin_to_bcd(month, &digit[2]);
break;
case 3:
FLAG.ST = 0; // We are now in second time
if(hr_24)
{
FLAG.PM = 0;
FLAG.AM = 0;
}
else
{
FLAG.PM = d_pm;
FLAG.AM = ! d_pm;
}
bin_to_bcd(d_minutes, digit);
bin_to_bcd(d_hours, &digit[2]);
break;
case 4:
FLAG.COLON = 1;
digit[2] = BLANK;
digit[3] = 0;
bin_to_bcd(seconds, digit);
}
}
}
/************************************************** **************************************/
/* Setup Routines */
/* */
/************************************************** **************************************/
if(setup)
{
switch(mode)
{
case 0:
/* setting time */
set_time();
minutes = digit[1] * 10 + digit[0];
hours = digit[3] * 10 + digit[2];
pm = FLAG.PM;
/* Set time format 24 Hr of 12 Hr */
setup = 1;
cursor_digit = 4;
digit[0] = ALPHA_H;
digit[1] = BLANK;
while(setup)
{
if(check_key(ADJ_KEY))
{
if(hr_24)
{
hr_24 = 0;
time_to_12H();
}
else
{
hr_24 = 1;
time_to_24H();
pm = 0;
al_pm = 0;
}
}
if(hr_24)
{
digit[2] = 4;
digit[3] = 2;
}
else
{
digit[2] = 2;
digit[3] = 1;
}
if(check_key(MODE_KEY))
setup = 0;
}
break;
case 1:
/* set alarm time */
set_time();
al_minutes = digit[1] * 10 + digit[0];
al_hours = digit[3] * 10 + digit[2];
al_pm = FLAG.PM;
FLAG.COLON = 1;
break;
case 2:
/* set day, date and month */
FLAG.COLON = 1;
end_of_month = month_end[month];
if( (month == 2) && (year & 0x03))
end_of_month --; // Not a leap year (untill 2100, this calc will be true)
while(setup)
{
FLAG.COLON = 1;
if(check_key(MODE_KEY))
cursor_digit ++;
if(check_key(ADJ_KEY))
digit[cursor_digit]++;
date = digit[1] * 10 + digit[0];
if (date > end_of_month)
date = 1;
month = digit[3] *10 + digit[2];
if(month > 12)
month = 1;
bin_to_bcd(date, digit);
bin_to_bcd(month, &digit[2]);
if(cursor_digit > 2 || ticks > ADJ_TIME)
setup = 0;
}
setup = 1;
while(setup)
{
FLAG.COLON = 1;
if(check_key(ADJ_KEY))
day++;
if(day >6)
day = 0;
if(check_key(MODE_KEY) || ticks > ADJ_TIME)
setup = 0;
}
break;
case 3:
/* setting the second time*/
set_time();
d_minutes = digit[1] * 10 + digit[0];
d_hours = digit[3] * 10 + digit[2];
d_pm = FLAG.PM;
break;
case 4:
/* set seconds */
digit[2] = BLANK;
digit[3] = 0;
while(setup)
{
FLAG.COLON = 1;
bin_to_bcd(seconds, digit);
if(check_key(ADJ_KEY))
{
if(seconds > 29)
minutes++;
seconds = 0;
if(minutes > 59)
minutes = 0;
}
if(check_key(MODE_KEY) || ticks > 60)
setup = 0;
}
break;
}// End of setup
}
if(AL_START)
{
if(j < 4)
{
if (i & 0x20)
{
start_beep();
i = 0;
j++;
}
}
else
{
if(i > (32*6))
j = 0;
}
if(check_key(ADJ_KEY) | check_key(MODE_KEY))
{
AL_ON = 0;
AL_START = 0;
}
}
else if(!SLEEP_STATE)
{
if(MODE_KEY[0] & 0x80)
{
setup = 1;
start_beep();
cursor_digit = 0;
ticks = 0;
while(MODE_KEY[0] & 0x80);
}
if(check_key(MODE_KEY))
{
show_al = 0;
mode ++;
update = 1;
if (mode > 4)
mode = 0;
}
/* A short press of ADJ key will show alarm 01's set time */
if(check_key(ADJ_KEY))
{
one_time = 1;
timer = 0;
show_alarm_time();
show_al = 1;
}
if(timer & 0x80)
show_al = 0;
if(show_al)
show_alarm_time();
/* End of showing alarm time */
if(ADJ_KEY[0] & 0x80)
{
FLAG.AL1 = ! FLAG.AL1;
start_beep();
while(ADJ_KEY[0] & 0x80);
}
RC2 = 0;
}
}
}
void start_beep()
{
SLEEP_STATE = 0; // Don't let the PIC go to sleep
ticks = 0;
count = BEEP_COUNT *2; // Set count for length of beep
CCP1CON = 0x0F; // Set the CCP module to PWM
PR2 = 122; // Set the period to 2048Hz
// CCPR1L = 3; // Set the duty cycle very low
CCPR1L = 48;
T2CON = 0b01111101; // Enable Timer2
TMR2IF = 0; // Clear the Timer2 Interrupt flag
TMR2IE = 1; // Enable the Timer2 Interrupt
}
void time_to_24H()
{
/* Change format of time from 12 hr to 24 hour */
/* First standard time */
if(pm)
{
if (hours !=12)
{
hours = hours + 12;
}
}
else if(hours == 12)
{
hours = 0;
}
/* Now do it for the d time */
if(d_pm)
{
if (d_hours !=12)
{
d_hours = d_hours + 12;
}
}
else if(d_hours == 12)
{
d_hours = 0;
}
/* change format of Alarm time */
if(al_pm)
{
if (al_hours !=12)
{
al_hours = al_hours + 12;
}
}
else if(al_hours == 12)
{
al_hours = 0;
}
}
void time_to_12H()
{
/* Change format of time from 24 hours to 12 Hours */
/* first standard time */
if(hours > 12)
{
hours = hours - 12;
pm = 1;
}
if(hours == 12)
{
pm = 1;
}
if (hours == 0)
{
hours = 1;
}
/* Do the same for d time */
if(d_hours > 12)
{
d_hours = d_hours - 12;
d_pm = 1;
}
if(d_hours == 12)
{
d_pm = 1;
}
if (d_hours == 0)
{
d_hours = 1;
}
/* Alarm time */
if(al_hours > 12)
{
al_hours = al_hours - 12;
al_pm = 1;
}
if(al_hours == 12)
{
al_pm = 1;
}
if (al_hours == 0)
{
al_hours = 1;
}
}
void set_time()
{
while(setup)
{
if(check_key(MODE_KEY))
cursor_digit++;
if(check_key(ADJ_KEY))
{
digit[cursor_digit]++;
if(digit[0] > 9)
digit[0] = 0;
if(digit[1] > 5)
digit[1] = 0;
if(digit[2] > 9)
{
digit[2] = 0;
digit[3] ++;
}
if( hr_24)
{
if(digit[3] > 1)
{
if(digit[2] > 3)
{
digit[3] = digit[2] = 0;
}
}
}
else
{
if(digit[3] > 0)
{
if(digit[2] > 2)
{
digit[2] = 1;
digit[3] = 0;
}
if(digit[2] == 2)
{
FLAG.AM = FLAG.PM;
FLAG.PM = !FLAG.PM;
}
}
}
}
if(cursor_digit > 2 || ticks > ADJ_TIME)
setup = 0;
}
}
void bin_to_bcd(unsigned char binary, unsigned char *bcd)
{
unsigned char count = 0;
for( ;binary > 9; binary = binary - 10)
{
count ++;
}
bcd[0] = binary;
bcd[1] = count;
}
void show_alarm_time()
{
if(hr_24)
{
FLAG.PM = FLAG.AM = 0;
}
else
{
FLAG.PM = al_pm;
FLAG.AM = !al_pm;
}
if(one_time)
{
update = 1;
digit[0] = digit[1] = BLANK;
digit[2] = ALPHA_L;
digit[3] = ALPHA_A;
if(timer & 0x40)
one_time = 0;
}
else
{
bin_to_bcd(al_minutes, digit);
bin_to_bcd(al_hours, &digit[2]);
}
}
unsigned char check_key(volatile unsigned char *key)
{
//key[0] = current, key[1] = old
static unsigned char temp;
temp = key[1];
// key[1] = key[0]; // Copy current --> Old
if ( key[0] < key[1])
{
key[1] = key[0];
if (temp < MIN_ON)
{
// key pressed less than MIN_ON time
return false;
}
else if (temp > MAX_ON)
{
return false;
}
else
{
ticks = 0;
start_beep();
return true;
}
}
key[1] = key[0];
return false;
}
void inc_day_date()
{
end_of_month = month_end[month];
if( (month == 2) && (year & 0x03))
end_of_month --; // Not a leap year
day++;
date++;
if(day >6)
day = 0;
if(date > end_of_month)
{
date = 1;
month ++;
}
if(month > 12)
{
month = 1;
year ++;
}
}
void interrupt disp()
{
static unsigned char digit_count, temp;
if(T0IF) // Interrupts on every 4.096 mS
{
i ++;
digit_count ++;
if(digit_count > 5)
{
digit_count = 0;
}
PORTB &= 0xF0;
PORTC &= PORTC & 0x1F;
/* Scan keys */
if(sw_0_cnt[0] < 0xFF)
sw_0_cnt[0] ++;
if(RB4)
sw_0_cnt[0] = 0;
if(sw_1_cnt[0] < 0xFF)
sw_1_cnt[0] ++;
if(RB5)
sw_1_cnt[0] = 0;
switch(digit_count)
{
case 0:
COM_5 = 1; // Disable COM 5
PORTB |= display_L[digit[0]];
PORTC |= display_H[digit[0]];
COM_0 = 1; // Enable COM_0
break;
case 1:
COM_0 = 0;
PORTB |= display_L[digit[1]];
PORTC |= display_H[digit[1]];
COM_1 = 1;
break;
case 2:
COM_1 = 0;
PORTB |= display_L[digit[2]];
PORTC |= display_H[digit[2]];
COM_2 = 1;
break;
case 3:
COM_2 = 0;
PORTB |= digit3_L[digit[3]];
PORTC |= PORTC | digit3_H[digit[3]];
COM_3 = 1;
break;
case 4:
/* COM_4 and COM_5 wired as commom cathode */
COM_3 = 0; // Disable COM_3
PORTB |= day_display_L[day];
PORTC |= day_display_H[day];
COM_4 = 0; // Enable COM_4
timer ++;
break;
case 5:
/* COM_4 and COM_5 wired as commom cathode */
COM_4 = 1; // Disable COM_4
PORTB |= flag;
PORTC |= flag;
COM_5 = 0; // Enable COM_5
}
if (setup && (timer &0x10))
{
/* in setup blink the correspondig digit */
if(cursor_digit == 3)
COM_4 = 1;
else if(cursor_digit == 4)
COM_5 = 1;
else
PORTA &= blink[cursor_digit];
}
T0IF = 0; // Enable TMR0 interrupt
}
if(RBIF) // Port change interrupt
{
SLEEP_STATE = 0;
ticks = 0;
temp = PORTB;
RBIF = 0;
}
if(TMR2IF && TMR2IE) // Timer2 Overflow used for beep
{
if(TMR2IE) // If Timer2 interrupt is enabled
{
count--; // Decrement count
if(!count) // If count has reached zero
{
CCP1CON = 0; // Disable CCP module
T2CON = 0; // Disable Timer2
CCPR1L = 0; // Clear the Duty Cycle
TMR2IE = 0; // Disable Timer2 Interrupt
// SLEEP_STATE = 1; // Enable PIC to SLEEP
}
}
TMR2IF = 0; // Clear Timer2 interrupt flag
}
if(TMR1IF) // Timer1 Overflow, once every sec
{
seconds++; // Increment seconds
if(seconds > 59) // check for seconds overflow
{
seconds = 0;
minutes++;
d_minutes ++; // inc the d time minutes
if(minutes > 59) // check for hours overflow
{
minutes = 0;
hours ++; // increment hours
if(hr_24)
{
if(hours >23)
{
hours = 0;
inc_day_date();
}
}
else
{
if(hours == 12)
{
if(pm)
{
inc_day_date();
}
pm = ! pm;
}
if(hours > 12)
{
hours = 1;
}
}
}
// Next, update the d time
if(d_minutes > 59) // check for d_hours overflow
{
d_minutes = 0;
d_hours ++; // increment d_hours
if(hr_24)
{
if(d_hours >23)
{
d_hours = 0;
}
}
else
{
if(d_hours == 12)
{
d_pm = ! d_pm;
}
if(d_hours > 12)
{
d_hours = 1;
}
}
}// end of updating d time
}
TMR1H |= 0x80; // Set Timer1 to 0x8000 + current time
FLAG.COLON = !FLAG.COLON; // Toggle the colon
ticks++; // increment ticks, used for timeout
TMR1IF = 0; // Clear Timer1 interrupt flag
update = 1;
}
}