One Gosub with multiple Returns - sometimes it runs sometimes not

120ThingsIn20Years

Senior Member
I have some code that runs sometimes and sometimes halts with Error msg - "Return without GoSub".

It runs perhaps 19 out of 20 times (those numbers are just a guess)

The problem is I'm not sure if I can use return like this. I can get around it, but I'd like to know for future reference if this is what's causing the problem, or if it's something else. I've noticed the debugger doesn't always stop on the bit of code that's causing the problem, especially with Do Loops, so I guess it could be caused elsewhere.

The question is, can I have multiple returns if only one gets read?


The code looks like this...

Code:
GetCurrentModeData:{
 	if CurrentMode = 1 then
		let ReportVariable = TodaysFeeds
		let LEDVariable = ReportFeedsTodayLED
		let LED2Variable = ReportFeedsTodayLED
		let ReportPause = LongReportPause
		return	    ' bail out because there's no need to go further
	end if


	if CurrentMode = 2 then 
		Readadc FeedSizePot,ReportVariable
		ReportVariable = ReportVariable / 5
		let LEDVariable = FeedSizeLED
		let LED2Variable = FeedSizeLED
		let ReportPause = ShortReportPause
		return
	end if


	if CurrentMode = 3 then 
		Readadc FeedsPerDayPot, ReportVariable
	 	ReportVariable = ReportVariable / 20
		LEDVariable = FeedsPerDayLED
		LED2Variable = FeedsPerDayLED
		ReportPause = ShortReportPause
		return
	end if
	
	if CurrentMode = 4 then
		Readadc DawnPot, ReportVariable 
	 	ReportVariable = ReportVariable / 5
		LEDVariable = FeedSizeLED 
		LED2Variable = FeedsPerDayLED
		ReportPause = ShortReportPause
		return
	endif
	
	if CurrentMode > MaxModes then 'if you have run out of modes 
		let CurrentMode = 1 'go back to the first mode
	end if
return
}
 

hippy

Technical Support
Staff member
There doesn't seem to be anything wrong with the code you show so presumably the error is caused by an error in some part of the code you have not included. Posting the full code ( perhaps as an attachment rather than within [code]..[/code] tags ) would be advised.
 

lbenson

Senior Member
You can eliminate the possibility of multiple returns causing the problem by using "elseif" as follows:

Code:
GetCurrentModeData:{
 	if CurrentMode = 1 then
		let ReportVariable = TodaysFeeds
		let LEDVariable = ReportFeedsTodayLED
		let LED2Variable = ReportFeedsTodayLED
		let ReportPause = LongReportPause
	elseif CurrentMode = 2 then 
		Readadc FeedSizePot,ReportVariable
		ReportVariable = ReportVariable / 5
		let LEDVariable = FeedSizeLED
		let LED2Variable = FeedSizeLED
		let ReportPause = ShortReportPause
	elseif CurrentMode = 3 then 
		Readadc FeedsPerDayPot, ReportVariable
	 	ReportVariable = ReportVariable / 20
		LEDVariable = FeedsPerDayLED
		LED2Variable = FeedsPerDayLED
		ReportPause = ShortReportPause
	elseif CurrentMode = 4 then
		Readadc DawnPot, ReportVariable 
	 	ReportVariable = ReportVariable / 5
		LEDVariable = FeedSizeLED 
		LED2Variable = FeedsPerDayLED
		ReportPause = ShortReportPause
	endif
	
	if CurrentMode > MaxModes then 'if you have run out of modes 
		let CurrentMode = 1 'go back to the first mode
	end if
return
}
(Note: SELECT CASE as suggested by IP below is arguably clearer than ELSEIF.)

As hippy implies, perhaps there is another way to get to your GetCurrentModeData subroutine, perhaps with a GOTO or perhaps by falling through into it.
 
Last edited:

inglewoodpete

Senior Member
While there are no obvious coding errors in the segment of code that you have posted, I would argue that its structure is not the best.

Just like there is normally only one entry to a subroutine, it is good practice to have only one exit. We could have a discussion like we had on your "Goto" thread:).

My Suggested structure would be:
Code:
GetCurrentModeData:{
 	Select Case CurrentMode
	Case 1
		<statements>
	Case 2
		<statements>
	Case 3
		<statements>
	Case 4
		<statements>
	Case > MaxModes then		 'if you have run out of modes 
		let CurrentMode = 1	 'go back to the first mode
	EndSelect
	Return
}
However, if there is a problem in code, it it probably in part that you have not posted.
 

120ThingsIn20Years

Senior Member
OK but I'm feeling a little shy :)

The bit I'm working on is Start2

And the reason I'm a little reluctant is because I still cant find a way around the GoTo's in the body of Start2. When I try to turn them into Do's they skip over the Remainder section :)

So...
The project is a demand fish feeder

Start2 is all about reading 3 pots and reporting 4 numbers by flashing their values on LEDs (The first is a count of the number of times a switch has been touched, the other three are adjustable values read from the trimpots)

The operation is based around a "Mode" button that cycles between the pots (to allow the user to adjust the settings), and the normal operating mode, which reports the first (TodaysFeeds) value every X seconds under normal operating conditions.
 

Attachments

120ThingsIn20Years

Senior Member
While there are no obvious coding errors in the segment of code that you have posted, I would argue that its structure is not the best.

Just like there is normally only one entry to a subroutine, it is good practice to have only one exit. We could have a discussion like we had on your "Goto" thread:).

My Suggested structure would be:
Code:
GetCurrentModeData:{
     Select Case CurrentMode
    Case 1
        <statements>
    Case 2
        <statements>
    Case 3
        <statements>
    Case 4
        <statements>
    Case > MaxModes then         'if you have run out of modes 
        let CurrentMode = 1     'go back to the first mode
    EndSelect
    Return
}
However, if there is a problem in code, it it probably in part that you have not posted.
I'll try it.

But I just saw this... " Error - #Directive Error - Invalid #simtask value for picaxe type."

I hadn't changed a thing and it's been running without returning that error for ever.

What is it with me, and turning up problems.

I'm starting to feel some slight compassion toward my Mum and her computer issues :)

Perhaps it isn't all her twitchy mouse movements after all :)
 

hippy

Technical Support
Staff member
Just throwing EXIT commands into the mix won't help; the EXIT after "next Counter1" will cause the LOOP to be exited, execution to continue at "GetCurrentModeData:", and it's all going down hill at that point.

Code:
	for Counter1 =1 to Counter2           'flash tens
		if Counter2=0 then 
			goto  Remainder 
			exit
		end if
A couple of things with that ...

Why check counter2 when you are in the FOR-NEXT loop, why not check before ?

With a GOTO before it, that EXIT will never ever get executed.

I think you are possibly trying to run at a level beyond your current capabilities. Nothing wrong with that, but it may help if you make the project simpler to start with, get simpler aspects of the project working and then build on that rather than trying to do it all in one go.
 

Armp

Senior Member
The Do.. Loop above the GetCurrentModeData: label contains a couple of 'Exit' statements

The exit command immediately terminates a do...loop or for...next program loop.
It is equivalent to &#8216;goto line after end of loop&#8217;.


So it looks like it will GOTO your sub?
 
Last edited:

inglewoodpete

Senior Member
First, an admission: I have not tried to fully understand your code.

Second, I was pleasantly surprised when I saw your code. You're on the right track. A bit rough in places but you're trying a variety of structures and commands. Keep it up! (In 20 years, you'll have mastered 120 commands:))

I suspect the problem is the "exit" statement just before the "FlashZero:" label. A bit of a killer really. Execution drops out of the main loop.... and into a subroutine. Once in the subroutine, execution eventually reaches a return statement but has no return address, since there was no GoSub to enter the subroutine.

Edit: Hmm, I'll have to type faster. I came in 3rd!
 

120ThingsIn20Years

Senior Member
Just throwing EXIT commands into the mix won't help; the EXIT after "next Counter1" will cause the LOOP to be exited, execution to continue at "GetCurrentModeData:", and it's all going down hill at that point.

Code:
    for Counter1 =1 to Counter2           'flash tens
        if Counter2=0 then 
            goto  Remainder 
            exit
        end if
A couple of things with that ...

Why check counter2 when you are in the FOR-NEXT loop, why not check before ?

With a GOTO before it, that EXIT will never ever get executed.

I think you are possibly trying to run at a level beyond your current capabilities. Nothing wrong with that, but it may help if you make the project simpler to start with, get simpler aspects of the project working and then build on that rather than trying to do it all in one go.
The "Exit" is left over form an earlier exploration into attempting to replace the goto's with Do's :). I thought I'd cleaned all that up.

>"Why check counter2 when you are in the FOR-NEXT loop, why not check before ?"

Perhaps I'm missing something, but that's because the "0" it refers to is not a real zero, but only a "zero tens remain". There are still units to be dealt with. There is a check for a genuine zero outside that loop with...
Code:
If ReportVariable = 0 Then
    goto FlashZero
    [exit]
End If

The reason this is version 4 is because I have had a simpler version working.

My approach is to read up about a command.
Put it into a working example that uses only stuff I'm familiar enough with to just type it out and have it work (except for the new latest command)
Then make something I can integrate into my project, still in a stand alone .bas file with nothing unfamiliar to me in it.
Then integrate it into my existing program to add whatever feature it offers.

I employ the same approach with the electronics side of things.

This way I get to actually learn what each component/command really does rather than just following an example. The downside is of course that it relies heavily on the helpful nature of others, because the problems always arise when I try to integrate the previously working code into the main project.

A fish feeder I can make.

A fishfeeder that reports and restricts how many feeds it offers I can make.

A trim pot reader I can make.

A trimpot reader that gets its data by dynamic use of variables so I can reuse some code I can make.

Integrating that stuff sees me standing on my own toes, and falling over like a baby :)



I can make this work (and have done) when I dont try to use dynamic variables in place of static ones ( yeah I know the concept of static variable doesn't mean anything but I don't have the language for what I'm doing with the reuse of code by assigning a variable a different variable) But the result is 4 times the code.

I thought I might learn something by writing it a little better.

Once again it's a case of trying to learn it right the first time.

If you really think I should just go with duplicate code, and keeping it simple tell me and I'll take your word for it (I have plenty of memory left for the project as these M2 chips are amazing). I have no problems with taking advice from people who obviously have a stack more knowledge than I do. Especially when faced with the fifty thousand of you that make up the forum membership :)

But this really is an attempt to improve what was already working (albeit without the infield adjustments from the trim pots) and more importantly an attempt to gain a thorough understanding of this PICAXE system over the next however many decades it takes.

Electronics and directly being able to interact with stuff in the real world via the PICAXE platform has been the most amazing eye opener of my life I think.

At once an amazing simplicity, and fascinating lifelong learning potential. Blah blah I'll shut up now
 

westaust55

Moderator
I see in the part listing and full code attachment brace type brackets ( ie { and } ) appearing around the body of subroutines, before comments on lines, etc.
Not sure if this is due to the way you cut and paste, my view with IPhone, or if actually there but if there in actual code are you not getting syntax errors?
 

120ThingsIn20Years

Senior Member
First, an admission: I have not tried to fully understand your code.

Second, I was pleasantly surprised when I saw your code. You're on the right track. A bit rough in places but you're trying a variety of structures and commands. Keep it up! (In 20 years, you'll have mastered 120 commands:))

I suspect the problem is the "exit" statement just before the "FlashZero:" label. A bit of a killer really. Execution drops out of the main loop.... and into a subroutine. Once in the subroutine, execution eventually reaches a return statement but has no return address, since there was no GoSub to enter the subroutine.

Edit: Hmm, I'll have to type faster. I came in 3rd!
Thanks for the encouragement :)

Do you get the same error as me if you simulate it?

I dont trust my software because sometimes it works ad sometimes it doesn't.

I hate not knowing if its me or a bug or something.

I dont think the Exit command even gets read, and I'm still not really sure what happens with all those returns. Sometimes I can work on some aspect of the program for an hour, running it in the simulator ever few minutes, and then suddenly it says my return structure is wrong, even though I haven't changed it for all those runs.

One thing I have noticed about the simulator, is that if there is a stack overflow, you need to re-run the simulator, and then stop it before the same error occurs to wipe out the error. ie the error persists if you change the program and run it again even when it shouldn't.

so...

Run the program...
see a stack overflow error...
fix the error
run it again
see the same error
run it and stop it before the error
you wont see the same error again

When the software comes out of a stack overflow error, rather than posting the notice, and leaving you to stop the code, it leaves you in some kind of no-mans land. You cant edit the code, but it isnt running.

If you run it again and then stop it before it gets to the error it fixes itself.

Perhaps it just some amazing stress test I'm putting the software through with my shi(pp)y code :)
 

hippy

Technical Support
Staff member
If you really think I should just go with duplicate code, and keeping it simple tell me and I'll take your word for it
No, I think you're heading in the right direction.

The problem perhaps is in trying to juggle too many things at once, not just making single code for multiple things work but trying to use new code structures (DO-LOOP) and new commands (EXIT) at the same time.

When something goes wrong it's then hard for you tell what's gone wrong and why; is your code in error, are you misunderstanding DO-LOOP, misunderstanding EXIT, and if you're not entirely clear on what those commands should be doing it's hard to tell if it's doing it right. You're ending up potentially feeling "I don't understand this!". You also risk rushing ahead and making silly mistakes like forgetting to take that EXIT out ( we've all done it, so I don't mean silly in an offensive way ), and that adds to your confusion.

Maybe it's a goal thing; you're trying too hard to have a perfect program and would be better and more comfortable accepting it won't be, that perfection comes with experience rather than just effort, and experience always takes time and practice.
 

120ThingsIn20Years

Senior Member
I see in the part listing and full code attachment brace type brackets ( ie { and } ) appearing around the body of subroutines, before comments on lines, etc.
Not sure if this is due to the way you cut and paste, my view with IPhone, or if actually there but if there in actual code are you not getting syntax errors?
The
{
}
Allow you to collapse the code between those brackets (view-options-tick enable collapsing blocks - then click - edit -collapse all blocks to see what I'm talking about.

Leaving you with a list of subs and a comment about what they do.

There is a + next to each shrunken block in the margin allowing you to expand it to work on it.

It allows you to compartmentalise so you can only see the bit of code you are working on, but still see an over all picture.

It's pretty handy for someone like me who gets lost in their own code :)
 

hippy

Technical Support
Staff member
One thing I have noticed about the simulator, is that if there is a stack overflow, you need to re-run the simulator, and then stop it before the same error occurs to wipe out the error. ie the error persists if you change the program and run it again even when it shouldn't.
You might be right; there could be an issue with the simulator which we will have to investigate. If you have created a 'stress test' which reveals that it's a good result, so thanks and please accept our apologies if the simulator has problems which have compounded the issues for you.

I haven't tried simulating the code yet, but it's on my list to do that.
 

120ThingsIn20Years

Senior Member
No, I think you're heading in the right direction.

The problem perhaps is in trying to juggle too many things at once, not just making single code for multiple things work but trying to use new code structures (DO-LOOP) and new commands (EXIT) at the same time.

When something goes wrong it's then hard for you tell what's gone wrong and why; is your code in error, are you misunderstanding DO-LOOP, misunderstanding EXIT, and if you're not entirely clear on what those commands should be doing it's hard to tell if it's doing it right. You're ending up potentially feeling "I don't understand this!". You also risk rushing ahead and making silly mistakes like forgetting to take that EXIT out ( we've all done it, so I don't mean silly in an offensive way ), and that adds to your confusion.

Maybe it's a goal thing; you're trying too hard to have a perfect program and would be better and more comfortable accepting it won't be, that perfection comes with experience rather than just effort, and experience always takes time and practice.
Yeah, you are probably right.

It's a compromise between excitement, and practicality :)

I'm better at excitement :)
 

120ThingsIn20Years

Senior Member
You might be right; there could be an issue with the simulator which we will have to investigate. If you have created a 'stress test' which reveals that it's a good result, so thanks and please accept our apologies if the simulator has problems which have compounded the issues for you.

I haven't tried simulating the code yet, but it's on my list to do that.
Perhaps I've found my calling :)

To boldly write code errors that nobody ever expected :)

At least I've finally found something for my tombstone :)

Here lies Bullwinkle II
He made errors nobody expected

:)
 

inglewoodpete

Senior Member
I dont trust my software because sometimes it works ad sometimes it doesn't.
I have to admit that I rarely use the simulator. I occasionally use it to develop a specific routine.

When I write a sizable block of code and it doesn't behave the way I expect, I include a lot of SerTxd statements to show variables. Alternatively, include lots of very basic SerTxds just to show the execution path.

Add a few commands like:
Code:
SerTxd ("a")
<your command>
SerTxd ("b")
<more commands>
SerTxd ("c")
If running the program in a real PICAXE, use the #Terminal directive to open the PE terminal to log data from the PICAXE.
In the terminal window, you'll get a log
like
abcdeffffffffffffffffffffffffffffffffffffffffffffffffff
or
abcdcdcd and then nothing
The log gives you a clue as to what the last thing was before the program crashed or got lost.

Remove old SerTxds and insert new ones as you go, until you find your bug. Enjoy the thrill of the chase!
 

120ThingsIn20Years

Senior Member
You might be right; there could be an issue with the simulator which we will have to investigate. If you have created a 'stress test' which reveals that it's a good result, so thanks and please accept our apologies if the simulator has problems which have compounded the issues for you.

I haven't tried simulating the code yet, but it's on my list to do that.
I have a few more. You seem to be willing to take them seriously, so if you want them, I'll write them up properly and PM them to you. Mostly they revolve around differences in the way the native software, and AXEPad see things.

I run Linux but have a windows XP box that I simulate stuff on. I tend to write the bulk of the code on the Linux box because it has Internet access ( I need all the help I can get ), then simulate it on the windows box that exists only to simulate PICAXE stuff.

The result is I run the same code on Linux and windows many times a day as I'm learning each command and making working examples.

The upshot of this is I'm probably testing their [some word like interoperability] pretty thoroughly.
 

120ThingsIn20Years

Senior Member
I have to admit that I rarely use the simulator. I occasionally use it to develop a specific routine.

When I write a sizable block of code and it doesn't behave the way I expect, I include a lot of SerTxd statements to show variables. Alternatively, include lots of very basic SerTxds just to show the execution path.

Add a few commands like:
Code:
SerTxd ("a")
<your command>
SerTxd ("b")
<more commands>
SerTxd ("c")
If running the program in a real PICAXE, use the #Terminal directive to open the PE terminal to log data from the PICAXE.
In the terminal window, you'll get a log
like
abcdeffffffffffffffffffffffffffffffffffffffffffffffffff
or
abcdcdcd and then nothing
The log gives you a clue as to what the last thing was before the program crashed or got lost.

Remove old SerTxds and insert new ones as you go, until you find your bug. Enjoy the thrill of the chase!
OK, I'm excited
but I don't really know why :)
I'm madly looking up most of the words in that post and seeing if they mean anything to normal folk :)
 

lbenson

Senior Member
@120

I agree with inglewoodpete that you have made impressive progress. In the matter of formatting, I find that your code, while fairly complex, is reasonably easy to read. I do find that the logic of the program flow is unnecessarily complicated at times (if I understand it properly). For instance, Start1 below:

Code:
Start1:'======= check for feed status============================== 
{
Pause 1000 'for Init
Do
	let LastFeed = time/OneMinute		'calculate  and store the number of minutes since last feed
	if FeedsRemain = 0 then
		goto Start1 ' bail out of the loop if they cant have any more feeds
	endif
	if LastFeed  < FeedWait then 
		goto Start1 ' bail out of the loop if time isnt up
	endif
	let feednow = 1
	if FeedNow = 1 then 
		high FishLeverLED
		Gosub CheckForLeverPress 'fish are not allowed to feed
	end if
Loop
}
Is the purpose to pause for one second, and then see if it is time to feed the fish if there is still a need to feed them today? If so, does the following do what you want?

Code:
Start1:'======= check for feed status============================== 
	Do while FeedsRemain > 0
		pause 1000
		let LastFeed = time/OneMinute		'calculate  and store the number of minutes since last feed
		if LastFeed  >= FeedWait then 
			high FishLeverLED
			Gosub CheckForLeverPress 'fish are not allowed to feed
		endif
	loop
There is no need to jump back to Start1 to re-enter the loop--let the loop itself do the repeating. Likewise, only check to see if it is time to feed if there are more feeding times scheduled today. And your "If FeedNow = 1" test is unnecessary, because you have set FeedNow to 1 in the previous statement.

I may have missed something, because I didn't look to see exectly what CheckForLeverPress does.

The code seems like this in many places--the complexity of the program flow can be reduced without any change in what the program actually accomplishes in the way of outputs and the timing of outputs.

Just a sample of what seems to me to be unnecessary complication. But again, kudos for your progress so far.
 

120ThingsIn20Years

Senior Member
The code under Start1: is just some stuff cut and peted from ver3 (the version before I discovered DO Loop. So I havnt even looked at that stuff yet. But I pasted your code, hilighted between it's own set of '0000000000000 so I know to look at it when trying to do that bit of code. So thanks :)

I tend to copy a sub over from the old version and either edit it. or re-write it while I'm looking at the old version so I can tell what it's supposed to do. That way the majority of the code in the new version is good (ish) and only the bit I'm working on is dodgy. At least that's the plan.

At the same time I'm trying to get into some better habits with my variables and use a few bit variables when I can. And I only just discovered constants.

So the code you mentioned hasn't been re-written, but was needed so I could increment the FeedsSoFarToday (or at least I think that's why I brought it over.

And thanks for the encouragement :)

I'm not seeing those same "return without gosub" errors today so perhaps the software wanted a system reboot.

At least that means I have some kind of chance to move ahead :)

'
 
Last edited:

120ThingsIn20Years

Senior Member
Do "DO Loop" count as one of the 8 deep GoSub layers I can use with M2 chips?

I wonder if that is where I'm getting my stack overflows from.
 

inglewoodpete

Senior Member
As mentioned previously, unless you have fixed them, your stack overflows are caused by having "Exit" commands in your main loop. This is/was dropping execution into a subroutine without a proper call to the subroutine.
 

120ThingsIn20Years

Senior Member
The exits were removed, but the error continued until a system reboot.

I do[nt] see that error any more, but I'm still seeing the #simtask error mentioned earlier.

" Error - #Directive Error - Invalid #simulcast value for picaxe type."

I moved the #simtask 2 line back into Main: where I was running it originally, but I see that error no matter where it is now.

The line is #simtask 2

And the chip is 14M2

I'll do a reboot
 
Last edited:

120ThingsIn20Years

Senior Member
Problem solved.

Mystery remains unsolved.

I opened up an old version and copied over each section of the latest version in turn to find where the problem lay.

I ended up copying the entire thing and still no duplication of the error.

Just to be sure I checked them with Meld diff viewer. A versioning tool that compares files. They were the same.
 

120ThingsIn20Years

Senior Member
the plot thickens...

The programmer text looks like this...

Code:
#NO_DATA ' to speed upload because there is no data to send
#PICAXE 14M2
#SIMTASK 2
'Demand Fish Feeder 14M2 ver 4 2011-11-08-2025
{'----------------------------------------------------------------
'NO RIGHTS RESERVED
The text file looks identical when I pasted it for comparison here, but the screen grab shows what it really looks like in the text file ...

screen grab.jpg

Is this normal? Or could this have something to do with my problems?
 

MartinM57

Moderator
Perhaps your contrived development environment is suffering the classic gotcha of Windows and Unix handling carriage returns/line feeds differently?

Why don't you stick to just one platform. It would make your life (and ours :)) much easier?
 

Technical

Technical Support
Staff member
Yes, your movement back and forth from Linux is the issue.

When you open your file in Windows Notepad you will see it in one long line, rather than on multiple lines. This is because the LF and CRs are corrupt. Programming Editor does already do its best to fix this automatically on the PC, but doesn't always get it 100%. So for instance your #simtask issue is because PE is actually getting <LF>#simtask 2 - an extra rogue LF character that you cannot see but can affect the compiler.

Get it looking right in Notepad and it will probably then work fine.
 

120ThingsIn20Years

Senior Member
The lack of simulator in AXEpad keeps me skipping over to my windows emulator to check code every now and again.

But if thats the problem I'll stop doing it.
 

120ThingsIn20Years

Senior Member
OK I'll give it a go.

Lately I've been a bit better at being able to just type in some code and have it work, rather than the first few weeks were everything had to be tried and tested. I guess that means I'm learning something :) . I even had a good day with the electronics side of things. A day where I programmed some stuff, soldered some stuff, had a fault, discovered the problem within a few minutes, fixed it and had the thing working. All within the same few hours :)

An entirely new experience for me :)
 

MartinM57

Moderator
I very rarely use the simulator - as said previously, if you're in a program--run-debug marathon session then a sprinkling of DEBUG commands (you've come across that command haven't you? - it's good but slow) and SERTXDs and LED flashing normally sorts out a problem pretty quickly...
 
Top