Stepper Motor Serial Monitor Arduino Running At Same Time
Control Stepper Motor Serial Monitor Arduino
Stepper Motor Serial Monitor Arduino Running At Same Time - Previously I have made an article about Keyes CNC Shield V4 GRBL and how to control via a4988 driver. But a problem arises when we can't control the stepper motor to rotate at the same time.
Therefore, I tried several methods and using a timer interrupt was the right choice after learning the program code from the video Coordinated stepper motor control (arduino) and then I edited a few lines of the program and set the right interrupt to run on the Arduino Uno / Nano.
A. A4988 CNC Shield Stepper Motor Schematic
In this article, I still use the CNC Shield V4 a4988 as a stepper motor controller to facilitate this test. For the schematic, please look at the following picture:
![]() |
CNC Shield Stepper Motor Schematic |
The stepper motor has 4 wires, red blue green and black, please make sure you connect it to the CNC Shield correctly. If the connection is wrong, it could be that the stepper is spinning incorrectly. I have provided the program code for you below.
B. Arduino Code Motor Stepper
This is a program that I modified, you can copy and paste into your arduino IDE, then upload it to arduino.
#define X_DIR_PIN 2 #define X_STEP_PIN 5 #define X_ENABLE_PIN 8 #define Y_DIR_PIN 3 #define Y_STEP_PIN 6 #define Y_ENABLE_PIN 8 #define Z_DIR_PIN 4 #define Z_STEP_PIN 7 #define Z_ENABLE_PIN 8 #define X_STEP_HIGH PORTD |= (1 << X_STEP_PIN); #define X_STEP_LOW PORTD &= ~(1 << X_STEP_PIN); #define Y_STEP_HIGH PORTD |= (1 << Y_STEP_PIN); #define Y_STEP_LOW PORTD &= ~(1 << Y_STEP_PIN); // #define Z_STEP_HIGH PORTD |= (1 << Z_STEP_PIN); #define Z_STEP_LOW PORTD &= ~(1 << Z_STEP_PIN); #define TIMER1_INTERRUPTS_ON TIMSK1 |= (1 << OCIE1A); #define TIMER1_INTERRUPTS_OFF TIMSK1 &= ~(1 << OCIE1A); byte a; int x = 0; int y = 0; int z = 0; String get_data[3]; String data; int stringData; String per_data; struct stepperInfo { // externally defined parameters float acceleration; volatile unsigned int minStepInterval; // ie. max speed, smaller is faster void (*dirFunc)(int); void (*stepFunc)(); // derived parameters unsigned int c0; // step interval for first step, determines acceleration long stepPosition; // current position of stepper (total of all movements taken so far) // per movement variables (only changed once per movement) volatile int dir; // current direction of movement, used to keep track of position volatile unsigned int totalSteps; // number of steps requested for current movement volatile bool movementDone = false; // true if the current movement has been completed (used by main program to wait for completion) volatile unsigned int rampUpStepCount; // number of steps taken to reach either max speed, or half-way to the goal (will be zero until this number is known) // per iteration variables (potentially changed every interrupt) volatile unsigned int n; // index in acceleration curve, used to calculate next interval volatile float d; // current interval length volatile unsigned long di; // above variable truncated volatile unsigned int stepCount; // number of steps completed in current movement }; void xStep() { X_STEP_HIGH X_STEP_LOW } void xDir(int dir) { digitalWrite(X_DIR_PIN, dir); } void yStep() { Y_STEP_HIGH Y_STEP_LOW } void yDir(int dir) { digitalWrite(Y_DIR_PIN, dir); } void zStep() { Z_STEP_HIGH Z_STEP_LOW } void zDir(int dir) { digitalWrite(Z_DIR_PIN, dir); } void resetStepperInfo( stepperInfo& si ) { si.n = 0; si.d = 0; si.di = 0; si.stepCount = 0; si.rampUpStepCount = 0; si.totalSteps = 0; si.stepPosition = 0; si.movementDone = false; } #define NUM_STEPPERS 3 volatile stepperInfo steppers[NUM_STEPPERS]; void setup() { Serial.begin(9600); pinMode(X_STEP_PIN, OUTPUT); pinMode(X_DIR_PIN, OUTPUT); pinMode(X_ENABLE_PIN, OUTPUT); pinMode(Y_STEP_PIN, OUTPUT); pinMode(Y_DIR_PIN, OUTPUT); pinMode(Y_ENABLE_PIN, OUTPUT); pinMode(Z_STEP_PIN, OUTPUT); pinMode(Z_DIR_PIN, OUTPUT); pinMode(Z_ENABLE_PIN, OUTPUT); digitalWrite(X_ENABLE_PIN, LOW); digitalWrite(Y_ENABLE_PIN, LOW); digitalWrite(Z_ENABLE_PIN, LOW); noInterrupts(); TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; OCR1A = 1000; // compare value TCCR1B |= (1 << WGM12); // CTC mode TCCR1B |= ((1 << CS11) | (1 << CS10)); // 64 prescaler interrupts(); steppers[0].dirFunc = xDir; steppers[0].stepFunc = xStep; steppers[0].acceleration = 1000; steppers[0].minStepInterval = 250; steppers[1].dirFunc = yDir; steppers[1].stepFunc = yStep; steppers[1].acceleration = 1000; steppers[1].minStepInterval = 250; steppers[2].dirFunc = zDir; steppers[2].stepFunc = zStep; steppers[2].acceleration = 1000; steppers[2].minStepInterval = 250; } void resetStepper(volatile stepperInfo& si) { si.c0 = si.acceleration; si.d = si.c0; si.di = si.d; si.stepCount = 0; si.n = 0; si.rampUpStepCount = 0; si.movementDone = false; } volatile byte remainingSteppersFlag = 0; void prepareMovement(int whichMotor, int steps) { volatile stepperInfo& si = steppers[whichMotor]; si.dirFunc( steps < 0 ? HIGH : LOW ); si.dir = steps > 0 ? 1 : -1; si.totalSteps = abs(steps); resetStepper(si); remainingSteppersFlag |= (1 << whichMotor); } volatile byte nextStepperFlag = 0; volatile int ind = 0; volatile unsigned int intervals[100]; void setNextInterruptInterval() { bool movementComplete = true; unsigned int mind = 999999; for (int i = 0; i < NUM_STEPPERS; i++) { if ( ((1 << i) & remainingSteppersFlag) && steppers[i].di < mind ) { mind = steppers[i].di; } } nextStepperFlag = 0; for (int i = 0; i < NUM_STEPPERS; i++) { if ( ! steppers[i].movementDone ) movementComplete = false; if ( ((1 << i) & remainingSteppersFlag) && steppers[i].di == mind ) nextStepperFlag |= (1 << i); } if ( remainingSteppersFlag == 0 ) { OCR1A = 65500; } OCR1A = mind; } ISR(TIMER1_COMPA_vect) { unsigned int tmpCtr = OCR1A; OCR1A = 65500; for (int i = 0; i < NUM_STEPPERS; i++) { if ( ! ((1 << i) & remainingSteppersFlag) ) continue; if ( ! (nextStepperFlag & (1 << i)) ) { steppers[i].di -= tmpCtr; continue; } volatile stepperInfo& s = steppers[i]; if ( s.stepCount < s.totalSteps ) { s.stepFunc(); s.stepCount++; s.stepPosition += s.dir; if ( s.stepCount >= s.totalSteps ) { s.movementDone = true; remainingSteppersFlag &= ~(1 << i); } } if ( s.rampUpStepCount == 0 ) { s.n++; s.d = s.d - (2 * s.d) / (4 * s.n + 1); if ( s.d <= s.minStepInterval ) { s.d = s.minStepInterval; s.rampUpStepCount = s.stepCount; } if ( s.stepCount >= s.totalSteps / 2 ) { s.rampUpStepCount = s.stepCount; } } else if ( s.stepCount >= s.totalSteps - s.rampUpStepCount ) { s.d = (s.d * (4 * s.n + 1)) / (4 * s.n + 1 - 2); s.n--; } s.di = s.d; // integer } setNextInterruptInterval(); TCNT1 = 0; } void runAndWait() { setNextInterruptInterval(); while ( remainingSteppersFlag ); } void loop() { TIMER1_INTERRUPTS_ON while (Serial.available() != 0) { data = Serial.readString(); for (a = 0; a < 3; a++) { get_data[a] = split(data, ' ', a); if (get_data[a] != NULL) { if (a == 0) { x = get_data[0].toInt(); } if (a == 1) { y = get_data[1].toInt(); } if (a == 2) { z = get_data[2].toInt(); } } } if (x != NULL) { prepareMovement( 0, x ); Serial.print("Stepper X : "); Serial.print(x); Serial.println(" steps"); } if (y != 0) { prepareMovement( 1, y ); Serial.print("Stepper Y : "); Serial.print(y); Serial.println(" steps"); } if (z != 0) { prepareMovement( 2, z ); Serial.print("Stepper Z : "); Serial.print(z); Serial.println(" steps"); Serial.println(); } runAndWait(); x = 0; y = 0; z = 0; } } String split(String data, char character, int pos) { stringData = 0; per_data = ""; for (int i = 0; i < data.length() - 1; i++) { if (data[i] == character) { stringData++; } else if (stringData == pos) { per_data.concat(data[i]); } else if (stringData > pos) { return per_data; break; } } return per_data; }
After that, open your Arduino Serial Monitor, and send the steps value in "x y z" format (make sure you are using space). For example, you want to rotate the stepper motor together with the steps position:
- X is 30 steps
- Y is 100 steps
- Z is 360 steps
In the serial monitor form, please write 30 100 360, then Enter. You can see the motors spinning together.
To simplify this illustration, I attached a video of the program above below.
Post a Comment for "Stepper Motor Serial Monitor Arduino Running At Same Time"