uncertain working with 08M2

YCPT

New Member
Hello !

This is my first post here. I'm quite new to PICAXE and i've been very enthusiastic so far. Please note that I live in France and my English is sometimes a bit lame. (yeah, I know, there is a french picaxe forum, but this one seems more active, and it helps me to practice my English...)

I've made a gadget in order to measure the time taken to solve a rubik's cube (a request from a friend)...

here it is, and as you can see, it works : http://www.youtube.com/watch?v=wi_8xX92SiQ (with a cup of water as a mass because I couldn't find any cube at the moment)

there is a moving plate and a spring, and a home made contactor made with 2 nice hemispherical brass nails. Hopefully they commute quite nicely and I haven't had too much bouncing so far.

I had to make it quick and easy, so i'm using a commercial chronometer instead of designing my own. Its buttons were hacked and replaced by opto-isolators, they works nicely.

so when the plate is low (with a mass on it) we have +Vcc on Input 1 of the 08M2. (I use 10k pull down resistors too), and 0v otherwise.
the goal is to make an impulsion on Output 2 when PinC.1 changes to 0, so i use an interrupt in this way. But i also want that it waits for the plate to be lowered once before starting immediately the chronometer at Picaxe start-up.

then the interrupt is changed to wait for a 0 to 1 change, whenever it happens another pulse is produced on PinC.2 to stop the clock, and after that the program loops and waits for reset.

Sometimes, there is a micro-bouncing on the contacts, or maybe dust, and the chrono fails to start, so it ends up running when the plate is low and stopping when it's high (the contrary of what's expected). To solve it, one may push the reset button (on pinC.3) for a longer moment, and the 08M2 is then sending a stop pulse on PinC.2 before the (two) reset pulses on pinC.4. This isn't very elegant, but does the job.

finally (hopefully !) here is the problem :

sometimes, the entire system just freezes completely. No response when moving the plate, and not either when pushing reset. I have to do a hard reset to solve the problem.
That's quite annoying, and it's happening often enough to be noticed. Besides, sometimes a reset doesn't solve the problem and I have to put power off and on twice. But I guess this is caused by the capacitor in parallel over the supply pins, which need a bit more time to discharge.

Could it be the result of the program interrupting constantly and backing to main although the interrupt cause wasn't cleared, when powering on for example ?
I would be very happy to hear suggestions to improve the program, as I said I'm a beginner.

Thanks a lot !

Jean-François :cool:

here is the program :

Code:
low C.2
low C.4
b2=0

setint %00000000,%00000010


main:

	pause 50
	low C.2 
	low C.4
	if PinC.1=1 then gosub activation
	goto main 
 

activation:

	pause 50
	if PinC.1=1 then
	let b2=1
	end if
	return
	
	
interrupt: 

	if b2=1 and PinC.1=1 then gosub impufrontdescendant
	if b2=1 and PinC.1=0 then gosub impufrontmontant
	if b2=0 and PinC.1=1 then gosub attente
	if b2=0 and PinC.1=0 then gosub attente
	
	return 
	 

	
attente:

	setint %00000000,%00000010
	return
	
	
impufrontmontant:
	high C.2
	pause 60
	low C.2
	setint %00000010,%00000010 
	return


impufrontdescendant:
	high C.2
	pause 60
	low C.2
	let b2=0
	setint %00000000,%00000010

	do while pinC.3=0
	pause 1
	loop 
	pause 300

	if pinC.3=0 then 
	high C.4
	pause 50
	low C.4
	pause 50
	high C.4
	pause 50
	low C.4
	elseif pinC.3=1 then
	high C.2
	pause 50 
	low C.2
	pause 50
	high C.4
	pause 50
	low C.4
	pause 50
	high C.4
	pause 50
	low C.4
	endif
	do while pinC.1=0
	low C.4
	loop

	return
 
Last edited:

westaust55

Moderator
Welcome to the PICAXE forum.

I have had a look at your code and there is the possibility for optimisation/rationalisation but without comments I do find it a little confusing.

Certainly is does not seem good that from starting you set an interrupt condition and keep breaking into and returning from that interrupt in a continuous loop until such time as the cube is placed on the "table".

In the subroutine impufrontdescendant:
you first have a loop
Code:
	do while pinC.3=0
	pause 1
	loop
then after a pause of 300 ms followed by the test and code structure
Code:
	if pinC.3 = 0 then 
	  ;pulse C.4 
	elseif pinC.3 = 1 then
	  ; pulse C.2
	  ; pulse C.4
	endif
with this structure are you specifically looking for a short or long change in pin C.3?
Without comments this is not immediately clear (it may be related to the late-ish time here).

Below is some code that will not work any better but ishows how we can optimise to minimise "nesting" of GOSUB and RETURN routines.
I have added a couple of SYMBOL statements at the start to help identify pin use and state conditons
Code:
#PICAXE 08M2
SYMBOL CubeDetect = pinC.1
SYMBOL CubeReset = pinC.3


SYMBOL CubeOn = 1 ; when cube is on the plate
SYMBOL CubeOff = 0 ; when the plate is empty

Init:
	low C.2
	low C.4
	b2=0

setint %00000000,%00000010 ; interrupt on Input C.1 (CubeDetect) low/off


main:
	DO
		pause 50
		low C.2 
		low C.4
		IF CubeDetect = CubeOn AND b2 = 0 THEN
	    		PAUSE 50
	    		IF CubeDetect = CubeOn THEN
	    			b2 = 1
			ENDIF
		ENDIF
	LOOP 
 
	
	
interrupt: 
	IF b2= 0 THEN attente

	if CubeDetect = CubeOn   then impufrontdescendant
	if CubeDetect = CubeOff  then impufrontmontant

	
attente:

	setint %00000000,%00000010 ; interrupt on Input C.1 low
	return
	
	
impufrontmontant:
	high C.2
	pause 60
	low C.2
	setint %00000010,%00000010 ; interrupt on Input C.1 high 
	return


impufrontdescendant:
	high C.2
	pause 60
	low C.2
	let b2=0


	do while CubeReset = 0
		pause 1
	loop 
	pause 300


	if CubeReset= 1 then
		high C.2
		pause 50 
		low C.2
		pause 50
	endif	
		high C.4
		pause 50
		low C.4
		pause 50
		high C.4
		pause 50
		low C.4

	do while CubeDetect = CubeOff
		low C.4
	loop
	
	setint %00000000,%00000010 ; interrupt on Input C.1 low
	return
It will I think be easier for someone to start from the base description of what you wish to achieve and create some new code for you.
see if others might help during the European day otherwise I can look further tomorrow.

Possibly in the meantime you can write some simple step by step instructions of what you wish to achieve without having to use a reset fix and also maybe add some comments and extra SYMBOL statements into the program code.
 
Last edited:

YCPT

New Member
Hello, thank you very much for your reply.

Yes, as you saw, I'm checking if one's pushing "reset" for a short or a long time, because a short push is to be done when all is normal, and a long push is useful if the chronometer lost the synchronisation with the picaxe program, i.e. the time is running when the cube is on the plate and stopping when it's not (which can occur sometimes)

I'm not familiar with SYMBOL, but of course I know I have many things to learn for sure, I will check that later in the evening.

In the meantime, I've added a few comments on my code, i'm sorry i didn't think to add it by default, as in my head my code was perfectly clear :-D :-D

Code:
low C.2                                  ' make sure the "start/stop" pin of the digital chronometer is not activated
low C.4                                  ' same for the "reset" pin, which is triggered via pinC.4 of 08M2
b2=0              ' bit used to monitor when the plate is moved for the first time, at any moment after picaxe boot

setint %00000000,%00000010                ' wait for the moving plate to go from low position (pinC.1=1) to high, thanks to the spring (PinC.1=0)


main:

	pause 50
	low C.2                           ' do nothing
	low C.4
	if PinC.1=1 then gosub activation         
	goto main 
 

activation:

	pause 50
	if PinC.1=1 then                    ' check if this first change of PinC.1 from 0 to 1 isnt a "false start" (waits 50ms to see)
	let b2=1                             ' let b2=1 to permit future action in interrupt    
	end if
	return
	
	
interrupt: 
	if b2=0 then gosub attente                              ' go to a sub where i set again the interrupt with no change
	
	if b2=1 and PinC.1=0 then gosub impufrontmontant          ' means the cube has been placed on the table for more than 50ms and then removed (starting to solve it)
	if b2=1 and PinC.1=1 then gosub impufrontdescendant         ' the cube was put again on table, end of resolution
	
	
	return 
	 

	
attente:

	setint %00000000,%00000010
	return
	
	
impufrontmontant:
	high C.2                                   'start chronometer
	pause 60
	low C.2
	setint %00000010,%00000010                  ' wait for the rising edge which is to come on Pin1
	return


impufrontdescendant:
	high C.2                                     'stop chronometer
	pause 60
	low C.2
	let b2=0                                      '
	setint %00000000,%00000010                    ' reset the parameters to wait for another cycle

	do while pinC.3=0                               'loop here, waiting for the push on the large reset button on the right (PinC.3)
	pause 1
	loop 
	pause 300

	if pinC.3=0 then                                ' checking if it is a short push or a long push on RESET , in the first case all
	high C.4					' is normal, just make a double pulse (double, to be sure) on "reset" pin of the chronometer (pinC.4) ;
	pause 50					' in the second case, it means the chronometer lost the synchronism with the PICAXE
	low C.4						' (an impulsion on pinC.1 was missed, or contact bouncing occured) then we must stop 
	pause 50					' the chronometer before resetting it, otherwise the chronometer enters in "intermediate timig" mode
	high C.4					
	pause 50
	low C.4
	elseif pinC.3=1 then
	high C.2
	pause 50 
	low C.2
	pause 50
	high C.4
	pause 50
	low C.4
	pause 50
	high C.4
	pause 50
	low C.4
	endif
	do while pinC.1=0				'waiting for the cube to be back in place before setting the interrupt
	low C.4
	loop

	return
thanks again
Jean François
 

westaust55

Moderator
One of the problems with your code is that you are calling subrotutines from within the interrupt: subroutine.
In the second level subroutines you are are using the SETINT command however the RETURN command in the second level subtroutine will re-activate the interrupts before you return to the primary interrupt routine.

This means that there may be cases such as at the start while waiting for the cube to be placed on the plate, there are many interrupts and each restores the interrpts at the second level (at the end of the attente: subroutine. This can result in stack overflow cause=ing the PICAXE to crash/reset/act abnormally.

The last code example I provided in post 2 overcomes this situation as I had changed the GOSUBS in the interrupt: subroutine to GOTO.
Can you try that program example and see if it solves any of the problems you experience before we delve deeper.


The version below is almost the same but has some extra SYMBOL declarations and uses PULSOUT commands rather than HIGH, PAUSE, LOW sequence.

Code:
#PICAXE 08M2
SYMBOL CubeDetect = pinC.1
SYMBOL CubeReset = pinC.3
SYMBOL StartStop =  C.2
SYMBOL TimerReset =  C.4


SYMBOL CubeOn = 1 ; when cube is on the plate
SYMBOL CubeOff = 0 ; when the plate is empty



Init:
	low StartStop
	low TimerReset
	b2=0

setint %00000000,%00000010 ; interrupt on Input C.1 (CubeDetect) low/off


main:
	DO
		pause 50
		low StartStop 
		low TimerReset
		IF CubeDetect = CubeOn AND b2 = 0 THEN
	    		PAUSE 50
	    		IF CubeDetect = CubeOn THEN
	    			b2 = 1
			ENDIF
		ENDIF
	LOOP 
 
	
	
interrupt: 
	IF b2= 0 THEN attente

	if CubeDetect = CubeOn   then impufrontdescendant
	if CubeDetect = CubeOff  then impufrontmontant

	
attente:

	setint %00000000,%00000010 ; interrupt on Input C.1 low
	return
	
	
impufrontmontant:
	pulsout StartStop, 60000   ; pulse to start the timer
	setint %00000010,%00000010 ; interrupt on Input C.1 high 
	return


impufrontdescendant:
	pulsout StartStop, 60000  ; pulse to stop the timer



	do while CubeReset = 0
		pause 1
	loop 
	pause 300


	if CubeReset= 1 then	; test if it is a longer reset press
	pulsout StartStop, 50000  ; if so activate the start stop again
		pause 50
	endif	
	pulsout TimerReset, 50000 ; now reset the timer
		pause 50
	pulsout TimerReset, 50000 ; and a second time to be sure

	do while CubeDetect = CubeOff
		low TimerReset
	loop
	let b2=0
	setint %00000000,%00000010 ; interrupt on Input C.1 low
	return
 
Last edited:

YCPT

New Member
Hi,

Thank you very much for your assistance ! Since my last post I read more carefully the manuals and using SYMBOL seems very clever indeed. The code is much more explicit with your improvements.
The crucial information I was lacking is the fact that the first RETURN reactivates the SETINT even if we aren't in the main interrupt routine. Besides, I didn't know well how to nest several IF structures, because the syntax and the need for ENDIF varies a bit among the cases, so I was experiencing compiling errors and that's why I decided to use GOSUB inside the interrupt.

I misunderstood the manual and I thought it was absolutely necessary to end the Interrupt routine with a RETURN... that's why I was using GOSUB, to be able to go back to the end of the main interrupt and to hit RETURN. Now that I'm more familiar with nested IF...ENDIF , I could put all that in the main interrupt but anyway, it works well now.

With your way to use GOTO, it works perfectly well.
I've only had some problems with PULSOUT to trigger the timer but this is another story of pulse durations, so I sticked to the inelegant "high-pause-low-pause" to be able to test your GOTO method quickly ; now I will have all the time to investigate on PULSOUT.

I tested the system dozens and dozens of times, with several variations (very fast or very slow switching, picaxe powered up for a long time, etc) and I never again experienced system crashing.

Looks like the problem is solved !


Thank you again !

JF
 

hippy

Technical Support
Staff member
One of the problems with your code is that you are calling subrotutines from within the interrupt: subroutine.
In the second level subroutines you are are using the SETINT command however the RETURN command in the second level subtroutine will re-activate the interrupts before you return to the primary interrupt routine.
That shouldn't actually be the case; interrupts should only re-enable when the interrupt's associated return is executed, returns from gosubs called within the interrupt shouldn't enable the interrupts on their returns.

If it did work that way an 'interrupt: ... goto main' could be made to work by simply calling a subroutine before the goto, but it would also create the problem noted of interrupts occurring while the interrupt routine were active.

If the interrupts are being enabled other than on the interrupt routine return it's something we would have to investigate but I suspect it is working as expected.
 

westaust55

Moderator
I tried the original code in the PE simulator and noted there that a SetInt within a second level routine Seemingly caused a direct return to the Interrupt: label if the condition still existed and after a few cycles the PE declared a stack error.
That my edited version solved the primary problem suggests the same situation exists in firmware but not tested in firmware by myself with actual chip.
 

YCPT

New Member
Very interesting,

so what do you suggest me to do ? Should I change the code because it doesn't seem normal that this one works ? And what would I have to change then ? As I said, I haven't seen bugs anymore but it's always instructive to look for the best solution !

JF
 

westaust55

Moderator
@hippy,

tonight in the PE simulator (with some IO changes to allow other PICAXE parts - ie by changing C.4 to C.6) and some extra LET assignment commands before the RETURN command in the primary Interrupt: subroutine I have, when using YCPT's code from post 3, found that the PE simulator for M2 and X2 parts always initialises a new SETINT from a command in a second level nested subroutine when the second level RETURN is executed and will branch from the second level back directly to the interrupt: label and not return to the primary subroutine which leads to stack overflow after a few passes as the RETURN comamnd in the interrupt routine is bypassed.
 

hippy

Technical Support
Staff member
@ westaust55 : Thanks for investigating.

This seems to be a simulator issue which I will pass along for investigation. Physical chips should only action the SETINT and re-enable interrupts on the primary RETURN.
 

YCPT

New Member
it's getting more and more bizarre,

in fact I was so impatient to test the code given by Westaust55 that I put it directly on the 08M2 without simulating, and the fact is that it works. But now as I hear you discuss, I simulated with the programming editor and it doesn't work.... the program keeps interrupting even if CubeDetect is activated before simulation, and then it continuously jumps from interrupt: to attente: without clearing the interruption even if CubeDetect is high...
In the code that I put onto the chip, there isn't any RETURN at the end of the interrupt: , they are at the end of the secondary routines.
 

hippy

Technical Support
Staff member
In the code that I put onto the chip, there isn't any RETURN at the end of the interrupt: , they are at the end of the secondary routines.
It's also getting more confusing; if you used westaust55's code there is a return, when the interrupt routine falls through into the "attente:" labelled code.

If you are using some other code it may be worth posting it as it's not clear what you have.
 

YCPT

New Member
Yes, you're right, there is also a problem of understanding each other as my explanations are not very clear.

here is the code what I use... of course there is a return which would finally be hit after the interrupt, but it is in attente1 or attente2, not directly in the interrupt, that's what I was trying to say :
Code:
#PICAXE 08M2
SYMBOL CubeDetect = pinC.1
SYMBOL CubeReset = pinC.3
SYMBOL StartStop =  C.2
SYMBOL TimerReset =  C.4


SYMBOL CubeOn = 1 ; when cube is on the plate
SYMBOL CubeOff = 0 ; when the plate is empty
SYMBOL Delai1 = 20
SYMBOL Delai2 = 10


Init:
low StartStop
low TimerReset
b2=0
setint %00000000,%00000010 ; interrupt on Input C.1 (CubeDetect) low/off


main:
	DO
		pause 50
		low StartStop 
		low TimerReset
		IF CubeDetect = CubeOn AND b2 = 0 THEN
	    		PAUSE 50
	    		IF CubeDetect = CubeOn THEN
	    			b2 = 1
			ENDIF
		ENDIF
	LOOP 
 
	
interrupt: 
	IF b2= 0 THEN attente1
	
	if CubeDetect = CubeOn   then 
		pause Delai2
		if CubeDetect = CubeOn then impufrontdescendant
		goto attente2
	endif
	
	
	if CubeDetect = CubeOff  then
		pause Delai1
		if CubeDetect = CubeOff then impufrontmontant
		goto attente1
	endif
	
	
attente1:

	setint %00000000,%00000010 ; interrupt on Input C.1 low
	return
	
attente2:

	setint %00000010,%00000010 ; interrupt on Input C.1 high
	return
	
impufrontmontant:
	high StartStop                                  'start chronometer
	pause 60
	low StartStop
	setint %00000010,%00000010 ; interrupt on Input C.1 high 
	return


impufrontdescendant:
	high StartStop                                     'stop chronometer
	pause 60
	low StartStop


	do while CubeReset = 0
		pause 1
	loop 
	pause 300


	if CubeReset= 1 then	; test if it is a longer reset press
	high StartStop                                   
	pause 60
	low StartStop			  ; if so activate the start stop again
		pause 50
	endif	
	
	high TimerReset                                     
	pause 60
	low TimerReset ; now reset the timer
	pause 50
	high TimerReset                                     
	pause 60
	low TimerReset; and a second time to be sure

	do while CubeDetect = CubeOff
		low TimerReset
	loop
	let b2=0
	setint %00000000,%00000010 ; interrupt on Input C.1 low
	return
thank you again for the interest you have on this topic, I find this very interesting because it helps to get all the tricks (and also some basics that I lack) of picaxe programming, but don't worry too much as the whole gadget is working properly... Delai1 and delai2 are delays I added for debouncing the switch.

Thanks ! JF
 

hippy

Technical Support
Staff member
That my edited version solved the primary problem suggests the same situation exists in firmware but not tested in firmware by myself with actual chip.
Just an update to say that the issue seems to be only with simulation and not with physical chips.
 

westaust55

Moderator
I have in fact this evening just done a text with an actual chip and concur that the firmware in physical chips does as expected.
 
Top