SetInt - testing interrupt condition

BCJKiwi

Senior Member
Sanity check please!

28x1 based circuit at setfreq m8
Have a tacho and two motors.
Only one motor can run at a time.
There is a separate reflective sensor for each motor and the RPM is delivered via the count command on whichever input is selected by a PB.
All this works well.

Have adapted this circuit so it will switch automatically to whichever motor is running.
This is presently achieved by dropping into a do .. loop when the RPM is below a useful speed (Count =<2)
Inside the do .. loop, the two inputs are monitored in turn (by counting the pulses) until one reaches a useful speed and the tacho is switched to that output. This is a relatively slow process as at the minimum speed, the count for each input needs to be for a .5sec duration to obtain a reliable count.

I would rather use an interrupt but understand the interrupt condition is not stored and may not be present when inside the interrupt: subroutine.

At the maximum rotational speed, the interrupt input condition should be present for around 50us and at the threshold speed for up to 2ms

1. Is there any register/system variable etc that retains the interrupt input byte?
2. As the motor ramps up to speed the tests are done at the low RPM end so one would expect the interrupt input condition to be long enough to reliably test the pin;
Proposed code is;
Code:
If Count_In =< 2 then
 RPM = 0
 ....
 ....
   LowSpeed:
      setint NOT %00000000,%00000110 ;interrupt on input 1 OR 2 high
   goto LowSpeed
EndIf
 ....
 ....
Interrupt:
   If Pin1 = 1 then
      let flag = 1
   Else
      let flag = 0
   EndIf 
Return
Would this expected to be reliable?

Thanks
 
Last edited:

inglewoodpete

Senior Member
BJCK: I'm not sure why you have the SetInt in such a tight loop. Once set, it will remain set until disabled or triggered. If triggered, the Interrupt is disabled and execution enters the subroutine labelled "Interrupt".

It is normal to reenable the Interrupt when the responding routine (not necessarily the Interrupt routine) processes the interrupt. In your case, it would be the routine that resets the variable "Flag".

Capturing very short pulses with a PICAXE Interrupt is difficult. It would probably be best to put an SR flip flop between the source and PICAXE. Of course, you will need to use a PICAXE output pin to reset the FF. Alternatively, use a simple pulse extender with a 4093 schmitt trigger.

Peter
 

BCJKiwi

Senior Member
The program only enters the interrupt section when the motor stops turning.
The reason it's in such a tight loop is that there is nothing else to do until one of the motors start turning.

Once a motor is turning, we just need to know which one and then there is no need for the interrupt routine until the motor stops again.

The present system works but response is slow on startup - have to work through a slow sequence repeatedly - the 1sec + loop of two .5sec count routines.

The question is all about reliable testing of the interrupt condition.

The thing I really don't understand is why the interrupt input condition is not available to the Interrupt Subroutine - this would seem to me to be a very basic and exteremely useful thing to have.
 

hippy

Senior Member
Most interrupts are usually single source so it's known what caused an interrupt to occur so it's not necessary to 'latch the cause of interrupt' in a special variable.

The PICAXE-X2's support the HINTSETUP command which will latch transitions at any time and with SETINTFLAGS can cause an interrupt when the executing command completes. Which pin caused the interrupt is indicated by the 'intXflag' variables. The HINTSETUP can be used without interrupts to flag transitions of the pins at any time so they can be polled if that is prefered.

It is also possible to achieve similar functionality on some PICAXE's by setting internal SFR's as required. 'Flag on edge' and 'Flag on change' events can be setup but can only be used by polling, not automatically invoking the 'Interrupt:' routine.
 

BCJKiwi

Senior Member
Thanks Hippy.

However, as indicated, this project uses a 28X1 for which the new x2 flags are not available.

The nearest indication is from the manual (28x1 SFRs);
"The system &#8216;flags&#8217; byte is broken down into individual bit variables. If the special
hardware feature of the flag is not used in a program the individual flag may be
freely used as a user defined bit flag."

Unfortunately have not been able to find anything that would indicate how this could be set up or if it has any relevance to this issue. Does this mean the 'flags' byte does in fact contain the information sought - the simulator would suggest not.
In this instance, polling would not be an issue as nothing else is going on anyway.

In an earlier post (2005!) you indicated;
"I have not used interrupts which have been anything other than an OR arrangement on a PICAXE."
and in my limited experience of interrupts I feel that the OR situation would be very common along with the single interrupt.
 

inglewoodpete

Senior Member
If the only thing the PICAXE is doing is waiting for the change-of-state on 1 of 2 input pins, it may be better to have your looping code do the checking rather than using the interrupt method.

Once again, a pulse extender would help. Since you only need to extend the pulse a few hundred microseconds, you may be able to get away with a diode, resistor and capacitor on each line. Even better if you can use schmitt trigger inputs on the PICAXE!
 

BCJKiwi

Senior Member
Pulse extenders are not really the answer as these incoming lines are from the optical switches and are what the count command is working on - need nice sharp Sq wave over full voltage range on the ST input to get an accurate count - pulses are around 50uS long at top speed.

However the pulses lengthen considerably anyway at the low speed where the interrupt routine would be used.

As indicated before, using the count code to do the job it takes a second + to respond depending on which motor input is starting up - interrupt should eliminate that 1 sec.
 

Tag16c

New Member
BCJKiwi,
I am new at the Picaxe but I have used a calculated goto for this in the past in assembly)
Maybe you could try this code
"
TightLoop:
ON PINS goto (TightLoop,Checkpin1,Checkpin2)
goto TightLoop
"
You may have to do 3 tight loops depending on the status of pin1 and pin2 and if there is something else going on with the other pins have a mask (more delays).
This is just another direction to try
 

Tag16c

New Member
BCJKiwi,
I don't think I explained well.
This is a lot more wordey but
See if this code makes more sense:


"
'asume stand still
Standstill:

On Pins goto (Tight1,Tight2,Tight3)

Tight1:
on Pins goto (Tight1,CheckPin1,CheckPin2,Tight1,CheckPin1,Checkpin2)' Repeat TightX,CheckPin1,CheckPin2 for all Tightx
goto Standstill 'This is an error code start over

Tight2:
on pins goto (CheckPin1,Tight2,CheckPin2) ' Pin1 starts high waiting for it to go low or Pin2 high
goto Standstill 'This is an error code start over

Tight3:
On pins goto (CheckPin2,CheckPin1,Tight3)' Both are high waiting on one to go low
goto Standstill 'This is an error code start over

CheckPin1:
Let flag = 1
Goto ...

CheckPin2:
Let flag = 0
goto ...

"
When the motor stops go back to standstill
 

hippy

Senior Member
If I've understood right, you have two inputs which could be receiving pulses but only one will be receiving pulses at a time. You need to count the pulse rate from the one which is producing pulses.

It should be possible to do all this by polling and without interrupts. Assuming inputs on pin 1 and 2 ...

Code:
DetectMotorStart:
  Do
    If pin1 = 1 Then Motor1Running
    If pin2 = 1 Then Motor2Running
  Loop
      
Motor1Running:
  Do
    Count 1, [i]period[/i], w0
    If w0 = 0 Then DetectMotorStart
    Gosub UpdateDisplayOrWhatever
  Loop

Motor2Running:
  Do
    Count 2, [i]period[/i], w0
    If w0 = 0 Then DetectMotorStat
    Gosub UpdateDisplayOrWhatever
  Loop
This gives an instant detect of the first motor which starts but there will be a delay ( the COUNT period ) when it stops. I don't see how this delay would be reduced by using interrupts as any active COUNT command would have to complete regardless.
 

hippy

Senior Member
I've identified a problem with the above code ...

If the motor comes to rest such that it permanently activates its opto sensor the code will believe it's running when it isn't. That can be overcome in software by a state machine seeing what state the pins are initially, then executing one of four routines which detect a change of pins.

The interrupt mechanism would suffer the same probem only more so ( permanently interrupting ) and could be more difficult to resolve.
 

BCJKiwi

Senior Member
@Hippy,

Already have code using count that does that job. It ensures it receives a minimum count.
The issue is that when starting up, the count rate is low so the period has to be (relatively) long.
The only thing I can figure that may fool it is if the opto is 'trembling' on the edge of the target in which case vibration may generate countable output.

As per Post #1, already have two working solutions - PB & count.
However the question was about interrupts and there were two;
1. is the interrupt input condition stored - answer no
2. how long would the input condition need to remain for the interrupt to act, jump to the interrupt routine, retest the input condition - probably have anywhere for 50uS (this is full speed so not really relevant) to say 1ms (low speed) with a 28x1 @ setfreq m8.

Any suggestions on how to create a custom flag which would store the input condition?
 
Last edited:

BCJKiwi

Senior Member
OK,

Stripped this thing out of the machine and ran some code changes/bench tests.

The Interrupt method seems to work OK on the bench when hit with a moving target at half full speed ~ 0.5ms

There were a number of issues that had to be dealt with;
1. goto replaced with do .. loop so the loop could be 'exited'
2. Flag required (used Count_In) inside interrupt routine so return from interrupt could be managed (exit from loop)
3. RPM had to be zeroed (else had false counts showing up).
4. A stationary target in front of the sensor generated an interrupt and a spurious low count (due to a FIFO and averaging elsewhere in the code) so the count and RPM had to be zeroed again within the routine.

Code:
..
..
If Count_In =< 3 then
  let Count_In = 0
  RPM = 0
  gosub Display
  do
    setint NOT %00000000,%00000110 ;interrupt on input 1 OR 2 high
    If Count_In > 3 then
      let Count_In = 0
      let RPM = 0
      Exit
    Endif
    If PB_In = 1 then
      gosub PushPush    ;Convert momentary switch to push push on/off sw
      Exit
    EndIf
  loop while count_In =<3 OR PB_In = 0
EndIf
..
..
 
Interrupt:
If Pin1 = 1 then 
..
Else  ; pin2 must = 1
..
..
EndIf
Let Count_In = 4
Return
 
Top