Motor controller with speed steps stack overflow error picaxe locks up

tecnition_ted

New Member
Hi All
I am trying to control a motor to have speed steps controlled by another picaxe through Ir numbers loaded into b0, the main idea of this project is to try and master gosub, return and PWM out.
The ultimate aim is to have the picaxe receive a number numbers 1 and 10 alter in puts C0 and C1 to controle forward/ reverse, number 20 is acceleration, 30 is deceleration.
I need the motor to slow before switching between forward and reverse then accelerate afterwards.

So far I have a IR module VS1838B connected to B.1 . C.0 and C.1 connected to in 1 and 2 on a L293E and C.2 (PWM out) goes into enable 1 on the L293E.
The SMPS sense is bridged to gnd on one and two.

Can anyone help make this work or explain why it does not
Thank you.

{code}
high c.0 ; change driver ic from satus to 0-1
low c.1
Let w2 = w2 max 10
Let w2 = w2 min 0
main:


symbol T1 = 500
irin [1000,main],B.1,b0 ;wait for new signal
DEBUG
if b0 = 1 then Mof ;motor forward
if b0 = 10 then Mor ;motor reverse
if b0 = 20 then Accel ;motor Accelerate
if b0 = 30 then Decel ;motor decelerate





Mof:

if w2 > 1 then gosub Decel
high c.0 ; change driver ic from satus to 0-1
low c.1
pause T1
if w2 < 10 then gosub Accel
if w2 = 10 then goto main



Mor:
if w2 > 1 then gosub Decel
high c.1 ; change driver ic from satus to 1-0
low c.0
pause T1
if w2 < 10 then gosub Accel
if w2 = 10 then goto main



Accel:
Let w2 = w2 max 10
Let w2 = w2 min 0
debug
pause T1
let w2 = w2+1
pause T1
gosub Main2
if w2 < 9 then Accel
return



Decel:
Let w2 = w2 max 10
Let w2 = w2 min 0
debug
pause T1
let w2 = w2-1
pause T1
gosub Main2
if w2 > 0 then Decel
return

Main2:if w2 = 1 then pwmout pwmdiv64, C.2, 255, 0
; send 0% pwm bursts out of pin c2
end if
if w2 = 2 then pwmout pwmdiv64, C.2, 255, 255
; send 25% pwm bursts out of pin c2
end if
if w2 = 3 then pwmout pwmdiv64, C.2, 255, 306
; send 30% pwm bursts out of pin c2
end if
if w2 = 4 then pwmout pwmdiv64, C.2, 255, 409 ;send pwm 40% bursts out of pin c2
End if
if w2 = 5 then pwmout pwmdiv64, C.2, 255, 511 ;send pwm 50% bursts out of pin c2
end if
if w2 = 6 then pwmout pwmdiv64, C.2, 255, 613 ;send pwm 60% bursts out of pin c2
end if
if w2 = 7 then pwmout pwmdiv64, C.2, 255, 716 ;send pwm 70% bursts out of pin c2
end if
if w2 = 8 then pwmout pwmdiv64, C.2, 255, 818 ;send pwm 80% bursts out of pin c2
end if
if w2 = 9 then pwmout pwmdiv64, C.2, 255, 920 ;send pwm 90% bursts out of pin c2
end if
if w2 = 10 then pwmout pwmdiv64, C.2, 255, 1023 ;send pwm 100% bursts out of pin c2
end if
return
 

lbenson

Senior Member
First housekeeping: your "{code}" seems to indicate that you wanted to use the forum tags to separate your code and preserve formatting. Excellent, except that you need square brackets "[]" rather than curly.
Here:
Code:
if b0 = 1 then Mof ;motor forward
if b0 = 10 then Mor ;motor reverse
if b0 = 20 then Accel ;motor Accelerate
if b0 = 30 then Decel ;motor decelerate
you need gosub instead of the implied goto; otherwise when you get to a "return", you get a stack error.

After those statements, do you intend to fall through into "Mof", and from there into "Mor", and from there into "Accel"?

There are more flow errors in this code than I have pointed out. I'd recommend that you try to execute your code in the simulator, and single step through it. That way you can see at exactly which point things go wrong or proceed unexpectedly.
 

oracacle

Senior Member
Your sub procedures call themselves which is going to cause issues with the stack. You would be better off using a while or for loop be. And like has been said the drop through is going to cause issues to
 

tecnition_ted

New Member
Thank you for your help. I have changed the code and this works but I know there is an easier way than what I have so far.

Code:
main:


IRsignal:
symbol T1 = 500
Low B.5 ; micro buzy indicator off
irin [1000,main],B.1,b0 ;wait for new signal
DEBUG
High B.5 ; micro buzy indicator on
if b0 = 1 then  Mof ;motor forward
if b0 = 2 then  Mor ;motor reverse
if b0 = 3 then  Accel ;motor Accelerate
if b0 = 4 then  Decel ;motor decelerate
goto IRsignal




Mof:
if w2 > 1 then gosub MofDecel
high c.0 ; change driver ic from satus to 0-1
low c.1
pause T1
if w2 < 10 then gosub MofAccel
Morfe: 
if w2 = 10 then gosub IRsignal



Mor:
if w2 > 1 then gosub MorDecel
high c.1 ; change driver ic from satus to 1-0
low c.0
pause T1
if w2 < 10 then gosub MorAccel
More:
if w2 = 10 then gosub IRsignal 



Accel:
Let w2 = w2 max 10
Let w2 = w2 min 0
pause T1
if w2 < 10 then let w2 = w2+1
end if 
debug
pause T1
gosub Speedlookup
if w2 < 10 then Accel 
gosub IRsignal

MofAccel:
Let w2 = w2 max 10
Let w2 = w2 min 0
pause T1
if w2 < 10 then let w2 = w2+1
end if
debug
pause T1
gosub Speedlookup
if w2 < 10 then MofAccel 
gosub Morfe

MorAccel:
Let w2 = w2 max 10
Let w2 = w2 min 0
pause T1
if w2 < 10 then let w2 = w2+1
end if 
debug
pause T1
gosub Speedlookup
if w2 < 10 then MorAccel
gosub More

Decel:
Let w2 = w2 max 10
Let w2 = w2 min 0
pause T1
if w2 > 0 then let w2 = w2-1
end if 
debug
pause T1
gosub Speedlookup
if w2 > 0 then Decel
gosub IRsignal

MofDecel:
Let w2 = w2 max 10
Let w2 = w2 min 0
pause T1
if w2 > 0 then let w2 = w2-1
end if 
debug
pause T1
gosub Speedlookup
if w2 > 0 then MofDecel
gosub Mof

MorDecel:
Let w2 = w2 max 10
Let w2 = w2 min 0
pause T1
if w2 > 0 then let w2 = w2-1
end if 
debug
pause T1
gosub Speedlookup
if w2 > 0 then MorDecel
gosub Mor


Speedlookup:if w2 = 1  then pwmout pwmdiv64, C.2, 255, 0 
; send 0% pwm bursts out of pin c2
end if
if w2 = 2 then pwmout pwmdiv64, C.2, 255, 255 
; send 25% pwm bursts out of pin c2
end if
if w2 = 3 then pwmout pwmdiv64, C.2, 255, 306
; send 30% pwm bursts out of pin c2 
end if
if w2 = 4 then pwmout pwmdiv64, C.2, 255, 409 ;send pwm 40% bursts out of pin c2 
End if
if w2 = 5 then pwmout pwmdiv64, C.2, 255, 511 ;send pwm 50% bursts out of pin c2
end if
if w2 = 6 then pwmout pwmdiv64, C.2, 255, 613 ;send pwm 60% bursts out of pin c2
end if
if w2 = 7 then pwmout pwmdiv64, C.2, 255, 716 ;send pwm 70% bursts out of pin c2
end if
if w2 = 8 then pwmout pwmdiv64, C.2, 255, 818 ;send pwm 80% bursts out of pin c2
end if
if w2 = 9 then pwmout pwmdiv64, C.2, 255, 920 ;send pwm 90% bursts out of pin c2
end if
if w2 = 10 then pwmout pwmdiv64, C.2, 255, 1023 ;send pwm 100% bursts out of pin c2
end if
return
 

lbenson

Senior Member
It's hard to understand how this can be working. There are many gosubs, and only one return, at the end of Speedlookup.

For instance, in MorDecel, you may call Speedlookup, and then return, after which you either goto MorDecel, or gosub Mor. It's not certain that this can produce a rational flow, and if it does, it's very hard to follow by eyeball. I'd be surprised if you didn't get stack errors if the program ran for very long.
 

AllyCat

Senior Member
Hi,

Indeed, 18 GOSUBs and only one RETURN is highly "suspicious" and indicative that a program is poorly constructed. But quite possibly it could "work", because calling too many "Subroutines" by using GOSUBs without matching RETURNs will NOT produce a stack "error" (i.e. a stack overflow) in itself (but the Simulator may "complain"). It is a RETURN without a matching GOSUB (i.e. attempting read an address that has never been written) that will cause a stack underflow and create a failure. The PIC and PICaxe have a "circular" stack buffer, so somebody (I hesitate to call them a Programmer) can keep on pushing addresses onto the stack as long as they like, without the "Program" actually failing.

I think the main problem is the "propaganda" that using a GOTO is fundamentally "bad" programming and that they should "never" be used; So novices use GOSUBs instead. That may indeed "work" (it's only an inappropriate RETURN that can actually cause a stack underflow), but is clearly much WORSE programming than simply using a GOTO. Therefore, my advice is DO NOT (try to) use Subroutines until you understand them! Try to learn from other people's programs how it is possible to avoid excessive use of GOTOs, by using better structures such as DO .. LOOP with WHILE / UNTIL , etc., and eventually you may also discover for yourself how useful Subroutines can be when they are used correctly.

Cheers, Alan.
 

Aries

New Member
Thanks guy's for your support its about as much use as a chocolate fireguard.
I'm disappointed in your response. Clearly several people have taken time to look at your problem (more than will actually have replied) and they have given various useful pieces of advice. I'm tempted to paraphrase the 19/20th century barrister whose name escapes me: "you may not be any wiser, but you are now better informed."
 

Technical

Technical Support
Staff member
People are only trying to help.

Using a pencil follow your program line by line. When you get to a goto move the pencil to the next label and just carry on.

When you get to a gosub think 'I will come back here whenever I next get to a return command'. Leave a pencil mark, then carry on. When you get to a return command, go back to the previous pencil mark and do the next line after the pencil mark.

If you dont have an equal number of pencil marks to 'return' commands, you have a problem. The problem here without a large rewrite is that many of your gosubs should probably just be goto's.
 

lbenson

Senior Member
As in post #2:
I'd recommend that you try to execute your code in the simulator, and single step through it. That way you can see at exactly which point things go wrong or proceed unexpectedly.
If you had done this, you'd have a much better idea of where the program logic is going as opposed to where you think it should be going. If you do it now, you'll learn a useful tool which can help you resolve this problem and many future ones you might have with PICAXE.
 

tecnition_ted

New Member
I was bit disapointed in the responces. I have maby one or two hours a month to learn anything and felt your responces were more hipacritical than maby providing a pice of program that worked on its own explaining how the picaxe used the gosub process.
The picaxe manual is helpfull but when many gosub comands are used they dont seem to work if you follow the structure in the manual and a stack overflow error occurs. Acording to the manual you can have 255 gosubs and if i read it right up to 8 retuning at any one time. I was using around 10. I tried putting in returns at the point in the program that i needed the gosub to return to and it did not work. At the moment the program works i know its wrong.

I have posted another project on the forum and had great help and understanding from both the original program creater and hippy both were able to explain in a way i understood.
Telling someone not to use gosubs and go and lern loppes does not help.

Sorry if you where affended but i comented how feel about the support on this page and felt like to me " o another nube with a basic problem". Im glad i didnt type what i first thought!

I think the picaxe is great the manual is ok but without alot of time it is difficult to do more than basic things.
 

Aries

New Member
The manual says that gosubs can be nested up to 8 deep. That means that you can have
Code:
...
gosub Sub1
...
Sub1: ...
gosub Sub2
...
return

Sub2:
gosub Sub3
...
return

Sub3: ...
gosub Sub4
...
return

Sub4: ...
gosub Sub5
...
return

Sub5:
gosub Sub6
...
return

Sub6:
gosub Sub7
...
return

Sub7:
gosub Sub8
...
return

Sub8:
...
return
but if you went from Sub8 to a Sub9, it would fail. The limit of 255 gosubs is the total number of places in the program where you have a "gosub" statement.
If you had gosubs 10 deep, then the program would fail, because you would have exceeded the maximum of 8.

We do try to help, but there does have to be an element of self-help here as well, so when lbenson suggested you step it though the simulator to see what was happening, did you do so? If so, what did you see?

Depending on our background, some of us are happy with "GOTO"s, some of us abhor them; We all like "GOSUB"s when the same code needs to be executed in more than one place. If you have to explain (or maintain) a program, then it is helpful if it is laid out in a fairly logical form, so that anyone can see how the parts link together.

I have always found this to be a friendly forum, with everybody prepared to spend their time to help others, and I have learnt a lot from it. When you feel you are not getting the help you need, try doing what has been suggested and them come back with more questions.
 

AllyCat

Senior Member
Hi,
I tried putting in returns at the point in the program that i needed the gosub to return to and it did not work.
Perhaps that is the problem. You must place the RETURN to show where the program flow should return FROM, not where to go TO.

But you never need to use a GOSUB , so don't (try to) use them until you understand why and how they can be so useful. Also, personally I almost never use the GOSUB command, I prefer the exactly equivalent command CALL which to me gives a better indication that the program is "visiting" somewhere else and then will always "come back here again later".

Cheers, Alan.
 

Aries

New Member
I think Alan has identified one of the problems. You need to understand the difference between GOTO and GOSUB (or CALL), and between RETURN and a LABEL.

GOTO, GOSUB and RETURN are all commands - meaning that when the program reaches one of them, it does what the command says (more on that in a moment). A LABEL is simply a tag which marks a particular place in the code. Labels are used by some commands, and can also be used by you to help find or identify sections of code.

GOTO label
means what it says - the program stops the sequential execution of code and carries on at the place marked by the label.

GOSUB label
does look like the same thing, but it differs because what it means is that the program branches out to the code at the place indicated by the label (known as the subroutine) - BUT when that piece of code finishes, it goes back to where it came from - the line after the GOSUB. That is the point of RETURN - it is the command in the subroutine that tells the program to go back.

These two pieces of code actually do the same thing:
Code:
GOSUB MySub
....

MySub:
...
RETURN
Code:
GOTO MySub
ComeBack:

MySub:
...
goto ComeBack
However, the GOSUB can be used repeatedly to call the same routine from different places (because RETURN knows where to go), but the GOTO can only be used once, because the return point is coded into MySub.

It is because RETURN knows where to go that there is a limit to the number of GOSUBs that can occur before their matching RETURNS (during program execution, not simply where they happen to be in the code), because the program has to remember the return point of each GOSUB as it happens, and there is space for 8 of them. If you do a ninth, then it overwrites one of the existing ones (a stack overflow) and the program will not behave as you expect (or want).

If you are new to programming - start simple. Start with the examples (there is an example of GOSUB in the manual), try it, change it, understand what it is doing. Discover the use of sertxd to print out (on the serial terminal) something about where you are in the program - for example, in my post #12, you could do something like
Code:
sertxd (cr,lf,"Starting")
...
sertxd (cr,lf,"Calling Sub1")
gosub Sub1
sertxd (cr,lf,"Returned from Sub1")
...

Sub1: ...
sertxd (cr,lf,"Starting Sub1")
...
sertxd (cr,lf,"Calling Sub2")
gosub Sub2
sertxd (cr,lf,"Returned from Sub2")
...
sertxd (cr,lf,"Returning from Sub1")
return

Sub2:
sertxd (cr,lf,"Starting Sub2")
...
sertxd (cr,lf,"Calling Sub3")
gosub Sub3
sertxd (cr,lf,"Returned from Sub3")
...
sertxd (cr,lf,"Returning from Sub2")
return
and see what happens as you put in more nested GOSUBs
 
Top