Hi, im looking for help with this piece of code that im writing for my arduino. Im using the 74HC595 IC to control my LEDs and an IR sensor with a remote to change the pattern that occurs when a button is pressed.
My trouble is, once im inside the loop of my first LED pattern, i cant seem to be able to leave the loop despite using irrecv.decode(&results) and irrecv.resume() in places where i thought would help but that hasn't seemed to have worked for me yet.
I've edited my code to use millis() instead of delay() because as i understand, the IRremote header file relies on interrupts to detect IR signals coming in? (Correct me if i'm wrong here)
Additionally, i've read the SeverThingsAtTheSameTimeRev1 code provided by Robin2 about concurrency and i believe i do understand the code he wrote there but cant seem to apply it with the IR sensor.
My code is based loosly around some example code that came with my Arduino Uno and i've just added to it to fit my needs.
Thanks in advance and i appreciate any help i can get
Code below:
#include <IRremote.h>
int receivePin = 5; //IR receiver pin
IRrecv irrecv(receivePin);//Creating Receiver Object
decode_results results;
int dataPin = 11; //IC data pin
int outputenablePin = 10; //IC output enable pin
int latchPin = 9; //IC Latch pin
int clockPin = 6; //IC clock Pin
byte leds = 0;
//Timing variables
unsigned long previousMillis = 0;
unsigned long currentMillis = 0;
long interval = 200;
void setup() {
// put your setup code here, to run once:
updateShiftRegister(); //Updating Leds on first run to be all off
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(receivePin, OUTPUT);
pinMode(outputenablePin, OUTPUT);
Serial.begin(9600);
irrecv.enableIRIn();//Starts the receiver
}
void translateIR()
{
switch (results.value)
{
case 0xFF30CF: circleLeds(); break;
/*case 0xFF18E7: insert odd sequence; break;
case 0xFF7A85: insert ends to middle sequence; break;
case 0xFF10EF: insert something ; break;
case 0xFF38C7: Serial.println("5"); break;
case 0xFF5AA5: Serial.println("6"); break;
case 0xFF42BD: Serial.println("7"); break;
case 0xFF4AB5: Serial.println("8"); break;
case 0xFF52AD: Serial.println("9"); break;
default:
//some idle led function*/
}// end case
}
void loop() {
// put your main code here, to run repeatedly:
leds = 255;
if (irrecv.decode(&results))
{
Serial.print("\nResult obtained: ");
Serial.print(results.value);
Serial.print("\n");
translateIR();
irrecv.resume();
}
}
void updateShiftRegister()
{
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, LSBFIRST, leds);
digitalWrite(latchPin, HIGH);
}
void circleLeds()
{
int bitty = 0;
leds = 0;
while (1)
{
currentMillis = millis();
//if 200ms has passed, light up LED
if (currentMillis - previousMillis >= interval)
{
previousMillis = currentMillis;
Serial.print("\ncircleLed if reached\n");
bitSet(leds, bitty);
updateShiftRegister();
//Let another 200ms pass before turning it off
while (1)
{
unsigned long holdMillis = millis();
if (holdMillis - previousMillis >= interval)
{
//turn off all LEDs too
leds = 0;
updateShiftRegister();
Serial.print("\nwhile if statement reached\n");
break;
}
}
//increment to next LED
bitty++;
Serial.print("\nBitty: ");
Serial.print(bitty);
Serial.print("\n");
//if bitty is over 8, make it 0
if (bitty == 8)
{
bitty = 0;
}
}
//listen out for IR signal again
irrecv.resume();
if (results.value != 0xFF30CF)
{
//Testing one way to exit the loop
Serial.print("\ncircleLed exitted\n");
loop();
}
}
}
salair456:
My trouble is, once im inside the loop of my first LED pattern, i cant seem to be able to leave the loop
If you need to break out of a loop then you should not be in the loop in the first place. Just allow the loop() function to do the repetition.
In Several Things at a Time note how each function runs very briefly and returns to loop() so the next one can be called. None of the functions tries to complete a task in one call. And there may be dozens of calls to a function before it is actually time for it to do anything.
WHILE and FOR are blocking statements and, in general, should only be used for loops that always complete in at most a few millisecs.
Okay, so i guess i should think about coding this differently? Im thinking of just changing the state of the LEDs based on the value received from the irrecv.decode(&results) line.
Also, i didnt know that FOR and WHILE are blocking statements, that actually helps me alot now, ill try to revise my code and will reply asap if i have a solution.
So this i what i managed to come up with and my code only runs once in the loop(). My bitty variable is always 1 and doesnt increment any further. Does this mean that where i have irrecv.resume() is causing the issue?
#include <IRremote.h>
int receivePin = 5; //IR receiver pin
IRrecv irrecv(receivePin);//Creating Receiver Object
decode_results results;
int dataPin = 11; //IC data pin
int outputenablePin = 10; //IC output enable pin
int latchPin = 9; //IC Latch pin
int clockPin = 6; //IC clock Pin
byte leds = 0;
//Timing variables
unsigned long previousMillis = 0;
unsigned long currentMillis = 0;
long interval = 200;
//State Variables
byte circleLEDs_State = LOW;
byte LED_State = LOW;
void setup() {
// put your setup code here, to run once:
updateShiftRegister(); //Updating Leds on first run to be all off
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(receivePin, OUTPUT);
pinMode(outputenablePin, OUTPUT);
Serial.begin(9600);
irrecv.enableIRIn();//Starts the receiver
}
void translateIR()
{
switch (results.value)
{
case 0xFF30CF: circleLEDs_State = HIGH; circleLeds(); break;
/*case 0xFF18E7: insert odd sequence; break;
case 0xFF7A85: insert ends to middle sequence; break;
case 0xFF10EF: insert something ; break;
case 0xFF38C7: Serial.println("5"); break;
case 0xFF5AA5: Serial.println("6"); break;
case 0xFF42BD: Serial.println("7"); break;
case 0xFF4AB5: Serial.println("8"); break;
case 0xFF52AD: Serial.println("9"); break;
default:
//some idle led function*/
}// end case
}
void loop() {
// put your main code here, to run repeatedly:
currentMillis = millis();
leds = 255;
if (irrecv.decode(&results))
{
Serial.print("\nResult obtained: ");
Serial.print(results.value);
Serial.print("\n");
translateIR();
irrecv.resume();
}
}
void updateShiftRegister()
{
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, LSBFIRST, leds);
digitalWrite(latchPin, HIGH);
}
void circleLeds()
{
int bitty = 0;
leds = 0;
//if 200ms has passed, light up LED
if ( (LED_State == LOW) && (currentMillis - previousMillis >= interval) )
{
previousMillis = currentMillis;
Serial.print("\ncircleLed if reached\n");
bitSet(leds, bitty);
updateShiftRegister();
LED_State = HIGH;
//Let another 200ms pass before turning it off
}
else if ((LED_State == HIGH) && (currentMillis - previousMillis >= interval) )
{
previousMillis = currentMillis;
//turn off all LEDs too
leds = 0;
updateShiftRegister();
LED_State = LOW;
Serial.print("\nelse if statement reached\n");
}
//increment to next LED
bitty++;
Serial.print("\nBitty: ");
Serial.print(bitty);
Serial.print("\n");
//if bitty is over 8, make it 0
if (bitty == 8)
{
bitty = 0;
}
}
So i didnt remove circleLeds(); from the function because i still plan on adding more Led flashing types so i figured i would still need to use a switch(); statement.
After re-reading my code, i actually got it to work, I got my LEDs to light up from top to bottom as they should.
FOR and WHILE Loops are a no go when it comes to concurrency like you said. I'll keep it in mind for the future.
What i did realize is that i needed a statment to cover for the fact for when there wasnt any input signal detected. That is seen in the else if statement in my loop(); and thats what made the difference in my case
Thanks alot for the guidance too, i really appreciate it!
Code just in case someone in my position needs the help:
#include <IRremote.h>
int receivePin = 5; //IR receiver pin
IRrecv irrecv(receivePin);//Creating Receiver Object
decode_results results;
int dataPin = 11; //IC data pin
int outputenablePin = 10; //IC output enable pin
int latchPin = 9; //IC Latch pin
int clockPin = 6; //IC clock Pin
byte leds = 0;
int bitty = 0;
//Timing variables
unsigned long previousMillis = 0;
unsigned long currentMillis = 0;
long interval = 200;
//State Variables
byte circleLEDs_State = LOW;
byte LED_State = LOW;
void setup() {
// put your setup code here, to run once:
updateShiftRegister(); //Updating Leds on first run to be all off
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(receivePin, OUTPUT);
pinMode(outputenablePin, OUTPUT);
Serial.begin(9600);
irrecv.enableIRIn();//Starts the receiver
}
void translateIR()
{
switch (results.value)
{
case 0xFF30CF: circleLEDs_State = HIGH; circleLeds(); break;
/*case 0xFF18E7: insert odd sequence; break;
case 0xFF7A85: insert ends to middle sequence; break;
case 0xFF10EF: insert something ; break;
case 0xFF38C7: Serial.println("5"); break;
case 0xFF5AA5: Serial.println("6"); break;
case 0xFF42BD: Serial.println("7"); break;
case 0xFF4AB5: Serial.println("8"); break;
case 0xFF52AD: Serial.println("9"); break;
default:
//some idle led function*/
}// end case
}
void loop() {
// put your main code here, to run repeatedly:
currentMillis = millis();
leds = 255;
//If we are receiving a signal, translate
if (irrecv.decode(&results))
{
Serial.print("\nResult obtained: ");
Serial.print(results.value);
Serial.print("\n");
translateIR();
irrecv.resume();
}
//If we are not receiving a signal, translate anyways (i.e use the last received value from IR remote)
else if(results.value > 0)
{
translateIR();
}
Serial.println(results.value);
}
void updateShiftRegister()
{
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, LSBFIRST, leds);
digitalWrite(latchPin, HIGH);
}
void circleLeds()
{
leds = 0;
//if 200ms has passed, light up LED
if ( (LED_State == LOW) && (currentMillis - previousMillis >= interval) )
{
previousMillis = currentMillis;
Serial.print("\ncircleLed if reached\n");
bitSet(leds, bitty);
updateShiftRegister();
LED_State = HIGH;
bitty++;
}
//If LED is ON(HIGH) and more than 200ms have passed, turn it OFF
else if ((LED_State == HIGH) && (currentMillis - previousMillis >= interval) )
{
previousMillis = currentMillis;
//turn off all LEDs too
leds = 0;
updateShiftRegister();
LED_State = LOW;
Serial.print("\nelse if statement reached\n");
}
Serial.print("\nBitty: ");
Serial.print(bitty);
Serial.print("\n");
//if bitty is over 8, make it 0
if (bitty == 8)
{
bitty = 0;
}
}
salair456:
So i didnt remove circleLeds(); from the function because i still plan on adding more Led flashing types so i figured i would still need to use a switch(); statement.
That seem to me all the more reason to move circleLeds() and all the future functions for the additional LEDs
Within translateIR() you could set a variable to indicate which of the LED functions is to be active and you could use SWITCH/CASE to do that.
Then in circleLeds() (for example) you could start with these few lines
void circleLeds() {
if (selectedLedAction != 'C') {
return;
}
This assumes that the variable selectedLedAction is set to 'C' (by the SWITCH/CASE statements) when you want the function circleLeds() to operate
Ah okay, i think i see what you're saying. But what advantage is there to this method though? Does it use less cpu cycles? Or is this just a more efficient way to write the code?