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