Ignoring repeated IR codes in switch case

Hey all, bare with me please. I am fairly new to this and just hit a wall and can't seem to break through it using Google. A little project background first. I am an RC fanatic. I built the RiCino receiver and transponders using Arduino and had huge fun doing so. Since then I have made a few smaller projects trying to get more familiar with the code side of things. I am great with the electronics side of things and not so much with the code.
Each one of our RC trucks is sending a specific modulated IR code per vehicle. I am trying to use the current IR sensor bridge I built for our lap timing system and make it display MPH, lap count, and eventually lap times per vehicle on a large segment display I built. I started basic on this. I currently have the MPH laser break beam sensor figured out and working for the first three digits. The next step is to make the IR system operate a lap counter. To start things slow, I wrote a simple code just using a small handheld remote control for ease of testing. I wrote the code using each IR hex as if it was the vehicle, and turned them into a switch case. I have the segment displays operating and it recognizes the IR code I send it and will count up and reset as I want it to. Unfortunately the sensor bridge will pickup on several hits as it goes under it, and for the life of me I cannot seem to figure out how to write the code to ignore multiple reads of the same IR code. I basically need to get the IR sensor to read the first hit and forget the rest for a set amount of time or until the next time the truck goes through the sensor bridge....lets just say, read the first hit and ignore that same code for the next 10 seconds. Here is the code, any help would be great. Take it easy on me, I am very much a code beginner!!! I know I will have more questions along the way as I think this might be the most involved I have been in the code. This will eventually expand into up to 30 IR codes, and a multi-zoned IR sensor system.

#include "IRremote.h"

int receiver = 12; // Signal Pin of IR receiver to Arduino Digital Pin 11
int Blue = 11;
int Red = 7;

int lap_count1;
int lap_count2;

int latchPin = 4;
int clockPin = 5;
int dataPin = 3;




byte segdisp[10] = {          B11111100,
                              B01100000,
                              B11011010,
                              B11110010,
                              B01100110,
                              B10110110,
                              B10111110,
                              B11100000,
                              B11111110,
                              B11100110,
  
   };


/*-----( Declare objects )-----*/
IRrecv irrecv(receiver);     // create instance of 'irrecv'
decode_results results;      // create instance of 'decode_results'

void setup()   /*----( SETUP: RUNS ONCE )----*/
{
  Serial.begin(9600);
  Serial.println("IR Receiver Button Decode"); 
  irrecv.enableIRIn(); // Start the receiver
  pinMode(Blue, OUTPUT);
  pinMode(Red, OUTPUT);
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);

  digitalWrite(latchPin, LOW);                        // send to 7 segmetn displays
  shiftOut(dataPin, clockPin, LSBFIRST, B11111100);
  shiftOut(dataPin, clockPin, LSBFIRST, B11111100);                     
  digitalWrite(latchPin, HIGH);
   


}/*--(end setup )---*/



/*-----( Function )-----*/
void translateIR() {// takes action based on IR code received
  int a;
  int b;
  int c;
  int d;
  a = lap_count1%10;
  b = lap_count1/10;
  c = lap_count2%10;
  d = lap_count2/10;
 
 


{

  switch(results.value)  // describe IR codes and what they will do
 
  {
     
   
  case 0xFF02F:
  Serial.println("Driver 1"); // GREEN button on tape light remote
  digitalWrite(Blue, HIGH);
  lap_count1 ++;
  Serial.println(lap_count1);
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, LSBFIRST, segdisp[a]);
  shiftOut(dataPin, clockPin, LSBFIRST, segdisp[b]);
  digitalWrite(latchPin, HIGH);
  digitalWrite(Blue, LOW);
  break;
     

  case 0xFF22D: Serial.println("Driver 2");   // RED button on tape light remote
  digitalWrite(Blue, HIGH);
  delay(50);
  digitalWrite(Blue, LOW);
  lap_count2 ++;
  Serial.println(lap_count2);
   digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, LSBFIRST, segdisp[c]);
  shiftOut(dataPin, clockPin, LSBFIRST, segdisp[d]);
  digitalWrite(latchPin, HIGH);
  break;

  case 0xFFA25: Serial.println("Reset");   // Play/Pause button on tape light remote
  digitalWrite(Red, HIGH);
  lap_count1 = 0;
  lap_count2 = 0;
  Serial.println(lap_count1, lap_count2);
   digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, LSBFIRST, B11111100);
  shiftOut(dataPin, clockPin, LSBFIRST, B11111100);
  digitalWrite(latchPin, HIGH);
   delay(1000);
  digitalWrite(Red, LOW);
  break;
   

  default: 
    Serial.println(" other button   ");

  }// End Case

  


} 
}

void loop() {  /*----( LOOP: RUNS CONSTANTLY )----*/
 
  
  
  if  (irrecv.decode(&results)){ // have we received an IR signal?
    
  {
    translateIR();
    irrecv.resume(); // receive the next value}
  
  }  }     }
 
      
/* --(end main loop )-- */

I basically need to get the IR sensor to read the first hit and forget the rest for a set amount of time or until the next time the truck goes through the sensor bridge

The first step is to only react when the received code has not changed since the last time it was received.

Save the received code then, when a code is received compare it with the previous one. If it has changed then react to it, if not ignore it

The element of time can be added afterwards but get the basics working first.

Thanks for the reply. I tried the below "if" statement I got from the other post I found and tried to alter it a few different ways but got no different results. I don''t want any one to write the code for me, but do you have an example of the suggestion you gave? The code language is still pretty foreign to me. I even went through my "Arduino for Dummies" book. My mind seems to work better at reverse engineering. Is this better to be done in the "void loop" section rather than in the "switch case" part of the code? Not sure how the code is handled in the different sections.

 case 0xFF02F:
  Serial.println("Driver 1"); // GREEN button on tape light remote
  if (results.value == 0xFF02F && millis() - ignoreMs> 3000){
  results.value = 0
  digitalWrite(Blue, HIGH);
  lap_count1 ++;
  Serial.println(lap_count1);
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, LSBFIRST, segdisp[a]);
  shiftOut(dataPin, clockPin, LSBFIRST, segdisp[b]);
  digitalWrite(latchPin, HIGH);
  digitalWrite(Blue, LOW);
  ingnoreMs = millis();
}
  break;

This may be something like you want

start of loop()
  if IR code received
    if IR code different than previous code (different truck) or timing is false (same truck after timeout)
      save millis() as start time
      set timing to true
      increment lap count for the coded vehicle
    end if
  end if
  if timing is true and current time - start time greater than 10 seconds
    set timing to false
  end if
end of loop()

Check the logic against what you need

should this be within the switch case or the void loop part of the code?

xxxWALDOxxx:
should this be within the switch case or the void loop part of the code?

All within the loop() function. You could use switch/case to differentiate between IR codes to update the appropriate lap count and I suggest that this would best be done in a function called when needed

well.....I suck at this I guess. I wrote the code I started this with pretty quickly and thought I had a pretty good understanding of what I was doing. I guess not. I tried taking you suggestions and running with them, but have had zero luck making the changes I am looking for. Seems no matter what I tried with your suggestions I can just tap away at the remote button and change the laps as fast as I can push the button. I guess the translation from your suggestions, through the brain, and into the code are just wrong. Seems like such a small thing to have such a hard time with. everything else works fine, just can not get the ignore side of things to work. I hate to ask again, but can you be a little more specific. I am starting to feel like I am just asking you to write it for me now.

Post what you tried after trying to implement my suggestions

before I post my latest attempt, I think my problem is not understanding your suggestion of setting timing true. I didn't think timing could actually be set to true/false. Maybe with a better description of this would help me get your suggestion right. Thanks

In my suggested "code" timing would be a boolean variable but feel free to give it a more descriptive name if you want. Perhaps change its name to timingIsOccuring. It's purpose is to control the reaction to repeated receipt of the same code after a period of time. This will presumably only happen if the same truck passes the counting place twice in succession with no other truck passing in the meantime

NICE!!! Thanks A LOT!!! finally progress. I have a couple other things now I need some guidance on.

  1. on the IR code 0xFF02F, after it runs the "IgnoreTime" and I press the button as fast as possible, it will continue counting up, seems like there is a delay before the program considers the IR code a viable read. In other words. I hit the button, it will add a count to the display, it runs the Ignore time, then counts up and keeps counting if I hit the button fast enough, as soon as my thumb gets tired enough to slow down it seems to start the ignore time again. The second IR code 0xFF22D seems to have no repeated hits within the 10 second IgnoreTime no matter how fast I press the button.

  2. I want to write this for 20+ different IR transponders for 20+ drivers. Is this the best way to do so? I have no problem writing this for this many Drivers, just want to make sure I am doing this in the most efficient way possible.

Thanks again for the help UKHeliBob. I hope someday I can help out. Here is my code so far.

#include "IRremote.h"

int receiver = 12; // Signal Pin of IR receiver to Arduino Digital Pin 11
int Blue = 11;
int Red = 7;

int lap_count1;
int lap_count2;

int latchPin = 4;
int clockPin = 5;
int dataPin = 3;

unsigned long StartMS;
unsigned long CurrentMS;


bool IgnoreTime = false;


byte segdisp[10] = {          B11111100,
                              B01100000,
                              B11011010,
                              B11110010,
                              B01100110,
                              B10110110,
                              B10111110,
                              B11100000,
                              B11111110,
                              B11100110,
  
   };


/*-----( Declare objects )-----*/
IRrecv irrecv(receiver);     // create instance of 'irrecv'
decode_results results;      // create instance of 'decode_results'

void setup()   /*----( SETUP: RUNS ONCE )----*/
{
  Serial.begin(9600);
  Serial.println("IR Receiver Button Decode"); 
  irrecv.enableIRIn(); // Start the receiver
  pinMode(Blue, OUTPUT);
  pinMode(Red, OUTPUT);
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);

  digitalWrite(latchPin, LOW);                        // send to 7 segmetn displays
  shiftOut(dataPin, clockPin, LSBFIRST, B11111100);
  shiftOut(dataPin, clockPin, LSBFIRST, B11111100);                     
  digitalWrite(latchPin, HIGH);
   


}/*--(end setup )---*/



/*-----( Function )-----*/
void translateIR() {// takes action based on IR code received
  int a;
  int b;
  int c;
  int d;
  a = lap_count1%10;
  b = lap_count1/10;
  c = lap_count2%10;
  d = lap_count2/10;
 
 


{

  switch(results.value)  // describe IR codes and what they will do
 
  {
     
   
  case 0xFF02F:
  Serial.println("Driver 1"); // GREEN button on tape light remote
  digitalWrite(Blue, HIGH);
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, LSBFIRST, segdisp[a]);
  shiftOut(dataPin, clockPin, LSBFIRST, segdisp[b]);
  digitalWrite(latchPin, HIGH);
  digitalWrite(Blue, LOW);
  break;
     

  case 0xFF22D: Serial.println("Driver 2");   // RED button on tape light remote
  digitalWrite(Blue, HIGH);
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, LSBFIRST, segdisp[c]);
  shiftOut(dataPin, clockPin, LSBFIRST, segdisp[d]);
  digitalWrite(latchPin, HIGH);
  digitalWrite(Blue, LOW);
  break;

  case 0xFFA25: Serial.println("Reset");   // Play/Pause button on tape light remote
  digitalWrite(Red, HIGH);
  lap_count1 = 0;
  lap_count2 = 0;
  Serial.println(lap_count1, lap_count2);
   digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, LSBFIRST, B11111100);
  shiftOut(dataPin, clockPin, LSBFIRST, B11111100);
  digitalWrite(latchPin, HIGH);
   delay(1000);
  digitalWrite(Red, LOW);
  break;
   

  default: 
    Serial.println(" other button   ");

  }// End Case

  


} 
}

void loop() {  /*----( LOOP: RUNS CONSTANTLY )----*/
 
  CurrentMS = millis();
  
  if  (irrecv.decode(&results)){ // have we received an IR signal?
    
  {
    translateIR();
    irrecv.resume(); // receive the next value}
    if (results.value == 0xFF02F){
      if ((results.value != 0xFF02F) || IgnoreTime == false){
        StartMS = millis();
        IgnoreTime = true;
        Serial.println("lap");
        Serial.println(lap_count1);
        lap_count1 ++;
      }
      }
    if ((IgnoreTime = true) && CurrentMS - StartMS > 10000){
      IgnoreTime = false;
      }
     if (results.value == 0xFF22D){
      if ((results.value != 0xFF22D) || IgnoreTime == false){
        StartMS = millis();
        IgnoreTime = true;
        lap_count2 ++;
        Serial.println("lap");
        Serial.println(lap_count2);
      }
      }
    if ((IgnoreTime = true) && CurrentMS - StartMS > 10000){
      IgnoreTime = false;
      }
      }
      }
  
}
 
      
/* --(end main loop )-- */

just a quick update. Doesn't seem to matter which IR code I use, it seems to be whatever IR code is placed first in the 'loop' function that has the problem.

Your code is missing a vital element in that it does not check whether the code received is different from the previous one received

I think that this is your attempt at doing that

      if (results.value == 0xFF02F)
      {
        if ((results.value != 0xFF02F) || IgnoreTime == false)

but if we just got 0xFF02F then the first part of the next test will always be false so why test it.

You need to save the previous value in a variable before reading the new one. Then you can test whether it has changed and act accordingly. Not quite the same thing, but have a look at the StateChangeDetection example in the IDE which uses this principle

As to efficient coding, you need to eliminate the repeated code by writing a function and calling it when a different code has been received or the same one after a period of time. Within the function it would be best to use switch/case and call a function to update the display.

I didn't have nearly as much time to spend on this as I wanted today, but I tried a few iterations of your last suggestion and ended up back with NO ignore time so I know I did something wrong. Also, wasn't sure if I should be saving the HEX codes as an unsigned long or int. Here is the last iteration I tried. What did I do wrong?

#include "IRremote.h"

int receiver = 12; // Signal Pin of IR receiver to Arduino Digital Pin 11
int Blue = 11;
int Red = 7;

int lap_count1;
int lap_count2;

int latchPin = 4;
int clockPin = 5;
int dataPin = 3;

unsigned long StartMS;
unsigned long CurrentMS;
int LastIR;
int CurrentIR;


bool IgnoreTime = false;


byte segdisp[10] = {          B11111100,
                              B01100000,
                              B11011010,
                              B11110010,
                              B01100110,
                              B10110110,
                              B10111110,
                              B11100000,
                              B11111110,
                              B11100110,
  
   };


/*-----( Declare objects )-----*/
IRrecv irrecv(receiver);     // create instance of 'irrecv'
decode_results results;      // create instance of 'decode_results'

void setup()   /*----( SETUP: RUNS ONCE )----*/
{
  Serial.begin(9600);
  Serial.println("IR Receiver Button Decode"); 
  irrecv.enableIRIn(); // Start the receiver
  pinMode(Blue, OUTPUT);
  pinMode(Red, OUTPUT);
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);

  digitalWrite(latchPin, LOW);                        // send to 7 segment displays
  shiftOut(dataPin, clockPin, LSBFIRST, B11111100);
  shiftOut(dataPin, clockPin, LSBFIRST, B11111100);                     
  digitalWrite(latchPin, HIGH);
   


}/*--(end setup )---*/



/*-----( Function )-----*/
void translateIR() {// takes action based on IR code received
  int a;
  int b;
  int c;
  int d;
  a = lap_count1%10;
  b = lap_count1/10;
  c = lap_count2%10;
  d = lap_count2/10;
 
 


{

  switch(results.value)  // describe IR codes and what they will do
 
  {
     
   
  case 0xFFC23:
  // BLUE button on tape light remote
  Serial.println("Driver 1");
  digitalWrite(Blue, HIGH);
  lap_count1 ++;
  Serial.println("Lap");
  Serial.println(lap_count1);
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, LSBFIRST, segdisp[a]);
  shiftOut(dataPin, clockPin, LSBFIRST, segdisp[b]);
  digitalWrite(latchPin, HIGH);
  digitalWrite(Blue, LOW);
  break;
     

  case 0xFF22D:   
  // RED button on tape light remote
  Serial.println("Driver 2");
  digitalWrite(Blue, HIGH);
  lap_count2 ++;
  Serial.println("Lap");
  Serial.println(lap_count2);
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, LSBFIRST, segdisp[c]);
  shiftOut(dataPin, clockPin, LSBFIRST, segdisp[d]);
  digitalWrite(latchPin, HIGH);
  digitalWrite(Blue, LOW);
  break;

  case 0xFFA25: Serial.println("Reset");   // Play/Pause button on tape light remote
  digitalWrite(Red, HIGH);
  lap_count1 = 0;
  lap_count2 = 0;
  Serial.println(lap_count1, lap_count2);
   digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, LSBFIRST, B11111100);
  shiftOut(dataPin, clockPin, LSBFIRST, B11111100);
  digitalWrite(latchPin, HIGH);
   delay(1000);
  digitalWrite(Red, LOW);
  break;
   

  default: 
    digitalWrite(Red, HIGH);
    delay(5);
    digitalWrite(Red, LOW);

  }// End Case

  


} 
}

void loop() {  /*----( LOOP: RUNS CONSTANTLY )----*/
 
  CurrentMS = millis();
  CurrentIR = results.value;
  
  if  (irrecv.decode(&results)){ // have we received an IR signal?
    
  {
    translateIR();
   irrecv.resume(); // receive the next value}
      if (results.value == 0xFFC23){
        results.value = LastIR;
        if ((CurrentIR != LastIR) || IgnoreTime == false){
        StartMS = millis();
        IgnoreTime = true;
        LastIR = CurrentIR;
      }
      }
    if ((IgnoreTime = true) && CurrentMS - StartMS > 10000){
      IgnoreTime = false;
      }
   
  }  }}
 
      
/* --(end main loop )-- */[code]

You seem to have gone wrong in a number of ways so try something simple first.

Try this (untested)

#include "IRremote.h"

const byte receivePin = 12;
unsigned long currentCode;
unsigned long previousCode;

IRrecv irrecv(receivePin);
decode_results results;

void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn();
}

void loop()
{
  if (irrecv.decode(&results))  //signal received
  {
    previousCode = currentCode; //save the previous code
    currentCode = results.value;  //get current code
    if (currentCode != previousCode)  //we have a new code
    {
      Serial.print("New code received : ");
      Serial.println(currentCode, HEX);
    }
    irrecv.resume();
  }
}

Does it detect when a different code is received ?

Fancy solution: Add a checkpoint about half way around the track, so you can be certain that a truck has gone the full distance before crossing the starting line again.

Less fancy solution: Make a struct like

struct Truck
{
	int id;
	int lapCount;
	unsigned long lastUpdateTime;
	unsigned long lapTimestamp[MAX_LAPS];
};

And then make an array of those structs for however many is the max racers. Make a global variable truckCount which is initially set to 0.

When a truck's ID is received, search through the array for the entry with that ID. If you can't find it, then add that truck to the list and increment truckCount (at the beginning of the race, this will automatically fill out the array). If you did find it already in the list, then check if it's been at least 10 seconds since the truck's lastUpdateTime, and if so, set that to the current time, set lapTimestamp[lapCount] = currentTime as well, and then increment lapCount. Lap times can be worked out by difference between timestamps.

Whilst I agree that there are (possibly) better solutions I don't think that the OP is quite ready for them yet.

My aim for the moment is to go back to basics and for him to add to it gradually until he has something that works based on what he started with. Maybe then we can suggest some improvements but code that works is always going to be better than neater code that doesn't.

dekutree64, I will definitely take that idea into consideration once I can make sense of the basics. I am hoping to use this as a real learning opportunity, considering there seems to be some very basic(my level) to some very sophisticated methods of getting the same end result.

UKHeliBob, I ran the last code you sent and studied what you did and can make sense of that part of it now and realized how and why I messed up my iteration. So it does work. Of course, the NEC IR codes has the repeat code, so at first it would just come up and say "new IR received" every time I pressed the same button on the remote, but it was just the repeat code sending. Once I could press the button fast enough for it to receive the original code it worked perfect. I think the code language is hard for me to get passed. I understand a lot of the language, after reading it over and over 100 times, just have a hard time implementing it, almost like (my interpretation != correct interpretation) && Thought == false. What should I do next. The step by step is helping me figure out what I am doing wrong......I think.

So, the test code works and you understand it. That is progress.

What next ?

Well, how about eliminating the problem with the repeat code for a start. You want to ignore the repeat code, which is 0xFFFFFFFF, I believe so test what you receive and only do anything if it is not 0xFFFFFFFF.

Let's also make a start on ignoring repeated receipt of the same code. When you receive a new code set a boolean variable to true and save the value of millis() ready to control timing for a period as the next step For debugging purposes print a message at that time.

This is only a small step and progress will seem slow but testing the code as you add features makes it easier to debug. Make the changes I have suggested, test them and post the code here

My transponders in our trucks only produce the single code programmed to them so I won't worry about the repeat code 0xFFFFFF for now. I kept with the basic sketch and added the IgnoreTime boolean variable as suggested along with the serial monitor printing for debugging.

#include "IRremote.h"

const byte receivePin = 12;
unsigned long currentCode;
unsigned long previousCode;
unsigned long StartMS;
unsigned long CurrentMS;
bool IgnoreTime = false;

IRrecv irrecv(receivePin);
decode_results results;

void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn();
}

void loop()
{
  CurrentMS = millis();
  
  if (irrecv.decode(&results))  //signal received
  {
    previousCode = currentCode; //save the previous code
    currentCode = results.value;  //get current code
    if (currentCode != previousCode) //we have a new code
    {
      Serial.print("New code");
      Serial.println(currentCode, HEX);
      StartMS = millis();
      IgnoreTime = true;
      }
      if ((IgnoreTime = true) && CurrentMS - StartMS > 10000){
        IgnoreTime = false;
        Serial.println(currentCode, HEX);
        Serial.println("Ignore for 10sec");       
      }
    irrecv.resume();
  }
}

I don't care how slow this goes, I am more here for the learning than in a hurry to do something I don't understand.

As I was implementing the new changes it made me wonder, which I then proved by testing, but now that I think I am understanding this a little better I want to make sure this is the case. But if it is the same code that is received after the ignored time of 10 seconds it will count every time the code is received, in other words. The first received code will be the saved code, ignored for 10 seconds, but if it is the same code after the 10 seconds it won't be ignored again until a different signal has been received.

I don't care if we deal with this issue later if it is jumping too far ahead for me right now, just thought I would mention it in case you weren't aware of this.