' {$STAMP BS2} ' {$PBASIC 2.5} ' {$PORT COM1} ' -----[ I/O Definitions ]------------------------------------------------------ ' 'Display TxPin PIN 3 'serial out to LCD 'DS1307 Clock Chip SQW PIN 2 '1 HZ square wave from DS1307 digital clock pin 7 SCL PIN 1 'i2c clock pin (chip pin 6) SDA PIN 0 'i2c data pin (clock chip pin 5 Audio PIN 8 led PIN 9 'control switches SW2 PIN 6 SW1 PIN 5 SW0 PIN 4 'ds1620 pins DQ16 PIN 15 'ds1620 pin 1 CLK16 PIN 14 'ds1620 pin 2 RST16 PIN 13 'ds1620 pin 3 ' -----[ Constants ]------------------------------------------------------------ ' Baud CON 32 '19200 baud DS1307 CON %11010000 'slave address for clock chip 'ds1620 constants wrcfg CON $0c 'write config register startc CON $EE 'start conversion rdtmp CON $AA 'read temp 'i2c constants Nak CON 1 ' Ack CON 0 ' -----[ Variables ]------------------------------------------------------------ ' Secs VAR Byte 'seconds Mins VAR Byte MinsHi VAR Mins.HIGHNIB 'tens of minutes MinsLo VAR Mins.LOWNIB 'units minutes Hrs VAR Byte 'hours hrsHi VAR Hrs.HIGHNIB hrsLo VAR hrs.LOWNIB Chrs VAR Nib 'time in hours, 1-12 Day VAR Nib 'day of week Date VAR Byte DateHi VAR Date.HIGHNIB DateLO VAR DATE.LOWNIB Month VAR Byte MonthHi VAR Month.HIGHNIB MonthLo VAR Month.LOWNIB Year VAR Byte YearHi VAR Year.HIGHNIB YearLo VAR Year.LOWNIB ch1 VAR Byte 'temp for text to print x VAR Nib 'used in printing text EvenMin VAR Bit 'time is xx:xx:00 chime VAR Bit 'the chime is enabled Min30 VAR Bit 'half-hour beep Dtemp VAR Bit 'display temperature bells VAR Nib 'number of chimes to sound LCnt VAR Byte 'how long until turn backlite off WordTmp VAR Word 'generally useful temp location temp VAR Byte 'temperature in Fahr i2cReg VAR Byte 'register in the slave device i2cData VAR Byte 'data to/from device i2cWork VAR Byte 'work byte for TX routine i2cDir VAR Bit 'i2c direction i2cAck VAR Bit Switches VAR Nib Swch0 VAR Switches.BIT0 'down Swch1 VAR Switches.BIT1 'up Swch2 VAR Switches.BIT2 'control Mode VAR Byte 'what mode we are in: '0: just keeping time '1: backlite on '2: setting hour '3: setting minute '4: clearing seconds '5: setting day '6: setting date '7: setting month '8: setting year ' -----[ EEPROM Data ]---------------------------------------------------------- ' DayNames DATA "SunMonTueWedThuFriSat" MonNames DATA "JanFebMarAprMayJunJulAugSepOctNovDec" Activity DATA "ClokLiteHourMinsSecsDay DateMnthYear" ' -----[ Initialization ]------------------------------------------------------- begin: HIGH TxPin PAUSE 100 SEROUT TxPin, Baud, [17] 'backlite on SEROUT TxPin, Baud, [22] 'no cursor SEROUT TxPin, Baud, [12] 'clear screen PAUSE 5 SEROUT TxPin, Baud, [248, %00110,%01001,%01001,%00110,0,0,0,0] 'degree symbol chime = 1 'turn on the chime Mode = 0 'initial mode is normal LCnt = 60 'leave Backlite on initially 1 minute DTemp = 1 'display temp rather than mode 'reset and start up the ds1620 HIGH RST16 'reset SHIFTOUT DQ16, CLK16, LSBFIRST, [wrcfg, %10] 'use with cpu, free-run LOW rst16 PAUSE 10 HIGH rst16 SHIFTOUT dq16, clk16, LSBFIRST, [StartC] 'start conversion LOW rst16 'start the clock if it is not running i2cDir = 1 i2cReg = 0 GOSUB i2cio 'read the seconds register IF ((I2cData & %10000000) = 0) THEN GOTO executive 'clock is running) i2cDir = 0 'write i2cReg = 0 'seconds reg i2cData = 0 GOSUB i2cio 'start the clock up i2cReg = 7 'SQWE reg i2cData = %00010000 ' 1 Hz GOSUB i2cIO ' -----[ Main Code ]------------------------------------------------------------ ' Executive: IF (SQW = 0) THEN GOTO Executive 'wait for beginning of second HIGH led IF (Min30 = 1) THEN FREQOUT Audio, 75, 1000 'half-hour beep PAUSE 100 FREQOUT Audio, 75, 1000 Min30 = 0 ENDIF IF (bells <> 0) THEN FREQOUT Audio, 120, 400, 1600 'chime Bells = Bells - 1 ENDIF IF ((Mode = 0) AND (LCnt <> 0)) THEN 'see if counting down backlite LCnt = LCnt - 1 IF (LCnt = 0) THEN SEROUT TxPin, Baud, [18] 'turn it off ENDIF Switches = INB 'read the switches Switches = 7 & (~Switches) 'any 1 says corresponding switch pushed IF (switches = 0) THEN GOTO exec10 'no switch pressed FREQOUT Audio, 50, 400 'switch feedback IF (Swch2 = 1) THEN 'mode switch Mode = Mode + 1 'new mode IF (Mode > 8) THEN Mode = 0 'just got done setting year GOSUB DMode 'new mode IF (Mode = 0) THEN GOTO MNorm 'we came back to normal mode IF (Mode = 1) THEN GOTO MLite 'we exited normal mode GOTO exec10 ENDIF 'if we come here, there is a button pushed to increase or decrease some time or day, etc 'or possibly just to turn the backlite on momentarily IF (Swch1 = 1) THEN BRANCH Mode, [UNorm, ULite, UHour, UMin, USec, UDay, UDate, UMonth, UYear] BRANCH Mode, [DNorm, DLite, DHour, DMin, DSec, DDay, DDate, DMonth, DYear] 'must be sw0 'no switch pushed, or completed action. update display exec10: GOSUB ReadHMS 'get the (new) time SEROUT TxPin, Baud, [128, HEX2 hrs, ":", HEX2 mins, ":", HEX2 secs] GOSUB rTemp 'and temperature IF (DTemp = 1) THEN IF (temp > 99) THEN SEROUT txPin, Baud, [" ", DEC3 temp, 0, "F"] 'display ELSE SEROUT TxPin, Baud, [" ", DEC2 temp, 0, "F"] ENDIF ENDIF GOSUB DayDate LOW led exec12: IF (SQW <> 0) THEN GOTO exec12 GOTO executive 'come here if switch2 pushed to enter normal mode (from setting year) or backlite on mode MNorm: SEROUT TxPin, Baud, [17] 'make sure backlite is lit LCnt = 15 'set up to count down backlite DTemp = 1 'show temperature GOTO exec10 MLite: SEROUT TxPin, Baud, [17] 'turn backlite on (and will leave it on) DTemp = 1 'show temperature GOTO exec10 'Here are the UP Button tasks UNorm: GOTO MNorm 'just turn on backlite for a few seconds ULite: 'exit light on mode with sw0 or sw1 SEROUT TxPin, Baud, [18] 'turn lite off Mode = 0 'force normal mode GOSUB DMode GOTO exec10 UHour: Wordtmp = (HrsHi * 10) + HrsLo 'convert to decimal Wordtmp = Wordtmp + 1 'increment IF (Wordtmp > 23) THEN Wordtmp = 0 'look for wrap UHour1: 'used by DHour as well HrsHi = Wordtmp / 10 'back to bcd HrsLo = Wordtmp // 10 i2cData = Hrs i2cReg = 2 'hours register i2cDir = 0 GOSUB i2cIO 'set new hours GOTO exec10 'and done UMin: Wordtmp = (MinsHi * 10) + MinsLo 'convert to decimal Wordtmp = Wordtmp + 1 'increment IF (Wordtmp > 59) THEN Wordtmp = 0 'look for wrap UMin1: 'used by DMin as well MinsHi = Wordtmp / 10 'back to bcd MinsLo = Wordtmp // 10 i2cData = Mins i2cReg = 1 'Minutes register i2cDir = 0 GOSUB i2cIO 'set new minutes GOTO exec10 'and done USec: i2cData = 0 'zero out seconds i2cReg = 0 i2cDir = 0 GOSUB i2cIO GOTO exec10 UDay: Day = Day + 1 'increment IF (Day > 7) THEN Day = 1 'look for wrap UDay1: 'used by DDay as well i2cData = Day i2cReg = 3 'Day of week register i2cDir = 0 GOSUB i2cIO 'set new minutes GOTO exec10 'and done UDate: Wordtmp = (DateHi * 10) + DateLo 'convert to decimal Wordtmp = Wordtmp + 1 'increment IF (Wordtmp > 31) THEN Wordtmp = 1 'look for wrap UDate1: 'used by DDate as well DateHi = Wordtmp / 10 'back to bcd DateLo = Wordtmp // 10 i2cData = Date i2cReg = 4 'Date register i2cDir = 0 GOSUB i2cIO 'set new Date GOTO exec10 'and done UMonth: Wordtmp = (MonthHi * 10) + MonthLo 'convert to decimal Wordtmp = Wordtmp + 1 'increment IF (Wordtmp > 12) THEN Wordtmp = 1 'look for wrap UMon1: 'used by DMonth as well MonthHi = Wordtmp / 10 'back to bcd MonthLo = Wordtmp // 10 i2cData = Month i2cReg = 5 'Month register i2cDir = 0 GOSUB i2cIO 'set new Date GOTO exec10 'and done UYear: Wordtmp = (YearHi * 10) + YearLo 'convert to decimal Wordtmp = Wordtmp + 1 'increment IF (Wordtmp > 99) THEN Wordtmp = 0 'look for wrap UYear1: 'used by DYear as well YearHi = Wordtmp / 10 'back to bcd YearLo = Wordtmp // 10 i2cData = Year i2cReg = 6 'Year register i2cDir = 0 GOSUB i2cIO 'set new Date GOTO exec10 'and done 'Here are the down button tasks DNorm: GOTO MNorm DLite: GOTO ULite DHour: Wordtmp = (HrsHi * 10) + HrsLo 'convert to decimal Wordtmp = Wordtmp - 1 'increment IF (Wordtmp = $FFFF) THEN Wordtmp = 23 'look for wrap GOTO UHour1 'and finish up DMin: Wordtmp = (MinsHi * 10) + MinsLo 'convert to decimal Wordtmp = Wordtmp - 1 'increment IF (Wordtmp = $FFFF) THEN Wordtmp = 59 'look for wrap GOTO UMin1 DSec: GOTO USec 'either switch DDay: Day = Day -1 IF (Day = 0) THEN Day = 7 GOTO UDay1 DDate: Wordtmp = (DateHi * 10) + DateLo 'convert to decimal Wordtmp = Wordtmp - 1 'increment IF (Wordtmp = 0) THEN Wordtmp = 31 'look for wrap GOTO UDate1 DMonth: Wordtmp = (MonthHi * 10) + MonthLo 'convert to decimal Wordtmp = Wordtmp - 1 'increment IF (Wordtmp = 0) THEN Wordtmp = 12 'look for wrap GOTO UMon1 DYear: Wordtmp = (YearHi * 10) + YearLo 'convert to decimal Wordtmp = Wordtmp - 1 'increment IF (Wordtmp = $FFFF) THEN Wordtmp = 99 'look for wrap GOTO UYear1 ' -----[ Subroutines ]---------------------------------------------------------- ' ReadHMS: 'come here once a second i2cDir = 1 'read... i2cReg = 0 'seconds GOSUB i2cIO secs = i2cData i2cReg = 1 'minutes GOSUB i2cIO mins = i2cData i2cReg = 2 'hours GOSUB i2cIO hrs = i2cData wordtmp = (hrsHi * 10) + hrsLo 'convert bcd hrs to dec hours IF (wordtmp > 11) THEN wordtmp = Wordtmp - 12 'noon or after IF (wordtmp = 0) THEN wordtmp = 12 'noon or midnite cHrs = wordtmp 'in case we need it EvenMin = 0 'nothing special known about the time IF (mins = $59) AND (secs = $52) AND (Mode = 0) THEN SEROUT TxPin, Baud, [17] 'turn on backlite for hours LCnt = 9 'get us past 59 seconds ENDIF IF (mins = $29) AND (secs = $55) AND (Mode = 0) THEN SEROUT TxPin, Baud, [17] 'turn on backlite for half-hour LCnt = 10 'for 10 seconds ENDIF IF (secs <> 0) THEN RETURN EvenMin = 1 'it is an exact minute IF ((mins = 0) AND (Chime = 1)) THEN bells = cHrs 'save number of chimes LCnt = bells + 5 'five seconds after bells done ENDIF IF (Mins = $30) THEN Min30 = 1 'half hour beep RETURN DayDate: 'display the day/date etc i2cDir = 1 'read i2cReg = 3 'day GOSUB i2cio Day = i2cData WordTmp = DayNames + ((Day - 1) * 3) 'first char of day we want SEROUT TxPin, Baud, [148] 'beginning of line number 1 FOR x = 0 TO 2 READ (WordTmp + x), ch1 SEROUT TxPin, Baud, [ch1] NEXT i2cReg = 4 'date (of month) GOSUB i2cio date = i2cData IF (dateHi = 0) THEN SEROUT TxPin, Baud, [" ", HEX1 DateLo, " "] ELSE SEROUT TxPin, Baud, [" ", HEX2 Date, " "] ENDIF i2cReg = 5 'month GOSUB i2cIO month = i2cData x = (monthHi * 10) + monthLo 'convert from BCD WordTmp = MonNames + ((x-1) *3) 'and month just like day of week FOR x = 0 TO 2 READ (WordTmp + x), ch1 SEROUT TxPin, Baud, [ch1] NEXT i2cReg = 6 'last two digits of year GOSUB i2cio year = i2cdata SEROUT TxPin, Baud, [" 20", HEX2 year] RETURN DMode: 'display mode WordTmp = Activity + (Mode * 4) SEROUT TxPin, Baud, [138] IF (Mode > 1) THEN DTemp = 0 FOR x = 0 TO 3 READ (WordTmp + x), ch1 SEROUT TxPin, Baud, [ch1] NEXT SEROUT TxPin, Baud, [" "] ' RETURN rTemp: 'come here to read the temp and convert to F HIGH rst16 SHIFTOUT DQ16, CLK16, LSBFIRST, [RdTmp] 'command SHIFTIN DQ16, CLK16, LSBPRE, [Wordtmp\9] 'read it in LOW rst16 Wordtmp = Wordtmp * 5 'convert to tenths Wordtmp = wordtmp */ $01CC + 320 'convert to farh times 10 Wordtmp = wordtmp + 5 'round to 1 degree temp = wordtmp / 10 RETURN '+++++++++++++++general purpose i2c IO routine+++++++++++++ 'i2cSlv 'i2c slave address is always %1101000x for DS1307 'i2cReg VAR Byte 'register in the slave device 'i2cData VAR Byte 'data to/from device; reused for oledr 'i2cWork VAR Byte 'work byte for TX routine 'i2cAck VAR Bit 'ack bit from device 'i2cDir VAR Bit '1 says read slave, 0 says write to slave i2cIO: GOSUB i2c_Start i2cWork = DS1307 & $FE 'no read bit GOSUB i2c_TX_Byte 'send slave address IF (i2cAck = Nak) THEN i2cIO 'wait for ack i2cWork = i2cReg GOSUB i2c_TX_Byte IF (i2cDir = 0) THEN i2cWork = i2cData 'this is the write case GOSUB i2c_TX_Byte ELSE GOSUB i2c_Start 'this is the read case i2cWork = DS1307 | 1 'send slave address with read indicator GOSUB i2c_TX_Byte GOSUB i2c_RX_Byte_Nak 'read the data (Just a single byte) i2cData = i2cWork 'return it in the right place ENDIF GOSUB i2c_Stop RETURN '---------Low level i2c subroutines i2c_Start: INPUT SCL LOW sda clock_Hold: DO : LOOP UNTIL (SCL =1) 'wait for clock release RETURN i2c_TX_Byte: SHIFTOUT SDA, SCL, MSBFIRST, [i2cWork\8] 'send byte to device SHIFTIN SDA, SCL, MSBPRE, [i2cAck\1] 'get ackn bit 'DEBUG CR, " transmit: ", HEX2 i2cWork, " i2cack: ", BIN1 i2cAck, " " RETURN '-----------Receive Byte I2C_RX_Byte_Nak: i2cAck = Nak 'no ack = high SHIFTIN SDA, SCL, MSBPRE, [i2cWork \8] 'get byte from device 'DEBUG CR, "recieve: ", HEX2 i2cWork SHIFTOUT SDA, SCL, LSBFIRST, [i2cAck\1] 'send ack or nak RETURN '--------stop sequence-------- I2C_Stop: LOW SDA 'i2c stop bit sequence INPUT SCL INPUT SDA RETURN