#rem dialClock.bas This uses interrupt on 1 Hz square wave and provides
clock pulses, program transmissioms and the time-date message.
Buttons provide for Daylight Saving Ttime selection and minute adjustment
memory assignment:
28-42 Transmitter message = txStart
45-65 Row0 time and date = row0Start, $80
70-90 Ror1 year, battery voltage, temperature, row1Start, $A0
95-115 Row2 Datlight Saving Time, message index 0 row2Start, $C0
120=140 Row3 soft key labels message index 1, row3Start, $E0
John Saunders 5/8/2022 Version with one clock access only, new memory locations,
5/10/2022 change Tx dst code, do not display then, 7/1/2022 change timeout from 40 to 6
#endrem
#Picaxe 18M2
rem NO_DATA
rem ports
symbol dispRst = B.0 'Display reset, not used
symbol driveY = B.2 'Alternate polarity clock motor drive pulses
symbol driveB = B.3 'Alternate polarity clock motor drive pulses
symbol dispOff = B.5 'Controls a power switch to de-power the display
symbol refPort = B.7 'A reference diode to indirectly measure the battery voltage
symbol button1 = pinC.0 'Number 2 button from the left
symbol button0 = pinC.1 'Left button
symbol hzIn = pinC.2 'Number 3 button from the left
symbol txOut = C.3 'A delicate connection to pin 3 of thr DS3231 real-Time Clock chip
symbol microsw = pinC.5
symbol button3 = pinC.6 'Right button
symbol button2 = pinC.7 'Number 3 button from the left
rem Flag variables
symbol dispOnFlag = bit1 'Denotes display mode on
symbol dstFlag = bit2 '1 is Daylight Saving time
symbol initFlag = bit3 'Commands initializing the display
symbol oldOnFlag = bit4 'To ensure initialzing only omce
rem interrupt variables
symbol phase = bit7 'High and low of 1 Hz square wave
symbol oneHz = bit8 'Alternating polarity of the clock drive pulses
symbol secCount = b3
symbol ptrSave = b4
rem local variables can be re-used but beware of nested subprograms
symbol decPoint = bit9 'For numerical display
symbol repeatFlag = bit10 'Transmissions are sent twich in case of interference
symbol overflow = bit11
symbol analogVal = w1 'For battery voltage calulation
symbol decVal = b5
symbol charVal = b6
symbol bcdval = b7
symbol tens = b8
symbol units = b9
symbol row = b10
symbol iter = b11
rem addressing variabes, may be used in indirect addressing
symbol dataAddr = b12 'In EEPROM
symbol memAddr = b13 'In display buffer in RAM
symbol dsAddr = b14 'In the RTC
symbol stringAddr = b15 'In the RAM
symbol dispAddr = b16 'In the display
rem global variables
symbol pgmIndx = b17 'An index into the lights programming table
symbol toCount = b18 'To automatically terminate the display
symbol stepCount = b19 'Controls time/date and program transmissions
symbol hour = b20 'Current RTC value in binary
symbol minute = b21 'Current RTC value in binary
symbol dispRow = b22 'An index into the mster table of available display formats
symbol keyCode = b23 'Receiver identifier in transmissions
rem --------------------------------- constants --------------------------------
symbol pulselen = 8 '30 milliseconds to clock drive
symbol maxToCount = 6 'Display timeout in seconds
symbol mainFreq = k250 'Low power oopertion when the display is off
symbol dispFreq = m4 'Faster operation necessary for button and display writing when om
symbol maxPgmIndx = 21 'Size of the lights program table index
symbol refVal = 63590 'Ref diode Volts = 2.484
rem memory addresses
symbol txStart = 150 'Transmit message buffer 15 bytes
symbol row0Start = 45
symbol row1Start = 70
symbol row2Start = 95
symbol row3Start = 120
symbol TDStart = 34
rem Data locations
symbol row2STD = 145 'EEPROM address of row 2 strings for STD
symbol row2DST = 149 'EEPROM address of row 2 strings for DST
symbol row3data = 153 'EEPROM address of row 3 strings
symbol dstSavAddr = 197 'Saving the Daylight Savings flag value
symbol dayStart = 198 'Start of the day-of-week table in EEPROM
symbol monthStart = 219 'Start of the month table in EEPROM
rem --------------------------------- Command table ---------------------------------
rem hour minute flag keyCode button
DATA 0, (17,25,"7") 'String Lights ON
DATA 3, (05,50,"7") 'String Lights ON
DATA 6, (19,40,"6") 'String Lights OFF
DATA 9, (07,00,"6") 'String Lights OFF
DATA 12, (17,26,"m") 'Clear Outlet ON
DATA 15, (05,53,"m") 'Clear Outlet ON
DATA 18, (06,56,"J") 'Clear Outlet OFF
DATA 21, (19,41,"J") 'Clear Outlet OFF
DATA 24, (20,37,"f") 'Floor Light OFF
DATA 27, (00,38,"f") 'Floor Light OFF
DATA 30, (25,00,"I") 'Hanging Lamp ON
DATA 33, (25,57,"I") 'Hanging Lamp ON
DATA 36, (19,42,"C") 'Hanging Lamp OFF
DATA 39, (06,58,"C") 'Hanging Lamp OFF
DATA 42, (17,30,"d") 'Ornaments ON
DATA 45, (19,38,"9") 'Ornaments OFF
DATA 48, (05,34,"d") 'Ornaments ON
DATA 51, (07,31,"9") 'Ornaments OFF
DATA 54, (17,31,"Y") 'Flashing ON
DATA 57, (19,37,"W") 'Flashing OFF
DATA 60, (05,35,"Y") 'Flashing ON
DATA 63, (07,37,"W") 'Flashing OFF
rem --------------------------------- Pages ---------------------------------
DATA 145,(189,182,164,0) 'Row 2 for STD
DATA 149,(193,182,164,0) 'Row 2 for DST
DATA 153,(189,193,172,177,0) 'Row 3
rem --------------------------------- Strings ---------------------------------
DATA 164,("Minutes")
DATA 172,("Incr")
DATA 177,("Decr");
DATA 182,("Select")
DATA 189,("STD")
DATA 193,("DST")
DATA 197,(0) 'Daylight Saving Time is 1
rem strings for abbreviations
DATA 198,("SunMonTueWedThuFriSat")
DATA 219,("JanFebMarAprMayJunJulAugSepOctNovDec")
init: '--------------------------------- Init ---------------------------------
HIGH dispOFF
HIGH dispRst
LET pgmIndx = 0
LET stepCount = 0
LET toCount = 0
LET dispOnFlag = 0
LET oldOnFlag = 0
READ dstSavAddr,dstFlag 'Restore Daylight-Saving Time selectio
HI2CSETUP I2CMASTER,$D0,I2Cslow,I2cbyte
HI2COUT 0x0E,(0) 'Sets the 1 Hz clock
'HI2COUT 0,(0x51,0x43,0x16,0x06,0x24,0x06,0x22)
SETFREQ mainFreq
SETINT %00000100,%00000100
main:
IF dispOnFlag = 1 AND stepCount <> 1 THEN 'Display on operations
SETFREQ dispFreq
IF initFlag = 1 THEN
GOSUB initDisp
LET dataAddr = row3Data
LET memAddr = row3Start
GOSUB storeFixed
LET initFlag = 0
ENDIF
IF button0 = 0 tHEN
LET dstFlag = 0
WRITE dstSavAddr,dstFlag
ENDIF
IF button1 = 0 tHEN
LET dstFlag = 1
WRITE dstSavAddr,dstFlag
ENDIF
IF button2 = 0 OR button3 = 0 THEN
GOSUB AdjMins
ENDIF
GOSUB storeRow0 'Get and store in ASCII RTC time and date
GOSUB storeRow1 'store yesr; Measure battery voltage, temperature
IF dstFlag = 1 THEN 'Show current selection
LET dataAddr = row2DST
ELSE
LET dataAddr = row2STD
ENDIF
LET memAddr = row2Start
GOSUB storeFixed
GOSUB DisplayBuffers
SETFREQ mainFreq
ENDIF
IF stepCount = 1 THEN 'Get the current hour and minute in binary for program comparison
LET dsAddr = TDStart
PEEK dsAddr,units,tens 'in bcd
LET bcdVal = units / 16
LET minute = 10 * bcdVal
LET minute = units & 0x0F + minute
LET bcdVal = tens / 16
LET hour = 10 * bcdVal
LET hour = tens & 0x0F + hour + dstFlag
IF hour > 23 THEN
LET hour = 0
ENDIF
LET memAddr = txStart
FOR iter = 0 TO 3 'Populate the transmit buffer time and date and commas in ASCII
LOOkUP iter,(5,4,2,1),dsAddr
LET DataAddr = TDStart + dsAddr - 1
PEEK DataAddr,bcdval
BCDTOASCII bcdval,tens,units
IF dsAddr = 2 AND dstFlag = 1 THEN
IF units < "9" THEN
INC units
ELSE
LET units = "0"
IF tens < "2" THEN
INC tens
ELSE
LET tens = "0"
ENDIF
ENDIF
ENDIF
LET memAddr = 3 * iter + txStart
POKE memAddr,tens, units, ","
NEXT
LET decVal = 0 'Calculate the checksum
LET bptr = txStart
FOR iter = 0 TO 10 'Don't include the last comma!
LET decVal = decVal + @bptrinc
NEXT
LET memAddr = txStart + 12 'Add the 2 checksum characters to the transmit buffer
LET charVal = decVal / 16
IF charVal < 10 THEN
LET charVal = charVal + "0"
ELSE
LET charVal = charVal + "7"
ENDIF
POKE memAddr,charVal
INC memAddr
LET charVal = decVal & $F
IF charVal < 10 THEN
LET charVal = charVal + "0"
ELSE
LET charVal = charVal + "7"
ENDIF
POKE memAddr,charVal
LET stepCount = 2
PAUSE 2000
ENDIF
IF stepCount = 3 THEN
rem Look for a hour and minute match in the lights table
dataAddr = 3* PgmIndx
READ dataAddr, tens, units, keyCode
IF stepCount > 3 THEN
FOR iter = 0 TO 10
PAUSE 200
NEXT
ENDIF
IF hour = tens AND minute = units THEN
LET stepCount = 4
ENDIF
IF stepCount = 3 THEN
IF pgmIndx < maxPgmIndx THEN
INC pgmIndx
ELSE
LET stepCount = 0
LET pgmIndx = 0
ENDIF
ENDIF
ENDIF
GOTO main
rem --------------------------------- Top level subroutines which call other subroutines ------------
storeRow0:
LET bptr = row0Start
FOR iter = 0 TO 4
LOOKUP iter,(2,1,3,5,4),dsAddr
LET dsAddr = dsAddr + TDStart - 1
PEEK dsAddr,bcdVal
LET tens = bcdVal / 16 + "0"
LET units = bcdVal & 0x0F + "0"
SELECT iter
CASE 0 'Hour
IF dstFlag = 1 THEN
IF units < "9" THEN
INC units
ELSE
LET units = "0"
INC tens
ENDIF
ENDIF
IF tens > "2" THEN
LET tens = "0"
ENDIF
LET @bptrinc = tens
LET @bptrinc = units
LET @bptrinc = ":"
LET @bptrinc = " "
CASE 1 'Minute
LET @bptrinc = tens
LET @bptrinc = units
LET @bptrinc = " "
LET @bptrinc = " "
CASE 2 'Day of week
LET decVal = bcdVal & 0x0F
LET dataAddr = 3 * decVal + dayStart - 3
READ dataAddr,@bptrinc
INC dataAddr
READ dataAddr,@bptrinc
INC dataAddr
READ dataAddr,@bptrinc
LET @bptrinc = " "
LET @bptrinc = " "
CASE 3 'Month
LET decVal = bcdVal / 16
LET decVal = 10 * decVal
LET decVal = bcdVal & 0x0F + decVal
LET dataAddr = 3 * decVal + monthStart - 3
READ dataAddr,@bptrinc
INC dataAddr
READ dataAddr,@bptrinc
INC dataAddr
READ dataAddr,@bptrinc
LET @bptrinc = " "
LET @bptrinc = " "
CASE 4 'Date
LET @bptrinc = tens
LET @bptrinc = units
ENDSELECT
NEXT
RETURN
storeRow1:
LET dsAddr = TDStart + 5
LET bptr = row1Start
PEEK dsAddr,bcdVal 'Store year
LET @bptrinc = "2"
LET @bptrinc = "0"
LET tens = bcdVal / 16 + "0"
LET units = bcdVal & 0x0F + "0"
LET @bptrinc = tens
LET @bptrinc = units
LET @bptrinc = " "
LET @bptrinc = " "
ADCCONFIG 0
READADC refPort,decVal 'Store battery voltage
LET analogVal = refVal/decVal
LET decPoint = 1
GOSUB storeAnalog
LET @bptrinc = " "
LET @bptrinc = " " 'Measure temperature in degrees Celcius
HI2CSETUP I2CMASTER,$D0,I2Cslow,I2cbyte
HI2CIN $11,(tens,units)
LET analogVal = tens & $7F
LET analogVal = 10 * analogVal
LET units = units / 64
LET units = 5 * units
LET analogVal = units/2 + analogVal
LET decPoint = 0
GOSUB storeAnalog
RETURN
rem --------------------------------- Subprograms for the display buffer ----------------
AdjMins: 'DO NOT USE IF THERE WILL BE OVERFLOW!
LET overflow = 0
LET dsAddr = TDStart
PEEK dsAddr,bcdVal
LET charVal = bcdVal & $F0
LET decVal = charVal/16
LET charVal = bcdVal & $0F
LET decVal = 10*decVal + charVal
IF button2 = 0 THEN
IF decVal < 59 THEN
INC decVal
ELSE
LET decVal = 0
LET overflow = 1
ENDIF
ENDIF
IF button3 = 0 THEN
IF decVal > 0 THEN
DEC decVal
ELSE
LET decVal = 59
LET overflow = 1
ENDIF
ENDIF
LET tens = decVal / 10 'Convert back to BCD
LET units = decVal // 10
LET bcdVal = 16*tens + units
IF overflow = 0 THEN
Hi2COUT 1,(bcdVal) 'minutes
LET dsAddr = TDStart
POKE dsAddr,bcdval
ENDIF
RETURN
storeAnalog: 'Set row and col and analogVal before calling
LET charVal = analogVal/100
LET charVal = charVal + "0" 'Ascii
LET @bptrinc = charVal 'Digit #1
IF decPoint = 1 THEN
LET @bptrinc = "." 'Digit 3 if period
ENDIF
LET AnalogVal = AnalogVal//100
LET charVal = AnalogVal/10
LET charVal = charVal + "0" 'Ascii
LET @bptrinc = charVal 'Digit #2 w/o period else digit 4
IF decPoint = 0 THEN
LET @bptrinc = "." 'Digit 3 if period
ENDIF
LET charVal = AnalogVal //10 'Least significant digit
LET charVal = charVal + "0" 'Ascii
LET @bptrinc = charVal 'Digit #3 w/o period else digit 5
LET @bptrinc = " "
IF decPoint = 1 THEN
LET @bptrinc = "V"
ELSE
LET @bptrinc = "C"
ENDIF
RETURN
storeFixed: 'Set row and data start addresses before calling
LET bptr = memAddr
DO
READ dataAddr,stringAddr
IF stringAddr > 100 THEN
DO
READ stringAddr,charVal
IF charVal > 0 THEN
LET @bptrinc = charVal
ENDIF
INC stringAddr
LOOP WHILE charVal > 0
LET @bptrinc = " "
LET @bptrinc = " "
ENDIF
INC dataAddr
LOOP WHILE stringAddr > 0
RETURN
rem --------------------------------- Subprograms for the display itself ----------------
initDisp: 'From the display datasheet
HI2CSETUP I2CMASTER,$78,i2cfast,i2cbyte 'The OLED Display
HIGH dispRst
PAUSE 1
HI2COUT (0,0x2A); //function set (extended command set)
HI2COUT (0,0x71); //function selection A
HI2COUT (0,0x00); // data(00) = disable regulator (5V I/O)
HI2COUT (0,0x28); //function set (fundamental command set)
HI2COUT (0,0x08); //display off, cursor off, blink off
HI2COUT (0,0x2A); //function set (extended command set)
HI2COUT (0,0x79); //OLED command set enabled
HI2COUT (0,0xD5); //set display clock divide ratio/oscillator frequency
HI2COUT (0,0x70); //set display clock divide ratio/oscillator frequency
HI2COUT (0,0x78); //OLED command set disabled
HI2COUT (0,0x09); //extended function set (4-lines)
HI2COUT (0,0x06); //COM SEG direction
HI2COUT (0,0x72); //function selection B
HI2COUT ($40,0x00); //ROM CGRAM selection A
HI2COUT (0,0x2A); //function set (extended command set)
HI2COUT (0,0x79); //OLED command set enabled
HI2COUT (0,0xDA); //set SEG pins hardware configuration
HI2COUT (0,0x10); //set SEG pins hardware configuration
HI2COUT (0,0xDC); //function selection C
HI2COUT (0,0x00); //function selection C
HI2COUT (0,0x81); //set contrast control
HI2COUT (0,0x7F); //set contrast control
HI2COUT (0,0xD9); //set phase length
HI2COUT (0,0xF1); //set phase length
HI2COUT (0,0xDB); //set VCOMH deselect level
HI2COUT (0,0x40); //set VCOMH deselect level
HI2COUT (0,0x78); //OLED command set disabled
HI2COUT (0,0x28); //function set (fundamental command set)
HI2COUT (0,0x01); //clear display
HI2COUT (0,0x80); //set DDRAM address to 0x00
HI2COUT (0,0x0C); //display ON
PAUSE 10
RETURN
DisplayBuffers: 'Done all at once to avoid flickering
HI2CSETUP I2CMASTER,$78,i2cfast,i2cbyte 'The OLED Display.
FOR row = 0 TO 3
LOOKUP row,(row0Start,row1Start,row2Start,row3Start),bptr 'Row addressess
LOOKUP row,($80, $A0, $C0, $E0),dispAddr
HI2COUT 0,(dispAddr) 'Set cursor to the beginning of the row
FOR Iter = 0 TO 19
LET charVal = @bptrinc
HI2COUT $40,(charVal)
NEXT
NEXT
PAUSE 2000
RETURN
interrupt: 'rem ------------------------------------ Interrupt --------------------------------------
LET ptrSave = bptr
LET phase = hzIn
IF phase = 0 THEN
SETFREQ m1
IF oneHz = 1 THEN 'Drive the clock
LET oneHz = 0
LOW driveY '
PAUSE pulseLen
LOW driveB
ELSE
LET oneHz = 1
HIGH driveY
PAUSE pulseLen
HIGH driveB
ENDIF
IF dispOnFlag = 1 THEN
SETFREQ dispFreq
ELSE
SETFREQ mainfreq
ENDIF
SETINT %00000100,%00000100
ELSE
rem Timed operations,Positive transition, clock is not updating
SETFREQ dispFreq
IF toCount > 0 THEN
DEC toCount
ELSE
LET dispOnFlag = 0
HIGH dispOFF
ENDIF
HI2CSETUP I2CMASTER,$D0,I2Cslow,I2cbyte
HI2CIN 0,(secCount)
IF secCount = 0 THEN
LET pgmIndx = 0
LET stepCount = 1
LET bptr = TDStart
HI2CIN 1,(@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptr)
ENDIF
IF stepCount = 2 THEN 'Transmit a time and date message
SETFREQ m4
HIGH TxOut
PAUSE 20
LOW TxOut
PAUSE 10
LET bptr = txStart
SEROUT TxOut,N2400_4,("14L1776t,G,",@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc, @bptrinc,@bptrinc, @bptrinc,@bptrinc,@bptrinc,13,10)
LET stepCount = 3
ENDIF
IF stepCount = 5 THEN 'Transmit a light programmessage
SETFREQ m4
HIGH TxOut
PAUSE 20
LOW TxOut
PAUSE 10
SEROUT TxOut,N2400_4,("14L1776",keyCode,13,10) 'Lights program command message
IF pgmIndx < maxPgmIndx THEN
INC pgmIndx
LET stepCount = 3
ELSE
LET pgmIndx = 0
LET stepCount = 0
ENDIF
ENDIF
IF stepCount = 4 THEN 'Transmit a light programmessage
SETFREQ m4
HIGH TxOut
PAUSE 20
LOW TxOut
PAUSE 10
SEROUT TxOut,N2400_4,("14L1776",keyCode,13,10) 'Lights program command message
LET stepCount = 5
ENDIF
IF microsw = 0 THEN
IF dispOnFlag = 0 THEN
LET initFlag = 1
LET toCount = maxToCount
ENDIF
LET dispOnFlag = 1
LOW dispOFF
ENDIF
IF button0 = 0 OR button1 = 0 OR button2 = 0 OR button3 = 0 THEN
LET toCount = maxToCount
ENDIF
IF dispOnFlag = 1 THEN
SETFREQ dispFreq
ELSE
SETFREQ mainfreq
ENDIF
SETINT %00000000,%00000100
ENDIF
LET bptr = ptrSave
RETURN