Need help with IR controlling

Hi.

I have been building an IR-controllable 4x4x4 LED cube as a school project. Like this.

The cube itself is ready and works fine but I encountered some nasty issues with implementing the IR. The code consists of functions and function calls. Different patterns are stored in functions which are called from main loop by using switch-case. I have a simple Keyes IR remote and I have devoted buttons 0-9 to produce a different LED blinking pattern. For example, when I press button 1, it should call function 1 by using the switch-case and loop it until I press another button from the remote. The main problem is that I can't get it to work correctly with IR.

I was able to get the cube play patterns once with push of the button, but when it comes to looping the pattern, I can't input another command and switch the loop. I realized that i should propably use interrupts and implemented a new piece of code.

#include <IRremote.h>

#define Button1 16738455
#define Button2 16750695
#define Button3 16756815
#define Button4 16724175
#define Button5 16718055
#define Button6 16743045
#define Button7 16716015
#define Button8 16726215
#define Button9 16734885
#define Button0 16712445
#define ButtonStar 16728765
#define ButtonSharp 16732845
#define LED_DELAY 2
#define ANIMATION_DELAY 300

int RECV_PIN = 2;

int column[16]={13,12,11,10,9,8,36,34,32,30,28,26,24,22,A4,A5};

int layer[4]={A3,A2,A1,A0};

IRrecv irrecv(RECV_PIN);

decode_results results;

volatile unsigned int value;

void CHECK_IR(){                            // Infrared scanning function
  while(irrecv.decode(&results)){
  Serial.println(results.value, DEC);   // Prints values from the remote, only used during building the code
  value = results.value;                    
  irrecv.resume();
  }
}

void setup()
{
  Serial.begin(9600);
  attachInterrupt(0,CHECK_IR,CHANGE);    //Interrupt
  irrecv.enableIRIn();                                //Start the receiver
}

void loop() {                                            //Main loop and function calls (only 2 of them displayed)

switch(value) {  
case Button1:


Pattern1();

                             
case Button2:

Pattern2();
}
}


/////////////////////////PATTERN FUNCTIONS///////////////// 

void Pattern1()
{
  while(1) {
  turnEverythingOff();
  int x = 50;
  for(int i = 0; i < 4; i++) {
  digitalWrite(layer[i], 1);
  }
  
  for(int y = 0; y < 4; y++) {
  digitalWrite(column[y], 0);
  delay(x);
  }

  for(int r = 7; r < 15; r=r+4) {
  digitalWrite(column[r], 0);
  delay(x);
  }

 for(int y = 15; y > 11; y--) {
  digitalWrite(column[y], 0);
  delay(x);
 }

  for(int y = 8; y > 3; y=y-4) {
  digitalWrite(column[y], 0);
  delay(x);
 }

  for(int y = 0; y < 4; y++) {
  digitalWrite(column[y], 1);
  delay(x);
  }

for(int r = 7; r < 15; r=r+4) {
  digitalWrite(column[r], 1);
  delay(x);
  }

 for(int y = 15; y > 11; y--) {
  digitalWrite(column[y], 1);
  delay(x);
 }

  for(int y = 8; y >= 0; y=y-4) {
  digitalWrite(column[y], 1);
  delay(x);
 }
 
}
}


//////Rest of the patter functions below, but not neccessary to include them here.

This piece of code does not light up any of the leds, so I can't get decoded button value from interrupt function to carry onto main loop. At least receiver is able to receive the signals and print them to serial monitor, so interrupt is working just fine. I have only a little knowledge about interrupts since I'm newbie in the coding sector, so it would be really helpful if someone could check my code and guide me to the right path. Thank you in advance.

int column[16]={13,12,11,10,9,8,36,34,32,30,28,26,24,22,A4,A5};

Using the smallest variable type that will hold the required values is a good thing. Pissing away memory storing pin numbers in ints is not.

  while(irrecv.decode(&results)){
  Serial.println(results.value, DEC);   // Prints values from the remote, only used during building the code
  value = results.value;                   
  irrecv.resume();
  }

Why is this a while loop? Once you get ONE value, you want to return and use that value, don't you?

  attachInterrupt(0,CHECK_IR,CHANGE);    //Interrupt

Reacting to IR input does NOT require the use of interrupts. It DOES require writing non-blocking code so that you can poll the IR often enough.

Reading IR data is a timed thing. The timing requires that interrupts be enabled. In your ISR, they are not.

PaulS:
Why is this a while loop? Once you get ONE value, you want to return and use that value, don't you?

So it is better to use if instead of while? I could try it out.

I am running out of time with this project and I should be finished with the IR this week. I've been battling with these problems way too long.

PaulS:
Reacting to IR input does NOT require the use of interrupts. It DOES require writing non-blocking code so that you can poll the IR often enough.

Reading IR data is a timed thing. The timing requires that interrupts be enabled. In your ISR, they are not.

So can I ask you what are you suggesting? Should I ditch the interrupt function and try something else? I'm sorry for my lack of knowledge, I'm still way too unskilled in these kinds of things.

Thanks for your guidance.

Threnody:
So can I ask you what are you suggesting? Should I ditch the interrupt function and try something else? I'm sorry for my lack of knowledge, I'm still way too unskilled in these kinds of things.

Look at the examples hat come with the library to see how things are supposed to be done.

Should I ditch the interrupt function

Yes.

and try something else?

Of course you'll need to do that.

Your Pattern1() function, for instance, will never return once called. Even if the interrupt WERE able to get a new value, Pattern1() doesn't know that that has happened, so it never ends.

STOP writing blocking code like that. The loop() function already loops. Let it call Pattern1() over and over, if there is nothing new to do.

  for(int r = 7; r < 15; r=r+4) {
  digitalWrite(column[r], 0);
  delay(x);
  }

Strange... I usually use i as a loop index, except when dealing with rows and columns. In that case, I use r and c, but I do NOT use r for the column index and c for the row index.

Even this code will block, until the for loop ends. During those (and the other) delay()s, you can NOT read the remote.

The only ways that you'll be able to use the remote to control the pattern are to:

  1. write non-blocking code from start to finish with NO for loops and NO delay()s.
  2. hold the remote key down until one iteration of PatternN() is complete. Doing THAT is problematic, since most remotes send a value that represents the key pressed when it is first pressed, and then send a repeat value, that means do that last thing again. This assumes that the receiver wasn't asleep at the controls, and knows what "that last thing" means. If all you know is that you are supposed to do something again, but you have no idea what to do, you'll have a rather difficult time doing it right.

I removed while-loop from functions and added do-while loops inside the switch-cases. Now it seems to do almost the right thing even when the interrupt is doing its thing in the code. It starts to loop after I press the button and shifts to other pattern when I press another button from the remote. I still have some issues with the remote (I have to press button few times to change the pattern) but they are minor, considering I got the code doing what I want it to do.

I also forgot to set digital pins as OUTPUT. Still little bit of rusty, but I will get better in this.

Thanks for your tips!