Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save kachurovskiy/2a82f0afa9eed04b754279835e187b60 to your computer and use it in GitHub Desktop.
Save kachurovskiy/2a82f0afa9eed04b754279835e187b60 to your computer and use it in GitHub Desktop.
#define STEP 12
#define ENA 13
// How fast we want to accelerate the stepper. Reasonable values 5 - 200.
#define ACCELERATION 5
// Time between the STEP pulses when starting slow. 400 pulses per second.
#define DELAY_US_MAX 2500
// Time between the STEP pulses at highest speed. 25*400 pulses per second.
#define DELAY_US_MIN 100
// Maximum size of the acceleration table. Arduino has little memory.
// If this is too small or ACCELERATION is too small, max speed won't be reached.
#define ACCEL_TABLE_MAX_SIZE 800
// Contains OCR1A values determining delay between pulses during acceleration phase.
int accelTable[ACCEL_TABLE_MAX_SIZE];
int accelTableSize;
// Points to accelTable index we're currently at.
volatile int accelTableCurrent = 0;
void setup() {
Serial.begin(9600);
// 800 step per revolution motor driver on this pin.
pinMode(STEP, OUTPUT);
// Enable stepper.
pinMode(ENA, OUTPUT);
digitalWrite(ENA, HIGH);
// Prepare acceleration table since it's going to be the same
// all the time and there's not enough time to re-calculate the next
// value while handling the interrupt.
long d = DELAY_US_MAX;
int i = 0;
while (i < ACCEL_TABLE_MAX_SIZE && d > DELAY_US_MIN) {
// ClockSpeed/(Hz/prescaler) - 1 =
// 16000000/(1000000/delay_usec)/8 - 1 =
accelTable[i] = 2 * d - 1;
d = 1000000.0 / (1000000.0 / d + ACCELERATION * d / 1000.0);
i++;
// Print the table for debugging.
Serial.print(accelTable[i]);
if (i % 30 == 0) {
Serial.println("");
} else {
Serial.print(" ");
}
}
accelTableSize = i;
Serial.println("");
Serial.print("Acceleration table size: ");
Serial.println(accelTableSize);
// See pages 108 - 112 of ATmega328P_Datasheet.pdf
// CS11 means prescaler = 8. WGM12 means issuing
// interrupt when TCNT1 == OCR1A and set TCNT1 to 0.
TCCR1B = (1 << WGM12) + (1 << CS11);
TCCR1A = 0;
TCNT1 = 0;
OCR1A = 1250; // 2000000/Hz - 1
TIMSK1 |= (1 << OCIE1A); // enable timer
}
volatile bool accelerate = true;
// Every 8 clock ticks, processor increments TCNT1.
// When TCNT1 == OCR1A, this method is called and TCNT1 is reset to 0.
// Keep code in this method to absolute minimum to achieve high stepper speeds.
ISR(TIMER1_COMPA_vect) {
// This can be further sped up (from 6us+6us to 0.125us+0.125us) using e.g. FastGPIO lib instead of digitalWrite().
// Beware that some stepper drivers ignore pusles that are too short - or place if (...) { ... } in between calls.
digitalWrite(STEP, LOW);
digitalWrite(STEP, HIGH);
// Adjust the time till next ISR(TIMER1_COMPA_vect) call by changing the timer counter max value OCR1A.
if (accelerate && accelTableCurrent < accelTableSize) {
OCR1A = accelTable[accelTableCurrent++];
} else if (!accelerate && accelTableCurrent > 0) {
OCR1A = accelTable[accelTableCurrent--];
}
}
void loop() {
delay(1000);
accelerate = !accelerate;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment