It would be really nice to make a Neopixel LED strip change animations by using an Infrared remote.
The remote is working and I can change colors without problems.
I can start 1 animation without problems.
The problem lies within receiving IR signals during animations:
I cannot receive IR signals at all when animation is running.
After reading through many forums, it became clear that this is a timing issue.
So i decided to buy additional arduino nano and use I2C to send decoded IR to arduino Uno.
Still, the exact same problem occurs.
Can anyone advise on how I must change my code to make this work?
I would like to decode IR with the nano, and controll LED via Uno.
Getting your ir receiving Arduino to send over i2c as soon as it receives an ir command does not solve anything. While updating the leds interrupts are disabled, so i2c messages cannot be received. The Nano must be the i2c slave and buffer the ir commands it receives until the Uno master requests them.
I will start looking for a method to let the Nano prepare the decoded commands until they are requested by the Uno. If there is an existing arduino code containing this process, it would help me greatly.
Using the examples found on the arduino website, the master controller can now succesfully request commands from the slave IR-decoder. I still have to give the master led controller time to request this data, since interruptions are disabled during strip.show command.
Is using a method with Millis() a good solution?
I will try to time a pause within animations to check for new IR commands and act accordingly.
I've had a similar WS2812 setup for a while and I recently added an IR receiver. The remote worked fine on its own on my test Arduino, but once I added it to the Arduino nano that is controlling the LEDs, I started getting garbled random seeming IR codes.
Is this the timing issue that the OP was referring to? He said he can't receive codes at all and I am receiving junk codes. I soldered the IR receive to the nano near the USB port (which is being used to power the Arduino but not the WS2812 LEDs), so I thought I might be getting some kind of interference on the IR receiver's output.
I'd actually given up on the IR port, and I just ordered a particle photon (which should be arriving next Tuesday) to control the LEDs and allow me to use my phone as the remote, but I'd be much happier with an IR remote.
You don't give much detail (code, schematic etc) but yes, it could be a similar problem. Receiving IR codes using the commonly used Arduino library relies on interrupts for it's operation, I suspect. Certainly accurate timing is vital. But the neopixel and fastled libraries disable interrupts when they send updates to the strip (because accurate timing is vital for this also) and bock other code from running until the entire strip has updated causing ir events to be missed.
Here's a simplified code sample. I did a quick hatchet job on a much longer sketch and then just made sure it compiled.
#include <Adafruit_NeoPixel.h>
#include <IRremote.h>
#define PIN 2 // led strand pin
#define NUMLEDS 150
#define receiver 10 // IR receiver pin
#define receiver_vcc 12 // using signal pins to supple vcc and ground to ir receiver
#define receiver_gnd 11
IRrecv irrecv(receiver); //create a new instance of receiver
decode_results results;
// Parameter 1 = number of pixels in strip
// Parameter 2 = pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
// NEO_RGB Pixels are wired for RGB bitstream
// NEO_GRB Pixels are wired for GRB bitstream
// NEO_KHZ400 400 KHz bitstream (e.g. FLORA pixels)
// NEO_KHZ800 800 KHz bitstream (e.g. High Density LED strip)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMLEDS, PIN, NEO_GRB + NEO_KHZ800);
void setup() {
Serial.begin(9600);
strip.begin();
strip.show(); // Initialize all pixels to 'off'
pinMode(receiver_vcc, OUTPUT);
pinMode(receiver_gnd, OUTPUT);
pinMode(receiver, INPUT_PULLUP);
digitalWrite(receiver_vcc, HIGH);
digitalWrite(receiver_gnd, LOW);
irrecv.enableIRIn(); //start the receiver
// Set up Timer/Counter1 for ~100 Hz interrupt
TCCR1A = _BV(WGM11); // Mode 14 (fast PWM), 1:64 prescale
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS11) | _BV(CS10);
ICR1 = F_CPU / 64 / 100; // ~100 Hz
TIMSK1 |= _BV(TOIE1); // Enable overflow interrupt
}
void loop() {
blueWhiteChase();
delay(100);
}
// Interrupt handler. Check for input from the IR sensor, update the proper settings if needed.
ISR(TIMER1_OVF_vect) {
static bool ledMode = false;
long result;
if (irrecv.decode(&results)) { //we have received an IR code
result = results.value;
Serial.println(result, HEX); // not actually intending to use serial in ISR, just added now to see what is going on with result value.
switch (result) {
case 0xFF6897: // Button 1
// do something else
break;
case 0xFF9867: // Button 2
// do something
break;
// many more cases in switch
} // switch
irrecv.resume(); //next value
} // if
}
void blueWhiteChase() {
static int i = 0;
for (int j = -5; j < NUMLEDS; j = j + 6) {
if (j+i < 0);
strip.setPixelColor(j+i, 0, 0, 30);
strip.setPixelColor(j+i+1, 0, 0, 100);
strip.setPixelColor(j+i+2, 0, 0, 255);
strip.setPixelColor(j+i+3, 30, 30, 30);
strip.setPixelColor(j+i+4, 90, 90, 90);
strip.setPixelColor(j+i+5, 180, 180, 180);
}
strip.show();
i = (i+1)%6;
}
Hardware is:
5v 10a SMPS connected to Vcc and GND of a 5m strip of 30 LED/m WS2812 LEDs, at the "output" end of the strip.
Arduino nano pin D2 and ground connected to input and GND of the LED strip at the opposite end.
Arduino nano powered through its USB port.
IR receiver module output connect to arduino nano pin D10. Ground and VCC to D11 and D12
LarryD:
Are you attempting a Serial.print inside of a isr?
ISRs should be as short as possible.
.
I'm well aware of that and I tried to explain it in my comment.
That is added temporarily only because I am not getting a working result from the IR remote. That particular delay will suffice to allow me to see the code returned from the IR library with the understanding that something else may go wrong when the is being printed. Even if it does break something else, I am still correctly getting the value stored in that variable. And that's all that matters at that point for debugging purposes.
The LED strip is updating correctly and I am getting the (garbled) IR code in my serial monitor.
Without the LED strip code running at all but that Serial.println present, I get the correct IR code consistently every time. That Serial.println is not causing the problem and not normally present in the code anyway.
Edit: Also, my understanding is that if the serial.println were causing problems it would simply deadlock my sketch because the serial buffer would fill up, and the print command would block until an interrupt-driven event clears the buffer and that even could never occur because my ISR masks that interrupt and my interrupt will never finish because it is blocked on the serial.println. That is not happening here.
Okay, so since this is not a sketch I'm using but a quick job to show PaulRB what my code and hardware are like, pretend it was done that way. With the serial statement not present, the problem is identical.
I'm not surprised that code does not work, with or without serial.print() in the interrupt routine. Can't really see the point of using the interrupt routine at all in this application. It won't avoid the problem that strip.show() disables interrupts while it is running, which will interfere with receiving ir commands.
PaulRB:
I'm not surprised that code does not work, with or without serial.print() in the interrupt routine. Can't really see the point of using the interrupt routine at all in this application. It won't avoid the problem that strip.show() disables interrupts while it is running, which will interfere with receiving ir commands.
Thanks for the reply, and I see your point. I wrote that sketch before I ever saw this thread, and I understand it is not a solution. I only used the ISR that way, because it's closer to the way I learned to design real-time applications and it's easier for me to visualize how the program works that way.
The reason I posted it is the OP said he cannot "receive any IR signals at all when the animation is running". In my case, every time I press a button on the remote, I do get a code, but about 95% of the time, the code looks like random noise, the wrong length and non-repeatable. About 5% of the time, I do get the correct code for the button pressed.
I'm curious if with my sketch, the behaviour I'm getting can result from the same issue the OP mentioned.
Also, if so, is there a simpler 1-arduino solution or is the best idea to use one arduino to decode the IR signals and a second to drive the LEDs.
Yes, I think you probably have a very similar problem to the OP.
No, I don't think a single Arduino solution will be satisfactory. A typical Arduino has a single core 16MHz processor. Both the standard ir and neopixel libraries were written assuming exclusive use of the processor in order to get precise timing correct and not miss any data. It's possible that an expert could write a library that would do both at the same time on a single processor, but do far no one has done so.
I would suggest using an attiny as a slave processor for receiving the ir commands, buffering them and acting as i2c slave to pass the data to a master Arduino. Unfortunately, my experience using attiny as i2c slave has not been completely successful.
You would have to do this with two key presses.
The first press would stop the animation.
The second press would select which animation and then start it.
I haven’t had much time lately to check the thread.
Apparently, I am not the only one struggling with W2812B strips and IR remote.
Receiving only part of the IR command is caused by cutting-off receiving the IR code by updating LEDs.
I have never had this problem, but it seems to be caused by too frequent ‘Led.show’ commands.
The IR sensor does not get enough time to receive the full IR signal and only decodes a part which causes random noise.
I have succesfully connected a Nano and Uno over I2C.
The nano acts as a IR-Receive/Decode slave an saves the last used IR code.
The Uno act as a LED Processor Master. It requests the last IR code from Nano every 500ms in between Led updating.
I’m still quite busy this week, but ill upload the code I have so far for both.
Currently, the systems works. But it sums up instructed animations, In other words: The first animation does not fully stop when the second animation is started.
Try this example, you will have to install my IR NEC library mention above.
The first button press will stop the animation at the end.
The second press will advance the animation to the next one.
It would be a simple matter to have a button code select a certain animation sequence.