Last active
November 23, 2023 19:00
-
-
Save yosemitebandit/536a4a5ebb577d5d44044b6f09655e9f to your computer and use it in GitHub Desktop.
controlling a stepper motor with PWM
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
/* Teensy LC sketch for controlling a stepper motor. | |
Reads comma-separate commands over serial. Sends back number of steps taken. | |
Commands are of the form: | |
step,300,800 -> stepper should move 300 sixteenth-steps forward at 800 steps per second | |
step,-124,100 -> stepper should move 124 sixteenth-steps backward at 100 steps per second | |
*/ | |
// Setup the builtin LED, the step and direction pins. | |
const int ledPin = 13; | |
const int stepPin = 3; | |
const int dirPin = 2; | |
// Set the PWM duty cycle and counter pin. | |
const int dutyCycle = 25; | |
const int counterPin = 9; | |
// Define step targets and counters. | |
int stepTarget; | |
volatile int stepsTaken = 0; | |
// Store the direction the stepper is moving (one or zero). | |
int stepperDir; | |
// Setup command-reading vars. | |
static char commandBuffer[80]; | |
int commandValue; | |
int commandFrequency; | |
// Periodically print status info. | |
elapsedMillis timeSinceLastPrint; | |
const int printDelayTime = 1000; | |
void setup() { | |
// Turn on the LED. | |
pinMode(ledPin, OUTPUT); | |
digitalWrite(ledPin, HIGH); | |
// Setup the stepper. | |
pinMode(dirPin, OUTPUT); | |
digitalWrite(dirPin, LOW); | |
pinMode(stepPin, OUTPUT); | |
// Setup the counter pin. | |
pinMode(counterPin, INPUT_PULLUP); | |
attachInterrupt(counterPin, stepInterrupt, RISING); | |
// Start serial comms over USB. | |
Serial.begin(57600); | |
} | |
int readline(int readch, char *commandBuffer, int len) { | |
/* Reads chars into a buffer until a carriage return is received. | |
Method via hackingmajenkoblog.wordpress.com | |
*/ | |
static int pos = 0; | |
int rpos; | |
if (readch > 0) { | |
switch (readch) { | |
// Ignore new lines but return on CR. | |
case '\n': | |
break; | |
case '\r': | |
rpos = pos; | |
pos = 0; | |
return rpos; | |
default: | |
if (pos < len-1) { | |
commandBuffer[pos++] = readch; | |
commandBuffer[pos] = 0; // ?? | |
} | |
} | |
} | |
// No end of line has been found, so return -1. | |
return -1; | |
} | |
void loop() { | |
// Try to read a command. | |
if (readline(Serial.read(), commandBuffer, 80) > 0) { | |
if (sscanf(commandBuffer, "step,%d,%d", &commandValue, &commandFrequency) == 2) { | |
// If the stepping command is valid, apply it. | |
if (commandValue > 0) { | |
digitalWrite(dirPin, HIGH); | |
stepperDir = 1; | |
} else { | |
digitalWrite(dirPin, LOW); | |
stepperDir = -1; | |
} | |
analogWriteFrequency(stepPin, commandFrequency); | |
stepTarget = stepsTaken + commandValue; | |
analogWrite(stepPin, dutyCycle); | |
} else { | |
Serial.print("Error: received message '"); | |
Serial.print(commandBuffer); | |
Serial.println("'"); | |
} | |
} | |
// Stop the stepper when it reaches its step target. | |
if (stepperDir == 1 && stepsTaken >= stepTarget) { | |
analogWrite(stepPin, 0); | |
} | |
else if (stepperDir == -1 && stepsTaken <= stepTarget) { | |
analogWrite(stepPin, 0); | |
} | |
// Periodically print the stepper position. | |
if (timeSinceLastPrint > printDelayTime) { | |
Serial.println(stepsTaken); | |
timeSinceLastPrint = 0; | |
} | |
} | |
// Setup counter interrupt. Increment the count in a direction-sensitive way. | |
void stepInterrupt() { | |
stepsTaken += stepperDir; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@ruizanthony -- it's a builtin if you use the teensy libs, same with
ellapsedMillis