I don't know how to do this, please help me work it out.

regpye

New Member
I am building a security system, most has been built and working but I wanted to add a section so that I could disarm the system and rearm it again at the press of a button.
I have only one pin left to work with which is C.1 of a 14M2 chip.
What I would like to do is when the button is pressed once it will take to a disarmed label and send a sound file and stay in a loop until the button is pressed a second time. After pressing the second time a different sound file will play and the system will then resume.

I could achieve this by simply turning the whole system off, but I want to have other parts of the system to be still active, so I really only want to isolate one part of the system (my workshop entry) while the rest is still protected.
Any ideas on how to do this part?
 

PhilHornby

Senior Member
You could use an Interrupt with Pin C.1.

The following skeleton code is triggered by C.1 going high. I would normally tend to trigger on C.1 going low (so I can use the pullup command and save a resistor). I leave that as 'an exercise for the student' :)
Rich (BB code):
#picaxe 14m2

      gosub Enable_interrupt              ;enable the interrupt 
      
      do
      ; The main program loop
      loop


interrupt:                                ;enters here when C.1 goes HIGH

;     Do something - Toggle a flag, probably.

;     then fall through to here and re-enable interrupt before leaving
Enable_interrupt:

      do 
      loop while PinC.1 = 1               ;wait for Pin to go low, else interrupt
                                          ;triggers immediately on return statement!

      setint %00000010,%00000010         ;enable interrupt on C.1 going high
      return                              ;resume operation
 

regpye

New Member
The following skeleton code is triggered by C.1 going high.
Thank you PhilHornby, I am not sure what this code does yet, it is a new process for me, but I will try and work it out.
What I should have also stated is that I intended to use a momentary button switch, although I could use a keyed switch as well.
I will have a play around with the code and see if I can understand it and get it to function for me.
 

regpye

New Member
Okay, I have had a play about with the code, but it is not working properly, maybe because I don't fully understand a few things yet.
Most of the code works, the B.3 needs to be activated for testing in simulation (busy signal) or the code will wait for a busy signal from the DFPlayer, shouldn't be a problem in a real situation.
I have tried putting PhilHornby code in my code with limited success, I have done something wrong, but it partly works.
here is the full code I am working on.
Code:
; *******************************
;    Written by: Reg Pye
;    Function:   DFPlayer security board     
;    Target PICAXE: 14M2   
; *******************************
Symbol BAUD_FREQ          = M8
Symbol BAUD               = T9600_8
Symbol MP3_SET_VOLUME     = $06     ; Set the volume
Symbol MAX_VOLUME         = $1E     ; Max volume level, $1E = 30
Symbol Busy_Delay = 200          ; Change Busy delay value here
Symbol PoliceFlash = B.1        ;power mosfet
Symbol FloodLED = B.2            ;power mosfet
Symbol Busy_Pin = PinB.3        ; DF Player Busy Pin
Symbol TX = B.4                ;DFPlayer RX
Symbol WarningLED = B.5            ;hardware flashing RED LED
Symbol In3 = PinC.0            ;Final warning - sound 0005
Symbol In2 = PinC.1            ;Armed - sound 0006,  Dis-Armed - sound 0004
Symbol In1 = pinC.2            ;First entry - sound 0003
Symbol PIR = pinC.3            ;Main entry - sound 0001 day, 0002 night
Symbol LDR = C.4
Symbol LDR_DAY    = 105         ; Greater or equal this it's day
Symbol LDR_NIGHT  =  95         ; Lower or equal this it's night
Symbol reserveW0  = w0          ; b1:b0
Symbol dayOrNight = w1          ; Set to IS_DAY or IS_NIGHT
Symbol IS_DAY     = 0           ; Set 'dayOrNight' to 0 to use 'On dayOrNight Goto Day, Night'
Symbol IS_NIGHT   = 1           ; Set 'dayOrNight' to 1 to use 'On dayOrNight Goto Day,Night'
Symbol breached       = b10
Symbol Armed_state    = b11
 ;---------------------------------------------------------
Begin:
SerTxd("Armed Status is Armed - sound 0006", CR, LF)
Armed_state = 0
SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $06, $EF )
  SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT
 ;---------------------------------------------------------
gosub Enable_interrupt 

Main:
do
;wait 45        ; Allow PIR to settle down before code starts
;wait 45        ; two waits because of 65 is the limit

;---------------------------------------------------------
What_time:
  Gosub DetermineDayOrNight
  On dayOrNight Goto Day, Night
;---------------------------------------------------------
Day:
#IfDef SIMULATING
    If dayOrNight = IS_DAY Then
      SerTxd("Day")
    Else
      SerTxd("Night")
    EndIf
#EndIf
low FloodLED    ; turn off light at day
SerTxd(" Floodlight off", CR, LF)
if PIR = 1 then gosub Day_warning ;Initial warning
if In1 = 1 then gosub first_entry ; second warning
if In2 = 1 then gosub Armed_status ;Dis-armed or Armed
if In3 = 1 then gosub Final_warning ; Final warning
goto main
;---------------------------------------------------------
Night:
 #IfDef SIMULATING
    If dayOrNight = IS_DAY Then
      SerTxd("Day")
    Else
      SerTxd("Night")
    EndIf
#EndIf
high FloodLED    ; turn on light at night
SerTxd(" Floodlight on", CR, LF)
if PIR = 1 then gosub Night_warning ;Initial warning
if In1 = 1 then gosub first_entry ; Second warning
if In2 = 1 then gosub Armed_status ;Dis-armed or Armed
if In3 = 1 then gosub Final_warning ; Final warning
goto main
;---------------------------------------------------------
DetermineDayOrNight:
  ReadAdc LDR, b10        ; Read LDR and set 'dayOrNight'
  If b10 > LDR_DAY Then
    dayOrNight = IS_DAY
  End If
  If b10 < LDR_NIGHT Then
    dayOrNight = IS_NIGHT
  End If

;---------------------------------------------------------
  Return
  
 Day_warning:
  SerTxd("Day_warning sound 0001", CR, LF)
  SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $01, $EF )
 SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT
  ; further code to be added here
  Return
;---------------------------------------------------------   
Night_warning:
  SerTxd("Night_warning sound 0002", CR, LF)
  SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $02, $EF )
  SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT
  ; further code to be added here
   Return  
;---------------------------------------------------------   

Check_Busy:
Do
pause Busy_Delay
loop while Busy_Pin=0
Return
;---------------------------------------------------------
first_entry:        ;PinC.2
SerTxd("First Entry breach sound 0003", CR, LF)
SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $03, $EF )
  SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT
; further code to be added here
return
;---------------------------------------------------------
Armed_status:    ;PinC.1
SerTxd("Armed Status is Disarmed - sound 0004", CR, LF)
SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $04, $EF )
  SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT
; further code to be added here
 toggle Armed_state 
goto Begin
return

;---------------------------------------------------------
Warning_Led:     ;B.5
if breached = 1 then high WarningLED
SerTxd("System has been breached", CR, LF)
; turn off system with key to reset warning light
endif
Return

;---------------------------------------------------------
Final_warning:        ;B.1 once started will flash for 3 minutes
SerTxd("PoliceFlash sound 0005", CR, LF)

 SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $05, $EF )
  SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT
 high PoliceFlash
 SerTxd("PoliceFlash on", CR, LF)
 for b9 = 1 to 18     ; 180 = 3 minutes
pause 60;000         ; wait 60 seconds     REDUCED FOR TESTING PURPOSES
next         
breached = 1
low PoliceFlash ; stop flashing lights
SerTxd("PoliceFlash off", CR, LF)
gosub Warning_Led
Loop
End

Return
;---------------------------------------------------------
interrupt: 
gosub Armed_status
Return
;---------------------------------------------------------
Enable_interrupt:

      do 
      loop while PinC.1 = 1               ;wait for Pin to go low, else interrupt
                                          ;triggers immediately on return statement!

      setint %00000010,%00000010         ;enable interrupt on C.1 going high
      return                              ;resume operation
 

PhilHornby

Senior Member
1) Make sure there is a pull-down resistor on C.1 to GND.

2) In the Interrupt Service Routine, you have removed the line
; then fall through to here and re-enable interrupt before leaving
and replaced it with Return, thus ensuring that it doesn't fall through and re-enable the interrupt :eek:

I'd better explain...

The setint command describes the conditions that should generate an interrupt (C1. going HIGH). When this condition is met, program execution passes to the label 'interrupt' where your own code should be placed.

Before leaving - and returning to wherever the program was before the interrupt - the interrupt configuration needs to be repeated. Otherwise, (weirdly), on Picaxe it is just a one-shot operation ...

The initial gosub EnableInterrupts 'shares' that final part of the Interrupt Service Routine that does the configuration. Apart from saving a tiny bit of space, it means that you only have a single setint in the program to maintain, rather than two.
 

regpye

New Member
Make sure there is a pull-down resistor on C.1 to GND.
Yes I have a 10K pulldown resistor.
I have tried to work out how this works and spent a few hours on it, but I am not getting it.
I don't fully understand the process and the more I have worked on it the more confused I have become.
 

kfjl

Member
There's a full explanation of what PhilHornby says on pages 215 to 217 in the picaxe_manual2.
From what I've been told, you should be able to understand it if you run it on the simulator.
 

PhilHornby

Senior Member
At the very least:-

Rich (BB code):
Armed_status:    ;PinC.1
SerTxd("Armed Status is Disarmed - sound 0004", CR, LF)
SetFreq BAUD_FREQ
Pause 10
SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $04, $EF )
  SerTxd(" ", CR, LF)
gosub Check_Busy
SetFreq MDEFAULT

toggle Armed_state 
goto Begin              ;*** THIS NEEDS TO BE REMOVED ***
return
and
Rich (BB code):
interrupt: 
gosub Armed_status
Return                  ;*** THIS NEEDS TO BE REMOVED ***
Enable_interrupt:
 

regpye

New Member
At the very least:-
I have removed those lines as I have done before earlier and still the problem persists.
On pressing the C.1 trigger, the system goes into disarmed as it is suppose to do, but it then stays there in a loop unable to continue with anything else until pressed again. It never goes back into the armed state.
This is what is throwing me, I am not knowledgeable enough to know what I am doing wrong.
What I would like to happen is that on triggering C.1 the system disarms only a part of the code, that is C.0 and when C.1 is pressed again the C.0 will become active again and the system will give a sound saying that the system is now active.
If it can't be done, then I will simply put a manual switch in the system to isolate that part of the code physically, but that makes it so that there will be no sound announcement to indicate the armed status.

Code:
Symbol BAUD_FREQ          = M8
Symbol BAUD               = T9600_8
Symbol MP3_SET_VOLUME     = $06     ; Set the volume
Symbol MAX_VOLUME         = $1E     ; Max volume level, $1E = 30
Symbol Busy_Delay = 200          ; Change Busy delay value here
Symbol PoliceFlash = B.1        ;power mosfet
Symbol FloodLED = B.2            ;power mosfet
Symbol Busy_Pin = PinB.3        ; DF Player Busy Pin
Symbol TX = B.4                ;DFPlayer RX
Symbol WarningLED = B.5            ;hardware flashing RED LED
Symbol In3 = PinC.0            ;Final warning - sound 0005
Symbol In2 = PinC.1            ;Armed - sound 0006,  Dis-Armed - sound 0004
Symbol In1 = pinC.2            ;First entry - sound 0003
Symbol PIR = pinC.3            ;Main entry - sound 0001 day, 0002 night
Symbol LDR = C.4
Symbol LDR_DAY    = 105         ; Greater or equal this it's day
Symbol LDR_NIGHT  =  95         ; Lower or equal this it's night
Symbol reserveW0  = w0          ; b1:b0
Symbol dayOrNight = w1          ; Set to IS_DAY or IS_NIGHT
Symbol IS_DAY     = 0           ; Set 'dayOrNight' to 0 to use 'On dayOrNight Goto Day, Night'
Symbol IS_NIGHT   = 1           ; Set 'dayOrNight' to 1 to use 'On dayOrNight Goto Day,Night'
Symbol breached       = b10
Symbol Armed_state    = b11
 ;---------------------------------------------------------
Begin:
SerTxd("Armed Status is Armed - sound 0006", CR, LF)
Armed_state = 0
SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $06, $EF )
  SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT
 ;---------------------------------------------------------
gosub Enable_interrupt 

Main:
do
;wait 45        ; Allow PIR to settle down before code starts
;wait 45        ; two waits because of 65 is the limit

;---------------------------------------------------------
What_time:
  Gosub DetermineDayOrNight
  On dayOrNight Goto Day, Night
;---------------------------------------------------------
Day:
#IfDef SIMULATING
    If dayOrNight = IS_DAY Then
      SerTxd("Day")
    Else
      SerTxd("Night")
    EndIf
#EndIf
low FloodLED    ; turn off light at day
SerTxd(" Floodlight off", CR, LF)
if PIR = 1 then gosub Day_warning ;Initial warning
if In1 = 1 then gosub first_entry ; second warning
if In2 = 1 then gosub Armed_status ;Dis-armed or Armed
if In3 = 1 then gosub Final_warning ; Final warning
goto main
;---------------------------------------------------------
Night:
 #IfDef SIMULATING
    If dayOrNight = IS_DAY Then
      SerTxd("Day")
    Else
      SerTxd("Night")
    EndIf
#EndIf
high FloodLED    ; turn on light at night
SerTxd(" Floodlight on", CR, LF)
if PIR = 1 then gosub Night_warning ;Initial warning
if In1 = 1 then gosub first_entry ; Second warning
if In2 = 1 then gosub Armed_status ;Dis-armed or Armed
if In3 = 1 then gosub Final_warning ; Final warning
goto main
;---------------------------------------------------------
DetermineDayOrNight:
  ReadAdc LDR, b10        ; Read LDR and set 'dayOrNight'
  If b10 > LDR_DAY Then
    dayOrNight = IS_DAY
  End If
  If b10 < LDR_NIGHT Then
    dayOrNight = IS_NIGHT
  End If

;---------------------------------------------------------
  Return
  
 Day_warning:
  SerTxd("Day_warning sound 0001", CR, LF)
  SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $01, $EF )
 SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT
  ; further code to be added here
  Return
;---------------------------------------------------------   
Night_warning:
  SerTxd("Night_warning sound 0002", CR, LF)
  SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $02, $EF )
  SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT
  ; further code to be added here
   Return  
;---------------------------------------------------------   

Check_Busy:
Do
pause Busy_Delay
loop while Busy_Pin=0
Return
;---------------------------------------------------------
first_entry:        ;PinC.2
SerTxd("First Entry breach sound 0003", CR, LF)
SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $03, $EF )
  SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT
; further code to be added here
return
;---------------------------------------------------------
Armed_status:    ;PinC.1
SerTxd("Armed Status is Disarmed - sound 0004", CR, LF)
SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $04, $EF )
  SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT
; further code to be added here
 toggle Armed_state 

return

;---------------------------------------------------------
Warning_Led:     ;B.5
if breached = 1 then high WarningLED
SerTxd("System has been breached", CR, LF)
; turn off system with key to reset warning light
endif
Return

;---------------------------------------------------------
Final_warning:        ;B.1 once started will flash for 3 minutes
SerTxd("PoliceFlash sound 0005", CR, LF)

 SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $05, $EF )
  SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT
 high PoliceFlash
 SerTxd("PoliceFlash on", CR, LF)
 for b9 = 1 to 18     ; 180 = 3 minutes
pause 60;000         ; wait 60 seconds     REDUCED FOR TESTING PURPOSES
next         
breached = 1
low PoliceFlash ; stop flashing lights
SerTxd("PoliceFlash off", CR, LF)
gosub Warning_Led
Loop
End

Return
;---------------------------------------------------------
interrupt: 
gosub Armed_status

Enable_interrupt:

      do 
      loop while PinC.1 = 1               ;wait for Pin to go low, else interrupt
                                          ;triggers immediately on return statement!

      setint %00000010,%00000010         ;enable interrupt on C.1 going high
      return
 

PhilHornby

Senior Member
On pressing the C.1 trigger, the system goes into disarmed as it is suppose to do, but it then stays there in a loop unable to continue with anything else until pressed again. It never goes back into the armed state.

What I would like to happen is that on triggering C.1 the system disarms only a part of the code, that is C.0 and when C.1 is pressed again the C.0 will become active again and the system will give a sound saying that the system is now active.
There seems to be an extraneous loop (and end) in the Final_Warning subroutine. They should be removed and just the return retained. As it stands, I'm not entirely sure what happens...

The only way I can see it getting 'stuck' in Armed_Status, is in that Check_Busy routine - which would have to be caused by the DFplayer 'Busy' signal, but I'm not convinced this is your problem. I do have a DFplayer somewhere, but I've never hooked it up.

I note that Armed_Status toggles the flag Armed_state, but nothing ever reads that variable! I presume that it should be checked somewhere in the main loop?

As it stands, the Interrupt Service Routine (which is invoked every time C.1 goes HIGH), always assumes that it intended to invoke "Sound 0004". But it's a toggle, so surely it needs to find out what the current state is and 'flip' it, then take the appropriate action.

Don't forget the 80/20 rule:
"If the first 80% of the work takes 80% of the time, then the last 20% of the work will take the other 80% of the time". ;)
 

regpye

New Member
There seems to be an extraneous loop (and end) in the Final_Warning subroutine
I have removed those and also found that I had left off a few pieces of code in the last code I posted, however I am still getting stuck in the waiting for the loop to break here

25913
After releasing the C.1 switch, the code continues, but still stays in the same state, does not toggle.

This is the code I had left out by mistake, problem with working on several versions at the same time.
Code:
Armed_status:    ;PinC.1
if Armed_state = 0 then gosub armed 
if Armed_state = 1 then gosub disarmed
return
;---------------------------------------------------------

armed:
SerTxd("Armed sound 0004", CR, LF)
SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $04, $EF )
  SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT
 pause 1000
 toggle Armed_state
return 

 Disarmed:
 SerTxd("Disarmed sound 0007", CR, LF)
SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $07, $EF )
  SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT
 pause 1000
 toggle Armed_state
return
PICAXE Editor 6.1.0.0.jpg
 

PhilHornby

Senior Member
I tested the sample code I posted - with a real Picaxe 14M2 and a real switch. It does work, as described ...

The Interrupt Service Routine cannot (sensibly) continue, until the condition that triggered it has 'gone away'. Otherwise, it would immediately retrigger when the return statement is executed. That is the reason for that loop.

I don't know what the simulator is doing; I've never really used it - it seems easier to me, to breadboard things for real.
 

PhilHornby

Senior Member
Just noticed...

The logic in this code looks incorrect.

Rich (BB code):
Armed_status:    ;PinC.1
if Armed_state = 0 then gosub armed 
if Armed_state = 1 then gosub disarmed
return
If Armed_state is 0, then it will call armed which will toggle it (i.e. set it to 1). So it will then call disarmed, which will toggle it back (i.e. set it back to 0).
 

regpye

New Member
If Armed_state is 0, then it will call armed which will toggle it (i.e. set it to 1). So it will then call disarmed, which will toggle it back (i.e. set it back to 0).
Yes you are right and that is what is happening. How can I correct it?
 

AllyCat

Senior Member
Hi,

I've not checked the remainder of the program, but the "correct" way to fix the problem is probably:
Code:
Armed_status:    ; PinC.1
if Armed_state = 0 then
   gosub armed
else 
   gosub disarmed
endif
return
Personally I would be tempted to put a colon ( : ) instead of the physical "Newline" before each of the GOSUB instructions to keep the listing more compact. Or in this particular case I might save some execution time and space with the "dirty trick" of using the RETURN of the subroutine that is being called, i.e.:
Code:
Armed_status:    ; PinC.1                     ; Comment: This is the entry to a subroutine
  IF Armed_state = 0 THEN GOTO armed          ; Comment: This is using (the RETURN of) another subroutine to exit from this subroutine
  IF Armed_state = 1 THEN GOTO disarmed       ; Comment: Or just "Fall into" disarmed: (which also makes the RETURN more obvious)
; No need for a RETURN here (Exit is via one in the called subroutines). Assuming "Armed_State" is (only ever) a Binary Value.
Cheers, Alan.
 

regpye

New Member
I've not checked the remainder of the program, but the "correct" way to fix the problem is probably:
Thanks for your input Alan.
Unfortunately that doesn't work because there is some other problem that is stopping the value of Armed_state to stay at zero. I think I am trying to do too much with the one variable and it is cancelling itself out each time.
I put a few SerTxd in the code to let me know what is going on or not going on. It never reaches Disarmed: because the value is always zero and never one.
I have been working on this now for over three weeks and getting nowhere with it.

Code:
Symbol BAUD_FREQ          = M8
Symbol BAUD               = T9600_8
Symbol MP3_SET_VOLUME     = $06     ; Set the volume
Symbol MAX_VOLUME         = $1E     ; Max volume level, $1E = 30
Symbol Busy_Delay = 200          ; Change Busy delay value here
Symbol PoliceFlash = B.1        ;power mosfet
Symbol FloodLED = B.2            ;power mosfet
Symbol Busy_Pin = PinB.3        ; DF Player Busy Pin
Symbol TX = B.4                ;DFPlayer RX
Symbol WarningLED = B.5            ;hardware flashing RED LED
Symbol In3 = PinC.0            ;Final warning - sound 0005
Symbol In2 = PinC.1            ;Armed - sound 0006,  Dis-Armed - sound 0004
Symbol In1 = pinC.2            ;First entry - sound 0003
Symbol PIR = pinC.3            ;Main entry - sound 0001 day, 0002 night
Symbol LDR = C.4
Symbol LDR_DAY    = 105         ; Greater or equal this it's day
Symbol LDR_NIGHT  =  95         ; Lower or equal this it's night
Symbol reserveW0  = w0          ; b1:b0
Symbol dayOrNight = w1          ; Set to IS_DAY or IS_NIGHT
Symbol IS_DAY     = 0           ; Set 'dayOrNight' to 0 to use 'On dayOrNight Goto Day, Night'
Symbol IS_NIGHT   = 1           ; Set 'dayOrNight' to 1 to use 'On dayOrNight Goto Day,Night'
Symbol breached       = b10
Symbol Armed_state    = b11
 ;---------------------------------------------------------
Begin:
SerTxd("Armed Status is Armed - sound 0006", CR, LF)
;Armed_state = 0
SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $06, $EF )
  SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT
 ;---------------------------------------------------------
gosub Enable_interrupt 

Main:
;do
;wait 45        ; Allow PIR to settle down before code starts
;wait 45        ; two waits because of 65 is the limit

;---------------------------------------------------------
What_time:
  Gosub DetermineDayOrNight
  On dayOrNight Goto Day, Night
;---------------------------------------------------------
Day:
#IfDef SIMULATING
    If dayOrNight = IS_DAY Then
      SerTxd("Day ")
    Else
      SerTxd("Night ")
    EndIf
#EndIf
low FloodLED    ; turn off light at day
SerTxd(" Floodlight off", CR, LF)
if PIR = 1 then gosub Day_warning ;Initial warning
if In1 = 1 then gosub first_entry ; second warning
if In2 = 1 then gosub Armed_status ;Dis-armed or Armed
if In3 = 1 then gosub Final_warning ; Final warning
goto main
;---------------------------------------------------------
Night:
 #IfDef SIMULATING
    If dayOrNight = IS_DAY Then
      SerTxd("Day ")
    Else
      SerTxd("Night ")
    EndIf
#EndIf
high FloodLED    ; turn on light at night
SerTxd(" Floodlight on ", CR, LF)
if PIR = 1 then gosub Night_warning ;Initial warning
if In1 = 1 then gosub first_entry ; Second warning
if In2 = 1 then gosub Armed_status ;Dis-armed or Armed
if In3 = 1 then gosub Final_warning ; Final warning
goto main
;---------------------------------------------------------
DetermineDayOrNight:
  ReadAdc LDR, b10        ; Read LDR and set 'dayOrNight'
  If b10 > LDR_DAY Then
    dayOrNight = IS_DAY
  End If
  If b10 < LDR_NIGHT Then
    dayOrNight = IS_NIGHT
  End If

;---------------------------------------------------------
  Return
  
 Day_warning:
  SerTxd("Day_warning sound 0001", CR, LF)
  SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $01, $EF )
 SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT
  ; further code to be added here
  Return
;---------------------------------------------------------   
Night_warning:
  SerTxd("Night_warning sound 0002", CR, LF)
  SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $02, $EF )
  SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT
  ; further code to be added here
   Return  
;---------------------------------------------------------   

Check_Busy:
Do
pause Busy_Delay
loop while Busy_Pin=0
Return
;---------------------------------------------------------
first_entry:        ;PinC.2
SerTxd("First Entry breach sound 0003", CR, LF)
SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $03, $EF )
  SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT
; further code to be added here
return
;---------------------------------------------------------

Armed_status:    ; PinC.1
if Armed_state = 0 then
   gosub armed
else 
   gosub disarmed
endif
return
;---------------------------------------------------------
Warning_Led:     ;B.5
if breached = 1 then high WarningLED
SerTxd("System has been breached ", CR, LF)
; turn off system with key to reset warning light
endif
Return

;---------------------------------------------------------
Final_warning:        ;B.1 once started will flash for 3 minutes
SerTxd("PoliceFlash sound 0005", CR, LF)

 SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $05, $EF )
  SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT
 high PoliceFlash
 SerTxd("PoliceFlash on ", CR, LF)
 for b9 = 1 to 18     ; 180 = 3 minutes
pause 60;000         ; wait 60 seconds     REDUCED FOR TESTING PURPOSES
next         
breached = 1
low PoliceFlash ; stop flashing lights
SerTxd("PoliceFlash off ", CR, LF)
gosub Warning_Led


Return

armed:
SerTxd("System is Armed sound 0004 ",#Armed_state, CR, LF)
SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $04, $EF )
  SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT

 toggle Armed_state
  SerTxd("Armed state now is ",#Armed_state, CR, LF)
return 

 Disarmed:
 SerTxd("System is Disarmed sound 0007 ",#Armed_state, CR, LF)
SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $07, $EF )
  SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT

 toggle Armed_state
 SerTxd("Armed state now is ",#Armed_state, CR, LF)
return

;---------------------------------------------------------
interrupt: 
gosub Armed_status

Enable_interrupt:

      do 
      loop while PinC.1 = 1               ;wait for Pin to go low, else interrupt
                                          ;triggers immediately on return statement!

      setint %00000010,%00000010         ;enable interrupt on C.1 going high
      return
 

regpye

New Member
I may have worked it out, please check if you can. In simulation, by pressing the C.1 button, it appears to toggle on and off like it should do, but I am too tired now to think clearly.


Armed_status: ; PinC.1
if Armed_state = 0 then
gosub armed
else
gosub disarmed
endif
return
;-------------------------------------------------
armed:
SerTxd("System is Armed sound 0004 ",#Armed_state, CR, LF)
SetFreq BAUD_FREQ
Pause 10
SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $04, $EF )
SerTxd(" ", CR, LF)
gosub Check_Busy
SetFreq MDEFAULT
Armed_state = 1 ; I added this line
toggle Armed_state
SerTxd("Armed state now is ",#Armed_state, CR, LF)
return

Disarmed:
SerTxd("System is Disarmed sound 0007 ",#Armed_state, CR, LF)
SetFreq BAUD_FREQ
Pause 10
SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $07, $EF )
SerTxd(" ", CR, LF)
gosub Check_Busy
SetFreq MDEFAULT
Armed_state = 0 ; I added this line
toggle Armed_state
SerTxd("Armed state now is ",#Armed_state, CR, LF)
return
 

AllyCat

Senior Member
Hi,

Yes it must be getting late over there. ;)
Armed_state = 1 ; I added this line
toggle Armed_state
The TOGGLE command is "suspicious" here because it's immediately reversing the previous command (i.e. equivalent to the single command Armed_state = 0). Sometimes the TOGGLE command can be very useful but it makes validating/debugging the program more difficult because you need to "know" the present state of the flag at the time. Unlikely to be an issue here, but you also need to be careful with interrupts, because they might occur at ANY time, so an interrupt might occur between the ...state = 1 and the TOGGLE command and interpret an incorrect value.

To assist with debugging, it's worth commenting the exact values in the SYMBOL commands, e.g. Symbol Armed_state = b11 ; Armed is Binary 0 (if that's correct). Personally, I would normally make "Armed" and "Day", etc = "True" (i.e. Binary 1), although there can be good (hardware) reasons for making for example LED_ON = 0 or Switch_Closed = 0. Also, to avoid "unexplained bugs" it might be better to use a NOT behaviour with Binary values , (particularly if stored in a variable Byte or Word!). For example: if Armed_state <> TRUE then gosub disarmed avoids any risk of neither condition being met. Alternatively, if you begin to really "run out of variables" then allocate the binary values to a single bit, e.g. Armed_state = bit0 , which can then only have a value of 0 or 1 (TRUE/FALSE).

Cheers, Alan.
 

regpye

New Member
I have not had time to think this through clearly yet, but got little sleep during the night because of it.

What if I added another physical component, like a double pole relay that has a keyed switch to activate it? That way I could use one pole to disconnect the the PIR which is what the end result is wanted and the other pole could be the trigger for the C.1 pin that controls the armed and disarmed sounds when either on or off.
It might overcome some or all the problems and make the coding easier??
As I said, not thought it though yet, so I may be off the track.
It is just 4:30am here is AU, so I am going back to bed to try and get some sleep, but I just had to put my ideas out there before I could relax.
 

regpye

New Member
but you also need to be careful with interrupts, because they might occur at ANY time, so an interrupt might occur between the ...state = 1 and the TOGGLE command and interpret an incorrect value.
I remmed out that interrupt and it allowed me to still use the toggle as in the code above, I left the routine there, but it is never seen by the code because I didn't use the gosub.

I am off the bed now.
 

regpye

New Member
I have worked out another approach and am now using a simple switch (keyed) to switch on the positive rails to both C.0 and C.1. By using the switch I can isolate the action of these two functions physically and that meant I had to rewrite the code. One problem that came up was repeating the sounds when armed and disarmed, but I worked out how to do that also. Next is to test the theory in a real life circuit.
new code seems to work in simulation.
Code:
; *******************************
;    Written by: Reg Pye
;    Function:   DFPlayer security board     
;    Target PICAXE: 14M2   
; *******************************
Symbol BAUD_FREQ          = M8
Symbol BAUD               = T9600_8
Symbol MP3_SET_VOLUME     = $06     ; Set the volume
Symbol MAX_VOLUME         = $1E     ; Max volume level, $1E = 30
Symbol Busy_Delay = 200          ; Change Busy delay value here
Symbol PoliceFlash = B.1        ;power mosfet
Symbol FloodLED = B.2            ;power mosfet
Symbol Busy_Pin = PinB.3        ; DF Player Busy Pin
Symbol TX = B.4                ;DFPlayer RX
Symbol WarningLED = B.5            ;hardware flashing RED LED
Symbol In3 = PinC.0            ;Workshop - sound 0005
Symbol In2 = PinC.1            ;Armed - sound 0006,  Dis-Armed - sound 0004
Symbol In1 = pinC.2            ;First entry - gate entry - sound 0003
Symbol PIR = pinC.3            ;Main entry - front area sound 0001 day, 0002 night
Symbol LDR = C.4
Symbol LDR_DAY    = 105         ; Greater or equal this it's day
Symbol LDR_NIGHT  =  95         ; Lower or equal this it's night
Symbol reserveW0  = w0          ; b1:b0
Symbol dayOrNight = w1          ; Set to IS_DAY or IS_NIGHT
Symbol IS_DAY     = 0           ; Set 'dayOrNight' to 0 to use 'On dayOrNight Goto Day, Night'
Symbol IS_NIGHT   = 1           ; Set 'dayOrNight' to 1 to use 'On dayOrNight Goto Day,Night'
Symbol breached       = b10
Symbol Rearmed = b11        ; test if armed has been switch on already
 ;---------------------------------------------------------
Begin:
SerTxd("Armed Status is Armed - sound 0006", CR, LF)
rearmed = 1
SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $06, $EF )
  SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT
 ;---------------------------------------------------------


Main:

;wait 45        ; Allow PIR to settle down before code starts
;wait 45        ; two waits because of 65 is the limit

;---------------------------------------------------------
What_time:
  Gosub DetermineDayOrNight
  On dayOrNight Goto Day, Night
;---------------------------------------------------------
Day:
#IfDef SIMULATING
    If dayOrNight = IS_DAY Then
      SerTxd("Day ")
    Else
      SerTxd("Night ")
    EndIf
#EndIf
low FloodLED    ; turn off light at day
SerTxd(" Floodlight off", CR, LF)
if PIR = 1 then gosub Day_warning ;Initial warning - front area daytime sound
if In1 = 1 then gosub first_entry ; second warning - gate entry
if In2 = 0 then gosub Disarmed ;Dis-armed or Armed - switched off for workshop
if In2 = 1 then gosub armed    ;armed - switched on for workshop
if In3 = 0 then gosub Workshop ; Final warning - workshop breached
goto main
;---------------------------------------------------------
Night:
 #IfDef SIMULATING
    If dayOrNight = IS_DAY Then
      SerTxd("Day ")
    Else
      SerTxd("Night ")
    EndIf
#EndIf
high FloodLED    ; turn on light at night
SerTxd(" Floodlight on ", CR, LF)
if PIR = 1 then gosub Night_warning ;Initial warning - front area nighttime sound
if In1 = 1 then gosub first_entry ;second warning - gate entry
if In2 = 0 then gosub Disarmed ;Dis-armed - switched on for workshop
if In2 = 1 then gosub armed    ;armed - switched on for workshop
if In3 = 0 then gosub Workshop ; Final warning - workshop breached
goto main
;---------------------------------------------------------
DetermineDayOrNight:
  ReadAdc LDR, b10        ; Read LDR and set 'dayOrNight'
  If b10 > LDR_DAY Then
    dayOrNight = IS_DAY
  End If
  If b10 < LDR_NIGHT Then
    dayOrNight = IS_NIGHT
  End If

;---------------------------------------------------------
  Return
  
 Day_warning:
  SerTxd("Day_warning sound 0001", CR, LF)
  SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $01, $EF )
 SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT
  
  Return
;---------------------------------------------------------   
Night_warning:
  SerTxd("Night_warning sound 0002", CR, LF)
  SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $02, $EF )
  SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT
  
   Return  
;---------------------------------------------------------   

Check_Busy:
Do
pause Busy_Delay
loop while Busy_Pin=0
Return
;---------------------------------------------------------
first_entry:        ;PinC.2
SerTxd("First Entry breach sound 0003", CR, LF)
SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $03, $EF )
  SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT

return
;---------------------------------------------------------

Warning_Led:     ;B.5 needs to be manually turned off if activated.
if breached = 1 then high WarningLED
SerTxd("System has been breached ", CR, LF)
; turn off system with key to reset warning light
endif
Return

;---------------------------------------------------------
Workshop:        ;B.1 once started will flash for 3 minutes Triggered by PinC.0
SerTxd("PoliceFlash sound 0005", CR, LF)

 SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $05, $EF )
  SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT

high PoliceFlash
 SerTxd("PoliceFlash on ", CR, LF)
 for b9 = 1 to 18     ; 180 = 3 minutes
pause 60;000         ; wait 60 seconds     REDUCED FOR TESTING PURPOSES
next         
breached = 1
low PoliceFlash ; stop flashing lights
SerTxd("PoliceFlash off ", CR, LF)
gosub Warning_Led
Return

armed:
if rearmed = 1 then return
endif
 rearmed = 1
SerTxd("System is Armed sound 0004 ", CR, LF)
SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $04, $EF )
  SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT
return 

 Disarmed:
 if rearmed = 0 then return
endif
 rearmed = 0
 SerTxd("System is Disarmed sound 0007 ", CR, LF)
 low B.1
SetFreq BAUD_FREQ
 Pause 10
 SerOut TX, BAUD, ( $7E, $FF, $06, $0F, $00, $01, $07, $EF )
  SerTxd(" ", CR, LF)
 gosub Check_Busy
 SetFreq MDEFAULT
return
 
Top