If I power the A-Star 32u4 Micro board via USB and use the serial monitor, everything seems to run OK (stepper motor plus speed control via rotary encoder). If I power the board via Vin, though, the stepper motor does not spin and it doesn’t catch the button press on the rotary encoder via the ClickEncoder library. If I comment out the #define DEBUG_MODE line (as shown below), though, then all works fine again. I believe I noticed the same odd behaviour with the A-Star 328PB, too.
Anyone know why?
/*
Constant Speed stepper motor control using AccelStepper library
TODOs
=====
1. Switch to non-blocking LED blinking (e.g. https://www.arduino.cc/en/tutorial/BlinkWithoutDelay)
SilentStepStick TMC2208
=======================
https://shop.watterott.com/SilentStepStick-TMC2208-Stepper-Motor-Driver
1/2 step mode (MS1 > +5V; MS2 > GND)
Current limiter: Vref = 210mV (400mV for 2 motors)
SparkFun Rotary Encoder
=======================
https://www.sparkfun.com/products/9117
Rotary Encoder Wiring
=====================
https://bildr.org/blog/wp-content/uploads/2012/03/Rotary_Encoder_Switch_Arduino_Hookup.png
*/
/*
IMPORTANT: COMMENT OUT THE LINE BELOW FOR PRODUCTION USE, OR WHEN POWERING BOARD
VIA Vin PIN (i.e. when not connected go your computer via USB cable)
*/
//#define DEBUG_MODE
// Libraries
// =========
#include <AccelStepper.h>
#include <ClickEncoder.h>
#include <TimerOne.h>
#include <EEPROM.h>
// Define pins for stepper motor control, and others
#define DIR_PIN 6 // Req'd for AccelStepper
#define STEP_PIN 5 // Step on rising edge
#define EN_PIN 4 // LOW: Driver enabled. HIGH: Driver disabled
#define LED_PIN LED_BUILTIN // Speed adjustment indicator
// Set up accelStepper intance
AccelStepper stepper(AccelStepper::DRIVER, STEP_PIN, DIR_PIN);
// Set up ClickEncoder instance
ClickEncoder *encoder;
// ClickEncoder Timer1 ISR
void timerIsr() {
encoder->service();
}
// Set up stepper speed details
// For NMB stepper with gear box reduction ratio of 1:41.66666:
// Motor step angle 15 deg
// Output shaft step angle 0.36 deg
// 1000 pulse output = 360 deg
float motorRPM = 660.0; // # of steps per second (1/2 step)
float maxRPM = motorRPM*2.0;
float minRPM = motorRPM/2.0;
float adjFactor = 10.0;
// Set up variables with for ramping up during setup()
unsigned long timeStamp1;
unsigned long previousAccel = 0;
int interval = 15; // # of milliseconds between speed increases (1/2 step)
bool motorRPMAdj = false;
unsigned long timeStamp2;
long elapsedTimeBeforeSave = 5000; // Wait 5sec after last change before saving new speed to EEPROM
int eeAddress = 0; // EEPROM address to start reading from
void setup()
{
// Prepare pins
pinMode(EN_PIN, OUTPUT);
digitalWrite(EN_PIN, HIGH); // Disable driver in hardware
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW); // Speed adj indicator should be off initially
stepper.setMaxSpeed(maxRPM);
stepper.setSpeed(10); // Set to a really low value in anticipation of ramping up to
// motorRPM in setup()
encoder = new ClickEncoder(A0, A1, 7, 4); // A0 = B; A1 = A; 7 = Btn; SparkFun rotary encoder has 12 indents = 4
encoder->setAccelerationEnabled(false);
encoder->setDoubleClickEnabled(false);
Timer1.initialize(1000);
Timer1.attachInterrupt(timerIsr);
digitalWrite(EN_PIN, LOW); // Enable driver in hardware
#ifdef DEBUG_MODE
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
#endif
// Get the float data from the EEPROM at position 'eeAddress'
float f = 0.00f; // Variable to store data read from EEPROM.
EEPROM.get( eeAddress, f );
#ifdef DEBUG_MODE
Serial.print("EEPROM f val: ");
Serial.println( f, 3 ); // This may print 'ovf, nan' if the data inside the EEPROM is not a valid float.
#endif
if (!isnan(f)) {
// EEPROM read yields numerical value, so set motorRPM to this if it's within min/max
if ((f >= minRPM) && (f <= maxRPM)) {
motorRPM = f;
}
}
#ifdef DEBUG_MODE
Serial.print("motorRPM: ");
Serial.println(motorRPM); // This may print 'ovf, nan' if the data inside the EEPROM is not a valid float.
#endif
// Initial ramp up to motorRPM on startup
while (stepper.speed() < motorRPM) {
timeStamp1 = millis();
if (timeStamp1 > previousAccel + interval) {
previousAccel = timeStamp1;
if (stepper.speed() + 2 > motorRPM) {
stepper.setSpeed(motorRPM);
} else {
stepper.setSpeed(stepper.speed() + 2);
}
}
stepper.runSpeed();
}
}
void loop()
{
// Check if rotary button pressed
ClickEncoder::Button b = encoder->getButton();
if (b != ClickEncoder::Open) {
switch (b) {
case ClickEncoder::Released:
// Enable speed adjustment via rotary encoder
motorRPMAdj = true; // Turn on state variable
timeStamp2 = millis(); // Start timer to determine when ajustments are done
digitalWrite(LED_PIN, HIGH); // Turn on speed adj indicator
break;
}
}
// Check if rotary encoder has changed & adjust speed accordingly
if (motorRPMAdj == true) {
checkEncoder();
}
stepper.runSpeed();
// Save new motor RPM after appropriate elapsed time
unsigned long currentTime = millis();
if ( motorRPMAdj == true && ( (currentTime - timeStamp2) > elapsedTimeBeforeSave) ) {
// EEPROM.put(eeAddress, motorRPM); // update EEPROM with new motorRPM
motorRPMAdj = false; // reset flag
digitalWrite(LED_PIN, LOW); // Turn off speed adj indicator
#ifdef DEBUG_MODE
Serial.print("motorRPMAdj: ");
Serial.println(motorRPMAdj);
Serial.print("Saved motorRPM: ");
Serial.println(motorRPM);
#endif
}
}
/*
Purpose: check if rotary encoder has been used and adjust stepper motor speed
Parameters: none
Returns: nothing
*/
void checkEncoder() {
int16_t encVal = encoder->getValue(); // returns 1 for CW; -1 for CCW (dependng on A/B connectuon); 0 if untouched
if (encVal != 0) {
// Rotary encoder knob was turned left or right
timeStamp2 = millis(); // reset timer every time the knob is turned
// Update stepper speed, keeping within min/max values
motorRPM = motorRPM + (encVal*adjFactor);
if (motorRPM < minRPM) {
motorRPM = minRPM;
}
if (motorRPM > maxRPM) {
motorRPM = maxRPM;
}
stepper.setSpeed(motorRPM);
#ifdef DEBUG_MODE
Serial.print("encVal: ");
Serial.println(encVal);
Serial.print("motorRPM: ");
Serial.println(motorRPM);
#endif
}
}