Using Interrupts in PICAXE 08M to change led lighting routines

I was in the process of completing this carzy project of mine, where i had a single picaxe 08m chip driving four leds (green, red and amber). Its intended to give my four year old daughter something fun to look at. However I am a bit stuck as in teh code I can only get the interrupt to fire once via teh simulator. 

Any help will be appreciated.

 

symbol green_led = 0

symbol yellow_led = 1

symbol red_led = 2

symbol wait_green = 3000

symbol wait_yellow = 500

symbol wait_red = 3000

let b13 = 1

setint %00000000,%00001000

main: 

select case b13

case 1

gosub traffic

case 2

gosub cycling

case 3

gosub eyes

else

b13 =1

endselect

 

 

goto main

traffic: 

 

high green_led

low red_led

low yellow_led

pause wait_green

low green_led

for b0 =1 to 6

high yellow_led

pause wait_yellow

low yellow_led

pause wait_yellow

next b0

high red_led

low yellow_led

pause wait_red

Return

 

cycling:

 

low green_led

low red_led

low yellow_led

pause wait_yellow

high green_led

low red_led

low yellow_led

pause wait_yellow

low green_led

high red_led

low yellow_led

pause wait_yellow

low green_led

low red_led

high yellow_led

pause wait_yellow

 

Return

eyes:

 

high green_led

low red_led

high yellow_led

 

pause wait_yellow

 

low green_led

high red_led

low yellow_led

Return

interrupt:

 

let b13 = b13 +1

if pin3 = 0 then interrupt

pause 2000

setint %00001000,%00000000

Return

 

In your interrupt routine,

In your interrupt routine, you need to reset the interrupt the same way you did it above the main routine.

interrupt:

let b13 = b13 +1

 

 if pin3 = 0 then interrupt

 

pause 2000

setint %00001000,%00000000

Return

Should be:

interrupt:

 

let b13 = b13 +1

if pin3 = 0 then interrupt

pause 2000

setint %00000000,%00001000

Return

 

What IG said. Your

What IG said.  Your interrupt routine is changing which i/o pin to monitor for the interrupt condition (and also chaning which state to look for).

OMG

yet another one of those weird programming errors. Thanks much peeps

OMG

So simple. Thanks peeps sometimes you just need a second pair of eyes

 

Interrupt returns to main but crashes with nesting error

So I fixed the first issue and ran into this next one

 

interrupt:

let b13 = b13 +1

'if pin3 = 0 then interrupt

pause 2000

setint %00000000,%00001000

'goto main

Return

if I leave the GOTO MAIN program crashes stack over flow due to maximum number of nesting levels exceeded. and when i leav it out i simple returns to the sub routine it was in when the interrupt was triggered. I saw somewhere where some dude cleverly bypassed this issue but not for the life if me can i find it via google again.

not an error

the interrupt routine must be at the bottom of the program and MUST be a subroutine (with return). You could set a “flag” i.e. set a bit to 1 while you are in the interrupt routine. Within the main loop, add a line to see if that bit is a 1 or not. If it is, you have interrupted. --Do what ever code you want to do at that point --and don’t forget to clear that flag back to a 0 so it will be ready the next time you interrupt.

I agree with what Chris said

I agree with what Chris said here. After the interrupt, your program returns you to the last point in program it was running before being interrupted. That’s how it works.

I think what he is saying about setting a flag is that you can then check for that flag within your program. If it has been set, you can then branch to whatever part of the program you want (I guess you want to start over back in main).

A really inelegant solution

would be to do away with the interrupt and just make a call to the subroutine that is interrupt at the end of each individual subroutine call and get rid of the setint in your program completely. For example:

eyes:
   high green_led
   low red_led
   high yellow_led
   pause wait_yellow
   low green_led
   high red_led
   low yellow_led
   gosub interrupt
return

interrupt:
   let b13 = b13 +1
   if pin3 = 0 then interrupt
   pause 2000
return

let me clarify

what i am trying to do is have multiple light flashing routines within the single picaxe 08M chip. There is a button on my circuit board that when pressed regardless of which routine the code is in at that point in time it should based on an internal variable exit and go to the next routine in the line up. Or more simply put I wanted a way to change operational modes. 

Mind u this is stepping stone project to add sumo mode and roaming mode to a robot i am building. wanted to get a full grash of teh interrupts

New angle

I don’t know how typical it is to want to use an interrupt to break out of a subroutine, but, rather than removing interrupts how about breaking down your subroutines into much smaller parts and rewritting your for loop as a do/while or do/until. Once you have your subroutines broken out encapsulate each one with a check to make sure that the interrupt has not occurred. Do the same with the Do/While or Do/Until loop that you replace your for loop with. It won’t be an instataneous switch, but it will be faster than it is currently.

Expanding on what you and

Expanding on what you and chris are saying, I would suggest creating a subroutine that can be called from each of the LED blinking subroutines  that does the check that chris was mentioning, this should save some code space. Also consider a do loop and the exit function to break out of the loop. See manual two for the example on exit. I also think that the setint function should be done outside of the actually interrupt subroutine as this could cause a nested subroute error if say the button was pressed with the right timing. Create another subroute to specifically set the int if you have to…this can then be called from anywhere and at the appropriate time(again, after the int subroutine has completed).

I have modified your

I have modified your interrupt routine so it can be used to cycle through your subroutines .

interrupt:

inc b13
if b13 > 3 then
    b13 = 1
endif
stayhere:
if pin3 = 0 then stayhere    'wait for interrupt condition to clear

pause 2000

setint %00000000,%00001000    'reenable interrupt

Return

In your original code b13 would be incremented   continuously while pin 3 was low . It would also get out of the range 1 - 3 . Interrupts always return to the next line from where they occurred so you can’t simply use a goto to return to your main label . This code will go to the next mode after your subroutine returns and the select case executes . This might seem sluggish if your in your traffic subroutine when the button is pushed . You can take out the pause 2000 in the interrupt routine to make it a little faster .  If you want the program to more quickley go to the next mode when the button is pushed you will have to change the way your program is structured . Like birdmun suggested . Since it’s for a child to play with they might not care . Hope this helps and good luck .

 

 

For fun I rewrote your code a bit.

symbol green_led = 0
symbol yellow_led = 1
symbol red_led = 2
symbol wait_green = 3000
symbol wait_yellow = 500
symbol wait_red = 3000
symbol flag = b1
let b1 = 0
let b13 = 1
setint %00000000,%00001000
 
main: 
flag = 0
select case b13
case 1
gosub traffic
case 2
gosub cycling
case 3
gosub eyes
else
b13 =1
endselect
goto main
 
traffic: 
 
gosub green
if flag !=1 then pause wait_green
endif
low green_led
 
b0=1
do while b0<7 and flag !=1
high yellow_led
if flag !=1 then pause wait_yellow
endif
low yellow_led
if flag !=1 then pause wait_yellow
endif
b0 = b0 + 1
loop
 
gosub red
if flag !=1 then pause wait_red
endif
return
 
cycling:
 
gosub ledoff
if flag !=1 then pause wait_yellow
endif
gosub green
if flag !=1 then pause wait_yellow
endif
gosub red
if flag !=1 then pause wait_yellow
endif
gosub yellow
if flag !=1 then pause wait_yellow
endif
return
 
eyes:
 
high green_led
low red_led
high yellow_led
if flag !=1 then pause wait_yellow
endif
gosub red
if flag !=1 then pause wait_red
endif
return
 
green:
 
if flag != 1 then
high green_led
low red_led
low yellow_led
endif
return
 
red:
 
if flag != 1 then
low green_led
high red_led
low yellow_led
endif
return
 
yellow:
 
if flag != 1 then
low green_led
low red_led
high yellow_led
endif
return
 
ledoff:
 
if flag != 1 then
low green_led
low red_led
low yellow_led
endif
return
 
interrupt:
 
let b13 = b13 +1
if b13 > 3 then b13 = 1
endif
if pin3 = 0 then interrupt
pause 2000
flag = 1
setint %00000000,%00001000
return

Say thank you DanM :slight_smile: He found a missing pause in the eyes routine and suggested the if b13 > 3 then b13 = 1 to make sure b13 is a random number versus always defaulting to 1 all the time. He went so far as to breadboard the circuit for testing.

Wow, loving the help from the community

this looks great gonna try it on the chi[p now. I started an alternative code that was gonna use variables to control the following

LED ligthing sequence

LED flash delay

whether or not an LED was apart of the sequence.

The interrupt routine would change the values of these variables based on b13 (device mode). the idea came to me after watching Green Lantern and coming home not being able to sleep. Needless to say I needed as you would put it a more elegant design because pretty soon I ran out of space on the 08M. 

Will put some more thought into it but now I know the key is how often I check to determine if the mode has been changed.

Once again thanks for all the help given so far from all

 

 

 

@Rick

I am sorry that I forgot you had already suggested the if then change to the interrupt routine. I did not mean to minimize your suggestion.

No problem . I liked your

No problem . I liked your solution of setting a flag in the interrupt and using it to jump over all the delays .

What you describe sounds

What you describe sounds like  a drum sequencer and it should be more effecient than all that inline code . Here is a link to good article about implementing one by Jon Williams in his Basic Stamp column .

http://www.parallax.com/Portals/0/Downloads/docs/cols/nv/vol5/col/nv110.pdf