Code help, state machine, different modes, using an 08M

ashleylad

Member
Been a while since I have been on here but have a need for a circuit for my 11 year old son's r/c car.

Need to flash headlights in different patterns by pressing a push button switch on pin 3, then return to the first after the 3rd sequence is reached. Been looking for examples for state machines, loops and push button presses and stumbled upon this from lbenson in 2010:-

Code:
symbol mode=b13

do
  if pin3 = 1 then
    do loop until pin3 = 0
    mode = mode + 1
    if mode > 3 then 
      mode = 1
    endif
    low B.1
    low B.2
    low B.3
    select mode
      case 1: HIGH B.1
      case 2: HIGH B.2
      case 3: HIGH B.3
    end select
  endif
loop
I was looking at the code and understanding how it works and seeing how I can make changes to implement my needs. I added some changes to the case states taking into account I am using an original 08M

Code:
symbol mode=b13

do
  if pin3 = 1 then
    do loop until pin3 = 0
    mode = mode + 1
    if mode > 3 then 
      mode = 1
    endif

    select mode
      case 1
high 0
pause 500
low 0
pause 500

      case 2
high 1
pause 500
low 1
pause 500

      case 3
high 2
pause 500
low 2
pause 500 
    end select
  endif
loop
The above outputs are just and example. Problem I have is the selected case only runs once. How can I tie it into the loop so the selected mode runs continually until interrupted by a button press. Been studying the manuals and other examples, making change, tried gosubs but scratching my head.

many thanks in advance and to lbenson for his advice and code snippet.

Ash
 

hippy

Ex-Staff (retired)
You can move the END IF up from after the END SELECT to before the SELECT CASE.

That will mean your switch is only checked once every second so it may require a different approach, but will at least get things looping and flashing.
 

SD70M

Senior Member
Move your last 'end if' above the 'select case' statement. Then all should be fine.

At the moment the select case statement only runs if pinX has been pressed on that iteration through the program.

HTH
Angie
 

vttom

Senior Member
Seems to me this would be a good opportunity to use an interrupt.

Put just the "select mode ... case ... end select" clause in your main loop, and handle the response to a button press with an interrupt.
 

ashleylad

Member
Hippy, SD70M, thank you. Got it going through the simulator now. Still some work to be done. Need to work on the code to understand now how to detect if the button has been pressed at any time and advance even if the program is half way through a case flash sequence.

This is what vttom is saying I think, more investigation and reading required. Pretty new to many areas of PICAXE still, so forgive me for not understanding some of the things that come natural to others. Still learning.

Thanks

Ash
 

ashleylad

Member
vttom,

I have been looking at the manuals trying to get my head around interrupts. I find if hard to understand how you can detect a button push while a particular sequence is running. I thought the picaxe has to execute an instruction before it can look elsewhere?

thanks

Ash
 

hippy

Ex-Staff (retired)
Interrupts take you away from what you are doing, then you come back to what you were doing.

As in real life, flipping pancakes in the kitchen, you'll answer a knock on the door, then come back to flipping the pancakes. If when you answered the door you were told gold coins were falling from the sky, when you come back to flipping pancakes, you may decide to turn the cooker off and head outside with a carrier bag instead.
 

ashleylad

Member
Thanks Hippy, boy it's been a while since I last had pancakes!! Looking at the manuals and some examples on interrupts.

One thing I have tried is substituting the switch press with a pulsin, so I could switch modes by flicking the button on channel 3 of his Spektrum radio on and off. I have added mode = 1 so the chip will run case 1 until any change is made. I have made several other circuits using the pulsin command to turn leds on and off with success but in this instance through the simulator it does not work. Detecting a switch change on Pin 3 works real time but reading the pulse length it just hangs until the chip is reset. Is the problem because I am using the pulsin command within a loop?

Code:
symbol mode=b1
mode = 1
do
pulsin 3,1,b2


  if b2 > 170 then
    do loop until b2 < 170
    mode = mode + 1
    if mode > 3 then 
      mode = 1
      'if pin3 = 1 then
    'do loop until pin3 = 0
    'mode = mode + 1
    'if mode > 4 then 
      'mode = 1
      
    endif
    
endif
    select mode
    
case 1
high 0: low 1: low 2: low 4
 

case 2
high 1: low 0: low 2: low 4


case 3
high 2: low 0: low 1: low 4

case 4
high 4: low 0: low 1: low 2

    end select
 
loop
No flash sequences just turning leds on 0 - 4.
 

hippy

Ex-Staff (retired)
if b2 > 170 then
do loop until b2 < 170


As nothing sets 'b2' to any other value, once it's over 170 it's going to remain over 170, the loop is going to loop forever, hanging the program.

PULSIN isn't a particularly good way of doing what you want as it will wait quite a while if there is no pulse.
 

ashleylad

Member
Doh, can see it now I have looked at it. Sometimes things are so obvious. Will look at alternative ways of detecting r/c servo pulses, thank you hippy

I have managed a little progress as far as interrupts go. I have simulated for a picaxe20M as I have one of these (somewhere). The switch press is now detected at any point in the sequence. So pretty happy with that ;). Only problem I have now is when the interrupt is cleared it returns to the last case for one cycle before advances to the next. How can I avoid this?

Code:
init:
#picaxe20m
symbol mode=b1
mode = 1
setint %00000010,%00000010 ' looking for pin 1 on 20m as interrupt

main:

if mode > 4 then 
mode = 1
end if

select mode
    
case 1
high 0: low 1: low 2: low 4
pause 500
 

case 2
high 1: low 0: low 2: low 4
pause 500


case 3
high 2: low 0: low 1: low 4
pause 500

case 4
high 4: low 0: low 1: low 2
pause 500

end select
    
goto main:

interrupt:

if pin1 = 1 then interrupt
mode = mode + 1
setint %00000010,%00000010
return
 
Last edited:

vttom

Senior Member
Well, this generally is poor programming practice, but sometime you have to do what it takes...

Instead of a "return" at the end of your interrupt handler, try a "goto main" instead.

Also, it looks to me that, with the way you've coded things, the interrupt handler will not complete until the user releases the button. This will cause your lighting sequence to freeze for as long as the button is held down. Is this what you want?
 

vttom

Senior Member
Actually, I got to thinking and made a few tweaks to your code. Pay particular attention to (1) the "iflag" symbol, (2) what happened to the "pause 500" statement, and (3) the use of multiple pins following a single "low" statement.

Code:
#picaxe20m
symbol mode=b1
symbol iflag=b2

init:
  mode = 1
  iflag = 0
  setint %00000010,%00000010 ' looking for pin 1 on 20m as interrupt

main:

  if mode > 4 then 
    mode = 1
  end if

  select mode
    
    case 1
      high 0 : low 1, 2, 4
 
    case 2
      high 1 : low 0, 2, 4

    case 3
      high 2 : low 0, 1, 4

    case 4
      high 4 : low 0, 1, 2

  end select

  if iflag = 0 then
    pause 500
  else
    iflag = 0
  endif
  
goto main


interrupt:

  if pin1 = 1 then interrupt
  mode = mode + 1
  iflag = 1
  setint %00000010,%00000010
  return
 

ashleylad

Member
vttom, thanks for giving your time and expertise. Was not aware of the multiple pin low commands, thank you, "everyday is a school day" as they say. Works a treat now.

Looking back at your comments in your last post. I would prefer it if the selected case continues to run until the push button has been released. How is it possible to execute and interrupt while continuing to run an already running part of code?
 

hippy

Ex-Staff (retired)
How is it possible to execute and interrupt while continuing to run an already running part of code?
The best way is to set the interrupt to happen on the push, then upon interrupt set it to next interrupt on release, then on push etc, only change mode on each push and not on release.
 

hippy

Ex-Staff (retired)
Doh, can see it now I have looked at it. Sometimes things are so obvious. Will look at alternative ways of detecting r/c servo pulses, thank you hippy
I've just read that from earlier - Are we using direct button pushes to set the mode or a changing servo pulse width to do that ?

If it's a servo pulse then interrupts probably won't help. You'll probably need a different mechanism and a more complicated loop structure to achieve what you want.
 
Top