This is the code for the main 18M2+.
#PICAXE 18M2 #terminal off ; Project: Word Clock v2. ; File: Word Clock V2.bas ; Description: ; Read time from DS1307 RTC and display on LED matrix, where ; the LEDs are behind a template with an array of cut out ; letters and the lit letters will spell out the time in ; words. The time will only br accurate to within five ; minutes. Time can also be displayed as numbers using 3x5 ; blocks of LEDs to display numbers. ; ; Copyright (C) 2014 Marc Symonds ; All rights reserved. ; ; This software may be used and redistributed, with or without ; modification, as long as it is understood that this software ; is provided as-is without any explicit or implied warranties ; of merchantablity or fitness of purpose. #rem DS1307 Pins +---+ X1 X|1 |X Vcc X2 X| |X SQW/OUT +VBatt X| |X I2C/SCL 0V X| |X I2C/SDA +---+ #endrem #rem PICAXE18-M2 Pins +---+ DISPLAYF/TEMP - (Out/In) C.2 -|1 |- C.1 (In/Out) - Button - Mode LOWBRIGHT/TEMP - (Out) C.3 -| |- C.0 (In/Out) - Button - Set SerIn - (In) C.4 -| |- C.7 (In/Out) - Piezo (In) C.5 X| |X C.6 (In/Out) 0V -|5 |- Vcc MAX7219/CLK - (Out/In) B.0 -| |- B.7 (In/Out) - Button - Adjust DS1307 - (Out/In/I2C SDA) B.1 -| |- B.6 (In/Out) - Button - Brightness MAX7219/DATA - (Out/In) B.2 -| |- B.5 (In/Out) - LDR MAX7219/LOAD - (Out/In) B.3 -|9 |X B.4 (In/Out/I2C SCL) - DS1307 +---+ #endrem #rem PICAXE-08M2 Pins +---+ +V -|1 |- 0V DISPLAYF/TEMP - (In) Serial in C.5 -| |- C.0 Serial out (Out/hserout/DAC) - MAX7219/CLK Temp Sensor - (Touch/ADS/Out/In) C.4 -| |- C.1 (In/Out/ADC/Touch/hserin/SRI/I2C SCL) - MAX7219/LOAD LOWBRIGHT/TEMP - (In) C.3 -| |- C.2 (In/Out/ADC/Touch/PWM/Tune/SRQ/I2C SDA) - MAX7219/DATA +---+ #endrem #rem Memory:- 00 - 27 - Registers 30 - 36 - Top half buffer. 37 - 43 - Bottom half buffer. 44 - 50 - Top half buffer compare. 51 - 57 - Bottom half buffer compare. Sending to the MAX7219 is slow, so we only send data where something has changed. Digit/Segment layout on display (11x10):- 0A 0B 0C 0D 0E 0F 0G 0P 5A 5B 5C 1A 1B 1C 1D 1E 1F 1G 1P 5D 5E 5F 2A 2B 2C 2D 2E 2F 2G 2P 5G 5P 6A First MAX7219 3A 3B 3C 3D 3E 3F 3G 3P 6B 6C 6D 4A 4B 4C 4D 4E 4F 4G 4P 6E 6F 6G -------------------------------- 0A 0B 0C 0D 0E 0F 0G 0P 5A 5B 5C 1A 1B 1C 1D 1E 1F 1G 1P 5D 5E 5F 2A 2B 2C 2D 2E 2F 2G 2P 5G 5P 6A Second MAX7219 3A 3B 3C 3D 3E 3F 3G 3P 6B 6C 6D 4A 4B 4C 4D 4E 4F 4G 4P 6E 6F 6G P = DP. #endrem symbol MAX7219_REGISTER = b0 symbol MAX7219_DATA_1 = b1 symbol DS1307_DATA = b0 ; Must use b0 as bitX is used to manipulate. MAX and DS not accessed at the same time, so can reuse variable. ;symbol vWVAR = w0 symbol MAX7219_DATA_2 = b2 symbol MAX7219_SEND_COUNT = b3 ;symbol vWVAR = w1 symbol MAX7219_SEND_DATA = b4 ;symbol vBVAR = b5 ;symbol vWVAR = w2 ;symbol vBVAR = b6 ;symbol vBVAR = b7 ;symbol vWVAR = w3 ;symbol vBVAR = b8 ;symbol vBVAR = b9 ;symbol vWVAR = w4 ;symbol MODE_BUTTON_COUNTER = b10 ;symbol SET_BUTTON_COUNTER = b11 symbol DISP_TABLE_IDX = w5 ;symbol BRIGHTNESS_BUTTON_COUNTER = b12 ;symbol ADJUST_BUTTON_COUNTER = b13 ;symbol vWVAR = w6 ;symbol vBVAR = b14 ;symbol vBVAR = b15 ;symbol vWVAR = w7 symbol DISP_MEM = b16 symbol DISP_DATA = b17 ;symbol vWVAR = w8 symbol DISP_MERGE = b18 symbol DISP_NUM_TO_SHOW = b19 ;symbol vWVAR = w9 symbol v_SECONDS = b20 symbol v_MINUTES = b21 ;symbol vWVAR = w10 symbol v_HOURS = b22 symbol v_SECONDS_PREV = b23 ;symbol vWVAR = w11 symbol v_MINUTES_PREV = b24 symbol v_MODE = b25 ;symbol vWVAR = w12 symbol v_BRIGHTNESS = b26 ;symbol vBVAR = b27 ;symbol vWVAR = w13 ' MAX7219 Pins symbol MAX7219_LOAD = B.2 symbol MAX7219_DIN = B.3 symbol MAX7219_CLK = B.0 ; MAX7219 Registers symbol MAX7219_NOOP = $00 symbol MAX7219_DIGIT0 = $01 symbol MAX7219_DIGIT1 = $02 symbol MAX7219_DIGIT2 = $03 symbol MAX7219_DIGIT3 = $04 symbol MAX7219_DIGIT4 = $05 symbol MAX7219_DIGIT5 = $06 symbol MAX7219_DIGIT6 = $07 symbol MAX7219_DIGIT7 = $08 symbol MAX7219_DECODE_MODE = $09 symbol MAX7219_INTENSITY = $0A symbol MAX7219_SCAN_LIMIT = $0B symbol MAX7219_SHUTDOWN = $0C symbol MAX7219_TEST_MODE = $0F ; DS1307 I2C Address. symbol DS1307_ADDRESS = %11010000 ; DS1307 Registers. symbol DS1307_SECONDS = $00 symbol DS1307_MINUTES = $01 symbol DS1307_HOURS = $02 symbol DS1307_WEEKDAY = $03 symbol DS1307_DAY = $04 symbol DS1307_MONTH = $05 symbol DS1307_YEAR = $06 symbol DS1307_CONTROL = $07 symbol DS1307_RAM = $08 ; to $3F ; DS1307 Bits (assumes b0 used to manipulate values) symbol DS1307_SECONDS_CH = bit7 ; Clock Halt - high = halt, low = go symbol DS1307_HOURS_1224 = bit6 ; high = 12 hour, low = 24 hour symbol DS1307_HOURS_AMPM = bit5 ; high = PM, low = AM (in 12 hour mode) symbol DS1307_CONTROL_OUT = bit7 symbol DS1307_CONTROL_SQWE = bit4 symbol DS1307_CONTROL_RS1 = bit1 symbol DS1307_CONTROL_RS0 = bit0 ; We'll use the DS1307 RAM to store some values in case main power is lost. symbol DS1307_USR_MODE = DS1307_RAM + $00 ; Display mode symbol DS1307_USR_BRIGHTNESS = DS1307_RAM + $01 ; Brightness level ; Display data will be buffered in these memory loctations, before being sent to the display (MAX7219). symbol MEM_DISPLAY_TOP = 30 ; Start of buffer for top half of display. symbol MEM_DISPLAY_TOP_END = 36 ; End of buffer for top half of display. symbol MEM_DISPLAY_BOTTOM = 37 symbol MEM_DISPLAY_BOTTOM_END = 43 symbol MEM_DISPLAY_TOP_CMP = 44 ; -> 50 symbol MEM_DISPLAY_BOTTOM_CMP = 51 ; -> 57 symbol MEM_BUT_MODE = 58 symbol MEM_BUT_SET = 59 symbol MEM_BUT_ADJUST = 60 symbol MEM_BUT_BRIGHTNESS = 61 symbol MEM_BRIGHT_CURR = 62 symbol MEM_BRIGHT_HIGHER = 63 symbol MEM_BRIGHT_COUNT = 64 ; Pins used for buttons. symbol BUT_MODE = C.1 symbol BUT_MODEP = pinC.1 symbol BUT_SET = C.0 symbol BUT_SETP = pinC.0 symbol BUT_ADJUST = B.7 symbol BUT_ADJUSTP = pinB.7 symbol BUT_BRIGHTNESS = B.6 symbol BUT_BRIGHTNESSP = pinB.6 ; Pin used for piezo. symbol PIEZO = C.7 ; symbol BRIGHTNESS_SENSOR = B.5 symbol TEMP_BRIGHTNESS = C.3 symbol TEMP_BRIGHTNESSP = pinC.3 symbol TEMP_FAREN = C.2 symbol TEMP_FARENP = pinC.2 ; Data for displaying digits. ; 0 - 9 On left of display. symbol TAB_NUM_LEFT = 0 table TAB_NUM_LEFT, (%01110000, %01010000, %01010000, %01010000, %01110000, 0, 0) ; 0 table (%00100000, %01100000, %00100000, %00100000, %01110000, 0, 0) ; 1 table (%01110000, %00010000, %01110000, %01000000, %01110000, 0, 0) ; 2 table (%01110000, %00010000, %00110000, %00010000, %01110000, 0, 0) ; 3 table (%01010000, %01010000, %01110000, %00010000, %00010000, 0, 0) ; 4 table (%01110000, %01000000, %01110000, %00010000, %01110000, 0, 0) ; 5 table (%01110000, %01000000, %01110000, %01010000, %01110000, 0, 0) ; 6 table (%01110000, %00010000, %00010000, %00010000, %00010000, 0, 0) ; 7 table (%01110000, %01010000, %01110000, %01010000, %01110000, 0, 0) ; 8 table (%01110000, %01010000, %01110000, %00010000, %01110000, 0, 0) ; 9 ; 0 - 9 In middle of display. symbol TAB_NUM_MIDDLE = 70 table TAB_NUM_MIDDLE, (%00000111, %00000101, %00000101, %00000101, %00000111, 0, 0) table (%00000010, %00000110, %00000010, %00000010, %00000111, 0, 0) table (%00000111, %00000001, %00000111, %00000100, %00000111, 0, 0) table (%00000111, %00000001, %00000011, %00000001, %00000111, 0, 0) table (%00000101, %00000101, %00000111, %00000001, %00000001, 0, 0) table (%00000111, %00000100, %00000111, %00000001, %00000111, 0, 0) table (%00000111, %00000100, %00000111, %00000101, %00000111, 0, 0) table (%00000111, %00000001, %00000001, %00000001, %00000001, 0, 0) table (%00000111, %00000101, %00000111, %00000101, %00000111, 0, 0) table (%00000111, %00000101, %00000111, %00000001, %00000111, 0, 0) ; 0 - 9 On right of display. symbol TAB_NUM_RIGHT = 140 table TAB_NUM_RIGHT, (0, 0, 0, 0, 0, %01111011, %01101111) table (0, 0, 0, 0, 0, %10101100, %00010111) table (0, 0, 0, 0, 0, %11110011, %01100111) table (0, 0, 0, 0, 0, %11110010, %01001111) table (0, 0, 0, 0, 0, %11011011, %01001001) table (0, 0, 0, 0, 0, %11111001, %01001111) table (0, 0, 0, 0, 0, %11111001, %01101111) table (0, 0, 0, 0, 0, %01110010, %01001001) table (0, 0, 0, 0, 0, %11111011, %01101111) table (0, 0, 0, 0, 0, %11111011, %01001111) ; H. symbol TAB_WRD_Hr = 210 table TAB_WRD_Hr, (%01001000, %01001000, %01111000, %01001000, %01001000, 0, 0) ; M. symbol TAB_WRD_Mi = 217 table TAB_WRD_Mi, (%01000100, %01101100, %01010100, %01000100, %01000100, 0, 0) ; Pixels to light to tell the time in words. These are the indexes for the table. symbol TAB_TIM_ITIS = 224 symbol TAB_TIM_OCLOCK = 228 symbol TAB_TIM_FIVE = 232 symbol TAB_TIM_TEN = 236 symbol TAB_TIM_A_QUARTER = 240 symbol TAB_TIM_TWENTY = 244 symbol TAB_TIM_TWENTYFIVE = 248 symbol TAB_TIM_HALF = 252 symbol TAB_TIM_PAST = 256 symbol TAB_TIM_TO = 260 symbol TAB_TIM_ONE = 264 symbol TAB_TIM_TWO = 268 symbol TAB_TIM_THREE = 272 symbol TAB_TIM_FOUR = 276 symbol TAB_TIM_FIVEw = 280 symbol TAB_TIM_SIX = 284 symbol TAB_TIM_SEVEN = 288 symbol TAB_TIM_EIGHT = 292 symbol TAB_TIM_NINE = 296 symbol TAB_TIM_TENw = 300 symbol TAB_TIM_ELEVEN = 304 symbol TAB_TIM_TWELVE = 308 ; Row 1st 8 Top End Bottom End table TAB_TIM_ITIS, ($00, %01101100, %00000000, %00000000) table TAB_TIM_OCLOCK, ($09, %10000011, %00000000, %00000111) table TAB_TIM_FIVE, ($02, %10000001, %10000001, %00000000) table TAB_TIM_TEN, ($03, %10000011, %00000000, %00000000) table TAB_TIM_A_QUARTER, ($01, %11011111, %00001000, %00000000) table TAB_TIM_TWENTY, ($02, %01111110, %00000000, %00000000) table TAB_TIM_TWENTYFIVE, ($02, %11111111, %10000001, %00000000) table TAB_TIM_HALF, ($03, %01111000, %00000000, %00000000) table TAB_TIM_PAST, ($04, %01111000, %00000000, %00000000) table TAB_TIM_TO, ($03, %00000000, %00000000, %00011000) table TAB_TIM_ONE, ($05, %01110000, %00000000, %00000000) table TAB_TIM_TWO, ($06, %00000000, %00001110, %00000000) table TAB_TIM_THREE, ($05, %10000001, %01110000, %00000000) table TAB_TIM_FOUR, ($06, %01111000, %00000000, %00000000) table TAB_TIM_FIVEw, ($06, %10000111, %00000000, %00000000) table TAB_TIM_SIX, ($05, %00001110, %00000000, %00000000) table TAB_TIM_SEVEN, ($08, %01111100, %00000000, %00000000) table TAB_TIM_EIGHT, ($07, %01111100, %00000000, %00000000) table TAB_TIM_NINE, ($04, %10000000, %00000000, %00000111) table TAB_TIM_TENw, ($09, %01110000, %00000000, %00000000) table TAB_TIM_ELEVEN, ($07, %10000011, %10000001, %01000000) table TAB_TIM_TWELVE, ($08, %10000011, %00000000, %00111000) ; ******************************************************************************** ; *** Start setfreq m4 ;let dirsB = %00001101 ;let dirsC = %10001100 output MAX7219_LOAD output MAX7219_DIN output MAX7219_CLK input BUT_MODE input BUT_SET input BUT_ADJUST input BUT_BRIGHTNESS input BRIGHTNESS_SENSOR output TEMP_BRIGHTNESS output TEMP_FAREN output PIEZO ; The 08M2 which is used to read the temperature is using its serial in pin ; as an input from this chip to indicate display mode. Therefore the 08M2 ; uses the disconnect function so that the pin can be used as a normal ; input pin. The program in the 08M2 has a long pause when it starts up so ; that it can still be programmed. ; The delay below allows the 08M2 to get through it's own delay before we ; start up. pause 3200 gosub MAX7219_Initialise gosub DS1307_Initialise ; Load saved settings from DS1307. setfreq m8 hi2cin DS1307_USR_MODE, (v_MODE, v_BRIGHTNESS) setfreq m32 ; Bit 7 is flag for temp display in F. let v_MODE = v_MODE & $03 if v_MODE > 2 then let v_MODE = 0 end if ; Bit 4 is flag for auto brightness. let v_BRIGHTNESS = v_BRIGHTNESS & $1f if v_BRIGHTNESS > $10 then let v_BRIGHTNESS = $10 end if gosub ResetDisplay ; *** Main loop main: gosub SampleBrightness ; Read the current time from the DS1307. setfreq m8 hi2cin DS1307_SECONDS, (v_SECONDS, v_MINUTES, v_HOURS) setfreq m32 ;peek MEM_BRIGHT_CURR, b0 ;gosub ShowNum if v_BRIGHTNESS > $0f then ; Auto brightness? peek MEM_BRIGHT_CURR, b0 let b1 = v_BRIGHTNESS & $0f if b1 <> b0 then let v_BRIGHTNESS = $10 + b0 gosub SetModeBrightness end if end if ; Display the time. let b0 = v_MODE & $7f on b0 gosub ShowTimeInWords, ShowHoursMinutes, ShowMinutesSeconds ; Check for button presses. ;BUTTON pin,downstate,delay,rate,bytevariable,targetstate,address peek MEM_BUT_MODE, b0 button BUT_MODE, 1, 255, 0, b0, 1, SwitchModeMain poke MEM_BUT_MODE, b0 peek MEM_BUT_BRIGHTNESS, b0 button BUT_BRIGHTNESS, 1, 255, 0, b0, 1, SwitchBrightnessMain poke MEM_BUT_BRIGHTNESS, b0 peek MEM_BUT_SET, b0 button BUT_SET, 1, 255, 0, b0, 1, SetTime poke MEM_BUT_SET, b0 pause 10 goto main ; Make a beep. KeySound: sound PIEZO, (20, 40) return ; Mode button pressed. SwitchModeMain: poke MEM_BUT_MODE, b0 gosub KeySound ; Hold for 1 second to set temp display. setfreq m8 let b0 = 0 do inc b0 pause 10 loop while b0 < 100 and BUT_MODEP = 1 setfreq m32 if b0 >= 100 then gosub KeySound gosub SwitchTempDisplayMode else gosub SwitchMode end if goto main ; Brightness button pressed. SwitchBrightnessMain: poke MEM_BUT_BRIGHTNESS, b0 gosub KeySound gosub SwitchBrightness goto main ; Set button pressed. SetTime: poke MEM_BUT_SET, b0 gosub KeySound gosub ClearDisplay ; Set top half of display dim and bottom half bright. let MAX7219_DATA_1 = $02 let MAX7219_DATA_2 = $0f gosub MAX7219_SetIntensity ; Change the hours. let DISP_TABLE_IDX = TAB_WRD_HR gosub DisplayTop gosub SendToDisplay do pause 10 loop while BUT_SETP = 1 let b18 = 0 let b15 = v_HOURS & $3f let b14 = $23 ; BCD gosub AdjustNumber if b17 = 0 then SetTimeEnd ; b17 = 0 means cancelled. let v_HOURS = v_HOURS & $C0 | b15 ; Change the minutes. gosub ClearDisplayTop let DISP_TABLE_IDX = TAB_WRD_MI gosub DisplayTop let b15 = v_MINUTES let b14 = $59 ; BCD gosub AdjustNumber if b17 = 0 then SetTimeEnd ; b17 = 0 means cancelled. let v_MINUTES = b15 if b18 = 0 then SetTimeEnd ; Nothing was changed, so don't update the DS1307. ; Save the new time to the DS1307. Set seconds to 0. setfreq m8 hi2cout DS1307_SECONDS, (0, v_MINUTES, v_HOURS) setfreq m32 SetTimeEnd: gosub ResetDisplay goto main AdjustNumber: gosub ClearDisplayBottom let DISP_NUM_TO_SHOW = b15 gosub DisplayNumBottom gosub SendToDisplay AdjustNumberButtons: ;peek MEM_BUT_ADJUST, b0 ;button BUT_ADJUST, 1, 100, 60, b0, 1, AdjustNumberInc ; Adjust number ;poke MEM_BUT_ADJUST, b0 if BUT_ADJUSTP = 1 then goto AdjustNumberInc peek MEM_BUT_SET, b0 button BUT_SET, 1, 255, 0, b0, 1, AdjustNumberSave ; Save number and move to next poke MEM_BUT_SET, b0 peek MEM_BUT_MODE, b0 button BUT_MODE, 1, 255, 0, b0, 1, AdjustNumberCancel ; Cancel adjust poke MEM_BUT_MODE, b0 pause 10 goto AdjustNumberButtons AdjustNumberInc: ; poke MEM_BUT_ADJUST, b0 gosub KeySound ; Working with BCD numbers, so need to faff about a bit. let b0 = b15 & $0f if b0 = $09 then let b15 = b15 & $f0 + $10 else inc b15 end if if b15 > b14 then let b15 = $00 end if let b18 = 1 ; Flag to indicate number has changed. goto AdjustNumber AdjustNumberSave: poke MEM_BUT_SET, b0 gosub KeySound do pause 10 loop while BUT_SETP = 1 let b17 = 1 return AdjustNumberCancel: poke MEM_BUT_MODE, b0 gosub KeySound do pause 10 loop while BUT_MODEP = 1 let b17 = 0 return SwitchBrightness: let b0 = v_BRIGHTNESS & $10 if b0 = 0 then if v_BRIGHTNESS = 0 then peek MEM_BRIGHT_CURR, b0 let v_BRIGHTNESS = $10 | b0 ; Turn on auto brightness. pause 100 gosub KeySound else dec V_BRIGHTNESS end if else let v_BRIGHTNESS = $0f ; Turn off auto brightness and set to max. end if ; Save the brightness to the DS1307. setfreq m8 hi2cout DS1307_USR_BRIGHTNESS, (v_BRIGHTNESS) setfreq m32 goto SetModeBrightness SampleBrightness: peek MEM_BRIGHT_CURR, b0 peek MEM_BRIGHT_HIGHER, b1 readadc BRIGHTNESS_SENSOR, b2 peek MEM_BRIGHT_COUNT, b3 let b2 = b2 / 25 + 4 if b2 < b0 then if b1 = 1 then poke MEM_BRIGHT_HIGHER, 0 let b3 = 0 else inc b3 if b3 > 100 then dec b0 poke MEM_BRIGHT_CURR, b0 let b3 = 0 end if end if elseif b2 > b0 then if b1 = 0 then poke MEM_BRIGHT_HIGHER, 1 let b3 = 0 else inc b3 if b3 > 100 then inc b0 poke MEM_BRIGHT_CURR, b0 let b3 = 0 end if end if else let b3 = 0 end if poke MEM_BRIGHT_COUNT, b3 return ; Save the mode to the DS1307. SaveMode: setfreq m8 hi2cout DS1307_USR_MODE, (v_MODE) setfreq m32 return SwitchMode: ; 0=Words, 1=Hours/Minutes, 2=Minutes/Seconds let b0 = v_MODE & $7f + 1 if b0 > 2 then let b0 = 0 end if let v_MODE = v_MODE & $80 + b0 gosub SaveMode ; Force update next time round. ResetDisplay: let v_MINUTES_PREV = $ff let v_SECONDS_PREV = $ff ; *** Fall-through. SetupMode: gosub ClearDisplay gosub SendToDisplay gosub SetTempDisplayMode ; *** Fall-through. SetModeBrightness: let MAX7219_DATA_2 = v_BRIGHTNESS & $0f let b1 = v_MODE & $7f if b1 = 0 then let MAX7219_DATA_1 = MAX7219_DATA_2 ' Normal "Word" mode, same brightness on top and bottom. else let MAX7219_DATA_1 = MAX7219_DATA_2 / 3 ; "Minute" or "Second" mode, set top half to 1/3 brightness. end if if MAX7219_DATA_2 > 7 then high TEMP_BRIGHTNESS else low TEMP_BRIGHTNESS end if goto MAX7219_SetIntensity SwitchTempDisplayMode: let b0 = v_MODE & $80 if b0 = 0 then let v_MODE = v_MODE | $80 else let v_MODE = v_MODE & $7f end if gosub SaveMode ; *** Fall-through. SetTempDisplayMode: let b0 = v_MODE & $80 let b1 = TEMP_FARENP if b0 = 0 then if b1 = 1 then low TEMP_FAREN end if else if b1 = 0 then high TEMP_FAREN end if end if return FromBCD: let b1 = b0 / 16 * 10 let b0 = b0 & $0f + b1 return ShowTimeInWords: if v_MINUTES <> v_MINUTES_PREV then gosub ClearDisplay ; Convert hours from BCD time in to normal values to deal with easier. let b0 = v_HOURS & $3f ; Remove 24 hour flag. gosub FromBCD let v_HOURS = b0 ; Clock is running in 24 hour mode, so convert hours to 12 hour. if v_HOURS = 0 then let v_HOURS = 12 elseif v_HOURS > 12 then let v_HOURS = v_HOURS - 12 end if ; IT IS let DISP_TABLE_IDX = TAB_TIM_ITIS gosub DisplayWord ; Fuzzy time 58-02=0, 03-07=5, 08-12=10, 13-17=15, 18-22=20, 23-27=25, 28-32=30, 33-37=35, 38-42=40, 43-37=45, 48-52=50, 53-57=55 ; Minutes if v_MINUTES <= $02 then let DISP_TABLE_IDX = TAB_TIM_OCLOCK elseif v_MINUTES <= $07 then let DISP_TABLE_IDX = TAB_TIM_FIVE elseif v_MINUTES <= $12 then let DISP_TABLE_IDX = TAB_TIM_TEN elseif v_MINUTES <= $17 then let DISP_TABLE_IDX = TAB_TIM_A_QUARTER elseif v_MINUTES <= $22 then let DISP_TABLE_IDX = TAB_TIM_TWENTY elseif v_MINUTES <= $27 then let DISP_TABLE_IDX = TAB_TIM_TWENTYFIVE elseif v_MINUTES <= $32 then let DISP_TABLE_IDX = TAB_TIM_HALF else if v_MINUTES <= $37 then let DISP_TABLE_IDX = TAB_TIM_TWENTYFIVE elseif v_MINUTES <= $42 then let DISP_TABLE_IDX = TAB_TIM_TWENTY elseif v_MINUTES <= $47 then let DISP_TABLE_IDX = TAB_TIM_A_QUARTER elseif v_MINUTES <= $52 then let DISP_TABLE_IDX = TAB_TIM_TEN elseif v_MINUTES <= $57 then let DISP_TABLE_IDX = TAB_TIM_FIVE else let DISP_TABLE_IDX = TAB_TIM_OCLOCK end if ; Gone past 30 minutes, so adjust hour to the hour we are coming up to. inc v_HOURS if v_HOURS > 12 then let v_HOURS = 1 end if end if gosub DisplayWord ; Past or To. If not O'Clock. if v_MINUTES >= $03 and v_MINUTES < $58 then if v_MINUTES < $33 then let DISP_TABLE_IDX = TAB_TIM_PAST else let DISP_TABLE_IDX = TAB_TIM_TO end if gosub DisplayWord end if ; Hour. let DISP_TABLE_IDX = v_HOURS - 1 * 4 + TAB_TIM_ONE gosub DisplayWord gosub SendToDisplay let v_MINUTES_PREV = v_MINUTES end if return ; -------------------------------------------------------------------------------- ; Display a word. Which LEDs to light are read from the table. DisplayWord: ; DISP_TABLE_IDX = Index in table of word to display. symbol DW_LINE = b2 symbol DW_MAIN_DATA = b3 symbol DW_MAIN_MEM_IDX = b4 symbol DW_OTHER_MEM_IDX = b6 symbol DW_DATA = b5 readtable DISP_TABLE_IDX, DW_LINE ; Line inc DISP_TABLE_IDX readtable DISP_TABLE_IDX, DW_MAIN_DATA ; Main data inc DISP_TABLE_IDX if DW_LINE > 4 then let DW_MAIN_MEM_IDX = DW_LINE - 5 + MEM_DISPLAY_BOTTOM let DW_OTHER_MEM_IDX = MEM_DISPLAY_BOTTOM_END - 1 else let DW_MAIN_MEM_IDX = DW_LINE + MEM_DISPLAY_TOP let DW_OTHER_MEM_IDX = MEM_DISPLAY_TOP_END - 1 end if peek DW_MAIN_MEM_IDX, DW_DATA let DW_DATA = DW_DATA or DW_MAIN_DATA poke DW_MAIN_MEM_IDX, DW_DATA readtable DISP_TABLE_IDX, DW_MAIN_DATA inc DISP_TABLE_IDX peek DW_OTHER_MEM_IDX, DW_DATA let DW_DATA = DW_DATA or DW_MAIN_DATA poke DW_OTHER_MEM_IDX, DW_DATA inc DW_OTHER_MEM_IDX readtable DISP_TABLE_IDX, DW_MAIN_DATA peek DW_OTHER_MEM_IDX, DW_DATA let DW_DATA = DW_DATA or DW_MAIN_DATA poke DW_OTHER_MEM_IDX, DW_DATA return ; -------------------------------------------------------------------------------- ; Show the time in hours and minutes. Hours in top half, minutes in bottom half. ShowHoursMinutes: if v_MINUTES <> v_MINUTES_PREV then gosub ClearDisplay ; NB. Time values are in BCD. let DISP_NUM_TO_SHOW = v_HOURS & $3f ; Take off the 24 Hour flag. gosub DisplayNumTop let DISP_NUM_TO_SHOW = v_MINUTES gosub DisplayNumBottom gosub SendToDisplay let v_MINUTES_PREV = v_MINUTES end if return ; -------------------------------------------------------------------------------- ; Show the time in minutes and seconds. Minutes in top half, seconds in bottom ; half. ShowMinutesSeconds: if v_SECONDS <> v_SECONDS_PREV then gosub ClearDisplay ; NB. Time values are in BCD. let DISP_NUM_TO_SHOW = v_MINUTES gosub DisplayNumTop let DISP_NUM_TO_SHOW = v_SECONDS gosub DisplayNumBottom gosub SendToDisplay let v_SECONDS_PREV = v_SECONDS end if return ; ******************************************************************************** ; *** Display Functions ********************************************************** ; ******************************************************************************** ; -------------------------------------------------------------------------------- ; Send the data from the display buffer to the MAX7219's. It only sends data that ; has changed since the last time data was sent to the MAX7219's. SendToDisplay: symbol STD_MEM_TOP = b5 symbol STD_MEM_BOT = b6 symbol STD_MEM_TOP_CMP = b7 symbol STD_MEM_BOT_CMP = b8 symbol STD_CMP_TOP_DATA = b3 symbol STD_CMP_BOT_DATA = b4 let MAX7219_REGISTER = MAX7219_DIGIT0 let STD_MEM_TOP = MEM_DISPLAY_TOP let STD_MEM_TOP_CMP = MEM_DISPLAY_TOP_CMP let STD_MEM_BOT_CMP = MEM_DISPLAY_BOTTOM_CMP for STD_MEM_BOT = MEM_DISPLAY_BOTTOM to MEM_DISPLAY_BOTTOM_END peek STD_MEM_TOP, MAX7219_DATA_1 ; Read new display data. peek STD_MEM_BOT, MAX7219_DATA_2 peek STD_MEM_TOP_CMP, STD_CMP_TOP_DATA ; Read last displayed data. peek STD_MEM_BOT_CMP, STD_CMP_BOT_DATA ; if b1 = b3 and b2 <> b4 then ; poke b8, b2 ; ; gosub MAX7219_SendCmdAndDataTo2 ; elseif b1 <> b3 and b2 = b4 then ; poke b7, b1 ; ; gosub MAX7219_SendCmdAndDataTo1 ; elseif b1 <> b3 and b2 <> b4 then ; If changed, then send to MAX7219. if MAX7219_DATA_1 <> STD_CMP_TOP_DATA or MAX7219_DATA_2 <> STD_CMP_BOT_DATA then ; If changed, then send to MAX7219. ; Save new displayed data. poke STD_MEM_TOP_CMP, MAX7219_DATA_1 poke STD_MEM_BOT_CMP, MAX7219_DATA_2 gosub MAX7219_SendCmdAndSepData2Both endif inc MAX7219_REGISTER ; Next digit. inc STD_MEM_TOP inc STD_MEM_TOP_CMP inc STD_MEM_BOT_CMP next goto MAX7219_ShutdownOff ; -------------------------------------------------------------------------------- ; Display 2 digit number in the top half of the display DisplayNumTop: ; NB. Values should in BCD. let DISP_TABLE_IDX = DISP_NUM_TO_SHOW & 15 gosub DisplayNum01Top let DISP_TABLE_IDX = DISP_NUM_TO_SHOW / 16 ; *** Fall-through ; Display the "Tens" part of the number. DisplayNum10Top: ; DISP_TABLE_IDX = Number to display. let DISP_TABLE_IDX = DISP_TABLE_IDX & $00FF * 7 + TAB_NUM_LEFT goto DisplayTopAdj: ; Display the "Unit" part of the number. DisplayNum01Top: ; DISP_TABLE_IDX = Number to display. let DISP_TABLE_IDX = DISP_TABLE_IDX & $00FF * 7 + TAB_NUM_MIDDLE goto DisplayTopAdj: ; -------------------------------------------------------------------------------- ; Display 2 digit number in the bottom half of the display DisplayNumBottom: ; NB. Values should in BCD. let DISP_TABLE_IDX = DISP_NUM_TO_SHOW & 15 gosub DisplayNum01Bottom ;return let DISP_TABLE_IDX = DISP_NUM_TO_SHOW / 16 ; *** Fall-through. ; Display the "Tens" part of the number. DisplayNum10Bottom: ; DISP_TABLE_IDX = Number to display. let DISP_TABLE_IDX = DISP_TABLE_IDX & $00FF * 7 + TAB_NUM_MIDDLE goto DisplayBottom ; Display the "Unit" part of the number. DisplayNum01Bottom: ; DISP_TABLE_IDX = Number to display. let DISP_TABLE_IDX = DISP_TABLE_IDX & $00FF * 7 + TAB_NUM_RIGHT goto DisplayBottom #rem ShowNum: let DISP_NUM_TO_SHOW = b0 gosub ClearDisplay gosub DisplayNum gosub SendToDisplay return DisplayNum: let DISP_TABLE_IDX = DISP_NUM_TO_SHOW / 100 * 7 + TAB_NUM_LEFT gosub DisplayTop let b0=DISP_NUM_TO_SHOW / 100 let DISP_TABLE_IDX = DISP_NUM_TO_SHOW % 100 / 10 * 7 + TAB_NUM_MIDDLE gosub DisplayTop let DISP_TABLE_IDX = DISP_NUM_TO_SHOW % 10 * 7 + TAB_NUM_RIGHT goto DisplayTop #endrem ; -------------------------------------------------------------------------------- ; Draw the "character" pointed to by DISP_TABLE_IDX in the top half of the ; display. DisplayTop: ; DISP_TABLE_IDX = Start table address to read from. DISP_TABLE_IDX will be updated. for DISP_MEM = MEM_DISPLAY_TOP to MEM_DISPLAY_TOP_END readtable DISP_TABLE_IDX, DISP_DATA peek DISP_MEM, DISP_MERGE let DISP_DATA = DISP_DATA | DISP_MERGE poke DISP_MEM, DISP_DATA inc DISP_TABLE_IDX next return ; -------------------------------------------------------------------------------- ; Draw the "character" pointed to by DISP_TABLE_IDX in the top half of the ; display adjusted one bit to the right. This is to offset the characters that ; will appear in the middle of the display. DisplayTopAdj: ; DISP_TABLE_IDX = Start table address to read from. DISP_TABLE_IDX will be updated. ;((x & 1) * 128) + ((x & 254) / 2) for DISP_MEM = MEM_DISPLAY_TOP to MEM_DISPLAY_TOP_END readtable DISP_TABLE_IDX, DISP_DATA ; Adjust right one pixel. let DISP_MERGE = DISP_DATA & 1 * 128 let DISP_DATA = DISP_DATA / 2 + DISP_MERGE peek DISP_MEM, DISP_MERGE let DISP_DATA = DISP_DATA | DISP_MERGE poke DISP_MEM, DISP_DATA inc DISP_TABLE_IDX next return ; -------------------------------------------------------------------------------- ; Draw the "character" pointed to by DISP_TABLE_IDX in the bottom half of the ; display. DisplayBottom: ; DISP_TABLE_IDX = Start table address to read from. DISP_TABLE_IDX will be updated. for DISP_MEM = MEM_DISPLAY_BOTTOM to MEM_DISPLAY_BOTTOM_END readtable DISP_TABLE_IDX, DISP_DATA peek DISP_MEM, DISP_MERGE let DISP_DATA = DISP_DATA | DISP_MERGE poke DISP_MEM, DISP_DATA inc DISP_TABLE_IDX next return ; -------------------------------------------------------------------------------- ; Clear the display. ClearDisplay: gosub ClearDisplayBottom ; *** Fall-through *** ClearDisplayTop: let b13 = MEM_DISPLAY_TOP_CMP for DISP_MEM = MEM_DISPLAY_TOP to MEM_DISPLAY_TOP_END poke DISP_MEM, 0 poke b13, 255 inc b13 next return ClearDisplayBottom: let b13 = MEM_DISPLAY_BOTTOM_CMP for DISP_MEM = MEM_DISPLAY_BOTTOM to MEM_DISPLAY_BOTTOM_END poke DISP_MEM, 0 poke b13, 255 inc b13 next return ; ******************************************************************************** ; *** DS1307 Functions *********************************************************** ; ******************************************************************************** DS1307_Initialise: setfreq m8 hi2csetup i2cmaster, DS1307_ADDRESS, i2cslow_8, i2cbyte gosub DS1307_24HourMode let b1 = 0 gosub DS1307_SetClockHalt goto DS1307_SetSQWE_1Hz ; Set the CH (Clock Halt) bit in RTC. DS1307_SetClockHalt: ; b1.0 = Clock Halth (CH) state hi2cin DS1307_SECONDS, (DS1307_DATA) if DS1307_SECONDS_CH <> bit8 then ;(bit8 = bit 0 of b1) let DS1307_SECONDS_CH = bit8 hi2cout DS1307_SECONDS, (DS1307_DATA) end if return DS1307_SetSQWE_1Hz: let DS1307_DATA = 0 ; Out = 0 and RS1/RS0 = 0. let DS1307_CONTROL_SQWE = 1 ; Set SQWE bit in DS1307_DATA (must be b0). hi2cout DS1307_CONTROL, (DS1307_DATA) return #rem ; Switch to 12 hour mode DS1307_12HourMode: hi2cin DS1307_HOURS, (DS1307_DATA) if DS1307_HOURS_1224 = 0 then ; BCD to BIN let b1 = DS1307_DATA & $30 / 16 * 10 let b1 = DS1307_DATA & $0f + b1 let b2 = 1 if b1 >= 12 then if b1 > 12 then let b1 = b1 - 12 endif let b2 = 1 else if b1 = 0 then let b1 = 12 end if let b2 = 0 endif ; BIN to BCD let DS1307_DATA = b1 / 10 * 16 let DS1307_DATA = b1 % 10 + DS1307_DATA if b2 = 1 then let DS1307_HOURS_AMPM = 1 ' Set AM/PM but in DS1307_DATA (must be b0). endif let DS1307_HOURS_1224 = 1 hi2cout DS1307_HOURS, (DS1307_DATA) end if return #endrem ; Switch to 24 hour mode DS1307_24HourMode: hi2cin DS1307_HOURS, (DS1307_DATA) if DS1307_HOURS_1224 = 1 then ; BCD to BIN let b1 = DS1307_DATA & $10 / 16 * 10 let b1 = DS1307_DATA & $0f + b1 if DS1307_HOURS_AMPM = 1 then if b1 < 12 then let b1 = b1 + 12 end if elseif b1 = 12 then let b1 = 0 end if ; BIN to BCD let DS1307_DATA = b1 / 10 * 16 let DS1307_DATA = b1 % 10 + DS1307_DATA ;let DS1307_HOURS_1224 = 0 ; Bit will already be 0, so don't need to explicitly set it. hi2cout DS1307_HOURS, (DS1307_DATA) end if return ; ******************************************************************************** ; *** MAX7219 Functions ********************************************************** ; ******************************************************************************** MAX7219_Initialise: setfreq m32 high MAX7219_LOAD low MAX7219_CLK low MAX7219_DIN pause 10 let MAX7219_REGISTER = MAX7219_DECODE_MODE let MAX7219_DATA_1 = $00 ; Don't use decode mode for any data. gosub MAX7219_SendCmdAndDataToBoth let MAX7219_DATA_1 = $03 let MAX7219_DATA_2 = $0c gosub MAX7219_SetIntensity let MAX7219_REGISTER = MAX7219_SCAN_LIMIT let MAX7219_DATA_1 = $06 ; Using 7 digits (0-6); not using the 8th digit. gosub MAX7219_SendCmdAndDataToBoth gosub MAX7219_ShutdownOff goto MAX7219_TestModeOff ; Return will be peformed by this function MAX7219_ShutdownOff: let MAX7219_REGISTER = MAX7219_SHUTDOWN let MAX7219_DATA_1 = $01 goto MAX7219_SendCmdAndDataToBoth ; Return will be peformed by this function #rem MAX7219_ShutdownOn: let MAX7219_REGISTER = MAX7219_SHUTDOWN let MAX7219_DATA_1 = $00 goto MAX7219_SendCmdAndDataToBoth ; Return will be peformed by this function #endrem MAX7219_TestModeOn: let MAX7219_REGISTER = MAX7219_TEST_MODE let MAX7219_DATA_1 = $01 goto MAX7219_SendCmdAndDataToBoth ; Return will be peformed by this function MAX7219_TestModeOff: let MAX7219_REGISTER = MAX7219_TEST_MODE let MAX7219_DATA_1 = $00 goto MAX7219_SendCmdAndDataToBoth ; Return will be peformed by this function MAX7219_SetIntensity: ; MAX7219_DATA_1 = Intensity level for top half. ; MAX7219_DATA_2 = Intensirt level for bottom half. let MAX7219_REGISTER = MAX7219_INTENSITY goto MAX7219_SendCmdAndSepData2Both ; Return will be peformed by this function MAX7219_SendCmdAndDataToBoth: ; MAX7219_REGISTER = Register ; MAX7219_DATA_1 = Data gosub MAX7219_SendCmdAndData ; This will send to the second MAX7219 gosub MAX7219_SendCmdAndData ; This will send to the first MAX7219 pulsout MAX7219_LOAD, 1 return MAX7219_SendCmdAndSepData2Both: ; MAX7219_REGISTER = Register ; MAX7219_DATA_1 = Data for chip 1 ; MAX7219_DATA_2 = Data for chip 2 swap MAX7219_DATA_1, MAX7219_DATA_2 ; We have to send the data for chip 2 first, so swap the Data values gosub MAX7219_SendCmdAndData ; Send to the second MAX7219 swap MAX7219_DATA_1, MAX7219_DATA_2 ; Swap the values back. gosub MAX7219_SendCmdAndData ; Send to the first MAX7219 pulsout MAX7219_LOAD, 1 return MAX7219_SendCmdAndDataTo1: ; MAX7219_REGISTER = Register. ; MAX7219_DATA_1 = Data for chip 1. gosub MAX7219_SendCmdAndData pulsout MAX7219_LOAD, 1 return MAX7219_SendCmdAndDataTo2: ; MAX7219_REGISTER = Register. ; MAX7219_DATA_2 = Data for chip 2. swap MAX7219_DATA_1, MAX7219_DATA_2 gosub MAX7219_SendCmdAndData ; Send data for chip 2. swap MAX7219_REGISTER, MAX7219_DATA_1 ; Need to preserve MAX7219_REGISTER. let MAX7219_REGISTER = MAX7219_NOOP ; Send NOOP for chip 1. gosub MAX7219_SendCmdAndData swap MAX7219_REGISTER, MAX7219_DATA_1 ; Restore MAX7219_REGISTER.. pulsout MAX7219_LOAD, 1 return MAX7219_SendCmdAndData: ; MAX7219_REGISTER = Register. ; MAX7219_DATA_1 = Data. ; b3 & b4 used as temp. let MAX7219_SEND_DATA = MAX7219_REGISTER gosub MAX7219_Send let MAX7219_SEND_DATA = MAX7219_DATA_1 ; *** Fall-through is intended. *** MAX7219_Send: ; b3 = Data to send for MAX7219_SEND_COUNT = 0 to 7 if MAX7219_SEND_DATA > 127 then high MAX7219_DIN else low MAX7219_DIN end if pulsout MAX7219_CLK, 1 MAX7219_SEND_DATA = MAX7219_SEND_DATA * 2 next low MAX7219_DIN return
Recent Comments