I wrote a small sketch to test this stepper motor control, but I can't get it to work properly.
I use Timer 1 to create a PWM signal with fixed pulsewidth where the frequency can be set to correspond to the desired stepper velocity (steps pr sec). This frequency is calculated in the function calcSpeed(acceleration, update interval). When I update the frequency inside the function it works, but stutters sometimes and my guess is that this happens because it updates the new frequency too close to the last pulse, and that this can be fixed by updating to the new frequency after the current cycle is over by setting the frequency inside an interrupt routine that is called when the counter overflows. I've tried to the best of my abilities to copy the examples in "Gammon Forum : Electronics : Microprocessors : Interrupts", but I'm not able to make the ISR work.
const int stepPin = 9;
const int directionPin = 8;
volatile float frequency = 50; // starting frequency
const byte prescaler = 8;
unsigned int pulsewidth_us = 50; // us
unsigned int pulsewidth_counts = pulsewidth_us * 2; // counts
float maxFrequency = 2400; // Hz
float minFrequency = 50;
void setup() {
Serial.begin(115200);
// put your setup code here, to run once:
pinMode(directionPin, OUTPUT);
digitalWrite(directionPin, LOW);
pinMode(stepPin, OUTPUT);
//Timer 1: Fast PWM, non-inverted, prescaler = 8.
bitWrite(TCCR1A, COM1A1, 1);
bitWrite(TCCR1A, COM1A0, 0);
bitWrite(TCCR1A, COM1B1, 0);
bitWrite(TCCR1A, COM1B0, 0);
bitWrite(TCCR1A, WGM11, 1);
bitWrite(TCCR1A, WGM10, 0);
bitWrite(TCCR1B, WGM13, 1);
bitWrite(TCCR1B, WGM12, 1);
bitWrite(TCCR1B, CS12, 0);
bitWrite(TCCR1B, CS11, 1);
bitWrite(TCCR1B, CS10, 0);
ICR1 = F_CPU / prescaler / frequency; // period in clock cycles for starting frequency
OCR1A = pulsewidth_counts; // pulse width
}
boolean newFrequency = 0; // flag to know if a new frequency is calculated.
ISR(TIMER1_OVF_vect){
if (newFrequency){
ICR1 = F_CPU / prescaler / frequency;
newFrequency = 0;
}
}
void loop() {
calcSpeed(500,50); // 500 Hz/s^2, update interval 50ms
}
void calcSpeed(int a, unsigned dt) {
// f += a * t;
static unsigned long PT = 0;
unsigned long CT = millis(); // Check if time to update frequency
if (CT - PT > dt) {
PT += dt;
float t = (float)dt * 0.001;
frequency += a * t;
if (frequency > maxFrequency) frequency = maxFrequency;
if (frequency < minFrequency) frequency = minFrequency;
//ICR1 = F_CPU / prescaler / frequency; // set new frequency <- works, but sometimes causes the motor to shake. Find a way to make this happen after a full cycle?
newFrequency = 1; // set flag so that interrupt routing updates the frequency at next cycle.
Serial.println(frequency);
}
}