Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@yosemitebandit
Last active November 23, 2023 19:00
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save yosemitebandit/536a4a5ebb577d5d44044b6f09655e9f to your computer and use it in GitHub Desktop.
Save yosemitebandit/536a4a5ebb577d5d44044b6f09655e9f to your computer and use it in GitHub Desktop.
controlling a stepper motor with PWM
/* 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;
}
@ruizanthony
Copy link

Can you please indicate where you got the analogWriteFrequency from ?

I gather that the ellapsedMillis type comes from
https://github.com/pfeerick/elapsedMillis

@yosemitebandit
Copy link
Author

@ruizanthony -- it's a builtin if you use the teensy libs, same with ellapsedMillis

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment