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.
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.
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 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).
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
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
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 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 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 .
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 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.
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
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 .