Created
November 24, 2022 19:51
-
-
Save kachurovskiy/2a82f0afa9eed04b754279835e187b60 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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