Anil,
> Thank you both, I would appreciate if you can share your code James :)
The project using this code runs on an Arduino Uno and attempts to maintain the height of a platform on which metal slide holders are dropped. The slides are ~1.5mm thick, so after each one is dropped the platform is lowered. Two light-sensitive resistors get light on them from LEDs - the top path should be clear and the bottom blocked. If both are blocked, the platform needs to be lowered, if both are clear the platform needs to be raised. Originally I had a robot arm dropping the slide holders (6x9cm) into a box, but they would fall at an angle and jam so that the robot arm would eventually try to push into the heap of metal slide holders sticking out of the box - not good. Now the new slide is dropped onto the tidy pile of slides with no gap to allow it to flip. There is also a switch to raise the platform to the top so that the slides can be removed.
As far as the interrupt code goes, the Auduino setup() routine includes this:
#include <AccelStepper.h>
#include <avr/io.h>
#include <avr/interrupt.h>
...
// initialize the stepper library for 4-wire on the nominated pins
AccelStepper myStepper(AccelStepper::FULL4WIRE, stepperPin1, stepperPin2, stepperPin3, stepperPin4);
/*****************************************************************************
** setup
** =====
*/
void setup()
{
...
// Set up interrupt routine to operate every 0.1ms = 100us
if(!SetUpInterrupts(100))
while(1) { // forever, something has gone wrong
DoBlink(motorUpLedPin, 100);
DoBlink(motorDownLedPin, 100);
}
}
/****************************************************************************/
The code to set up the interrupt service hander is:
/*****************************************************************************
** SetUpInterrupts
** ===============
Set up interrupt routine to service stepper motor run() function.
*/
bool SetUpInterrupts(const int usecs)
{
// initialize Timer1
cli(); // disable global interrupts
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // same for TCCR1B
// set compare match register to desired timer count (1ms):
// ATmega328 with a 16MHz clock, clk/8
// (# timer counts + 1) = (target time) / (timer resolution)
// = .0001s / 6.25e-8 s * 8
// = 200
const float targetSecs = ((float) usecs) / 1e6;
const float timerSteps = 6.25e-8; // 1/16MHz
int count = 0;
int prescale = 1; // valid values: 1, 8, 64, 256, 1024
do {
count = targetSecs / (timerSteps * prescale);
if(count < 65535) // Timer 1 is 16-bits wide
break;
prescale *= 8;
} while (prescale <= 1024);
if(prescale > 1024) // time too long
return false;
if(prescale == 1 && count < 100) // time too short
return false;
OCR1A = count; // Eg, 200 = 0.1ms - I found 1ms gives rough acceleration
// turn on CTC mode (Clear Timer on Compare Match):
TCCR1B |= (1 << WGM12);
// Set CS10 and CS12 bits for 1024 prescaler:
// CS12 CS11 CS10
// 0 0 0 no clock source, Timer/counter stopped
// 0 0 1 clk/1 no prescaling
// 0 1 0 clk/8
// 0 1 1 clk/64
// 1 0 0 clk/256
// 1 0 1 clk/1024
// 1 1 0 external clock on T1 pin, falling edge
// 1 1 1 external clock on T1 pin, rising edge
switch(prescale) {
case 1:
TCCR1B |= (1 << CS10); // 0 0 1
break;
case 8:
TCCR1B |= (1 << CS11); // 0 1 0
break;
case 64:
TCCR1B |= (1 << CS11) & (1 << CS10); // 0 1 1
break;
case 256:
TCCR1B |= (1 << CS12); // 1 0 0
break;
case 1024:
TCCR1B |= (1 << CS12) & (1 << CS10); // 1 0 1
break;
}
// enable timer compare interrupt:
TIMSK1 |= (1 << OCIE1A);
// enable global interrupts:
sei();
return true;
}
/****************************************************************************/
The interrupt service hander routine itself is just this:
/*****************************************************************************
** ISR
** ===
Interrupt service routine for when Timer 1 matches compare value
*/
ISR(TIMER1_COMPA_vect)
{
myStepper.run();
}
/****************************************************************************/
The Arduino loop() function includes calls to modify stepper motor activity, eg:
myStepper.setAcceleration(accel); // steps/sec/sec
myStepper.stop(); // decelerate to a stop at new position
myStepper.setMaxSpeed(motorSpeed); // steps/sec
myStepper.move(-1000); // start moving the distance specified
For example, a blocking stop loop (ie, stop before doing anything else) can be programmed as follows:
const int kMotorDecelNormal = 500;
...
if(state != 0) { // not stopped already
myStepper.setAcceleration(kMotorDecelNormal); // steps/sec/sec
myStepper.stop(); // decelerate to a stop at new position
while(myStepper.distanceToGo() != 0) ; // wait for stop
}
Even while stuck in the "wait for stop" while loop, the myStepper.run(); function continues to be called in the interrupt handler.
I hope that is enough to get you going.
James Conway