Arduino should act as a Push Button when the loop is done

Here I go again :wink: Well i wanted to give my running light some sound , and so i wanted to try to use Pin 8 as a push button but I can't get it to work.

I tried delay (); but that affects the whole code and speed of the light, so I tried "blink with millis" but that doesn't work either. I found out that the button has to be pressed about 30ms to get registered by the soundboard.

It should work like this , when the loop begins, the "button" should be pressed 30-50ms then released. (The Soundboard playes the rest of the sound automatically) When the loop is done and begins again the switch should be pressed again for 30-50ms

The Original Code is

#include <FastLED_NeoPixel.h>
#define MAX_P 122
CRGB leds[MAX_P];

Adafruit_NeoPixel strip = Adafruit_NeoPixel(MAX_P, 3, NEO_BRG + NEO_KHZ800);

int potPin0 = 0;    // select the input pin for the potentiometer
int potPin1 = 1;    // select the input pin for the potentiometer
int val0 = 0;       // variable to store the value coming from the sensor
int val1 = 0;       // variable to store the value coming from the sensor
int li=0;
int direction=+1;
uint32_t Red=strip.Color(255, 0, 0);
uint32_t Blank=strip.Color(0, 0, 0);

void setup() {

      FastLED.addLeds<NEOPIXEL, 3>(leds, MAX_P);
      FastLED.setBrightness(255);
      FastLED.clear ();
      fadeAnimation(255, 0, 0);
      delay(500);

  strip.begin();
  strip.show(); 
}

void loop() {

  val0 = analogRead(potPin0) / 50;    // read the value from the sensor
  val1 = analogRead(potPin1) / 34.1;    // read the value from the sensor

  //decay
  for(uint16_t i=0; i<MAX_P; i++) {
    uint8_t r= (strip.getPixelColor(i)>>16) & 0xff;
    r=(r*(69+val1))/100;
      strip.setPixelColor(i, r, 0, 0);
  }

  strip.setPixelColor(li, Red);
  if(li>(MAX_P-1)){
    li=MAX_P;
    direction=-1;
  }else if(li<0){
    li=-1;
    direction=1;
  }
  li+=direction;
  strip.show();
  delay(val0);
}

void fadeAnimation(int red, int green, int blue){
  float r, g, b;

  // FADE OUT
  for(int i = 255; i >= 0; i--) {
    r = (i/256.0)*red;
    g = (i/256.0)*green;
    b = (i/256.0)*blue;
    fill_solid(leds, MAX_P, CRGB(r, g, b));
    FastLED.show();
    delay(8);
    
  }
}

Hello DJTOMCAT

I assume that you have written the programme by yourself, then it is quite easy to find the error.

There's a trick to figuring out why something isn't working:

Use a logic analyzer to see what happens.
Put Serial.print statements at various places in the code as diagnostic prints to see the values of variables, especially ones that control the motors, and determine whether they meet your expectations.

Have a nice day and enjoy coding in C++.

the magic numbers arent really very helpful.

I dont see any mention of pin 8 nor of buttons in your code?

Is that one long ledstrip of 122 leds ?
I made your project in Wokwi:

@Koepel yes it is 122leds long :wink: it is a 144leds/m strip about 85cm long.

@johnerrington because I posted the original code , I do not know how to start properly and tried different code snippets. These "magic numbers" are just for the 100k pots I use because I am not familar with programming

@paulpaulson I found these code snippets about 2/3 years ago and put them with trial and error together, I am not a program expert or something. Last programs I wrote were 30+ yrs ago in C64 Basic.

This is untested but I've cleaned up the code and added the fixes for your wants hope it works:

#include <Adafruit_NeoPixel.h>
#define MAX_P 122
#define BUTTON_PIN 8

Adafruit_NeoPixel strip = Adafruit_NeoPixel(MAX_P, 3, NEO_BRG + NEO_KHZ800);

int potPin0 = 0;
int potPin1 = 1;
int val0 = 0;
int val1 = 0;
int li = 0;
int direction = 1;
uint32_t Red = strip.Color(255, 0, 0);
uint32_t Blank = strip.Color(0, 0, 0);
unsigned long buttonPressTime = 0;

void setup() {
  strip.begin();
  strip.show();
  strip.setBrightness(255);

  for (int i = 0; i < MAX_P; i++) {
    strip.setPixelColor(i, Blank);
  }
  strip.show();
  delay(500);
}

void loop() {
  if (millis() - buttonPressTime >= 30 && millis() - buttonPressTime <= 50) {
    // Simulate button press action
    // You can add your code for the soundboard action here
  }

  // Your existing code

  val0 = analogRead(potPin0) / 50;
  val1 = analogRead(potPin1) / 34.1;

  // Decay and update colors
  for (int i = 0; i < MAX_P; i++) {
    uint32_t pixelColor = strip.getPixelColor(i);
    uint8_t r = (pixelColor >> 16) & 0xFF;
    r = (r * (69 + val1)) / 100;
    strip.setPixelColor(i, r, 0, 0);
  }

  strip.setPixelColor(li, Red);
  if (li >= (MAX_P - 1) || li <= 0) {
    direction *= -1;
  }
  li += direction;

  strip.show();
  delay(val0);
  buttonPressTime = millis(); // Record the time for the button press
}

void fadeAnimation(int red, int green, int blue) {
  float r, g, b;

  // FADE OUT
  for (int i = 255; i >= 0; i--) {
    r = (i / 256.0) * red;
    g = (i / 256.0) * green;
    b = (i / 256.0) * blue;

    for (int j = 0; j < MAX_P; j++) {
      strip.setPixelColor(j, strip.Color(r, g, b));
    }
    strip.show();
    delay(8);
  }
}

This code simulates a button press action for 30-50ms at the beginning of each loop iteration. You can add your code for the soundboard action inside the if statement where the button press is simulated.

1 Like

Hi @DJTOMCAT,

if you would write

void Xoop() [

instead of

void loop() {

what happends? The compiler would complain with an error that the compiler does not know what " Xoop() " is.

In Programming you have to be very precise. Almost everywhere.
Same thing in your description

which loop?

  • void loop()?
  • the for-loop inside function loop()?
  • the for-loop inside function fadeAnimation()?

using the millis() function is not a simple replace if delay() with millis().
The code must be restructured from
linear running down waiting
to
circular repeating with repeated time-comparising

This short sentence just shows there is a big difference.
This sentence is too short to understand the whole concept.

recently user @xfpd
posted links of two youtube-videos that explain the concept very good

These 30 minutes of time are really worth watching these two videos.
It will save you minimum 2 * 30 = 60 minutes in understanding how non-blocking timing works.

additionally too make your code completely non-blocking you can replace the for-loops with
"let void loop() do the looping" like visulalised here:

best regards Stefan

@codingapacalyspe

thank you for helping me with that :slight_smile: but the running light won't run at all with your changes in code, so i coupled both scripts with your addons.

well at pin 8 is just closing to gnd on the soundboard. I tried digitalWrite(8,HIGH) but it won't work
when put it after loop directly at least the button is "pressed"

for faster startup I removed the Fading at the beginning , also shorted the strip length for testing purposes

Here is the Online Sample
Edited the Sample
Thanks to @Koepel , didn't know about that

#include <FastLED_NeoPixel.h>
#define MAX_P 30
#define BUTTON_PIN 8
CRGB leds[MAX_P];

Adafruit_NeoPixel strip = Adafruit_NeoPixel(MAX_P, 3, NEO_BRG + NEO_KHZ800);

int potPin0 = 0;    
int potPin1 = 1;    
int val0 = 0;       
int val1 = 0;       
int li = 0;
int direction = 1;
uint32_t Red = strip.Color(255, 0, 0);
uint32_t Blank = strip.Color(0, 0, 0);
unsigned long buttonPressTime = 0;

void setup() {


  pinMode(8, OUTPUT);

  strip.begin();
  strip.show(); 
  
}

void loop() {

  digitalWrite (8, LOW);

// digitalWrite(8, HIGH); // Here the trigger is pulled high permanently 

  if (millis() - buttonPressTime >= 1000 && millis() - buttonPressTime <= 1000) {

  digitalWrite(8, HIGH); // not working ?

  }
  val0 = analogRead(potPin0) / 50;    // for 100k pot speed
  val1 = analogRead(potPin1) / 34.1;    // for 100k pot tail

  //decay
  for(uint16_t i=0; i<MAX_P; i++) {
    uint8_t r= (strip.getPixelColor(i)>>16) & 0xff;
    r=(r*(69+val1))/100;
      strip.setPixelColor(i, r, 0, 0);
  }

  strip.setPixelColor(li, Red);
  if(li>(MAX_P-1)){
    li=MAX_P;
    direction=-1;
  }else if(li<0){
    li=-1;
    direction=1;
  }
  li+=direction;
  strip.show();
  delay(val0);
  buttonPressTime = millis(); // Record the time for the button press

}

@StefanL38 Ich schreibe jetzt einfach mal auf Deutsch :wink: Ich habe null ahnung vom Programmieren und ich habe auch kaum Freizeit mich mit C+ oder was auch immer das ist stunden oder Tagelang zu beschäftigen :frowning: Das erlaubt mein Umfeld einfach nicht und ich bin sogar gewillt eine kleinigkeit zu zahlen, hauptsache der Code ist fertig und ich muss mir da keinen Kopf drum machen.

Das Lauflicht an sich läuft ja schon so, wie ich es möchte, aber es soll halt bei bei jedem Start des Loops am Soundboard der Sound getriggert werden, was durch einen einfach Druck des Knopfes ausgelöst werden soll. Sprich High für 30ms und dann wieder Low bis der Loop wieder von vorne beginnt.

Read that aloud. It is true only if

millis() - buttonPressTime

is exactly zero.

If all you want is a button press-like event of 40 milliseconds at the beginning of every loop, try

    digitalWrite(8, HIGH);
    delay(40);
    digitalWrite(8, LOW);

You said you tired that, show us that attempt.

As for @codingapacalyspe. I truly believe she has posted untested nonsense "written" by an AI.

HTH

a7

1 Like

@alto777 when I use delay in the code, this affects the running speed of the light. So thats why I need something else. Even when you see in the simulation the relay get triggered every 40ms not for 40ms every loop

40ms Delay
vs
without delay

Hello @DJTOMCAT - I like to make patterns on NeoPixel strips, and I write the patterns with "blocking" code because I want the pattern to complete before changing to the next (button-selectable) pattern. My "blocking" code makes button-pushing difficult to sense, so I use a very simple interrupt scheme to sense the button, then once a blocking stage is finished, acts on the button press. Here is an interrupt reading a pushbutton inside a neopixel simulation... If you need me to explain this version of using an interrupt, just say so.

OK, we have unatgled your logic a bit, and played with the potentiometers.

BTW pro tip: use the linear slide fader in the wokwi, it is mucg easier to manipulate than the rotary pot part.

This should fix you problem. It only issues the 40 millisecond blip, which I cannot see, when the animation changres direction:

void loop() {

  static int myDirection;
  if (myDirection != direction) {
    myDirection = direction;
    digitalWrite(8, HIGH);
    delay(40);
    digitalWrite(8, LOW);
  }

// then rest of you original loop

If you change direction, it notices that and issues a 40 ms puklse on pin 8. It remembers the direction for next time and won't do it again until direction changes.

Works planted in your wokwi.

One doe wonder, however, how this works at the very fast end of your speed controls. It looks like 40 ms would be making hiccups... on the same hand, or is the other hand, what mean those pulses for your application when the animation is at the fast end?

a7

@alto777 yeah thats in the right "direction" but it needs only at the "start" , not at every direction change :smiley: so every 40ms when from right to left , then left to right, 40ms trigger

where in the code do find a line that does something with a variable named similar to the word "direction"?

OK, challenge yourself. Fix my fix so it only issues the blip on 8 when the direction change warrants it.

a7

i'm feeling like learning speaking spanish or italian ;D I'm too dumb to understand how to fix your fix.
Give me some wood, some drills, metal or something, that's what i can work with :smiley:

Edit:
What i found out is, that

void setup() {
  pinMode(8, OUTPUT);

supresses the "hickups" :wink:

Was indeed missing and needed in your original code. But it has been part of many posted sketches since.

I did not notice that omission, sry. The wokwi makes the error less obvious. IRL you'd see right away the output wasn't getting drivey enough to run an LED, though it might have worked for the relay module. Or it might have been unsatisfactory in some other way.


Now you have a variable direction, your code means it to take on values of 1 and -1.

My fix issues the pin 8 blip irrespective of the current value of direction, basing the trigger on any change to direction.

Pplease study this as I hand it you on a tiny virtual precious metal platter:

  static int myDirection;
  if (myDirection != direction) {
    myDirection = direction;
    if (direction == 1) {
      digitalWrite(8, HIGH);
      delay(40);
      digitalWrite(8, LOW);
    }
  }

Only blip on detecting a new direction when the direction has changed to 1.

HTH

a7

1 Like

@alto777 thank you so much, now I have it 3in1. I also "optimized" the code a little bit, gave the variables names etc.

Here's the final code working

#include <FastLED_NeoPixel.h>
#define MAX_P 122
CRGB leds[MAX_P];

Adafruit_NeoPixel strip = Adafruit_NeoPixel(MAX_P, 3, NEO_BRG + NEO_KHZ800);

int potPin0 = 0;   // 100k pot for Speed 
int potPin1 = 1;   // 100k pot for tail
int speed = 0;       
int tail = 0;       
int li = 0;
int direction = 1;
uint32_t Red = strip.Color(255, 0, 0);
uint32_t Blank = strip.Color(0, 0, 0);
uint8_t fade;
uint16_t ledaddress=0;
static int myDirection;

void setup() {

  pinMode(8, OUTPUT);     // Play as Loop without Sync
  pinMode(9, OUTPUT);     // Sync with Lights one direction
  pinMode(10, OUTPUT);    // Sync with Lights both direction
  digitalWrite(8, HIGH);  // Aus beim Start (High = Aus, Low = An)
  digitalWrite(9, HIGH);  // Aus beim Start (High = Aus, Low = An)
  digitalWrite(10, HIGH); // Aus beim Start (High = Aus, Low = An)

    FastLED.addLeds<NEOPIXEL, 3>(leds, MAX_P);
    FastLED.setBrightness(255);
    fadeAnimation(255, 0, 0);

  strip.begin();
  strip.show(); 

  digitalWrite(8, LOW); // Schaltet Pin 8 dauerhaft auf An = Loop am Soundboard
}

void loop() {
  if (myDirection != direction) {
  myDirection = direction;
     if (direction == 1) {
    digitalWrite(9, LOW); 
    digitalWrite(10, LOW);
    delay(30);
    digitalWrite(9, HIGH);
    digitalWrite(10, HIGH);
    }else{
    digitalWrite(10,LOW);
    delay(30);
    digitalWrite(10,HIGH);
    }

  }

  speed = analogRead(potPin0) / 50;    // for 100k pot speed
  tail = analogRead(potPin1) / 34;    // for 100k pot tail

  for(ledaddress=0; ledaddress<MAX_P; ledaddress++) {
    fade= (strip.getPixelColor(ledaddress)>>16) & 0xff;
    
    fade=(fade*(69+tail))/100;
      strip.setPixelColor(ledaddress, fade, 0, 0);
  }
  strip.setPixelColor(li, 255, 0, 0);
  if(li>(MAX_P-1)){
    li=MAX_P;
    direction=-1;
  }else if(li<1){
    direction=1;
  }
  li+=direction;
  strip.show();
  delay(speed);
}

void fadeAnimation(int red, int green, int blue){
  float r, g, b;

  // FADE OUT
  for(int i = 255; i >= 0; i--) {
    r = (i/256.0)*red;
    g = (i/256.0)*green;
    b = (i/256.0)*blue;
    fill_solid(leds, MAX_P, CRGB(r, g, b));
    FastLED.show();
    delay(3);
    }
}

Simlation on Wokwi

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.