Bins Alarm

cpedw

Senior Member
Where I live (Connel, Argyll), we have a simple but confusing system of bin collections: Recycling blue bins are collected fortnightly on Fridays and Landfill green bins are collected 3-weekly, also on Fridays. The algorithm is straightforward but remembering on Thursday (bins are emptied early in the morning) which part of the cycle applies is challenging.

I used an MSF based clock to tell the date and a simple bit of arithmetic using the Julian Date number (offset to a start date on which I know the bins state) to work out the states of the two bins. Green or Blue LEDs are lit on Thursday morning and stay lit until Friday night as appropriate. I used the Universal Solder MSF module.

I added a Red LED to warn if the MSF clock is not working. It sometimes loses the signal for a few minutes. The TIME variable is used to keep the clock moderately correct. It only needs to get the day of the week right. If the MSF clock has failed for over 24 hours, the Red LED flashes. I haven't noticed this happen in 2 years of operation. I am about 120 miles from the Anthorrn (Cumbria) MSF transmitter.

I am indebted to contributors to the forum:
Hippy's Show bits MSF decoder, http://www.picaxeforum.co.uk/showthread.php?11334-Decoding-UK-s-NPL-MSF-Time-Signal post 36
and
T.Ikeda's Julian day number (JDN) calculator https://picaxeforum.co.uk/threads/julian-date-code-for-picaxe.8674/

Code:
#PICAXE 08M2
#NO_DATA
' Bins alarm MSF self start
' DW 2/24
' Show when which bins should go out. Lights up on Wednesday midnight and stays on until Friday midnight

' Take date data from MSF clock, convert to JDN starting 24/3/23=0, calculate when Green or Blue bin goes out

' Uses MSF to find what date it is
'Receive MSF data based on:
'Hippy's Show bits as received and display date/time info from
'http://www.picaxeforum.co.uk/showthread.php?11334-Decoding-UK-s-NPL-MSF-Time-Signal post 36

' Red LED on C.0 flashing if no MSF for 12 hours or more. On steady if MSF not working but <12 hr since last time fix. Off when MSF working.

' Diagnotic output for LCD/OLED on C.4. 

'Julian day number (JDN) calculator
'Created: 2007-12-23 (T.Ikeda - KA1OS)
'Latest mod: 2008-01-27
'From https://picaxeforum.co.uk/threads/julian-date-code-for-picaxe.8674/

' Uses LCD/OLED to display diagnostics.

SYMBOL RedLight =C.0    ' Red LED on leg 7, along with Programming line
SYMBOL BlueLight=C.1    ' Blue LED on leg 6
SYMBOL GreenLight=C.2    ' Green LED on leg 5

Symbol SIGNAL      = pinC.3' Radio signal Input Pin (leg 4)
Symbol LCDout    = C.4    ' LCD diagnostics out (leg 3)

Symbol ACTIVE  = 1       ' Active level ( 0 or 1 )
Symbol INACTIVE = ACTIVE ^ 1

Symbol gapchar = "-"

Symbol bitest  = bit0        'Counts bits for parity tests
Symbol btyr       = bit1        'Parity test 17-24
Symbol btmd       = bit2        'Parity test 25-35
Symbol btdow   = bit3        'Parity test 36-38
Symbol bttim   = bit4        'Parity test 39-51
Symbol Paritycheck=bit5        'Overall parity result (1=good) 
Symbol bitA       = bit6
Symbol bitB       = bit7

SYMBOL GFlag = bit8        ' High when Green bin is due
SYMBOL BFlag = bit9        ' High when Blue bin is due
SYMBOL RFlag = bit10    ' High when red light is on or flashing
SYMBOL FlFlag= bit11    ' High if MSF hasn't worked for 12 hours

Symbol bcd     = b2        ' MSF workspace
Symbol bitVal  = b3        ' MSF workspace
SYMBOL JDN     = w2        'b4,b5 Julian date number
SYMBOL JDtest=w3        'b6,b7 JDN or JDN+1 so we score a hit on Thursday and Friday
SYMBOL test = b8        ' 0 on Thursday/Friday

SYMBOL hour        = b14
SYMBOL mins        = b15
SYMBOL dow        = b16
SYMBOL yr        = b17
SYMBOL mon        = b18
SYMBOL date        = b19
Symbol bits        = b22
SYMBOL putPtr    = b23

SYMBOL mn        = w13    ; b26, b27 minutes after midnight

SYMBOL p50 = 50        'For default freq M4
Symbol p100= 100
Symbol p200=200
SYMBOL tmax=43200        ' 12hrs in seconds for TIME. For 4MHz
SYMBOL baudmode = N2400_4 

    LOW BlueLight         ' All bin lights off to start
    LOW GreenLight
    HIGH RedLight        ' MSF Clock not working yet
    FlFlag = 0            ' Set after tmax without MSF, flashing red
    TIME = 0

    BFlag = 0
    GFlag = 0
    RFlag = 1

 Do                        ' Wait for the MSF clock to get started
    Gosub ReadBit
 Loop
Paritycheck=0

WaitForMinute:

    IF Paritycheck=1 THEN            ' If MSF is working, use its time; reset error flags
        LOW RedLight
        FlFlag = 0            ' No Flashing or steady Red light
        RFlag = 0
        TIME = 0
        hour = mn/60
          mins = mn//60
        Paritycheck=0
serout LCDout, baudmode, (254,128," using MSF ")
    ELSEIF RFlag=0 THEN    ' MSF Clock not working 
        RFlag = 1    ' MSF was working but now it's not
        HIGH RedLight
        TIME = 0
    ELSEIF TIME>tmax THEN
        FlFlag = 1 ' MSF hasn't worked for 12 hours so start flashing
        TIME = 0
        RFlag = 1
    ELSEIF FlFlag=1 THEN
        IF TIME>0 THEN
            Toggle RedLight        ' MSF not working>12hrs, keep flashing
            RFlag = 1
            TIME = 0
        ENDIF
    ENDIF

    IF mins<10 THEN            
        serout LCDout, baudmode, (254,139,#hour,":0",#mins,"   ")
    ELSE
        serout LCDout, baudmode, (254,139,#hour,":",#mins,"   ")
    ENDIF
    serout LCDout, baudmode, (254,192,#BFLag," ",#GFlag,"    ",#DOW,"        ")
    
'  Correct time has been established.        

'Julian day number (JDN) calculator by T.Ikeda
'From https://picaxeforum.co.uk/threads/julian-date-code-for-picaxe.8674/
'Works with dates from 2000-01-01 to 2178-12-31
'
'Original program had 2000-01-01, JDN = 0 (Epoch: 2000-01-01) 
' To extend usefulness, moved Epoch to 2023-03-24 has JDN=0.

JDN = 0
If mon > 2 Then
    JDN = 1
End If

JDN = yr + JDN * 7 / 4
JDN = 367 * yr - JDN
JDN = mon * 3912 / 128 + date - 31 + JDN

'Add correction for 2100 not being a leap year...
If JDN > 36584 Then
    JDN = JDN -1
End If

    JDN = JDN - 8483        'JDN epoch moved to 2023-03-24=day0.  Blue bin next week Green in 2 weeks.    
    JDtest     = JDN + 1
    test = JDtest//7
    test = JDN//7 * test    ' Is Zero on Thursdays & Fridays
    
    IF test=0 THEN
        BFlag     = JDtest // 14 / 7    ' Every 2 weeks
        GFlag    = JDtest // 21 / 14    ' Every 3 weeks 
    ELSE
        BFlag = 0
        GFlag = 0
    ENDIF    


    IF BFLag=1 THEN    'This is a Blue week
        HIGH BlueLight
    ELSE
        LOW BlueLight
    ENDIF

    IF GFlag=1 THEN    'This is a Green week
        HIGH GreenLight
    ELSE
        LOW GreenLight
    ENDIF
serout LCDout, baudmode, (254,192,#JDN, "   ",#BFlag, "   ",#GFlag,"       ")
  
  Do                    ' Back to MSF clock
    Gosub ReadBit
  Loop
END

StartMinute:

 putPtr  = $50
  bits = 16 :              Gosub ReadBcd ' $50,$51 Unused bits  16
  bits = 8  : bitVal = 8 : Gosub ReadBcd : btyr = bitest ' $52,$53 Year bits    4+4
  bits = 5  : bitVal = 1 : Gosub Readbcd : btmd = bitest ' $54,$55 Month bits   1+4
  bits = 6  : bitVal = 2 : Gosub ReadBcd : btmd = btmd + bitest ' $56,$57 Day bits     2+4
  bits = 3  : bitVal = 4 : Gosub Readbcd : btdow = bitest ' $58,$59 DOW bits     3    
  bits = 6  : bitVal = 2 : Gosub ReadBcd : bttim = bitest' $5A,$5B Hour bits    2+4
  bits = 7  : bitVal = 4 : Gosub Readbcd : bttim = bttim + bitest ' $5C,$5D Minutes bits 3+4   
  bits = 2  :              Gosub ReadBcd ' Unused bits  2
  bits = 1  :              Gosub ReadBcd : btyr = btyr + bitB ' Year parity check bit 54B
  bits = 1  :              Gosub ReadBcd : btmd = btmd + bitB ' Month/day parity check bit 55B
  bits = 1  :              Gosub ReadBcd : btdow= btdow+ bitB ' DOW parity check bit 56B
  bits = 1  :              Gosub ReadBcd : bttim= bttim+ bitB ' Time parity check 57B
 
IF btyr=1 AND btmd=1 AND btdow=1 AND bttim=1 THEN
    Paritycheck = 1

    putPtr = $52
    DO
        Peek putPtr,bcd

        IF putPtr = $52 THEN
            yr = bcd
        ENDIF
        IF putPtr = $54 THEN
            mon = bcd
        ENDIF
          IF putPtr = $56 THEN
            date = bcd
        ENDIF
            IF putPtr = $58 THEN
            dow = bcd
        ENDIF
          IF putPtr = $5A THEN
            mn = bcd*60
        Endif
        IF putPtr = $5C THEN
            mn = mn + bcd
        ENDIF
         putPtr = putPtr+1
        Peek putPtr,bcd
         putPtr = putPtr+1
      Loop until putPtr>$5C

  ENDIF
  
  Goto WaitForMinute

ReadBcd:
  bcd = 0                                'Accumulate data into bcd bit by bit
  bitest = 0
  Do 
    Gosub ReadBit
    bcd = bitVal * BitA + bcd            'Add next bit
    bitest = bitest + bitA
    bitVal = bitVal / 2                    'Define next bit's value
    bits = bits - 1                        'Keep count of bits
    If bits = 4 Then                        'If it's a 2 digit result, this is the tens
      bcd = bcd * 10
      bitVal = 8
    End If
  Loop Until bits = 0
  Poke putPtr,bcd
  putPtr = putPtr+1
  Poke putPtr,gapChar
  putPtr = putPtr+1
  Return

ReadBit:
  Do : Loop Until SIGNAL IS INACTIVE
  Do : Loop Until SIGNAL IS ACTIVE
  Pause  p50
  If SIGNAL IS INACTIVE Then WaitForMinute
  Pause p100
  bitA = SIGNAL ^ INACTIVE
  Pause p100
  bitB = SIGNAL ^ INACTIVE
  Pause p200
  If SIGNAL IS ACTIVE Then StartMinute
'sertxd( #bitA )
  Return
 
I was interested in some of the code in this application, so I loaded into the PE simulator to explore more.
When looking at the 'ReadBit' subroutine near the end of the code, I think I've found a bug in the simulator.
Your symbol line 'INACTIVE = ACTIVE ^ 1', whilst unusal, does work, 'INACTIVE' is set to 0.
However, the tooltip display shows 'INACTIVE = ACTIVE', which it demonstrably isn't !.

This is a simulator bug, but I also think there maybe an error in your code.

If c.3 is repeatedly toggled, after a few times there is a stack overflow, due to more 'gosubs' than 'returns'.
The fault is in the lines 'If SIGNAL IS ACTIVE Then StartMinute' or 'If SIGNAL IS INACTIVE Then WaitForMinute'.
This is because the 'Then' is causing a 'goto' to the target line, thus exiting the 'ReadBit' subroutine without executing a 'return'.

The usual fix is to use 'then gosub', but when I tried this the fault just moved to one of the 'Gosub ReadBcd' lines !.
This due to the 'WaitForMinute' code calling 'ReadBit', and the 'ReadBit' code then jumping back to 'WaitForMinute'. This creates a stack of 'gosubs', but no 'returns'.

The simulator reports this condition, but on a real chip the effect is different, it doesn't stop. What this does to the sequence depends on the code, but whatever it is, it's not what is supposed to happen.

The only solution is to structure the code properly, but it's too late for me to do that tonight !.

Cheers,

Buzby
 
If c.3 is repeatedly toggled, after a few times there is a stack overflow, due to more 'gosubs' than 'returns'.
The fault is in the lines 'If SIGNAL IS ACTIVE Then StartMinute' or 'If SIGNAL IS INACTIVE Then WaitForMinute'.
This is because the 'Then' is causing a 'goto' to the target line, thus exiting the 'ReadBit' subroutine without executing a 'return'.
I am relying on hippy's code and his excuse (post 36, https://www.picaxeforum.co.uk/threads/decoding-uks-npl-msf-time-signal.11334/) "Yes, the bale out of 'ReadBit' by GOTO is bad practice but does work. As the PICAXE stack is circular it's not a problem." I can't make sense of the details of processing the MSF signal anyway, so I have relied on hippy's confident assertion. It may be poor practice but in my experience (I've built other MSF clocks with time as well as date) it works. The weakness is getting a good MSF signal.
 
Your symbol line 'INACTIVE = ACTIVE ^ 1', whilst unusal, does work, 'INACTIVE' is set to 0.
However, the tooltip display shows 'INACTIVE = ACTIVE', which it demonstrably isn't !.
I think that's a widespread problem; any symbol definition that includes arithmetic seems to be truncated to the first component of the symbol definition.
 
I think that's a widespread problem; any symbol definition that includes arithmetic seems to be truncated to the first component of the symbol definition.
I can understand that the symbol might be truncated, but why are the tooltips different formats ?
PE BUG.JPGPE BUG3.JPG
 
When a symbol is defined from a constant the value is displayed in the tooltip, when a symbol is derived from another symbol the original symbol is displayed instead, this is deliberate by design to match the code. However we agree that it is a bug that when a mathematical symbol is also used the tooltip is being truncated early. The actual value used is correct, it is only the tooltip display that is being truncated.

The simple workaround here is to just use this instead:

Symbol ACTIVE = 1 ' Active level ( 0 or 1 )
Symbol INACTIVE = 0
 
I am relying on hippy's code and his excuse ... "Yes, the bale out of 'ReadBit' by GOTO is bad practice but does work. As the PICAXE stack is circular it's not a problem." ...
Well, although I will bow to Hippy's greater knowledge, I'm not sure how it can work in all cases. If there were multiple unique, 'returns' in the stack, one of which doesn't get 'popped' because it's subroutine exited early, could that cause a 'return' to the wrong address ?.

In this particular case it probably works because the subroutine is called from the same location each time, so all the return addresses are the same.
 
In this particular case it probably works because the subroutine is called from the same location each time, so all the return addresses are the same.
My understanding of this is limited but I think it might impact on another project that I'm working on. Up to now, my MSF clocks have been standalone 08M2 programs with serout to communicate with other things. This bins project incorporates other code but without any subroutines other than the MSF code.

My latest project plans to integrate the MSF code into the AXE133 LCD driver with many other GOSUBs. Is this likely to be foiled by the MSF's GOSUBs without RETURN?
 
I wouldn't trust jumping out of any subroutine if there is any possibilty of screwing the 'return' stack. Much better to re-write the code using proper structures.
 
Back
Top