After much frustration, I've finally programmed the Rev 3 motor shield to microstep at 16 microsteps per step. The clock drive mechanics calls for one full step every 1.2 seconds, or 75 mS per microstep. I use the TimerOne library to generate an interrupt every 75 mS. The interrupt service routine then writes values from a table to DIRA, DIRB, PWMA, and PWMB.
The control pad has buttons for 8X speed forward and backward, plus 2X speed forward and a Pause button. The speed is changed by dividing the interrupt interval (75 mS) by either 2 or 8. The Pause button disables the stepper drivers and allows manual adjustment of the RA.
Here's the code:
/*
* Sketch to run a stepper-motor-based telescope clock drive. Uses the Arduino motor shield Rev 3.
*/
#include "TimerOne.h"
// Define number of steps per revolution:
const int stepsPerRevolution = 200;
// Give the motor control pins names:
#define pwmA 3
#define pwmB 11
#define brakeA 9
#define brakeB 8
#define dirA 12
#define dirB 13
// Give the control button inputs names:
#define X8slow 0
#define X8fast 1
#define X2fast 4
#define RApause 2
// Other defines:
#define baudRate 9600 //UART baud rate
#define baseRate 75000 // 1.2s/step; 75ms/micro-step
#define mainGearT 60; // Main gear = 60 teeth
#define driverGearT 24; // Driver gear = 24 teeth
// Main gear rate = 10 minutes per revoluion => 600 s/rev
// Driver gear rate = 24/60 * 600 s/rev = 240 s/rev
// Stepper rate = 240/200 = 1.2 s/step
//
// Global variables
int stepTableIndex = 0;
int stepTableIncrement = 1;
long int stepRate = baseRate;
int pauseState = 0;
#define stepTableModulus 64
int stepTable [stepTableModulus][4] = // DIRA, DIRB, ENA, ENB
{
{ 0, 0, 255, 255 }, // step 1
{ 0, 0, 250, 255 },
{ 0, 0, 236, 255 },
{ 0, 0, 212, 255 },
{ 0, 0, 180, 255 },
{ 0, 0, 142, 255 },
{ 0, 0, 98, 255 },
{ 0, 0, 50, 255 },
{ 0, 0, 0, 255 },
{ 1, 0, 50, 255 },
{ 1, 0, 98, 255 },
{ 1, 0, 142, 255 },
{ 1, 0, 180, 255 },
{ 1, 0, 212, 255 },
{ 1, 0, 236, 255 },
{ 1, 0, 250, 255 },
{ 1, 0, 255, 255 }, // step 2
{ 1, 0, 255, 250 },
{ 1, 0, 255, 236 },
{ 1, 0, 255, 212 },
{ 1, 0, 255, 180 },
{ 1, 0, 255, 142 },
{ 1, 0, 255, 98 },
{ 1, 0, 255, 50 },
{ 1, 0, 255, 0 },
{ 1, 1, 255, 50 },
{ 1, 1, 255, 98 },
{ 1, 1, 255, 142 },
{ 1, 1, 255, 180 },
{ 1, 1, 255, 212 },
{ 1, 1, 255, 236 },
{ 1, 1, 255, 250 },
{ 1, 1, 255, 255 }, // step 3
{ 1, 1, 250, 255 },
{ 1, 1, 236, 255 },
{ 1, 1, 212, 255 },
{ 1, 1, 180, 255 },
{ 1, 1, 142, 255 },
{ 1, 1, 98, 255 },
{ 1, 1, 50, 255 },
{ 1, 1, 0, 255 },
{ 0, 1, 50, 255 },
{ 0, 1, 98, 255 },
{ 0, 1, 142, 255 },
{ 0, 1, 180, 255 },
{ 0, 1, 212, 255 },
{ 0, 1, 236, 255 },
{ 0, 1, 250, 255 },
{ 0, 1, 255, 255 }, // step 4
{ 0, 1, 255, 250 },
{ 0, 1, 255, 236 },
{ 0, 1, 255, 212 },
{ 0, 1, 255, 180 },
{ 0, 1, 255, 142 },
{ 0, 1, 255, 98 },
{ 0, 1, 255, 50 },
{ 0, 1, 255, 0 },
{ 0, 0, 255, 50 },
{ 0, 0, 255, 98 },
{ 0, 0, 255, 142 },
{ 0, 0, 255, 180 },
{ 0, 0, 255, 212 },
{ 0, 0, 255, 236 },
{ 0, 0, 255, 250 }
};
void setup() {
pinMode(pwmA, OUTPUT);
pinMode(pwmB, OUTPUT);
pinMode(brakeA, OUTPUT);
pinMode(brakeB, OUTPUT);
pinMode(dirA, OUTPUT);
pinMode(dirB, OUTPUT);
digitalWrite(dirA, stepTable[stepTableIndex][0]);
digitalWrite(dirB, stepTable[stepTableIndex][1]);
analogWrite(pwmA, stepTable[stepTableIndex][2]);
analogWrite(pwmB, stepTable[stepTableIndex][3]);
// Set up the control button inputs
pinMode(X8slow, INPUT_PULLUP);
pinMode(X8fast, INPUT_PULLUP);
pinMode(X2fast, INPUT_PULLUP);
pinMode(RApause, INPUT_PULLUP);
Timer1.initialize(baseRate); // 1.2s per step
Timer1.attachInterrupt(interruptService);
}
void interruptService()
{
Timer1.initialize(stepRate);
digitalWrite(dirA, stepTable[stepTableIndex][0]);
digitalWrite(dirB, stepTable[stepTableIndex][1]);
if (pauseState) //Disable the stepper driver
{
digitalWrite(pwmA,LOW);
digitalWrite(pwmB,LOW);
}
else //Write analog values to enables
{ analogWrite (pwmA, stepTable[stepTableIndex][2]);
analogWrite (pwmB, stepTable[stepTableIndex][3]);
}
stepTableIndex += stepTableIncrement;
stepTableIndex = (stepTableIndex + stepTableModulus) % stepTableModulus;
}
void loop() {
int X8fastState = HIGH;
int X8slowState = HIGH;
int X2fastState = HIGH;
int RApauseState = HIGH;
// Check the state of the pushbuttons:
X8fastState = !digitalRead(X8fast);
X8slowState = !digitalRead(X8slow);
X2fastState = !digitalRead(X2fast);
RApauseState = !digitalRead(RApause);
// Adjust step rate and increment based on button states:
if (X8fastState) {stepRate = baseRate/8; stepTableIncrement = 1;}
else if (X8slowState) {stepRate = baseRate/8; stepTableIncrement = -1;}
else if (X2fastState) {stepRate = baseRate/2; stepTableIncrement = 1;}
else if (RApauseState) {pauseState = 1; stepTableIncrement = 0;}
else {stepRate = baseRate; stepTableIncrement = 1; pauseState = 0;}
}