How to enter a multi-digit value from an IR remote and store the final value

Hi Folks!

Newbie here.

I'd like to implement a remotely controlled volume control.
The 'Volume' variable ranges from 0 to 127.
What I'd like to achieve is:
entering the 3-digit value from an IR remote, then store the final value by pressing the 'Enter' button.

As an example:

let's say I need to set the volume to '58', so I would need three button presses,

1st press: button '5',
2nd press: button '8',
3rd press: button 'enter' to store the final composed value.

The problem: unfortunately I have no idea on how to correctly implement this. Could you please help?

Any suggestion greatly appreciated.

TIA !

How far have you got ?
Are you intending to use an Arduino infra red library and a circuit which includes an IR receiver such as a TSOP4838 ?
Maybe look at something like this: Receiving and Decoding IR | Using an Infrared Library on Arduino | Adafruit Learning System

As a starter - take a look at examples for keypad library & code - to accumulate a numeric value in a buffer, and then display or act on that value.

Then swap out the keypad code - and replace with an IR receiver library.

A relatively simple project to stretch your learner chops.

Hi guys, much thanks for the replies!
Yes, I'm using the IR lib and TSOP 2438 IR receiver.

If I undestand correctly, I could use a string to accumulate the digits, then use atoi function to get the integer.

I came up with the following code, inspired by other example sketches I've found (as suggested).

Do you think it will work?

#include <IRremote.h>
/*
 * Variables
 */
int RECV_PIN = 11;
const int MaxChars = 3; 
char strValue[MaxChars + 1];   // String for 3 digits + null char
char ch;
int index = 0;
int accumulVal = 0;

IRrecv irrecv(RECV_PIN);

decode_results results;

void setup()
{
  Serial.begin(9600);
  // In case the interrupt driver crashes on setup, give a clue
  // to the user what's going on.
  Serial.println("Enabling IRin");
  irrecv.enableIRIn(); // Start the receiver
  Serial.println("Enabled IRin");
}

void loop() {
  if (irrecv.decode(&results)) {
    Serial.println(results.value, DEC);
    irrecv.resume(); // Receive the next value
  }
  delay(100);

  if ( results.value == 0x20DFA857 )  // Button '5' on my remote  
  { 
    ch = '5';   // assign number '5' to button '5' press
  }

  if ( results.value == 0x20DF18E7 )  // Button '8' on my remote  
  { 
    ch = '8';   // assign number '8' to button '8' press
  }

  /*
   * Accumulation
   */
  if ( index < MaxChars){
    strValue[index++] = ch;     // add the ASCII character to the string
  }

  else
    {
      // here when the buffer is full or on the first non digit
      strValue[index] = 0;          // terminate the string with a 0
      accumulVal = atoi(strValue);  // use atoi to convert string to an int
      index = 0;                    // reset index to receive other data
    }
  
} // loop end

Do you think it will work?

Try it and let us know.

Okay, I've uploaded the sketch on a Leo board.
It only takes the final value:

i.e. if I press 1 it accumulates to 111,
if I press 8 it accumulates to 888.

Any suggestion?

You press '1' once, and get three ones?

So a bit of debugging, Serial.print() will do - to help locate the specific issue.
it sounds like you're almost there.
Just stay calm, think logically, and try to understand each line of code as opit executes.

lastchancename:
You press '1' once, and get three ones?

Yes, exactly.
I got the impression that it keeps accumulating, instead it should get
the first press char and store it to the right (LSB), then wait for the second press to pass the first-pressed character to the left, towards the MSB, and replace the LSB value with the new
2nd press char value.

I'm assuming the Index bit order is:
2 1 0 (so MSB to LSB)

Am I misinterpreting here?

Unfortunately I have no clue on how to do this (limited knowledge).

Any help/suggestion highly appreciated.

Updated code:

#include <IRremote.h>
/*
 * Variables
 */
int RECV_PIN = 11;
const int MaxChars = 3; 
char strValue[MaxChars + 1];   // String for 3 digits + null char
char ch;
int index = 0;
int accumulVal = 0;

IRrecv irrecv(RECV_PIN);

decode_results results;

void setup()
{
  Serial.begin(9600);
  // In case the interrupt driver crashes on setup, give a clue
  // to the user what's going on.
  Serial.println("Enabling IRin");
  irrecv.enableIRIn(); // Start the receiver
  Serial.println("Enabled IRin");
}

void loop() {
  if (irrecv.decode(&results)) {
    Serial.println(results.value, DEC);
    irrecv.resume(); // Receive the next value
  }
  delay(100);

   if ( results.value == 0x20DF8877 )  // Button '1' on my remote  
  { 
    ch = '1';   // assign number to button press
  }

  if ( results.value == 0x20DF48B7 )  // Button '2' on my remote  
  { 
    ch = '2';   // assign number to button press
  }

  if ( results.value == 0x20DFC837 )  // Button '3' on my remote  
  { 
    ch = '3';   // assign number to button press
  }

  if ( results.value == 0x20DF28D7 )  // Button '4' on my remote  
  { 
    ch = '4';   // assign number to button press
  }

  if ( results.value == 0x20DFA857 )  // Button '5' on my remote  
  { 
    ch = '5';   // assign number '5' to button '5' press
  }

  if ( results.value == 0x20DF6897 )  // Button '6' on my remote  
  { 
    ch = '6';   // assign number to button press
  }

  if ( results.value == 0x20DFE817 )  // Button '7' on my remote  
  { 
    ch = '7';   // assign number to button press
  }

  if ( results.value == 0x20DF18E7 )  // Button '8' on my remote  
  { 
    ch = '8';   // assign number '8' to button '8' press
  }

  if ( results.value == 0x20DF9867 )  // Button '9' on my remote  
  { 
    ch = '9';   // assign number to button press
  }

   if ( results.value == 0x20DF08F7 )  // Button '0' on my remote  
  { 
    ch = '0';   // assign number to button press
  }

  /*
   * Accumulation
   */
  if ( index < MaxChars && isDigit(ch) ){
    strValue[index++] = ch;     // add the ASCII character to the string
  }

  else
    {
      // here when the buffer is full or on the first non digit
      strValue[index] = 0;          // terminate the string with a 0
      accumulVal = atoi(strValue);  // use atoi to convert string to an int
      index = 0;                    // reset index to receive other data
    }

    Serial.print("Accumulated value: ");
    Serial.println(accumulVal, DEC);
  
} // loop end

Why do you check results.value on every iteration of loop()?

AWOL:
Why do you check results.value on every iteration of loop()?

I know, many IF statements.
It is to easily assign a digit value to each button on my remote. I'm sure there's a better way.

What were you thinking?

I was thinking of only checking when you receive a keypreas.

AWOL:
I was thinking of only checking when you receive a keypreas.

Okay, how can this be done? (newbie here).

Thnks

Sorry "keypress".

Sure, which way to do this?

Two steps
Replace the multiple IF's with a switch() block.
As AWOL suggested, only validate and accumulate your buffer after a new keycode is received... not every time around the loop().
(You /may/ need to detect unwanted, 'non' keys to effectively debounce/ignore any stream of recurring characters.

lastchancename:
Two steps
Replace the multiple IF's with a switch() block.

I should be able to do that, thanks.

lastchancename:
As AWOL suggested, only validate and accumulate your buffer after a new keycode is received... not every time around the loop().
(You /may/ need to detect unwanted, 'non' keys to effectively debounce/ignore any stream of recurring characters.

Don't know how to do it.
Any help ?

Once you've implemented the switch() block, test if the character is 'different' than the previous button received before you store the character.
(This could be done before or after the switch()

if (newKey != prevKey) {   // check if a key and different than previous key
   switch(newKey) {
      case AAA:
         // save the AAA value
         strValue[index++] = AAA;
         break;
      case BBB:
         // save the BBB value
         strValue[index++] = BBB;
         break;
      case CCC:
         // save the CCC value
         strValue[index++] = CCC;
         break;
      default;
         ; // whatever
   }
   prevKey = newKey;   // keep for next comparison
}
/*
Personally I would prefer to use a pointer to accumulate the chars, but you know where you're going - so leave it this way for now.

    {
      // here when the buffer is full or on the first non digit
      strValue[index] = 0;          // terminate the string with a 0
      accumulVal = atoi(strValue);  // use atoi to convert string to an int
      index = 0;                    // reset index to receive other data
    }

    Serial.print("Accumulated value: ");
    Serial.println(accumulVal, DEC);
/*
}

Good luck.
A bit of help - but some thinking for you too!

Thanks for the reply!

Unfortunately I couldn't upload the modded sketch.
Error on line 40 (if newKey!=prevKey statement):

exit status 1
expected primary-expression before 'if'

What I do not understand is how you associate each case to the IRrecv decoded number, so I've added
newKey=results.value, on line 35.

Further, it's not clear to me why the line

if newKey!=prevKey

since I expect I can enter the value '11', '22', 33' etc., and this would obviously imply 2 presses
with the same key.

I'm a bit confused. :o

The new code (which I cannot upload because of the error) below:

#include <IRremote.h>
/*
 * Variables
 */
int RECV_PIN = 11;
const int MaxChars = 3; 
char strValue[MaxChars + 1];   // String for 3 digits + null char
char ch;
int index = 0;
int accumulVal = 0;
int newKey = 0;
int prevKey = 0;

IRrecv irrecv(RECV_PIN);

decode_results results;

void setup()
{
  Serial.begin(9600);
  // In case the interrupt driver crashes on setup, give a clue
  // to the user what's going on.
  Serial.println("Enabling IRin");
  irrecv.enableIRIn(); // Start the receiver
  Serial.println("Enabled IRin");
}

void loop() {
  if (irrecv.decode(&results)) {
    Serial.println(results.value, DEC);
    irrecv.resume(); // Receive the next value
  }
  delay(100);

newKey = results.value;
/* ------------
 * -- CASES --- 
 */------------

if (newKey != prevKey) {   // check if a key and different than previous key
 switch(newKey)
 {
   case 0x20DF8877 :  // Button '1' on my remote   
    strValue[index++] = '1';
    break;   // assign number to button press
  
  case 0x20DF48B7 :  // Button '2' on my remote  
    strValue[index++] = '2';
    break;

  case 0x20DFC837 :  // Button '3' on my remote  
    strValue[index++] = '3';
    break;

  case 0x20DF28D7 :  // Button '4' on my remote  
    strValue[index++] = '4';
    break;

  case 0x20DFA857 :  // Button '5' on my remote  
    strValue[index++] = '5';
    break;

  case 0x20DF6897 :  // Button '6' on my remote  
    strValue[index++] = '6';
    break;

  case 0x20DFE817 :  // Button '7' on my remote  
    strValue[index++] = '7';
    break;

  case 0x20DF18E7 :  // Button '8' on my remote  
    strValue[index++] = '8';
    break;

  case 0x20DF9867 :  // Button '9' on my remote  
    strValue[index++] = '9';
    break;

  case 0x20DF08F7 :  // Button '0' on my remote  
    strValue[index++] = '1';
    break;

  }  // end of cases
  prevKey = newKey;
}

  /*
   * Accumulation
   */


  else
    {
      // here when the buffer is full or on the first non digit
      strValue[index] = 0;          // terminate the string with a 0
      accumulVal = atoi(strValue);  // use atoi to convert string to an int
      index = 0;                    // reset index to receive other data
    }

    Serial.print("Accumulated value: ");
    Serial.println(accumulVal, DEC);
  
} // loop end
/* ------------
 * -- CASES --- 
 */------------

Oops

The block of code which i offered is called 'pseudo code', the purpose being to get you thinking and asking more questions.

It had some meaningful structures - to help make your code more readable and intuitive. Whether it achieves those goals is dependent on how ready you are to learn, understand, experiment and be guided.

I doubt anyone here is going to finish your project - you can go to the Gigs & Collaborations section for that.
We'll keep watching and helping, but you. need to inject the same effort.