hello, i wrote a code that runs various animations that can be changed from the pc interface using arduino nano and neopixel strip led. i communicate with the serial port via arduino nano with the interface i designed in c#, and i run various functions according to the data i read from the serial communication. the problem is that the animation i run (for example rainbow) rotates once and stops. i want the function i selected to rotate continuously until another function is selected. but i tried a few things and i can't succeed. do you have any ideas?
One idea is to read and follow the directions in the "How to get the best out of this forum" post, linked at the head of every forum category.
It explains what you need to do to get help.
Post your best attempt, using code tags when you do
//a piece of code
void loop() {
if (Serial.available()) {
String command = Serial.readStringUntil('\n');
command.trim();
if (command == "RAINBOW") {
rainbowEffect();
} else if (command == "BLINK") {
blinkEffect();
}
}
void rainbowEffect() {
for (long firstPixelHue = 0; firstPixelHue < 65536; firstPixelHue += 768) {
strip.rainbow(firstPixelHue);
strip.show();
}
}
void blinkEffect() {
for (int i = 0; i < 3; i++) {
strip.fill(strip.Color(255, 0, 0), 0, LED_COUNT);
strip.show();
delay(500);
strip.clear();
strip.show();
delay(500);
}
}
What does that mean?
until another function is selected
Unfortunately, you have to exit the display function in order to input another selection command.
You need to learn how to use millis() to write non-blocking code.
using System;
using System.IO.Ports;
using System.Windows.Forms;
using System.Drawing;
namespace NeoPixelController
{
public partial class Form1 : Form
{
SerialPort serialPort;
public Form1()
{
InitializeComponent();
serialPort = new SerialPort("COM3", 115200); // Burayı kendi COM portuna göre değiştir
serialPort.Open();
}
private void btnColor_Click(object sender, EventArgs e)
{
using (ColorDialog colorDialog = new ColorDialog())
{
if (colorDialog.ShowDialog() == DialogResult.OK)
{
Color color = colorDialog.Color;
string command = $"RGB {color.R} {color.G} {color.B}\n";
serialPort.Write(command);
}
}
}
private void btnRainbow_Click(object sender, EventArgs e)
{
serialPort.Write("RAINBOW\n");
}
private void btnBlink_Click(object sender, EventArgs e)
{
serialPort.Write("BLINK\n");
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void btnFadeOut_Click(object sender, EventArgs e)
{
serialPort.Write("FADEOUT\n");
}
private void btnTheaterChase_Click(object sender, EventArgs e)
{
serialPort.Write("THEATERCHASE\n");
}
private void btnStrobe_Click(object sender, EventArgs e)
{
serialPort.Write("STROBE\n");
}
private void btnCylon_Click(object sender, EventArgs e)
{
serialPort.Write("CYLON\n");
}
private void btnRandomTwinkle_Click(object sender, EventArgs e)
{
serialPort.Write("RANDOMTWINKLE\n");
}
private void btnSparkle_Click(object sender, EventArgs e)
{
serialPort.Write("SPARKLE\n");
}
private void btnRunningLights_Click(object sender, EventArgs e)
{
serialPort.Write("RUNNINGLIGHTS\n");
}
private void btnMeteorRain_Click(object sender, EventArgs e)
{
serialPort.Write("METEORRAIN\n");
}
}
}
When I send rainbow data via serial communication, the function runs once and the rainbow freezes. This is valid for all other animations. My goal is to have that animation function run continuously whenever I send data to start any animation.
To get started writing non-blocking code, study this "Blink without delay" tutorial.
Instead of a millis() timeout, you can use Serial.available() to determine whether the program should process serial input.
I will solve the millis problem last. The main problem is that when I send a data, Arduino detects this data with Serial.available() and saves it to a variable. The rest of the code consists of if, else commands that work on this variable. For example, when I send the word "RAINBOW" with serial, it will be saved to my variable. Since I do not send data on it again, this word should be saved to a variable and my function should work continuously, right? In my scenario, it seems that after the word "RAINBOW", another data came and was saved to a variable. I can't understand why.
Probably because you did not use the correct line ending parameters when sending the data. Check for CR and/or LF in the data -- those characters aren't valid in numbers or keywords.
Post ALL the code in one post.
You could debug the situation by printing in HEX the new message that is causing the problem.
// arduino code
#include <Adafruit_NeoPixel.h>
#define LED_PIN 3
#define LED_COUNT 249
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
void setup() {
Serial.begin(115200);
strip.begin();
strip.show();
strip.setBrightness(50);
Serial.println("PC'den komut bekleniyor...");
}
void loop() {
dongu();
}
void setColor(int red, int green, int blue) {
for (int i = 0; i < LED_COUNT; i++) {
strip.setPixelColor(i, strip.Color(red, green, blue));
}
strip.show();
}
void rainbowEffect() {
for (long firstPixelHue = 0; firstPixelHue < 65536; firstPixelHue += 768) {
strip.rainbow(firstPixelHue);
strip.show();
}
}
void blinkEffect() {
for (int i = 0; i < 3; i++) {
strip.fill(strip.Color(255, 0, 0), 0, LED_COUNT);
strip.show();
delay(500);
strip.clear();
strip.show();
delay(500);
}
}
void fadeOutEffect() {
for (int j = 0; j < 3; j++) {
for (int k = 0; k < 256; k += 10) {
switch (j) {
case 0: setAll(k, 0, 0); break;
case 1: setAll(0, k, 0); break;
case 2: setAll(0, 0, k); break;
}
showStrip();
delay(3);
}
for (int k = 255; k >= 0; k -= 10) {
switch (j) {
case 0: setAll(k, 0, 0); break;
case 1: setAll(0, k, 0); break;
case 2: setAll(0, 0, k); break;
}
showStrip();
delay(3);
}
}
}
void theaterChaseEffect() {
int color1 = strip.Color(255, 0, 0);
int color2 = strip.Color(0, 255, 0);
for (int j = 0; j < 10; j++) {
for (int i = 0; i < LED_COUNT; i += 3) {
strip.setPixelColor(i, color1);
strip.setPixelColor(i + 1, color2);
strip.setPixelColor(i + 2, color1);
}
strip.show();
delay(100);
for (int i = 0; i < LED_COUNT; i++) {
strip.setPixelColor(i, 0);
}
strip.show();
delay(100);
}
}
void strobeEffect(byte red, byte green, byte blue, int StrobeCount, int FlashDelay, int EndPause) {
for (int j = 0; j < StrobeCount; j++) {
setAll(red, green, blue);
showStrip();
delay(FlashDelay);
setAll(0, 0, 0);
showStrip();
delay(FlashDelay);
}
delay(EndPause);
}
void CylonBounce(byte red, byte green, byte blue, int EyeSize, int SpeedDelay, int ReturnDelay) {
for (int i = 0; i < LED_COUNT - EyeSize - 2; i++) {
setAll(0, 0, 0);
setPixel(i, red / 10, green / 10, blue / 10);
for (int j = 1; j <= EyeSize; j++) {
setPixel(i + j, red, green, blue);
}
setPixel(i + EyeSize + 1, red / 10, green / 10, blue / 10);
showStrip();
delay(SpeedDelay);
}
delay(ReturnDelay);
for (int i = LED_COUNT - EyeSize - 2; i > 0; i--) {
setAll(0, 0, 0);
setPixel(i, red / 10, green / 10, blue / 10);
for (int j = 1; j <= EyeSize; j++) {
setPixel(i + j, red, green, blue);
}
setPixel(i + EyeSize + 1, red / 10, green / 10, blue / 10);
showStrip();
delay(SpeedDelay);
}
delay(ReturnDelay);
}
void TwinkleRandom(int Count, int SpeedDelay, boolean OnlyOne) {
setAll(0, 0, 0);
for (int i = 0; i < Count; i++) {
setPixel(random(LED_COUNT), random(0, 255), random(0, 255), random(0, 255));
showStrip();
delay(SpeedDelay);
if (OnlyOne) {
setAll(0, 0, 0);
}
}
delay(SpeedDelay);
}
void Sparkle(byte red, byte green, byte blue, int SpeedDelay) {
int Pixel = random(LED_COUNT);
setPixel(Pixel, red, green, blue);
showStrip();
delay(SpeedDelay);
setPixel(Pixel, 0, 0, 0);
}
void RunningLights(byte red, byte green, byte blue, int WaveDelay) {
int Position=0;
for(int j=0; j<LED_COUNT*2; j++)
{
Position++;
for(int i=0; i<LED_COUNT; i++) {
setPixel(i,((sin(i+Position) * 127 + 128)/255)*red,
((sin(i+Position) * 127 + 128)/255)*green,
((sin(i+Position) * 127 + 128)/255)*blue);
}
showStrip();
delay(WaveDelay);
}
}
void meteorRain(byte red, byte green, byte blue, byte meteorSize, byte meteorTrailDecay, boolean meteorRandomDecay, int SpeedDelay) {
setAll(0,0,0);
for(int i = 0; i < LED_COUNT+LED_COUNT; i++) {
for(int j=0; j<LED_COUNT; j++) {
if( (!meteorRandomDecay) || (random(10)>5) ) {
fadeToBlack(j, meteorTrailDecay );
}
}
for(int j = 0; j < meteorSize; j++) {
if( ( i-j <LED_COUNT) && (i-j>=0) ) {
setPixel(i-j, red, green, blue);
}
}
showStrip();
delay(SpeedDelay);
}
}
void fadeToBlack(int ledNo, byte fadeValue) {
#ifdef ADAFRUIT_NEOPIXEL_H
uint32_t oldColor;
uint8_t r, g, b;
int value;
oldColor = strip.getPixelColor(ledNo);
r = (oldColor & 0x00ff0000UL) >> 16;
g = (oldColor & 0x0000ff00UL) >> 8;
b = (oldColor & 0x000000ffUL);
r=(r<=10)? 0 : (int) r-(r*fadeValue/256);
g=(g<=10)? 0 : (int) g-(g*fadeValue/256);
b=(b<=10)? 0 : (int) b-(b*fadeValue/256);
strip.setPixelColor(ledNo, r,g,b);
#endif
#ifndef ADAFRUIT_NEOPIXEL_H
leds[ledNo].fadeToBlackBy( fadeValue );
#endif
}
void showStrip() {
#ifdef ADAFRUIT_NEOPIXEL_H
strip.show();
#endif
#ifndef ADAFRUIT_NEOPIXEL_H
FastLED.show();
#endif
}
void setPixel(int Pixel, byte red, byte green, byte blue) {
#ifdef ADAFRUIT_NEOPIXEL_H
strip.setPixelColor(Pixel, strip.Color(red, green, blue));
#endif
#ifndef ADAFRUIT_NEOPIXEL_H
leds[Pixel].r = red;
leds[Pixel].g = green;
leds[Pixel].b = blue;
#endif
}
void setAll(byte red, byte green, byte blue) {
for (int i = 0; i < LED_COUNT; i++) {
setPixel(i, red, green, blue);
}
showStrip();
}
void dongu() {
if (Serial.available()) {
String command = Serial.readStringUntil('\n');
command.trim();
if (command.startsWith("RGB")) {
int r, g, b;
sscanf(command.c_str(), "RGB %d %d %d", &r, &g, &b);
setColor(r, g, b);
} else if (command == "RAINBOW") {
rainbowEffect();
} else if (command == "BLINK") {
blinkEffect();
} else if (command == "FADEOUT") {
fadeOutEffect();
} else if (command == "THEATERCHASE") {
theaterChaseEffect();
} else if (command == "STROBE") {
strobeEffect(0xff, 0xff, 0xff, 10, 50, 1000);
} else if (command == "CYLON") {
CylonBounce(0xff, 0, 0, 4, 10, 50);
} else if (command == "RANDOMTWINKLE") {
TwinkleRandom(20, 100, false);
} else if (command == "SPARKLE") {
Sparkle(0xff, 0xff, 0xff, 0);
} else if (command == "RUNNINGLIGHTS") {
RunningLights(0xff,0xff,0x00, 50);
} else if (command == "METEORRAIN") {
meteorRain(0xff,0xff,0xff,10, 64, true, 5);
}
}
}
// visual studio code
using System;
using System.IO.Ports;
using System.Windows.Forms;
using System.Drawing;
namespace NeoPixelController
{
public partial class Form1 : Form
{
SerialPort serialPort;
public Form1()
{
InitializeComponent();
serialPort = new SerialPort("COM3", 115200); // Burayı kendi COM portuna göre değiştir
serialPort.Open();
}
private void btnColor_Click(object sender, EventArgs e)
{
using (ColorDialog colorDialog = new ColorDialog())
{
if (colorDialog.ShowDialog() == DialogResult.OK)
{
Color color = colorDialog.Color;
string command = $"RGB {color.R} {color.G} {color.B}\n";
serialPort.Write(command);
}
}
}
private void btnRainbow_Click(object sender, EventArgs e)
{
serialPort.Write("RAINBOW\n");
}
private void btnBlink_Click(object sender, EventArgs e)
{
serialPort.Write("BLINK\n");
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void btnFadeOut_Click(object sender, EventArgs e)
{
serialPort.Write("FADEOUT\n");
}
private void btnTheaterChase_Click(object sender, EventArgs e)
{
serialPort.Write("THEATERCHASE\n");
}
private void btnStrobe_Click(object sender, EventArgs e)
{
serialPort.Write("STROBE\n");
}
private void btnCylon_Click(object sender, EventArgs e)
{
serialPort.Write("CYLON\n");
}
private void btnRandomTwinkle_Click(object sender, EventArgs e)
{
serialPort.Write("RANDOMTWINKLE\n");
}
private void btnSparkle_Click(object sender, EventArgs e)
{
serialPort.Write("SPARKLE\n");
}
private void btnRunningLights_Click(object sender, EventArgs e)
{
serialPort.Write("RUNNINGLIGHTS\n");
}
private void btnMeteorRain_Click(object sender, EventArgs e)
{
serialPort.Write("METEORRAIN\n");
}
}
}
You will only run your functions when the correct serial data is received. If there is no serial data, the functions for the LEDs will not be executed.
Separate the action from the receive.
void dongu()
{
static String command = "";
if (Serial.available())
{
command = Serial.readStringUntil('\n');
command.trim();
}
if (command.startsWith("RGB"))
{
int r, g, b;
sscanf(command.c_str(), "RGB %d %d %d", &r, &g, &b);
setColor(r, g, b);
}
...
...
}
Note the use of the static keyword; the result is that the received command is remembered between successive calls to loop().
You might encounter other problems. Updating your LEDs takes approximately 8 milliseconds. During that time interrupts are disabled and during that time serial data can not be received reliably.