Schema for the display of the time:-
Schema for the display of the temperature:-
You don't stop playing because you get old; You get old because you stop playing.
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
I originaly thought of reading and displaying the temperature from the PICAXE 18M2+, however there wasn't a lot of program memory left, and additionally reading the temperature using the readtemp12 command actually stops the chip from doing anything else – like responding to button presses – for about ¾ of a second, so I decided instead to use a separate PICAXE 08M2 to read and display the time.
Light reflector array drilled in to a piece of MDF. I drilled pilot holes first, then used large countersink to produce the beveled edge:-
I wandered a bit in the lower left corner, so stuck on some cardboard to fill the holes along the edge.
This program is used on a PICAXE 08M2 to read the temperature from a DS18B20 temperature sensor and display it on a 3 digit 7 segment LED display. A MAX7219 LED driver is used to drive the display.
The main processor can also control this chip through 2 inputs; one to control the brightness level, and the other display the temperature in farenheit.
#picaxe 08m2 #no_data ; Project: Word Clock v2. ; File: ReadDisplayTemp.bas ; Description: ; Read temperature from a DS18B20 and display on a three ; digit 7 segment LED display using a MAX7219 LED display ; driver. ; ; 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. ; MAX7219 Pins symbol MAX7219_LOAD = C.1 symbol MAX7219_CLK = C.0 symbol MAX7219_DIN = C.2 ; 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 ; DS18B20 Pins symbol DS18B20_DQ = C.4 ; Pins used by main processor to control display. symbol DISPLAY_F = C.5 ; Display in Farenheit. symbol DISPLAY_FP = pinC.5 symbol LOW_BRIGHTNESS = C.3 ; Display brightness high or low. symbol LOW_BRIGHTNESSP = pinC.3 symbol P_Register = b0 symbol P_Data = b1 symbol V_Temp1 = b3 symbol V_Temp2 = b4 symbol V_Neg = b8 symbol V_TempFrac = b9 symbol V_TempWhole = b10 symbol V_Digit0 = b11 symbol V_Digit1 = b12 symbol V_Digit2 = b13 symbol V_Temperature = w3 ; b6 b7 symbol V_LowBrightness = b14 letThereBeLight: setfreq m4 ; This long delay is to allow the chip to be more easily programmed later, ; because further down we "disconnect" the chip so that it stops looking for ; new downloads. pause 3000 let V_LowBrightness = 0 input DISPLAY_F input LOW_BRIGHTNESS gosub MAX7219_Initialise ; We are using C.5 (serial in) as an input (to display farenheit), so we need ; to stop the chip from scanning the serial in pin looking for a new download. ; Once the disconnect command has run, you have to do a hard-reset to download ; a new program; see the manual. disconnect main: setfreq m4 readtemp12 DS18B20_DQ, V_Temperature setfreq m8 gosub displayTemp if LOW_BRIGHTNESSP <> V_LowBrightness then let V_LowBrightness = LOW_BRIGHTNESSP if V_LowBrightness = 0 then let P_Data = $05 else let P_Data = $0E end if gosub MAX7219_SetIntensity end if ;pause 1000 sleep 2 goto main ; The 3 digit 7 segment display I'm using has some segments that don't work; ; notably the e segment of the first character, and the DP segments of the ; first and third characters. ; So the displaying of the temperature below is a bit more complicated than ; would normally be required, to work around the problems with the display. displayTemp: let V_Neg = 0 if V_Temperature > $7FFF then let V_Temperature = -V_Temperature let V_Neg = 1 end if if DISPLAY_FP = 1 then ; Convert C to F. 115/64 = 1.7968 (1.8 ish), and 512 is 32 * 16 (temp from DS18B20 is in 16th's of a degree). let V_Temperature = V_Temperature * 115 / 64 + 512 end if let b9 = V_Temperature & 15 * 10 / 16 ; frac let b10= V_Temperature / 16 ; whole ; Work out what to display in each of the three digits. if V_Neg = 1 then let V_Digit0 = 10 ; minus sign. if b10 > 99 then ; Can't display anything below -99, so show EE. If it's below -99 we're probably dead anyway. let b12 = 11 ; E let b13 = 11 ; E elseif b10 > 9 then let b12 = b10 / 10 let b13 = b10 % 10 else let b12 = b10 | $80 ; Turn on DP let b13 = b9 end if else if b10 > 99 then let b11 = b10 / 100 let b12 = b10 / 10 % 10 let b13 = b10 % 10 elseif b10 < 20 then if b10 > 9 then let b11 = b10 / 10 else let b11 = 15 ; blank end if let b12 = b10 % 10 | $80 ; Turn on DP let b13 = b9 else let b11 = 15 let b12 = b10 / 10 let b13 = b10 % 10 end if end if ; Display it. let b0 = MAX7219_DIGIT0 let b1 = b11 gosub MAX7219_SendCmdAndDataTo1 let b0 = MAX7219_DIGIT1 let b1 = b12 gosub MAX7219_SendCmdAndDataTo1 let b0 = MAX7219_DIGIT2 let b1 = b13 gosub MAX7219_SendCmdAndDataTo1 return ; ******************************************************************************** ; *** MAX7219 Functions ********************************************************** ; ******************************************************************************** MAX7219_Initialise: output MAX7219_LOAD output MAX7219_CLK output MAX7219_DIN low MAX7219_LOAD low MAX7219_CLK low MAX7219_DIN pause 10 gosub MAX7219_TestModeOff gosub MAX7219_ShutdownOff let b0 = MAX7219_SCAN_LIMIT let b1 = $02 ; Using 3 digits. gosub MAX7219_SendCmdAndDataTo1 let b0 = MAX7219_DECODE_MODE let b1 = $7 ; Use BCD for digits 0, 1 and 2. gosub MAX7219_SendCmdAndDataTo1 let b1 = $0C ' Max brightness. gosub MAX7219_SetIntensity return MAX7219_ShutdownOff: let b0 = MAX7219_SHUTDOWN let b1 = $01 goto MAX7219_SendCmdAndDataTo1 ; Return will be peformed by this function #rem MAX7219_ShutdownOn: let b0 = MAX7219_SHUTDOWN let b1 = $00 goto MAX7219_SendCmdAndDataToBoth ; Return will be peformed by this function #endrem MAX7219_TestModeOn: let b1 = $01 goto MAX7219_TestModeSet ; Return will be peformed by this function MAX7219_TestModeOff: let b1 = $00 MAX7219_TestModeSet: let b0 = MAX7219_TEST_MODE goto MAX7219_SendCmdAndDataTo1 ; Return will be peformed by this function MAX7219_SetIntensity: ; b1 = Intensity level for top half. ; b2 = Intensirt level for bottom half. let b0 = MAX7219_INTENSITY ; *** Fall-through *** MAX7219_SendCmdAndDataTo1: ; b0 = Register. ; b1 = Data for chip 1. gosub MAX7219_SendCmdAndData ; For 7219 you only need to pulse the LOAD pin to load the data. pulsout MAX7219_LOAD, 1 return MAX7219_SendCmdAndData: ; b0 = Register. ; b1 = Data. ; b3 & b4 used as temp. let b3 = b0 gosub MAX7219_Send let b3 = b1 ; *** Fall-through is intended. *** MAX7219_Send: ; b3 = Data to send for b4 = 0 to 7 if b3 > 127 then high MAX7219_DIN else low MAX7219_DIN end if pulsout MAX7219_CLK, 1 b3 = b3 * 2 next low MAX7219_DIN return #rem 3 Digit/7 Segment display Pins 1 1 1 a 2 1 0 9 8 7 --- | | | | | | f| |b +-----------+ | g | | | --- | 8. 8. 8. | e| |c | | | | +-----------+ --- O | | | | | | d 1 2 3 4 5 6 1 = Digit 0 cathode 2 = Segment e 3 = Segment d 4 = Digit 1 cathode 5 = Segment c 6 = DP 7 = Digit 2 cathode 8 = Segment b 9 = Segment g 10 = Segment a 11 = Segment f 12 = NC #endrem
I decided to have a go at making a Word Clock, which, as the name implies, shows the time as words. The face of the clock will contain a grid of letters, and will show the approximate time by highlighting appropriate words within the grid.
For the processor I will use a PICAXE 18M2+ as I've used PICAXE before. The chips are cheap (£2) and are easy to program using the free Programming Editor.
To maintain the time I will use a DS1307 RTC with an external resonator. A better option was the DS3232 which has an internal resonator, but that only appears to be available in a surface mount package, which I've found difficult to build in to a circuit. The DS1307 comes in a simple, fat finger friendly, 8 pin DIP.
The clock face will contain a grid of 110 letters, 11 letters across by 10 down. Each letter will have a single LED to light it, thus requiring the ability to drive 110 LEDs.
I have gone for the MAX7219 drivers which are designed to drive up to 8 seven segment displays (plus decimal); i.e. a MAX7219 can drive a total of 64 LEDs. So I will need to use two of these.
The clock will be housed in a deep, 10 inch square picture frame. The clock face will consist of a vinyl mask with the letters cut out.
DS1307 RTC IC | http://www.techsupplies.co.uk | £2.30 | £3.50 |
32.768 kHz resonator | http://www.techsupplies.co.uk | £0.22 | |
CR2032 battery holder | http://www.techsupplies.co.uk | £0.40 | |
PICAXE-18M2 microcontroller | http://www.techsupplies.co.uk | £2.00 | |
MAX7219CNG LED driver (x2) | eBay (it_2002) | £3.90 | £1.35 |
5V AC-DC power supply | eBay (megabrokers) | £6.49 | |
3mm Ulra Bright White LED (x110) | eBay (bright_components) | £6.14 | £0.99 |
10 inch square 40mm deep picture frame | eBay (alanw7865 – Essex Gallery) | £13.00 | £3.00 |
SPST Momentary push switch (x4) | eBay (ha5ia) | £2.38 | |
2.1mm DC power panel mount socket | eBay (donedeal1966) | £0.28 | |
Royal Blue vellum paper | eBay (lynneduncan) | £0.10 | |
Resister 1k5 (x2) | |||
Resister 1k0 (x4) | |||
Resister 10k0 (x4) | |||
Resister 18k0 (x2) | |||
Resister 4k7 (x2) | |||
5mm standard red LED | |||
Capacitor 10uF Electrolytic (x2) | |||
Vinyl for clock face | http://www.provinylcutz.co.uk/ | £15.00 |
I did some initial testing of the electronics using a breadboard.
Since I don't have the ability to create proper circuit boards, I will be using strip board. I drew a rough sketch of the circuit layout:-
Starting to build the circuit:-
The leads next to the battery are to a socket which is used for programming the 18M2 micro controller.
Originally I placed a diode on the +V line as a way to protect the components if the power was connected incorrectly. However, I found that the ICs seemed to act erratically, so I assumed the diode was causing too much of a voltage drop resulting in the problem, so I took it out and everything worked OK.
The completed circuit:-
The MAX7219 ICs require a 0.33uF electrolytic capacitor on the power lines. Since there wasn't enough room on the top of the board, I soldered a capacitor on the underside of the board directly from the +V pin to the 0V pin.
The bundles of black and blue wires coming from the MAX7219 ICs are the leads for the LEDs.
The black wires between the resistors next to the 18M2 go to the 4 buttons.
The clock face will be illuminated by an array of 110 white LED's; one for each letter. The layout of the letters are on a fixed grid; 11 letters across by 10 letters down. The layout I decided on have letters that are 13mm tall, and spaced 12mm (on centre) horizontally, and 20mm (on centre) vertically. The grid is centred within a 250mm (10 inch) square.
The vinyl template, still with it's backing paper:-
I copied the letter grid from a similar project I saw on MAKE: http://blog.makezine.com/projects/small-word-clock/
The vinyl template has a sticky side and needed to be stuck to a a piece of glass. I decided to stick it to a piece of clear Perspex that I had available. It turned out to be quite difficult to get the vinyl positioned correctly and to remove air bubbles, of which there are still a few. I used the "wet method" to position the vinyl, which involved spraying water on the back of the vinyl and the surface it was going to be fixed to. The water is, apparently, supposed to allow some movement of the vinyl when it is positioned, but I found that as soon as touched the Perspex it became fixed – The vinyl is quite thin, so I didn't want to pull on it too hard to try and lift it again.
I decided to use a piece of thin Perspex, since it's easy to cut and drill for mounting the LED's. Once the clock was built though, an issue became apparent where ambient light from an LED went out through the Perspex and up in to adjacent cells.
Thin perspex marked with positions of LED's:-
Drilled and LEDs inserted:-
A small drop of superglus was used to hold each LED in place. I also drew in the digit and segment relations from the MAX7219 ICs. One MAX7219 will drive the top 5 rows of the grid, and the other MAX7219 will drive the lower 5 rows.
LEDs wired up:-
To wire the grid of LEDs, I simply used the legs of the LED's and soldered them to next LED. For each "digit" driven by the MAX7219, I joined all of the cathodes together, and for each "segment" driven by the MAX7219 I joined all of the anodes remembering that one MAX7219 drives the first 5 rows and the other drives the bottom 5 rows. I then just ran wires from an appropriate point in the LED lines to the circuit board.
Testing the display:-
Testing the display by showing the time as digits. The first MAX7219, which is driving the top half of the display, is set to about one third brightness, while the second MAX7219 is set to full brightness.
The restrict the amount of light leakage from one letter to the next, I created a grid using cardboard strips. I simply cut a number of card strips the same width, created cuts within each strip at appropriate intervals and made the grid simply by slotting the pieces together:-
I glued small tabs to each corner of the completed cardboard grid, and then used those tabs to tape the grid to the back of the perspex with the vinyl mask. I also inserted a piece of blue vellum paper to provide some colour and diffuse the light from the LED's:-
Completed clock:-
Below is the code for the PICAXE:-
#PICAXE 18M2 #terminal off ; Copyright (c) 2013 Marc Symonds. ; Feel free to copy and modify as you wish. #rem DS1307 Pins +---+ X1 -|1 |- Vcc X2 -| |- SQW/OUT +VBatt -| |- I2C/SCL 0V -| |- I2C/SDA +---+ PICAXE18-M2 Pins +---+ Piezo - (Out/In) C.2 -|1 |- C.1 (In/Out) - Button - Mode (Out) C.3 -| |- C.0 (In/Out) - Button - Set (In) C.4 -| |- C.7 (In/Out) - Button - Adjust (In) C.5 -| |- C.6 (In/Out) - Button - Brightness 0V - |5 |- Vcc (Out/In) B.0 -| |- B.7 (In/Out) - MAX7219/DATA DS1307 - (Out/In/I2C SDA) B.1 -| |- B.6 (In/Out) (Out/In) B.2 -| |- B.5 (In/Out) - MAX7219/CLK MAX7219/LOAD - (Out/In) B.3 -|9 |- B.4 (In/Out/I2C SCL) - DS1307 +---+ 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):- 0P 0A 0B 0C 0D 0E 0F 0G 6P 6A 6B 1P 1A 1B 1C 1D 1E 1F 1G 6C 6D 6E 2P 2A 2B 2C 2D 2E 2F 2G 6F 6G 7P First MAX7219 3P 3A 3B 3C 3D 3E 3F 3G 7A 7B 7C 4P 4A 4B 4C 4D 4E 4F 4G 7D 7E 7F -------------------------------- 0P 0A 0B 0C 0D 0E 0F 0G 6P 6A 6B 1P 1A 1B 1C 1D 1E 1F 1G 6C 6D 6E 2P 2A 2B 2C 2D 2E 2F 2G 6F 6G 7P Second MAX7219 3P 3A 3B 3C 3D 3E 3F 3G 7A 7B 7C 4P 4A 4B 4C 4D 4E 4F 4G 7D 7E 7F P = DP. #endrem ; MAX7219 Pins symbol MAX7219_LOAD = B.3 symbol MAX7219_DIN = B.7 symbol MAX7219_CLK = B.5 ; 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 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 symbol MEM_DISPLAY_BOTTOM_CMP = 51 ; Pins used for buttons. symbol BUT_MODE = C.1 symbol BUT_SET = C.0 symbol BUT_ADJUST = C.7 symbol BUT_BRIGHTNESS = C.6 symbol PIEZO = C.2 ; Data for displaying digits. ; 0 - 9 On left of display. symbol TAB_NUM_LEFT = 0 table TAB_NUM_LEFT, (%11100000, %10100000, %10100000, %10100000, %11100000, 0, 0) table (%01000000, %11000000, %01000000, %01000000, %11100000, 0, 0) table (%11100000, %00100000, %11100000, %10000000, %11100000, 0, 0) table (%11100000, %00100000, %01100000, %00100000, %11100000, 0, 0) table (%10100000, %10100000, %11100000, %00100000, %00100000, 0, 0) table (%11100000, %10000000, %11100000, %00100000, %11100000, 0, 0) table (%11100000, %10000000, %11100000, %10100000, %11100000, 0, 0) table (%11100000, %00100000, %00100000, %00100000, %00100000, 0, 0) table (%11100000, %10100000, %11100000, %10100000, %11100000, 0, 0) table (%11100000, %10100000, %11100000, %00100000, %11100000, 0, 0) ; 0 - 9 In middle of display. symbol TAB_NUM_MIDDLE = 70 table TAB_NUM_MIDDLE, (%00001110, %00001010, %00001010, %00001010, %00001110, 0, 0) table (%00000100, %00001100, %00000100, %00000100, %00001110, 0, 0) table (%00001110, %00000010, %00001110, %00001000, %00001110, 0, 0) table (%00001110, %00000010, %00000110, %00000010, %00001110, 0, 0) table (%00001010, %00001010, %00001110, %00000010, %00000010, 0, 0) table (%00001110, %00001000, %00001110, %00000010, %00001110, 0, 0) table (%00001110, %00001000, %00001110, %00001010, %00001110, 0, 0) table (%00001110, %00000010, %00000010, %00000010, %00000010, 0, 0) table (%00001110, %00001010, %00001110, %00001010, %00001110, 0, 0) table (%00001110, %00001010, %00001110, %00000010, %00001110, 0, 0) ; 0 - 9 On right of display. symbol TAB_NUM_RIGHT = 140 table TAB_NUM_RIGHT, (0, 0, 0, 0, 0, %11110110, %11011110) table (0, 0, 0, 0, 0, %01011001, %00101110) table (0, 0, 0, 0, 0, %11100111, %11001110) table (0, 0, 0, 0, 0, %11100101, %10011110) table (0, 0, 0, 0, 0, %10110111, %10010010) table (0, 0, 0, 0, 0, %11110011, %10011110) table (0, 0, 0, 0, 0, %11110011, %11011110) table (0, 0, 0, 0, 0, %11100100, %10010010) table (0, 0, 0, 0, 0, %11110111, %11011110) table (0, 0, 0, 0, 0, %11110111, %10011110) ; hr. symbol TAB_WRD_Hr = 210 table TAB_WRD_Hr, (%10000000, %11100010, %10010100, %10010100, %00000000, 0, 0) ; mi. symbol TAB_WRD_Mi = 217 table TAB_WRD_Mi, (%01010000, %10101010, %10101010, %10001010, %00000000, 0, 0) ; Pixels to light to tell the time in words. symbol TAB_TIM_ITIS = 224 symbol TAB_TIM_OCLOCK = 228 symbol TAB_TIM_FIVE = 232 symbol TAB_TIM_TEN = 236 symbol TAB_TIM_AQUARTER = 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, %11011000, %00000000, %00000000) table TAB_TIM_OCLOCK, ($09, %00000111, %00000000, %00001110) table TAB_TIM_FIVE, ($02, %00000011, %00000011, %00000000) table TAB_TIM_TEN, ($03, %00000111, %00000000, %00000000) table TAB_TIM_AQUARTER, ($01, %10111111, %00010000, %00000000) table TAB_TIM_TWENTY, ($02, %11111100, %00000000, %00000000) table TAB_TIM_TWENTYFIVE, ($02, %11111111, %00000011, %00000000) table TAB_TIM_HALF, ($03, %11110000, %00000000, %00000000) table TAB_TIM_PAST, ($04, %11110000, %00000000, %00000000) table TAB_TIM_TO, ($03, %00000000, %00000000, %00110000) table TAB_TIM_ONE, ($05, %11100000, %00000000, %00000000) table TAB_TIM_TWO, ($06, %00000000, %00011100, %00000000) table TAB_TIM_THREE, ($05, %00000011, %11100000, %00000000) table TAB_TIM_FOUR, ($06, %11110000, %00000000, %00000000) table TAB_TIM_FIVEw, ($06, %00001111, %00000000, %00000000) table TAB_TIM_SIX, ($05, %00011100, %00000000, %00000000) table TAB_TIM_SEVEN, ($08, %11111000, %00000000, %00000000) table TAB_TIM_EIGHT, ($07, %11111000, %00000000, %00000000) table TAB_TIM_NINE, ($04, %00000001, %00000000, %00001110) table TAB_TIM_TENw, ($09, %11100000, %00000000, %00000000) table TAB_TIM_ELEVEN, ($07, %00000111, %00000011, %10000000) table TAB_TIM_TWELVE, ($08, %00000111, %00000000, %01110000) symbol v_SECONDS = b20 symbol v_MINUTES = b21 symbol v_HOURS = b22 symbol v_SECONDS_PREV = b23 symbol v_MINUTES_PREV = b24 symbol v_MODE = b25 symbol v_BRIGHTNESS = b26 ; ******************************************************************************** ; *** Start setfreq m4 pause 500 ; Give other chips time to start up. let dirsB = %10101101 let dirsC = %11000011 gosub DS1307_Initialise gosub MAX7219_Initialise ; Load saved settings from DS1307. setfreq m8 hi2cin DS1307_USR_MODE, (v_MODE, v_BRIGHTNESS) setfreq m32 if v_MODE > 2 then let v_MODE = 0 end if let v_BRIGHTNESS = v_BRIGHTNESS & $0f gosub ResetDisplay main: setfreq m8 hi2cin DS1307_SECONDS, (v_SECONDS, v_MINUTES, v_HOURS) setfreq m32 on v_MODE gosub ShowTimeInWords, ShowHoursMinutes, ShowMinutesSeconds ;BUTTON pin,downstate,delay,rate,bytevariable,targetstate,address button BUT_MODE, 1, 255, 0, b10, 1, SwitchModeMain button BUT_BRIGHTNESS, 1, 255, 0, b11, 1, SwitchBrightnessMain button BUT_SET, 1, 255, 0, b12, 1, SetTime pause 10 goto main KeySound: sound PIEZO, (20, 40) return SwitchModeMain: gosub KeySound gosub SwitchMode goto main SwitchBrightnessMain: gosub KeySound gosub SwitchBrightness goto main SetTime: gosub KeySound gosub ClearDisplay ; Set top half of display dim and bottom half bright. let b1 = $03 let b2 = $0f gosub MAX7219_SetIntensity let w0 = TAB_WRD_HR gosub DisplayTop do pause 10 let b0 = BUT_SET loop while b0 = 1 let b15 = v_HOURS & $3f let b16 = $23 gosub AdjustNumber if b17 = 0 then SetTimeEnd let v_HOURS = v_HOURS & $C0 | b15 gosub ClearDisplayTop let w0 = TAB_WRD_MI gosub DisplayTop let b15 = v_MINUTES let b16 = $59 gosub AdjustNumber if b17 = 0 then SetTimeEnd let v_MINUTES = b15 ; 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 b5 = b15 gosub DisplayNumBottom gosub SendToDisplay AdjustNumberButtons: button BUT_ADJUST, 1, 100, 60, b13, 1, AdjustNumberInc ; Adjust number button BUT_SET, 1, 255, 0, b12, 1, AdjustNumberSave ; Save number and move to next button BUT_MODE, 1, 255, 0, b10, 1, AdjustNumberCancel ; Cancel adjust pause 10 goto AdjustNumberButtons AdjustNumberInc: 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 > b16 then let b15 = 0 end if goto AdjustNumber AdjustNumberSave: gosub KeySound do pause 10 let b0 = BUT_SET loop while b0 = 1 let b17 = 1 return AdjustNumberCancel: gosub KeySound do pause 10 let b0 = BUT_MODE loop while b0 = 1 let b17 = 0 return SwitchBrightness: if v_BRIGHTNESS = 0 then let v_BRIGHTNESS = $0f else dec v_BRIGHTNESS end if ; Save the brightness to the DS1307. setfreq m8 hi2cout DS1307_USR_BRIGHTNESS, (v_BRIGHTNESS) setfreq m32 goto SetModeBrightness SwitchMode: ; 0=Words, 1=Hours/Minutes, 2=Minutes/Seconds inc v_MODE if v_MODE > 2 then let v_MODE = 0 end if ; Save the mode to the DS1307. setfreq m8 hi2cout DS1307_USR_MODE, (v_MODE) setfreq m32 ; Force update next time round. ResetDisplay: let v_MINUTES_PREV = $ff let v_SECONDS_PREV = $ff ; *** Fall-through. SetupMode: gosub ClearDisplay gosub SendToDisplay ; *** Fall-through. SetModeBrightness: let b2 = v_BRIGHTNESS if v_MODE = 0 then let b1 = b2 else let b1 = b2 / 3 end if goto MAX7219_SetIntensity 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 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 w0 = 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 w0 = TAB_TIM_OCLOCK elseif v_MINUTES <= $07 then let w0 = TAB_TIM_FIVE elseif v_MINUTES <= $12 then let w0 = TAB_TIM_TEN elseif v_MINUTES <= $17 then let w0 = TAB_TIM_AQUARTER elseif v_MINUTES <= $22 then let w0 = TAB_TIM_TWENTY elseif v_MINUTES <= $27 then let w0 = TAB_TIM_TWENTYFIVE elseif v_MINUTES <= $32 then let w0 = TAB_TIM_HALF else if v_MINUTES <= $37 then let w0 = TAB_TIM_TWENTYFIVE elseif v_MINUTES <= $42 then let w0 = TAB_TIM_TWENTY elseif v_MINUTES <= $47 then let w0 = TAB_TIM_AQUARTER elseif v_MINUTES <= $52 then let w0 = TAB_TIM_TEN elseif v_MINUTES <= $57 then let w0 = TAB_TIM_FIVE else let w0 = 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 w0 = TAB_TIM_PAST else let w0 = TAB_TIM_TO end if gosub DisplayWord end if ; Hour. let w0 = v_HOURS - 1 * 4 + TAB_TIM_ONE gosub DisplayWord gosub SendToDisplay let v_MINUTES_PREV = v_MINUTES end if return DisplayWord: readtable w0, b2 ; Line inc w0 readtable w0, b3 ; Main data inc w0 if b2 > 4 then let b4 = b2 - 5 + MEM_DISPLAY_BOTTOM let b6 = MEM_DISPLAY_BOTTOM_END - 1 else let b4 = b2 + MEM_DISPLAY_TOP let b6 = MEM_DISPLAY_TOP_END - 1 end if peek b4, b5 let b5 = b5 or b3 poke b4, b5 readtable w0, b3 inc w0 peek b6, b5 let b5 = b5 or b3 poke b6, b5 inc b6 readtable w0, b3 peek b6, b5 let b5 = b5 or b3 poke b6, b5 return ShowHoursMinutes: if v_MINUTES <> v_MINUTES_PREV then gosub ClearDisplay let b5 = v_HOURS & $3f gosub DisplayNumTop let b5 = v_MINUTES gosub DisplayNumBottom gosub SendToDisplay let v_MINUTES_PREV = v_MINUTES end if return ShowMinutesSeconds: if v_SECONDS <> v_SECONDS_PREV then gosub ClearDisplay let b5 = v_MINUTES gosub DisplayNumTop let b5 = v_SECONDS gosub DisplayNumBottom gosub SendToDisplay let v_SECONDS_PREV = v_SECONDS end if return ; ******************************************************************************** ; *** Display Functions ********************************************************** ; ******************************************************************************** SendToDisplay: ; Sending to the MAX7219 is slow, so we only send data where something has changed. let b0 = MAX7219_DIGIT0 let b5 = MEM_DISPLAY_TOP let b7 = MEM_DISPLAY_TOP_CMP let b8 = MEM_DISPLAY_BOTTOM_CMP for b6 = MEM_DISPLAY_BOTTOM to MEM_DISPLAY_BOTTOM_END peek b5, b1 ' Read new display data. peek b6, b2 peek b7, b3 ' Read last displayed data. peek b8, b4 ; 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 b1 <> b3 or b2 <> b4 then ' If changed, then send to MAX7219. poke b7, b1 poke b8, b2 gosub MAX7219_SendCmdAndSepData2Both endif inc b0 inc b5 inc b7 inc b8 next goto MAX7219_ShutdownOff DisplayNumTop: let b0 = b5 & 15 gosub DisplayNum01Top let b0 = b5 / 16 ; *** Fall-through DisplayNum10Top: ; b0 = Number to display. let b1 = 0 let w0 = w0 * 7 + TAB_NUM_LEFT goto DisplayTopAdj: DisplayNum01Top: ; b0 = Number to display. let b1 = 0 let w0 = w0 * 7 + TAB_NUM_MIDDLE goto DisplayTopAdj: DisplayNumBottom: let b0 = b5 & 15 gosub DisplayNum01Bottom let b0 = b5 / 16 ; *** Fall-through. DisplayNum10Bottom: ; b0 = Number to display. let b1 = 0 let w0 = w0 * 7 + TAB_NUM_MIDDLE goto DisplayBottom: DisplayNum01Bottom: ; b0 = Number to display. let b1 = 0 let w0 = w0 * 7 + TAB_NUM_RIGHT goto DisplayBottom: DisplayTop: ; w0 = Start table address to read from. w0 will be updated. for b2 = MEM_DISPLAY_TOP to MEM_DISPLAY_TOP_END readtable w0, b3 peek b2, b4 let b3 = b3 | b4 poke b2, b3 let w0 = w0 + 1 next return ; Display data adjusted right by one bit. DisplayTopAdj: ; w0 = Start table address to read from. w0 will be updated. for b2 = MEM_DISPLAY_TOP to MEM_DISPLAY_TOP_END readtable w0, b3 peek b2, b4 let b3 = b3 / 2 | b4 ; Divide by 2 to adjust right. poke b2, b3 let w0 = w0 + 1 next return DisplayBottom: ; w0 = Start table address to read from. w0 will be updated. for b2 = MEM_DISPLAY_BOTTOM to MEM_DISPLAY_BOTTOM_END readtable w0, b3 peek b2, b4 let b3 = b3 | b4 poke b2, b3 let w0 = w0 + 1 next return ClearDisplay: gosub ClearDisplayBottom ; *** Fall-through *** ClearDisplayTop: for b0 = MEM_DISPLAY_TOP to MEM_DISPLAY_TOP_END poke b0, 0 next return ClearDisplayBottom: for b0 = MEM_DISPLAY_BOTTOM to MEM_DISPLAY_BOTTOM_END poke b0, 0 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, (b0) if DS1307_SECONDS_CH <> bit8 then ;(bit8 = bit 0 of b1) let DS1307_SECONDS_CH = bit8 hi2cout DS1307_SECONDS, (b0) end if return DS1307_SetSQWE_1Hz: let b0 = 0 ; Out = 0 and RS1/RS0 = 0 let DS1307_CONTROL_SQWE = 1 hi2cout DS1307_CONTROL, (b0) return #rem ; Switch to 12 hour mode DS1307_12HourMode: hi2cin DS1307_HOURS, (b0) if DS1307_HOURS_1224 = 0 then ; BCD to BIN let b1 = b0 & $30 / 16 * 10 let b1 = b0 & $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 b0 = b1 / 10 * 16 let b0 = b1 % 10 + b0 if b2 = 1 then let DS1307_HOURS_AMPM = 1 endif let DS1307_HOURS_1224 = 1 hi2cout DS1307_HOURS, (b0) end if return #endrem ; Switch to 24 hour mode DS1307_24HourMode: hi2cin DS1307_HOURS, (b0) if DS1307_HOURS_1224 = 1 then ; BCD to BIN let b1 = b0 & $10 / 16 * 10 let b1 = b0 & $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 b0 = b1 / 10 * 16 let b0 = b1 % 10 + b0 ;let DS1307_HOURS_1224 = 0 ; Bit will already be 0, so don't need to explicitly set it. hi2cout DS1307_HOURS, (b0) end if return ; ******************************************************************************** ; *** MAX7219 Functions ********************************************************** ; ******************************************************************************** MAX7219_Initialise: setfreq m32 high MAX7219_LOAD low MAX7219_CLK low MAX7219_DIN pause 10 let b0 = MAX7219_DECODE_MODE let b1 = $00 ; Don't use decode mode for any data. gosub MAX7219_SendCmdAndDataToBoth let b1 = $03 let b2 = $0c gosub MAX7219_SetIntensity let b0 = MAX7219_SCAN_LIMIT let b1 = $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 b0 = MAX7219_SHUTDOWN let b1 = $01 goto MAX7219_SendCmdAndDataToBoth ; Return will be peformed by this function #rem MAX7219_ShutdownOn: let b0 = MAX7219_SHUTDOWN let b1 = $00 goto MAX7219_SendCmdAndDataToBoth ; Return will be peformed by this function #endrem MAX7219_TestModeOn: b0 = MAX7219_TEST_MODE b1 = $01 goto MAX7219_SendCmdAndDataToBoth ; Return will be peformed by this function MAX7219_TestModeOff: b0 = MAX7219_TEST_MODE b1 = $00 goto MAX7219_SendCmdAndDataToBoth ; Return will be peformed by this function MAX7219_SetIntensity: ; b1 = Intensity level for top half. ; b2 = Intensity level for bottom half. let b0 = MAX7219_INTENSITY goto MAX7219_SendCmdAndSepData2Both ; Return will be peformed by this function MAX7219_SendCmdAndDataToBoth: ; b0 = Register ; b1 = Data low MAX7219_LOAD gosub MAX7219_SendCmdAndData ; This will send to the second MAX7219 ; pause 1 gosub MAX7219_SendCmdAndData ; This will send to the first MAX7219 high MAX7219_LOAD return MAX7219_SendCmdAndSepData2Both: ; b0 = Register ; b1 = Data for chip 1 ; b2 = Data for chip 2 low MAX7219_LOAD swap b2, b1 ; We have to send the data for chip 2 first, so swap the Data values gosub MAX7219_SendCmdAndData ; Send to the second MAX7219 swap b2, b1 ; Swap the values back. gosub MAX7219_SendCmdAndData ; Send to the first MAX7219 high MAX7219_LOAD return MAX7219_SendCmdAndDataTo1: ; b0 = Register. ; b1 = Data for chip 1. low MAX7219_LOAD gosub MAX7219_SendCmdAndData high MAX7219_LOAD return MAX7219_SendCmdAndDataTo2: ; b0 = Register. ; b2 = Data for chip 2. low MAX7219_LOAD swap b1, b2 gosub MAX7219_SendCmdAndData swap b0, b1 ; Need to preserve b0. let b0 = MAX7219_NOOP gosub MAX7219_SendCmdAndData swap b0, b1 ; Restore b0. high MAX7219_LOAD return MAX7219_SendCmdAndData: ; b0 = Register. ; b1 = Data. ; b3 & b4 used as temp. let b3 = b0 gosub MAX7219_Send let b3 = b1 ; *** Fall-through is intended. *** MAX7219_Send: ; b3 = Data to send for b4 = 0 to 7 if b3 > 127 then high MAX7219_DIN else low MAX7219_DIN end if pulsout MAX7219_CLK, 1 b3 = b3 * 2 next return
Recent Comments