PIC16F84A Alarm Clock
A simple alarm clock with programmable weekly alarms
A simple PIC16F84A alarm clock with programmable weekly alarms.
Overview
A simple PIC16F84A alarm clock. Counts seconds, minutes, hours and day of the week. Time displayed on 4 seven-segment LED displays, adjustable with three buttons (up, down, enter).
Programmable day, hour, minute and duration of alarms. Alarm output on RA4 open collector. Program is in BASIC (mikroBasic). Target: PIC16F84A, 16 MHz crystal.
Circuit Schematic
Basic Source Code
alarmClock.bas
'******************************************************************************
' PIC16F84A ALARM CLOCK
'******************************************************************************
'
' feel free to use this code at your own risks
'
' target : PIC16F84A, 16 Mhz crystal
' HS clock, no watchdog.
'
'******************************************************************************
program alarmClock
'
' if you are using COMMON CATHODE LED display, uncomment this definition.
' if you are using COMMON ANODE LED display, comment this definition.
'
'#define CATHODE_COMMUNE
symbol LUNDI = 0 ' monday
symbol MARDI = 1 ' thuesday
symbol MERCREDI = 2 ' wednesday
symbol JEUDI = 3 ' thursday
symbol VENDREDI = 4 ' friday
symbol SAMEDI = 5 ' saturday
symbol DIMANCHE = 6 ' sunday
symbol LMMJV = 7 ' from monday to friday included
'
' alarm definitions, to be changed on your needs
'
symbol NBALARM = 16 ' number of programmed alarms
const alarmTable as byte[NBALARM * 4] = (
' DAY HOUR MINUTE DURATION (in seconds, max is 59)
LUNDI, 8, 30, 10,
LUNDI, 12, 30, 10,
LUNDI, 14, 00, 10,
LUNDI, 16, 30, 10,
MARDI, 8, 30, 10,
MARDI, 12, 30, 10,
MARDI, 14, 00, 10,
MARDI, 16, 30, 10,
JEUDI, 8, 30, 10,
JEUDI, 12, 30, 10,
JEUDI, 14, 00, 10,
JEUDI, 16, 30, 10,
VENDREDI, 8, 30, 10,
VENDREDI, 12, 30, 10,
VENDREDI, 14, 00, 10,
VENDREDI, 16, 30, 10
)
dim maxcount as word ' number of TMR0 overflow per second
dim scaler as word ' RTC scaler
dim jj as byte ' day of week, 0 is monday
dim hh as byte ' hour
dim mn as byte ' min
dim ss as byte ' sec
dim digiled as byte[4] ' 4 x 7 segment table
dim digit as byte ' current digit to display
dim dp as byte ' decimal point
dim key as byte ' key code
dim alarm as byte ' alarm flag
'
' the ISR works as real time clock
'
sub procedure interrupt
dim i as byte
scaler = scaler + 1
if scaler > maxcount
then
scaler = 0
inc(ss)
if ss = 60
then
ss = 0
inc(mn)
if mn = 60
then
mn = 0
inc(hh)
if hh = 24
then
hh = 0
inc(jj)
if jj = 8
then
jj = 1
end if
end if
end if
end if
end if
' LED display
#ifdef CATHODE_COMMUNE
PORTA = PORTA and $f0
TRISA = $0f
key = PORTA
TRISA = 0
PORTB = 0
#else
PORTA = PORTA or $0f
TRISA = $0f
key = PORTA
key = not(key)
TRISA = 0
PORTB = $ff
#endif
key = key and $07
digit = digit + 1
if digit > 3
then
digit = 0
i = $01
else
i = $01 << digit
end if
#ifdef CATHODE_COMMUNE
PORTB = digiled[digit]
PORTA = PORTA or i
#else
PORTB = digiled[digit]
PORTB = not(PORTB)
PORTA = PORTA and not(i)
#endif
INTCON.T0IF = 0
end sub
' converts digit to 7 segment
sub function intTo7seg(dim n as byte) as byte
select case n
case 0 result = $3F
case 1 result = $06
case 2 result = $5B
case 3 result = $4F
case 4 result = $66
case 5 result = $6D
case 6 result = $7D
case 7 result = $07
case 8 result = $7F
case 9 result = $6F
end select
end sub
' select a value with keys
sub procedure setValue(dim v as ^byte, dim s as byte, dim max as byte)
digiled[0] = s
digiled[1] = 0
while 1
if key.0
then
inc(v^)
if(v^ > max)
then
v^ = 0
end if
end if
if key.1
then
if(v^ = 0)
then
v^ = max
else
dec(v^)
end if
end if
if key.2
then
Delay_ms(50)
while key.2
wend
Delay_ms(50)
scaler = 0
ss = 0
return
end if
digiled[2] = intTo7seg(v^ / 10)
digiled[3] = intTo7seg(v^ mod 10)
delay_ms(300)
wend
end sub
' program entry
main:
dim i as byte
dp = 0
hh = 0
mn = 0
ss = 0
jj = 0
maxcount = 15625
PORTA = %00010000
TRISA = %00000000
PORTB = 0
TRISB = $00
INTCON = %10100000
OPTION_REG = %11011000
Delay_ms(50)
' clock adjustment
setValue(@hh, 116, 23)
setValue(@mn, 55, 59)
setValue(@jj, 14, 6)
' forever loop
while true
if key
then
digiled[0] = intTo7seg(jj)
digiled[1] = 0
digiled[2] = intTo7seg(ss / 10)
digiled[3] = intTo7seg(ss mod 10)
else
if hh < 10
then
digiled[0] = 0
digiled[1] = intTo7seg(hh)
else
digiled[0] = intTo7seg(hh / 10)
digiled[1] = intTo7seg(hh mod 10)
end if
digiled[2] = intTo7seg(mn / 10)
digiled[3] = intTo7seg(mn mod 10)
end if
' blinks semicolon
if scaler > maxcount / 2
then
dp.1 = 1
else
dp.1 = 0
end if
digiled[0].7 = dp.0
digiled[1].7 = dp.1
digiled[2].7 = dp.2
digiled[3].7 = dp.3
' check for alarm condition
alarm = 0
for i = 0 to (NBALARM - 1) * 4
if ((alarmTable[i] = jj) or ((alarmTable[i] = LMMJV) and (jj < SAMEDI)))
and (alarmTable[i + 1] = hh)
and (alarmTable[i + 2] = mn)
and (alarmTable[i + 3] > ss)
then
inc(alarm)
end if
next i
if alarm
then
dp.3 = 1
PORTA.4 = 0
else
dp.3 = 0
PORTA.4 = 1
end if
wend
end.
Note
No separate project ZIP file was provided for this project. The source code above is the complete mikroBasic program — copy and paste it into your mikroBasic IDE to build the project.
Notes
- Can be built for common cathode or common anode LED display.
- The number of alarms is limited by ROM space only.
- The alarm table includes 16 programmable entries.