Hello guys, I need your help please. I am trying to have a stepper motor (28BYJ-48) and one led ws2811 3W to run together controlled by Digispark. I would like the stepper motor to have continuous clockwise rotation while the led would do a continous raindow fade. I have tried to merge 2 codes together but the stepper rotates, then stops for the led to fade through one rainbow cycle. How can I merge the code so that the stepper doesn't stop and goes into continuous rotation while the led fades through rainbow continously. Please find my code below:
/* Example sketch to control a 28BYJ-48 stepper motor with ULN2003 driver board and Arduino UNO. More info: https://www.makerguides.com */
// Include the Arduino Stepper.h library:
#include <Stepper.h>
#include <Adafruit_NeoPixel.h>
// Define number of steps per rotation:
const int stepsPerRevolution = 2048;
const int ledPin = 4; // the number of the neopixel strip
const int numLeds = 1;
// Create stepper object called 'myStepper', note the pin order:
Stepper myStepper = Stepper(stepsPerRevolution, 3, 1, 2, 0);
Adafruit_NeoPixel strip = Adafruit_NeoPixel(numLeds, ledPin, NEO_GRB + NEO_KHZ800);
void setup() {
// Set the speed to 5 rpm:
myStepper.setSpeed(12);
strip.begin();
strip.setBrightness(20); // 1/3 brightness
// Begin Serial communication at a baud rate of 9600:
Serial.begin(9600);
}
void loop() {
// Step one revolution in one direction:
Serial.println("Rotating Anti-clockwise...");
myStepper.step(-stepsPerRevolution);
delay(10);
rainbow(30);
delay(10);
}
void rainbow(uint8_t wait) {
uint16_t i, j;
for(j=0; j<256; j++) {
for(i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel((i*1+j) & 255));
}
strip.show();
delay(wait);
}
}
// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
if(WheelPos < 85) {
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
else if(WheelPos < 170) {
WheelPos -= 85;
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
}
else {
WheelPos -= 170;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
}
Your for loop runs a complete cycle every time it is called.
What you want is for it to advance one step each time it is called.
maybe something like this:
// Change rainbow one step at a time
void rainbowSteps(uint8_t wait) {
uint16_t nextStep;
strip.setPixelColor(i, Wheel((i * 1 + j) & 255)); // change this since i&j are no longer here <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
strip.show();
delay(wait);
nextStep++;
if (nextStep > 256) {
nextStep = 0;
}
}
Thank you for your reply. Where exactly in the code do I have to change it? I have tried multiple of times but unfortunately it's coming with an error message. Thank you
We get this question at least once a day in various guises. The answer is always to write the code as a state machine.
So a simple forum surcharge for things like
State machine
Two things at once
The problem here is that you can't interrupt the stepping motor driver to send the update to the LEDs without making it stutter. So you have to generate the steps with external hardware. Like this board.
Thank you for your reply. Is there a way to just modify the code as I am very limited with space to be able to add another small pcb. I got it running but the only problem is the stepper motor does not rotate continuously.
If you create the steps based on a timer-interrupt it might work.
There is a different stepper-motor-library called MobaTools that works this way.
But I don't know if this library runs on digisparks.
or if you can setup a timer-interrupt at all on a digispark.
If it does not work based on a timer-interrupt
to have the step-pulses created spot-on-regularly in time your complete code needs to be restructured to use absolutely consequently non-blocking timing.
non-blocking timing means replace each and every delay() by non-blocking timing
non-blocking timing means: changethinking from sequential mutliple looping based on for-loops / while-loops
to
single-top-level looping where the only allowed loop is void loop itself
So at this time you have the learning steps for advanced coding in front of you.
No.
Because the code that sends out the information to the addressable strips must be done with the interrupts turned off. That means no other code can run during this time.
However if you change the type of addressable LEDs you use from neopixel to dot star you can do this, because the dot star LEDs use a data and clock signal and so that code is not tied to the software producing precise timing.
However many people will be reluctant to spend more money on a different sort of strip.
Yes I have tried to change it according to the updated second post but as soon as I change it, I get an error message. The code that is working now is the code in my first post. It may make sense what Grumpy_Mike says but I can't understand why there is no way to modify the code just to have the stepper rotate continuously in one direction and a rainbow fade effect on one LED.
// Include the Arduino Stepper.h library:
#include <Stepper.h>
#include <Adafruit_NeoPixel.h>
// Define number of steps per rotation:
const int stepsPerRevolution = 2048;
const int ledPin = 4; // the number of the neopixel strip
const int numLeds = 1;
// Create stepper object called 'myStepper', note the pin order:
Stepper myStepper = Stepper(stepsPerRevolution, 3, 1, 2, 0);
Adafruit_NeoPixel strip = Adafruit_NeoPixel(numLeds, ledPin, NEO_GRB + NEO_KHZ800);
void setup() {
// Set the speed to 5 rpm:
myStepper.setSpeed(12);
strip.begin();
strip.setBrightness(20); // 1/3 brightness
// Begin Serial communication at a baud rate of 9600:
Serial.begin(9600);
}
void loop() {
// Step one revolution in one direction:
Serial.println("Rotating Anti-clockwise...");
myStepper.step(-stepsPerRevolution);
delay(10);
rainbow(30);
delay(10);
}
void rainbow(uint8_t wait) {
uint16_t i, j;
for(j=0; j<256; j++) {
for(i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel((i*1+j) & 255));
}
strip.show();
delay(wait);
}
}
// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
if(WheelPos < 85) {
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
else if(WheelPos < 170) {
WheelPos -= 85;
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
}
else {
WheelPos -= 170;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
}
Thank you so much for your help. It is exactly working the way it needs. One last thing, is there a way to adjust the time that it takes to cycle through rainbow colour to make it slower?
Thank you
I did try to add the 30 to the loop but then I get an error as per picture. I am very sorry for my capability at coding as I am very new and am trying to understand
This common pattern, which you will know about when you find time to look at "blink without delay" and the other pointers that may have been provided on this thread or things than turn up when you search
static unsigned long lastTime = 0;
if (millis() - lastTime >= 30)
{
lastTime = millis();
rainbow();
}
calls rainbow() to take a single step every 30 milliseconds.
What might you change to make it call rainbow() every 60 milliseconds, so as to run the effect at half speed?
What might you change to make it call rainbow() every 15 milliseconds, so as to run the effect at double speed?
You have to start putting your finger o the code and stepping yourself through it to see how it works…