Go Down

Topic: Remote Control to adjust brightness of RGBW NeoPixels (Read 386 times) previous topic - next topic

sinnk

Hello! I am currently working with individually adressable LEDs aka the NeoPixels (RGBW chip). My goal is to adjust the brightness of the strip by using a remote control while different programs are running and then read the final value of brightness (a value between 0-255). 
With this code so far it works fine, red can be dimmed.

Code: [Select]
#include <RCSwitch.h>
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif

#define PIN 10

RCSwitch mySwitch = RCSwitch();
Adafruit_NeoPixel strip = Adafruit_NeoPixel(500, PIN, NEO_GRBW + NEO_KHZ800);

int counter = 0;

void setup()
{
  strip.begin();
  strip.clear();
  strip.show();
  Serial.begin(9600);
  mySwitch.enableReceive(0); 

  pinMode(PIN, OUTPUT);
}
void loop() {

  if (mySwitch.available())
  {int value = mySwitch.getReceivedValue();
    if (value == 20483)
    {counter = counter + 5;
      if (counter >= 255) {
        counter = 255;
      }    }
    if (value == 20492)
    {counter = counter - 5;
      if (counter <= 0) {
        counter = 0;
      }    }

    Serial.println(counter);

    mySwitch.resetAvailable();
    strip.fill(strip.Color(counter, 0, 0, 0), 0, 14);
    strip.show();
  }
}



By using "Processing" as GUI or just the Serial Monitor, I am sending letters to Arduino to switch between different use-cases. For example if I type "a" LEDs will light up red at 1/5 of brightness first,  but the brightness will not update when I push up or down buttons on the remote control. I have to type "a" again so that I can get the updated value. As long as I am in case 'a', I want to be able to adjust the brightness with the rc. I will have a lot more than just two cases, but only posting those two guys to avoid complexity. Any help to fix the code is appreciated!

Code: [Select]
#include <RCSwitch.h>
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif

#define PIN 10

RCSwitch mySwitch = RCSwitch();
Adafruit_NeoPixel strip = Adafruit_NeoPixel(500, PIN, NEO_GRBW + NEO_KHZ800);
int cycle[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int counter = 55; 
void setup()
{
  strip.begin();
  strip.clear();
  strip.show();
  Serial.begin(9600);
  mySwitch.enableReceive(0); 
  pinMode(10, OUTPUT);
}

void remote() {
  if (mySwitch.available())
  {int value = mySwitch.getReceivedValue();
    if (value == 20483)
    {counter = counter + 5;
      if (counter >= 255) {
        counter = 255;
      } }
    if (value == 20492)
    {counter = counter - 5;
      if (counter <= 0) {
        counter = 0;
      } }
    Serial.println(counter);

    mySwitch.resetAvailable();
  }}

void loop() {
  remote();
  if(Serial.available()){
   char val = Serial.read();
   switch (val){
case 'a':   
    strip.fill(strip.Color(counter, 0, 0, 0), 0, 14);
    strip.show();
    while(Serial.available() == 0);
    break;
case 'b':   
   while(cycle[1] < 10){cycle[1]++;
    strip.fill(strip.Color(counter, 0, 0, 0), 116, 353); // (R, G, B), Pixel pos., +n Pixels
    strip.show();
    delay(1000);
    strip.fill();
    strip.show();
    delay(1000);}
    while(Serial.available() == 0);
    break;
}
}}

PaulRB

Looks simple enough to fix, if you understand the code you have. If you have cut & pasted different sketches from different authors together without understanding line-by-line how they work, then it will seem like a mystery. I can tell you probably did that because of tell-tale signs like inconsistent indentation and braces in strange positions.

Some people claim that they learn coding best by working with other example sketches, adapting & combining them. I think that's like putting together a 1000 piece Jigsaw without seeing the picture on the box. There is a reason we give children jigsaws with only a few pieces. Assuming we even give children jigsaws these days, perhaps they get iPads instead...

Enough preaching. You have two types of "events" that affect your leds. Data arriving from Serial and data arriving from the remote. The code in loop(), essentially the "switch" statement, needs to be called when a remote event has happened, and/or when a serial event has happened, so it can execute the important code for either type of event. So maybe make a new function to contain the switch section of the code. Then you can call that function when a serial event occurs and when a remote event occurs.

Two things to watch out for. The variable "val" that holds the character received from serial is not global, so it's value is quickly lost and won't be available when needed because a remote event has occurred. Good idea to rename the variable at the same time to something like "mode" or "useCase". Secondly, when you send a character like 'a' from serial monitor, it is followed by line feed and/or carriage return characters. A line of code inside the switch is currently reading and discarding those. Those characters won't come when a remote event happens, so that code will have to be moved so it only gets executed when a serial event happens.

Does that help a little?

sinnk

Hello PaulRB,
Thank you for the reply. I adopted the code "remote" from the internet and modified it a little bit, you are right about that and I appreciate the way you are trying to help out by showing me the way rather than just giving the solution.
I renamed the variable "val" to "useCase" and assigned it as global, also created a function to contain the switch statement. Can you please elaborate this part I do not quite understand it.
 
Secondly, when you send a character like 'a' from serial monitor, it is followed by line feed and/or carriage return characters. A line of code inside the switch is currently reading and discarding those. Those characters won't come when a remote event happens, so that code will have to be moved so it only gets executed when a serial event happens.
What code exactly and where does it have to be moved? My coding expertise is at beginner level sorry.

PaulRB

I meant this line, that appears in two places:
Code: [Select]
    while(Serial.available() == 0);
But now I realise it does not read and discard characters from serial, but it does hold up the sketch until one or more characters are available to be read from serial. As I said, there will be more characters after the 'a' or 'b', which are CR/LF. So in fact these lines will never cause the sketch to wait, as the sketch is as it is above. So right now those lines are pointless and harmless. But after your adaptations, the switch statement will get executed when a remote code is received, so then there will be no serial characters, and those lines would cause the sketch to stall. So they need to be removed. I wonder why they were there in the first place...

Currently, the CR/LF character(s) will get read on the next execution of loop() and because they don't match 'a' or 'b', the switch statement does nothing. But when you make val into global variable useCase, then that could get overwritten with a CR/LF character and you could lose the important value. So after reading a new useCase from serial, after you need to read and discard any further characters that have been sent. For example
Code: [Select]

    while(Serial.available() > 0) {
      char discard = Serial.read();
    }

Makes sense?

Go Up