What I would do, is extend multistepper to support a global volatile flag, that is initialized to zero in the user
init() function, and set in the interrupt function.
Necessary changes to
MultiStepper.cpp include replacing the last two functions with
Code:
external volatile unsigned char emergency_stopped;
// Returns true if any motor is still running to the target position.
boolean MultiStepper::run()
{
uint8_t i;
boolean ret = false;
for (i = 0; i < _num_steppers; i++)
{
if ( _steppers[i]->distanceToGo() != 0)
{
if (!emergency_stopped)
{
_steppers[i]->runSpeed();
}
ret = true;
}
}
return ret;
}
// Blocks until all steppers reach their target position and are stopped
void MultiStepper::runSpeedToPosition()
{
while (run() && !emergency_stopped)
;
}
// Blocks until all steppers reach their target position and are stopped
void MultiStepper::runSpeedToPosition()
{
while (!emergency_stopped && run())
;
}
and probably two functions in
AccelStepper.cpp ,
Code:
external volatile unsigned char emergency_stopped;
// Implements steps according to the current step interval
// You must call this at least once per step
// returns true if a step occurred
boolean AccelStepper::runSpeed()
{
// Do nothing if emergency stopped
if (emergency_stopped)
return false;
// Dont do anything unless we actually have a step interval
if (!_stepInterval)
return false;
unsigned long time = micros();
if (time - _lastStepTime >= _stepInterval)
{
if (_direction == DIRECTION_CW)
{
// Clockwise
_currentPos += 1;
}
else
{
// Anticlockwise
_currentPos -= 1;
}
step(_currentPos);
_lastStepTime = time; // Caution: does not account for costs in step()
return true;
}
else
{
return false;
}
}
and
Code:
// Blocks until the target position is reached and stopped
void AccelStepper::runToPosition()
{
while (!emergency_stopped && run())
;
}
In your own code, you declare the flag,
Code:
volatile unsigned char emergency_stopped;
clear it in your
init() function using
before initializing the steppers; you can also do that whenever the emergency stop is canceled (so it acts more like an immediate "pause" than stop),
and in your interrupt function that gets called whenever the emergency stop is enabled, add
It only uses one additional byte of RAM, and a tiny bit of Flash/ROM.
The idea is that the flag acts like a big red "DON'T DO IT!" to the multistepper library. It is marked
extern in the MultiStepper files, because it is not declared there (it is declared in your own code); and it is also marked
volatile to tell the compiler that its value can change at any time, so must not be cached. "Caching" in the compiler context means that if it sees it used in a
while loop condition, means that even if it sees that the loop body does not change the value, it cannot just check it once before the loop; it must check it every loop iteration.
Normally, such flags are made internal to the class. Here, I deliberately made it part of your own code, accessed "externally" by the modifications in the multistepper library, as it is a kinda "global" feature.
It would not be difficult to think about this for a bit, then submit a patch to the maintainer (Mike McCauley at AirSpayce), to implement it more properly. Probably, the
AccelStepper class should have a public volatile flag, say
stopped , that the above functions access; cleared in the constructor, and set in the user emergency stop function.
However, I do not use AccelStepper/MultiStepper myself, and haven't even bothered to check if the above code works: I'm too lazy, sorry.