Instruction Cycle Time 14M2

alhoop

Member
I have a routine for counting N-Scale model railroad axles and speed among other things.
The East or West routine starts when a wheel set is detected from either direction of travel.
It measures elapsed time until the same wheel set is detected at the end of a 24 inch timing gate
and uses the elapsed time to index into a speed table.
The axle count is set to 1 when the timing gate is entered and then axles are counted when
the second and following wheel sets are detected at the end of the timing gate. The distance between
two wheel sets on the same truck is 0.45 inches which give 55 milliseconds time between wheel sets at a scale speed of 73mph.
I sometimes get one extra count with any number of axles. I think the first wheel set is triggering
the interrupt routine. I think I need some delay between line 14 and line 15 but how much delay.
I think the cycle time for the instructions in line 8 through line 15 is about 10 milliseconds but I don't
know how to measure that. I would feel safe including a delay of about 90% of the 55 milliseconds
between wheel sets.
Thanks for any suggestions for improvements and maybe some way to measure those instruction cycles.
Al

Code:
1 Start:
2 setfreq m32
3 low b.5    'disble display
4 setint %00000000,%00000000
5 cnt = 1		;number of axles
6 cont:
7 if pinc.2 = 1 then east   ; if pinc.2  high train detected from east direction
8 if pinc.1 = 0 then cont
9 west:		;if pin c.1 high train detected from west direction
10 time = 0
11 dir = 1
12 contw:
13 if pinc.2 <> 1 then contw
14 et = time		;et is used to index into a speed table
15 setint %00000100,%00000100  ;set int on east
16 for b5 = 0 to 30	;routine
17 pause 100	        ;to continue 
18 next b5		;checking axles until time expires ie, no more axles to count
19 goto calc
east:		same as west routine except for setting int
.
.
.
Calc:
;calculations and display of the results routines
goto start
end

interrupt:
	if pinc.1  = 1 or pinc.2 = 1 then interrupt
	inc cnt
	if dir = 0 then
	setint %00000010,%00000010	;set interrupt on west
	else
	setint %00000100,%00000100 	;set interrupt on east
  	endif
  	b5 = 0
	return
 
Last edited:

hippy

Technical Support
Staff member
It looks like your algorithm is as follows -

Wait until a train is detected from the east or west.
Note which direction it is coming from and reset the count.
If west sensor triggered, count interrupts on the east.
If east sensor triggered, count interrupts on the west.
Do that for 3 seconds.

The sensors are 24" apart so it seems unlikely that you need a delay after first detecting the train and the first interrupt arrives.

I am not sure you are counting too many axles; In initially setting your count to 1 it seems you should be counting one too many, and the fault is that you are actually sometimes losing one. For example, a two axle train ...

East detection, set count = 1
West interrupt on first axle, count increments to 2
West interrupt on second axle, count increments to 3

The problem might not be in the interrupt per se. It could be a feature of interrupts prematurely ending PAUSE commands. You might not always be timing for 3 seconds if those PAUSE 300 are truncated.

Instead of "FOR b5 = 0 TO 30 : PAUSE 100", try ""FOR b5 = 0 TO 150 : PAUSE 20", see if results are more consistent with that.
 

AllyCat

Senior Member
Hi,

I'm not sure why you're using interrupts, one disadvantage, as hippy implies, is that they terminate the time delay of any PAUSEs. It's not possible to predict the execution time between lines 8 and 15 because of the "waiting" loop back to contw: (and any interrupts which might occur). But I would expect the basic instructions in those lines to execute in only a few ms at m32.

Maybe not too important if you're only using an integer lookup table, but do beware that although TIME = 0 sets the time variable to zero, it does NOT reset the "ticks" produced by the prescaler. So time may increment after anything between 0 and 1 second later and the final ET value may vary and report up to 1 second "long".

Cheers, Alan.
 

hippy

Technical Support
Staff member
I'm not sure why you're using interrupts
I think that is simply to provide for a timeout to indicate the train has completely passed the counting sensor while simultaneously counting axles.

But that did make me take a look at the code again, and I think I may have spotted a potential issue. I had slightly misinterpreted the algorithm, which seems to actually be -

Wait for the first sensor.
Wait for the other sensor ( allows speed timing )
Enable interrupts.

That makes sense and explains why the axle count is set to one, because the first axle isn't counted by interrupt.

But, depending on how quickly the train is moving, there may or may not be an interrupt immediately when enabled.

It might just need a simple change to fix things, to ensure the axle has passed and won't cause an interrupt -

Code:
12 contw:
13 if pinc.2 <> 1 then contw
14 et = time		;et is used to index into a speed table
    [b]do : loop until pinc.2 = 0[/b]
15 setint %00000100,%00000100  ;set int on east
That -

Code:
interrupt:
	if pinc.1  = 1 or pinc.2 = 1 then interrupt
could also present issues for a long train if axles are passing over both sensors. The first front axle will trigger the interrupt, it will enter that loop. If a rear axle then arrives over the rear sensor before the front axle clears it, and the next front axle arrives before the back axle clears the sensor, that would count as one axle rather than the two there really were.

Might not be a problem in practice and depends on the nature of the train configuration.

I think the lesson here is that we need to figure out what is happening and why it is not working as expected before trying to fix the problem.
 

alhoop

Member
Thanks for the replies.
Alan - I do know about the almost/up to 1 second error when using the timer. That's ok - I'm measuring speed any where between
9 and 100 smph. That measurement doesn't have to be precise - the axle count does.
The time between axles can vary from 36 milliseconds at 100smph for a 6 scale foot wheelbase truck to about 5 seconds for the
distance between trucks on an 80' passenger car when traveling at 9 smph. I'm using the pause routine to keep the count going
between these two extremes, not to count axles.
I set the axle count at 1 at the start of the program as I only use the first axle detected at the start of the 24" timing section
and at the end of the section.to start and stop the timer. The second and following axles are counted using the interrupt routine.
Just as the first line in the interrupt routine checks to see if the cause of the interrupt has gone away - I think I need to make
sure the first axle doesn't cause an interrupt when the interrupts are set in line 15 or in a corresponding line in the East routine.
Thanks
Al
 

alhoop

Member
Hippy - thanks for the reply and your do loop solution between lines 14 and 15 is exactly what I was looking for.
As to the first line in the interrupt routine -
Code:
interrupt :
         if pinc.1 = 1 or pinc.2 = 1 then interrupt
that supposedly is not a problem as only the West sensor is checked when in the East routine and the East sensor
when in the West routine. I didn't know of any other way to do it other than using the Dir variable to differentiate
between East and West in the interrupt routine. Now if Picaxe allowed two different Interrupt routines as does
Arduino it would be simple:).
I tried using the 20x2 for this but could never figure out the timer setups and what the results would be.
Looks like we were typing and posting at the same time in the two previous posts.
Thanks again
Al
PS Hippy- I'm wrong - that might be a problem - will check it further.
 

hippy

Technical Support
Staff member
... I didn't know of any other way to do it other than using the Dir variable to differentiate between East and West in the interrupt routine.
That is how I would do it, possibly as simple as doing ...

Code:
interrupt:
	inc cnt
	if dir = 0 then
	[b]do : loop until pinC.1 = 0[/b]
	setint %00000010,%00000010	;set interrupt on west
	else
	[b]do : loop until pinC.2 = 0[/b]
	setint %00000100,%00000100 	;set interrupt on east
  	endif
  	b5 = 0
	return
 

alhoop

Member
That is how I would do it, possibly as simple as doing ...

Code:
interrupt:
	inc cnt
	if dir = 0 then
	[b]do : loop until pinC.1 = 0[/b]
	setint %00000010,%00000010	;set interrupt on west
	else
	[b]do : loop until pinC.2 = 0[/b]
	setint %00000100,%00000100 	;set interrupt on east
  	endif
  	b5 = 0
	return
Thanks Hippy - The above code works fine and your solution in post #4 fixed the problem of one extra count
at times, no matter how many axles are processed.
I appreciate yours and others help -just one more question - is it possible to get fraction of seconds times using the X2 parts?
Regards
Al
 

alhoop

Member
Looks like I was unduly concerned about cycle time as stated in post #1 of this topic.
The unit will run at 4 mhz checking speeds up to 218smph(18 ms between 6 scale feet wheel base wheel sets).
Thanks to Hippy's help - guess a lot of us could say that.
I only have to switch to 8 mhz to drive the Emic-2 text to speech module.
Below are a couple of photos of the unit's waveforms. First is a diesel 4 axle locomotive followed by two 24' ore cars and one 40' boxcar
with a cleaning pad attached. Second is a 80' 6 axle passenger car that was pushed through the axle counter.
It bugs me that I don't know how to check Picaxe instruction cycle time.

Al
 

Attachments

AllyCat

Senior Member
Hi,

Most people just put the intruction(s) in a loop (between marker output pulses) and measure the time with a stopwatch or 'scope.

But for some measured values and an alternative method, see (in particular) #12 of this thread.

Cheers, Alan.
 

hippy

Technical Support
Staff member
One way to have more accurate timing is to use SETTIMER or one can take control of an internal on-chip timer by using PEEKSFR and POKESFR, start it and stop it, and see what the elapsed time was.

That's actually easier than it sounds but is a bit complicated if not familiar with the internals of a PIC micro which the PICAXE is built upon. A bit like flying a plane; a doddle once you know how to.

That should fit the scheme you currently have. There is some example code on the forum and there will be more help available on doing that.
 
Top