#rem This is the green box with a sloping front and a line receptacle on top
Wattmeter.bas. Modified to provide an output for the Universal Transmitter
John Sainders 10/19/2021
#endrem
#picaxe 14M2
symbol RS232_out = B.0 'SEROUT, also used for the transmitter output
symbol Disp_clk = B.4 '74HC164 clocks on low to high
symbol Disp_en = B.5 'Positive pulse clocks the data & RS into the QC1602 display
symbol Disp_data = C.1 'MSB first
'input ports
symbol Watt_Port = B.1
symbol Curr_Port = B.2
symbol Volt_Port = B.3
symbol Two_Hz = pinC.0 'An interrupt port for the 14M2
symbol RangeX10 = pinC.2 'These 3 go low when the position named is selected
symbol Range100 = pinC.3
symbol Range300 = pinC.4
'Constants
DATA 0,(128,64,32,16,8,4,2,1) 'Mask for shifting into the 74HC164
DATA 8,($30,$30,$30,$38,$0C,$01,$06,$14,$80) 'Display Initialization string
DATA 17,($80,"Overload! ",0) '$80 is first line, $C0 2nd line
DATA 35,($85," W ",0)
DATA 40,($8D," MA",0)
DATA 45,($C5," V ",0)
DATA 50,($CD," WH",0)
DATA 55,($8D," A ",0)
DATA 60,($84," W ",0)
symbol Volt_off = 751 'There is a bias on the voltage circuit so that the count is 10/volt
'variables
symbol RS = bit0 'Low for command, High for data
symbol BLZ = bit1 'Blank leading zeroes, (not last one)
symbol Sec_phase = bit2 'Divides a second ito two halves
symbol Char = b1 'Used to bit-bang to the 74HC164 shift register
symbol Mask = b2 'Used to bit-bang to the 74HC164 shift register
symbol Mask_Addr = b3 'Used to bit'Used to bit-bang to the 74HC164 shift register
symbol Scratch = b4 'Used to bit'Used to bit-bang to the 74HC164 shift register
symbol Data_addr = b5 'Location of the data character in un-named memory
symbol Range = b6 '0=20W,1=60W,2=200W,3=600W,4=2000W, 5=overload
symbol Disp_loc = b7 'Position in the display to place a data item
symbol DP_loc = b8 'Location of the decimal point 0 = no DP, 1=X.XXX, etc
symbol Factor = b9 'For scaling watts and current
symbol Cycle_cnt = b10 'Increments every half second to 128 to transmit logging every minute
symbol Iter = b11 'General use
symbol Dummy = b12 'General use
symbol String_addr = b13 'Location of string in EEPROM
symbol CkSum = b14 'For Transmit
symbol MsgStartAddr = b15 'For Transmit
symbol LenChar = b16 'For Transmit
symbol MsgEndAddr = b17 'For Transmit
symbol Watt_sec = W11 'Watts is added every second, each minute 3600 is repeatdly subtracted
symbol Watt_hrs = W12 'Increments for each watt-hour
symbol Disp_val = W13 'Value to be displayed
init:
SETFREQ m16 'Lowest frequency to write one line in less than 500 ms
LOW Disp_en
LOW Disp_clk
FOR Data_addr = 8 TO 16
READ Data_addr,Char
GOSUB Disp_cmd
NEXT
SETINT %00000001,%00000001 'Interrupt when pin C.0 goes high
FOR Iter = 28 TO 67 'The fixed values of the logging output are pre-loaded
POKE Iter,","
NEXT
POKE 28,"H" 'If this order is reversed, you get blank lines in between logging rows
POKE 36,"W"
POKE 50,"C" 'If this order is reversed, you get blank lines in between logging rows
POKE 57,"V"
main:
PAUSE 1000 'This is always cut short by the interrupt at 500 ms
GOTO main
interrupt: 'every 500 ms
LET Range = 2*Range100 + Range300
LET Range = 2*RangeX10 + Range
LET Range = 5 - Range
INC Cycle_cnt
IF Cycle_cnt >= 128 THEN
LET Cycle_cnt = 0 '1 minute
ENDIF
IF Range = 5 THEN 'Overload takes preference
LET String_addr = 17
GOSUB Disp_String
ELSE
LET Sec_Phase = Cycle_cnt & %00000001 'Splits flow into two 500 ms sets
IF Sec_Phase = 0 THEN '300 ms
GOSUB Disp_Volts
GOSUB Disp_WH
ELSE
GOSUB Disp_Watts '150 ms
IF Cycle_Cnt = 63 OR Cycle_Cnt = 123 THEN
GOSUB Transmit
ELSE
GOSUB Disp_Current '150 ms
ENDIF
ENDIF
ENDIF
DO
PAUSE 1
LOOP WHILE Two_Hz = 1
SETINT %00000001,%00000001 'Interrupt when pin C.0 goes high
RETURN
Disp_Watts:
READADC10 Watt_Port,Disp_val
LOOKUP Range,(12,8,12,8,12),factor
LET Disp_val = factor * Disp_val
LOOKUP Range,(5,1,5,1,5),factor
LET Disp_val = Disp_val/Factor
LOOKUP Range,(1,1,2,2,5),DP_Loc
LET Disp_loc = $80
LET Scratch = Range + "0"
POKE 38,Scratch
LET Data_addr = 40
GOSUB Disp_4dec
LOOKUP Range,(100,100,10,10,1),factor
LET Disp_val = Disp_val/factor
LET Watt_sec = Watt_sec + Disp_val
DO WHILE Watt_sec >= 3600
INC Watt_Hrs
LET Watt_sec = Watt_sec - 3600
LOOP
IF Range < 4 THEN
LET String_addr = 35
ELSE
LET String_addr = 60
ENDIF
GOSUB Disp_string
RETURN
Disp_Current:
READADC10 Curr_Port,Disp_val
LOOKUP Range,(12,8,12,8,12),factor
LET Disp_val = factor * Disp_val
LOOKUP Range,(5,1,5,1,5),factor
LET Disp_val = Disp_val/Factor
LOOKUP Range,(2,2,0,0,1),DP_Loc
LET Disp_loc = $88
LET Data_addr = 52
GOSUB Disp_4dec
IF Range < 2 THEN
LET String_addr = 40
ELSE
LET String_addr = 55
ENDIF
GOSUB Disp_string
RETURN
Disp_Volts: '157 ms @ 16 Mhz
READADC10 Volt_Port,Disp_val
LET Disp_val = Disp_val + Volt_off
LET Disp_loc = $C0
LET DP_loc = 2
LET Data_addr = 59
GOSUB Disp_4dec
LET String_addr = 45
GOSUB Disp_String
RETURN
Disp_WH: 'Recycles at 65535, which is 65 KWH, about $10
LET Disp_loc = $C8
LET Data_addr = 30
GOSUB Disp_5dec
LET String_addr = 50
GOSUB Disp_String
RETURN
Disp_4dec: 'Watts, Current or Volts
'Displays number in Disp_val at location Disp_loc.
'Data starts at Data_addr, decimal point in DP_val
LET Char = Disp_loc 'Place cursor at desired location on the display
GOSUB Disp_Cmd
LET bptr = Data_addr
BINTOASCII Disp_val,Dummy,@bptrinc,@bptrinc,@bptrinc,@bptr 'MSD first, does not exceed 8184
LET bptr = Data_addr
FOR Iter = 0 TO 3
LET Char = @bptrinc
SELECT Iter
CASE 0
IF Char = "0" THEN
LET BLZ = 1
ELSE
LET BLZ = 0
ENDIF
CASE 1 TO 2
IF BLZ = 1 AND Char <> "0" THEN
LET BLZ = 0
ENDIF
CASE 3
LET BLZ = 0
ENDSELECT
IF BLZ = 1 AND Iter < DP_loc THEN
LET Char = " "
ENDIF
GOSUB Disp_Char
IF DP_loc = Iter THEN
LET Char = "."
GOSUB Disp_Char
ENDIF
NEXT
RETURN
Disp_5dec: 'Watt - Hours only, no dP
'Displays number in Disp_val at location Disp_loc.
'Data starts at Data_addr
LET Char = Disp_loc 'Place cursor at desired locatio on the display
GOSUB Disp_Cmd
LET bptr = Data_addr
BINTOASCII Watt_hrs,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptr 'MSD first
LET bptr = Data_addr
FOR Iter = 0 TO 4
LET Char = @bptrinc
SELECT Iter
CASE 0
IF Char = "0" THEN
LET BLZ = 1
ELSE
LET BLZ = 0
ENDIF
CASE 1 TO 3
IF BLZ = 1 AND Char <> "0" THEN
LET BLZ = 0
ENDIF
CASE 4
LET BLZ = 0
ENDSELECT
IF BLZ = 1 THEN
LET Char = " "
ENDIF
GOSUB Disp_Char
NEXT
RETURN
Disp_Cmd:
LET RS = 0
GOSUB Shift_164
RETURN
Disp_Char:
LET RS = 1
GOSUB Shift_164
RETURN
'Picaxe has no shiftout command! Slow, but the REV-ED algorithim is worse
Shift_164: '11.4 ms @ 16 mhz
FOR Mask_Addr = 0 to 7
READ Mask_Addr,Mask
LET Scratch = Char & Mask
LOW Disp_data
IF Scratch = 0 THEN BitisLow
HIGH Disp_data
BitisLow:
PULSOUT Disp_clk,2 'measures 8 microseconds
NEXT
IF RS = 0 THEN
LOW Disp_data
ELSE
HIGH Disp_data
ENDIF
PULSOUT Disp_en,5 'measures 16 microseconds
RETURN
Disp_string: 'First entry is the display location, last is null
READ String_Addr,Char
GOSUB Disp_Cmd
DO
INC String_addr
READ String_addr,Char
IF Char = 0 THEN
EXIT
ENDIF
GOSUB Disp_Char
LOOP
RETURN
Transmit:
#rem Message 0 is sent on Cycle_Cnt = 123 and Message 1 on Cycle_Cnt = 63
Message 0: bptr=28 is "H", Watt-Hour Data = 30-34. 36 = "W", Range = 38, Watt Data = 40-43. 45&46 are checksum
Message Length = 16, Msg-Len character = "L"
Message 1: bptr=50 is "C", Current Data = 52-55. 57 = "V", Volts Data = 59-62. 64&65 are checksum
Message Length = 13, Msg-Len character = "K"
#endrem
rem Customize for differences in the 2 messages
IF Cycle_Cnt = 123 THEN
LET MsgStartAddr = 28
LET MsgEndAddr = 43
LET LenChar = "L"
ELSE
LET MsgStartAddr = 50
LET MsgEndAddr = 62
LET LenChar = "I"
ENDIF
rem Calculate the checksum
LET CkSum = 0
FOR bptr = MsgStartAddr TO MsgEndAddr
LET CkSum = CkSum + @bptr
NEXT
rem convert the checksum into hex and store it
LET bptr = MsgEndAddr + 2
LET Scratch = CkSum / 16 + "0"
IF Scratch > "9" THEN
LET Scratch = Scratch + 7
ENDIF
LET @bptrinc = Scratch
LET CkSum = CkSum & $0f + "0"
IF CkSum > "9" THEN
LET CkSum = Cksum + 7
ENDIF
LET @bptr = Cksum
rem Now transmit the buffer - the receivers are incompatable with HSEROUT
SETFREQ m4
HIGH RS232_out
PAUSE 20
LOW RS232_out
PAUSE 10
SEROUT RS232_out,N2400_4,("14L1776w,",LenChar,",")
LET Scratch = MsgEndAddr + 3 'To add the checksum
FOR bptr = MsgStartAddr TO Scratch
SEROUT RS232_out,N2400_4,(@bptr)
NEXT
SEROUT RS232_out,N2400_4,(13,10)
SETFREQ m16
RETURN