The Picaxe LED Guitar clock is based on a Picaxe 20M2 microcontroller and DS3231 Real Time Clock chip. It reads the time stored in the RTC and display it on a 7 segment display made up of individual LEDs. The project makes use of 6 74HC595 serial to parallel shift registers to save on I/O pins, one for each 7 segment digit. The entire circuit is housed inside an acoustic guitar casing. It has 3 push button switches, one to enter time set mode, and the other two for incrementing, decrementing the hours/minutes/seconds. The clock also has an AM/PM LED indicator.
View attachment 18222View attachment 18223
Code:
init: pause 500
setfreq m32
i2cslave %11010000, i2cslow, i2cbyte 'Set slave address for DS3231 module
pause 40
'#########Create symbols for 74HC595 Data, Clock and Latch pins
symbol sclk=c.1
symbol latch=c.3
symbol sdata=c.2
'#########Initialize Variables
symbol bitcounter = b1
symbol outbit = b2
symbol outbyte = b3
symbol counter = b4
symbol seconds = b5
symbol mins = b6
symbol hour = b7
symbol hour12=b8
symbol ampm_bit=b9
symbol digout = b10
symbol bcdmin=b11
symbol bcdmax=b12
symbol bcdnum=b13
symbol work=b20
symbol timesetledflash=b21
symbol temp=b22
'#######Create symbols for time setting buttons
symbol setbutton=pinc.0
symbol incbutton=pinb.4
symbol decbutton=pinb.3
symbol up=0
symbol down=1
'##########Set MR LOW and OE HIGH on 74HC595 Shift Register
symbol MR=c.5
symbol OE=c.4
high MR
low OE
'#############Ensure Data CLK, Data-In and Latch pins are initially low
low sclk
low sdata
low latch
'#############Main Loop
MAIN:
do
if setbutton=down then
gosub settime
else
gosub displaytime
endif
loop
SETTIME:
high c.7 '###########Time Set LED indicator
for timesetledflash = 1 to 5
high c.4
high b.2
pause 1000
low c.4
low b.2
pause 1000
next timesetledflash
do while setbutton=down loop
readi2c 0,(seconds,mins,hour)
gosub displaytime
gosub sethour
gosub setmins
gosub setseconds
gosub setampm
low c.7
do while setbutton=down loop
return
'############Subprocedure for setting the hour
SETHOUR:
do while setbutton=down loop
bcdmax=$12:bcdmin=$01
do
if incbutton=down then
bcdnum=hour & $1F
gosub bcdinc
temp = hour & $20
if temp = 32 then
hour=bcdnum | %01100000
else
hour=bcdnum | %01000000
endif
writei2c 2,(hour)
do while incbutton=down loop
endif
if decbutton=down then
bcdnum=hour & $1F
gosub bcddec
temp = hour & $20
if temp = 32 then
hour=bcdnum | %01100000
else
hour=bcdnum | %01000000
endif
writei2c 2,(hour)
do while decbutton=down loop
endif
gosub displaytime
if setbutton=down then exit
loop
return
'############Subprocedure for setting the minutes
SETMINS:
do while setbutton=down loop
bcdmax=$59:bcdmin=$00
do
if incbutton=down then
bcdnum=mins
gosub bcdinc
mins=bcdnum
writei2c 1, (mins)
do while incbutton=down loop
endif
if decbutton=down then
bcdnum=mins
gosub bcddec
mins=bcdnum
writei2c 1, (mins)
do while decbutton=down loop
endif
gosub displaytime
if setbutton=down then exit
loop
return
'############Subprocedure for setting the seconds
SETSECONDS:
do while setbutton=down loop
bcdmax=$59:bcdmin=$00
do
if incbutton=down then
bcdnum=seconds
gosub bcdinc
seconds=bcdnum
writei2c 0,(seconds)
do while incbutton=down loop
endif
if decbutton=down then
bcdnum=seconds
gosub bcddec
seconds=bcdnum
writei2c 0, (seconds)
do while decbutton=down loop
endif
gosub displaytime
if setbutton=down then exit
loop
return
'############Subprocedure for setting AM/PM
SETAMPM:
do while setbutton=down loop
bcdmax=$01:bcdmin=$00
do
if incbutton=down then
bcdnum=hour & $20 /32
gosub bcdinc
bcdnum=bcdnum * 32
hour=hour & $DF | bcdnum
hour=hour | %01000000
writei2c 2,(hour)
do while incbutton=down loop
endif
if decbutton=down then
bcdnum=hour & $20 /32
gosub bcdinc
bcdnum=bcdnum * 32
hour=hour & $DF | bcdnum
hour=hour | %01000000
writei2c 2,(hour)
do while decbutton=down loop
endif
gosub displaytime
if setbutton=down then exit
loop
return
'############Subprocedure for incrementing values in Time Set mode
BCDINC:
bcdnum=bcdnum+1
work=bcdnum & $0F
if work=10 then
bcdnum=bcdnum+6
endif
if bcdnum > bcdmax then
bcdnum=bcdmin
endif
return
'############Subprocedure for decrementing values in Time Set mode
BCDDEC:
if bcdnum=bcdmin then
bcdnum=bcdmax
else
bcdnum=bcdnum -1
work = bcdnum & $0F
if work >= $0F then
bcdnum=bcdnum - 6
endif
endif
return
'############Output time to 7 Segment displays
DISPLAYTIME:
readi2c 0,(seconds, mins, hour)
gosub CONVERT_TO_12HOUR
gosub CHECK_AM_PM
'###########Convert BCD values to ASCII
bcdtoascii seconds,b14,b15 'SECONDS
bcdtoascii mins,b16,b17 'MINS
bcdtoascii hour12,b18,b19 'HOURS
'###########Convert ASCII values to Characters
b14=b14 - $30
b15=b15 - $30
b16=b16 - $30
b17=b17 - $30
b18=b18 - $30
b19=b19 - $30
'############Pass decimal digit values to Shift Subroutine
digout = b15
gosub shift595
digout = b14
gosub shift595
digout = b17
gosub shift595
digout = b16
gosub shift595
digout = b19
gosub shift595
digout = b18
gosub shift595
pulsout latch,4
return
'#########Subroutine to push data bits to shift registers
shift595:
lookup digout, ($FC,$60,$DA,$F2,$66,$B6,$BE,$E0,$FE,$E6), outbyte 'Lookup digits and convert to byte patterns for output to 7 segment displays
for bitcounter = 0 to 7
outbit = outbyte & 128
if outbit = 128 then
high sdata
else
low sdata
endif
pulsout sclk, 1
outbyte=outbyte * 2
next bitcounter
return
'Subprocedure to extract 12 Hour time and check for single/double digits
CONVERT_TO_12HOUR:
hour12 = b7 and $1F 'Extract 12 hour time from hour byte
if hour12 < 10 then
pause 200
high b.2
else
low b.2
endif
return
'############Subprocedure for setting AM/PM LED
CHECK_AM_PM:
ampm_bit=b7 and $20 'Extract AM/PM bit from hour byte
if ampm_bit=32 then 'Test AM/PM bit and turn on associated LED
low b.1
else
high b.1
endif
return