To keep the time, I used a real time clock module from sparkfun:
http://www.sparkfun.com/shop/index.php?shop=1&cat=45Todd gave me some code/tips for the chip. It was easy to use, note the three pull up 4.7K OHM resistors. (diagram possibly)
I used serout to check the time and debug my code. [see code]
Basically you program the PIC chip with a subroutine to set the time and then reprogram the chip without the subroutine. If you don’t do this, the clock will RESET everytime you turn power on/off.
Todd pointed me to a way to simulate a clock without the IC. I tried this method, but since the chip used in the example was different than the PIC chip I was using, I decided to use the clock chip.
http://www.picbasic.co.uk/forum/showthread.php?t=2129 For the minutes portion of the clock, I wanted to use 12 LEDs (each representing 5 minutes). My plan for the code was to put all the ports into an array and navigate through the array. Unforunately after much discussion, Tom Igoe confirmed this was not possible. Ben Brown suggested I take the long route and code all the conditions. It’s lengthy, but works.
'****************************************************************
'* Name : clock.BAS *
'* Author : Avani Patel *
'* Notice : Copyright (c) 2005 2004 *
'* : All Rights Reserved *
'* Date : 4/21/2005 *
'* Version : 1.0 *
'* Notes : *
'* : *
'****************************************************************
Include "modedefs.bas" ' Include serial modes
TX var portc.6 ' Define serial output pin
SDA var PORTC.4 ' I2C data pin
SCL var PORTC.5 ' I2C clock pin
SQW var portc.3
RTCData VAR BYTE[8] ' Data byte array
input PORTB.6 'hour set
input PORTB.5 'second set
input PORTB.4 'set time
setHour var PORTB.6
setMinute var PORTB.5
setTime var PORTB.4
RTCSec var byte ' Seconds
RTCMin var byte ' Minutes
RTCHour var byte ' Hours
RTCWDay var byte ' Weekday
RTCDay var byte ' Day
RTCMonth var byte ' Months
RTCYear var byte ' Year
RTCCtrl var byte ' Control
DecimalHours var byte
DecimalMinutes var byte
DecimalSeconds var byte
address var byte
dataHours var byte
dataMinutes var byte
dataSeconds var byte
'testLight var PORTB.7 'blink this light at the begining_only happens once
i var byte
'use this subroutine only when programming for the first time
gosub setClock
'LED minutes vars
bSpace CON 200 'between blinks
longBSpace CON 1000 'between rounds
seqSpace CON 2000 ' end of main pause
'PORT SETUP'
'output portb.7 'light once, not neccessary
'set remaining ports to output for LEDs
output portc.2
output portc.3
output portd.0
output portd.1
'output portd.2
ADCON1=%10000111 'makes porta digital
'setting alias for LED ports, all on LEFT side of PIC
p1 var porta.0
p2 var porta.1
p3 var porta.2
p4 var porta.3
p5 var porta.4
p6 var porta.5
p7 var porta.6
p8 var porta.7
p9 var portc.2
p10 var portc.3
p11 var portd.0
p12 var portd.1
potVar VAR word
potMin VAR Byte
potLED Var BYTE
potMod Var BYTE
'inputVar var byte
'i var BYTE
'end LED vars
'servo hour vars
TRISB = %00000000
s1 var portb.7
s2 var portb.6
s3 var portb.5
s4 var portb.4
s5 var portb.3
s6 var portb.2
LotOpening VAR BYTE
pulseWidth VAR BYTE
' set up constants with the minimum and maximum pulsewidths
minPulse CON 140
maxPulse CON 220
openPetal CON 140
closePetal CON 220
'write method for opening and closing
' set up a constant with the time between pulses:
refreshPeriod CON 20
' set an initial pulsewidth:
pulseWidth = closePetal 'start with closed petal stata
LotOpening = 1 ' it's opening
'end servo hour vars
main:
I2CRead SDA,SCL,$D0,$00,[RTCSec,RTCMin,RTCHour,RTCWDay,RTCDay,RTCMonth,RTCYear,RTCCtrl]
gosub bcdtodec
'Serout2 TX,16468,[HEX RTCMonth,"/",HEX RTCDay,"/",HEX RTCYear," - ",HEX RTCHour, ":",HEX RTCMin,":",HEX RTCSec,13,10]
'pause 1000
goto main
bcdtodec:
'Convert BCD to decimal... assume variable RTCSeconds holds the seconds in BCD format...
'Hours
DecimalHours=RTCHour & $70
DecimalHours=DecimalHours>>4
DecimalHours=DecimalHours*10
DecimalHours=DecimalHours+(RTCHour & $0F)
'convert from 24 hr time to 12
if (DecimalHours >= 13) then
low PORTB.7
decimalHours = DecimalHours - 12
else
high PORTB.7
decimalHours = DecimalHours
endif
'address = 2
dataHours = (DecimalHours * 255)/12
'Minutes
DecimalMinutes=RTCMin & $70
DecimalMinutes=DecimalMinutes>>4
DecimalMinutes=DecimalMinutes*10
DecimalMinutes=DecimalMinutes+(RTCMin & $0F)
'address = 1
dataMinutes = (DecimalMinutes * 255)/60
'Seconds
DecimalSeconds=RTCsec & $70
DecimalSeconds=DecimalSeconds>>4
DecimalSeconds=DecimalSeconds*10
DecimalSeconds=DecimalSeconds+(RTCSec & $0F)
'address = 0
dataSeconds = (DecimalSeconds * 255)/60
'GOSUB subdigiout
gosub minLEDs
GOSUB hrServos
Serout2 TX,16468,[dec DecimalHours, ":",dec DecimalMinutes,":",dec DecimalSeconds,13,10]
Serout2 TX,16468,[dec dataHours, ":",dec dataMinutes,":",dec dataSeconds,13,10,13,10]
return
hrServos:
' change the angle for the next time around:
IF (pulseWidth > openPetal) AND (LotOpening=1) THEN 'if the pulse is greater than 50
pulseWidth = pulseWidth-1 ' knock it down
GOSUB move
HIGH portd.2
ENDIF
IF (pulseWidth = openPetal) THEN 'when pulseWidth reaches totally open state
LotOpening=0
PAUSE 1000
pulseWidth = pulseWidth+1
ENDIF
IF (pulseWidth < closePetal) AND (LotOpening=0) THEN
pulseWidth = pulseWidth+1
GOSUB move
HIGH portd.1
ENDIF
IF (pulseWidth = closePetal) THEN 'when pulseWidth reaches totally open state
LotOpening=1
PAUSE 1000
pulseWidth = pulseWidth-1
ENDIF
RETURN
move:
'take the output pin low so we can pulse it high
'LOW PORTC.3
' pulse the pin
if DecimalHours==1 THEN
SEROUT2 portc.6, 16468, ["servo 1", 13,10,13,10]
PULSOUT s1, pulseWidth
ENDIF
IF DecimalHours==2 THEN
PULSOUT s1, pulseWidth
PULSOUT s2, pulseWidth
ENDIF
IF DecimalHours==3 THEN
PULSOUT s1, pulseWidth
PULSOUT s2, pulseWidth
PULSOUT s3, pulseWidth
ENDIF
IF DecimalHours==4 THEN
PULSOUT s1, pulseWidth
PULSOUT s2, pulseWidth
PULSOUT s3, pulseWidth
PULSOUT s4, pulseWidth
ENDIF
IF DecimalHours==5 THEN
PULSOUT s1, pulseWidth
PULSOUT s2, pulseWidth
PULSOUT s3, pulseWidth
PULSOUT s4, pulseWidth
PULSOUT s5, pulseWidth
ENDIF
if DecimalHours==6 THEN
PULSOUT s1, pulseWidth
PULSOUT s2, pulseWidth
PULSOUT s3, pulseWidth
PULSOUT s4, pulseWidth
PULSOUT s5, pulseWidth
PULSOUT s6, pulseWidth
ENDIF
' pause for as long as needed:
PAUSE refreshPeriod
RETURN
minLEDS: 'figures out values for lights
'potMin=23 'temp constant value
' potLED=potMin/5 'to give 1-12 for minutes
'potMod=potMin//5 'modulus value, to give remindar for blinking LED
potLED=DecimalMinutes/5
potMod=DecimalMinutes//5
gosub blinkLEDs
RETURN
'DO NOT CHANGE- this sub works perfect! ONLY mess with pauses!
blinkLEDs:
If potLED==0 THEN 'less than 5 min
SEROUT2 portc.6, 16468, ["in pot=0", 13,10,13,10]
if potMod > 0 THEN
for i=1 to potMod
' high PORTD.2
high p1
pause bspace
' LOW PORTD.2
low p1
pause bspace
next i
pause longBspace ' long blink seperate out minutes
ENDIF
ENDIF
if potLED >=1 AND potLED < 2 then '5 mins
SEROUT2 portc.6, 16468, ["in pot>=1", 13,10,13,10]
HIGH p1
If potMod > 0 THEN
for i=1 to potMod
high p2
pause bspace
low p2
pause bspace
next i
pause longBspace
ENDIF
pause seqSpace
endif
if potLED >=2 AND potLED < 3 then '10 mins
HIGH p1
HIGH p2
SEROUT2 portc.6, 16468, ["in pot>=2", 13,10,13,10]
If potMod > 0 THEN
for i=1 to potMod
high p3
pause bspace
low p3
pause bspace
next i
pause longBspace
ENDIF
pause seqSpace
endif
if potLED >=3 AND potLED < 4 then '15 mins
HIGH p1
HIGH p2
HIGH p3
If potMod > 0 THEN
for i=1 to potMod
high p4
pause bspace
low p4
pause bspace
next i
pause longBspace
ENDIF
pause seqSpace
endif
if potLED >= 4 and potLED < 5 then '20 mins
High p1
high p2
high p3
HIGH p4
If potMod > 0 THEN
for i=1 to potMod
high p5
pause bspace
low p5
pause bspace
next i
pause longBspace
ENDIF
pause seqSpace
endif
if potLED >= 5 AND potLED < 6 then '25 mins
High p1
high p2
high p3
HIGH p4
HIGH p5
If potMod > 0 THEN
for i=1 to potMod
high p6
pause bspace
low p6
pause bspace
next i
pause longBspace
ENDIF
pause seqSpace
endif
if potLED >= 6 AND potLED <7 then '30 mins
High p1
high p2
high p3
HIGH p4
HIGH p5
HIGH p6
If potMod > 0 THEN
for i=1 to potMod
high p7
pause bspace
low p7
pause bspace
next i
pause longBspace
ENDIF
pause seqSpace
endif
if potLED >= 7 AND potLED < 8 then '35 mins
High p1
high p2
high p3
HIGH p4
HIGH p5
HIGH p6
HIGH p7
If potMod > 0 THEN
for i=1 to potMod
high p8
pause bspace
low p8
pause bspace
next i
pause longBspace
ENDIF
pause seqSpace
endif
if potLED >= 8 then '40 mins
High p1
high p2
high p3
HIGH p4
HIGH p5
HIGH p6
HIGH p7
HIGH p8
If potMod > 0 THEN
for i=1 to potMod
high p9
pause bspace
low p9
pause bspace
next i
pause longBspace
ENDIF
pause seqSpace
endif
if potLED >= 9 then '45 mins
High p1
high p2
high p3
HIGH p4
HIGH p5
HIGH p6
HIGH p7
HIGH p8
HIGH p9
If potMod > 0 THEN
for i=1 to potMod
high p10
pause bspace
low p10
pause bspace
next i
pause longBspace
ENDIF
pause seqSpace
endif
if potLED >= 10 then '50 mins
High p1
high p2
high p3
HIGH p4
HIGH p5
HIGH p6
HIGH p7
HIGH p8
HIGH p9
HIGH p10
If potMod > 0 THEN
for i=1 to potMod
high p11
pause bspace
low p11
pause bspace
next i
pause longBspace
ENDIF
pause seqSpace
endif
if potLED >= 11 then '55 mins
High p1
high p2
high p3
HIGH p4
HIGH p5
HIGH p6
HIGH p7
HIGH p8
HIGH p9
HIGH p10
HIGH p11
If potMod > 0 THEN
for i=1 to potMod
high p12
pause bspace
low p12
pause bspace
next i
pause longBspace
ENDIF
pause seqSpace
endif
if potLED == 12 then '60 mins 'does not exist AVANI!
High p1
high p2
high p3
HIGH p4
HIGH p5
HIGH p6
HIGH p7
HIGH p8
HIGH p9
HIGH p10
HIGH p11
HIGH p12
pause seqSpace
endif
'Pause 1000 'this needs to compensate for rest of minute
high portd.2
pause 400
low portd.2
SEROUT2 portc.6, 16468, ["end sequence here", 13,10,13,10]
goSub turnLow
RETURN
turnLow: 'turns all LEDs off
PAUSE 1000
'LOW p1
LOW p2
LOW p3
LOW p4
LOW p5
LOW p6
LOW p7
LOW p8
LOW p9
LOW p10
LOW p11
LOW p12
RETURN
setClock:
'Write command
RTCSec=$00 ' Seconds
RTCMin=$08 ' Minutes
RTCHour= $01 ' Hours
RTCWDay=$01 ' Weekday
RTCDay=$19 ' Day
RTCMonth=$05 ' Months
RTCYear=$05 ' Year
RTCCtrl=$10 ' Control preset to output 1 second 'Tick' on SQWpin
I2CWrite SDA,SCL,$D0,$00,[RTCSec,RTCMin,RTCHour,RTCWDay,RTCDay,RTCMonth,RTCYear,RTCCtrl]
Pause 1000
return