How do we use an IR remote control & detect multiple button-presses?

OLDmarty

Senior Member
Hi all,

As the title states...."How do we use an IR remote control & detect multiple button-presses?"

I'm building a small IR-picaxe interface to add into a legacy piece of equipment, but the equipment needs to detect a single button-press up to a 3 digit button-press to enable different modes etc.

So, pressing "1" will perform a certain function and pressing "12" will perform something else, and pressing "123" will perform something else entirely.
The picaxe "function" might just toggle a few bits on a picaxe to control the external equipment, or somethimes send a full byte value to a picaxe port etc.

My initial challenge is how i go about detecting each IR-remote button-press and then store/process it within the picaxe?

My first thoughts are to maybe create 4 variables, such as b0, b1, b2, b3.
I would use b0 to detect the incoming IR button code, then i would check to see which of the variables b1 or b2, or b3 are empty, and then copy b0's data into that empty (available) b1, or b2, or b3.

Assuming i press "12" or "123", the data currently in b0 would need to be checked which of the b1,b2,b3 bytes are empty and can accept this byte.
Of course, after the 1, 2 or 3 button-presses have been detected and processed, the picaxe would then clear all 4 variables in readiness for the next IR codes at a later time.

Am i on the right track so far?, or is there a much simpler way to handle multiple button-presses from an IR remote control?

Thanks in advance, if anyone can share there previous IR multi-byte experience with me.
 

hippy

Technical Support
Staff member
I would use a word variable which I multiplied by 10 and added the new button value to on each key so, at the end of 1, 12 or 123 it would automatically contain that value. Something like -
Code:
w1 = 0
Do
  IrIn IR_PIN, b0
  w1 = w1 * 10 + b0
  SerTxd("Pressed so far : ", #w1, CR, LF)
Loop
You would need to convert the key code to a digit value 0-9, and also handle a cancel or abort or whatever. You can use a timeout so you can tell when a key hasn't been pressed to action whatever value has been accumulated.
 

hippy

Technical Support
Staff member
A more complete version ...
Code:
Symbol IR_PIN     = C.3

Symbol reserveW0 = w0 ; b1:b0
Symbol number    = w1 ; b3:b2
Symbol key       = b4

Main:
  Do
    Gosub GetFirstKey
    number = key
    Do
      Gosub GetNextKey
      If key <= 9 Then
         number = number * 10 + key
      End If
    Loop While key <= 9 And number < 100
    SerTxd("Command is ", #number, CR, LF)
  Loop

GetFirstKey:
  Do
    IrIn IR_PIN, key
    Gosub ConvertKeyCodeToValue
  Loop Until key <= 9
  Return

GetNextKey:
  Do
    IrIn [5000, NoKeyPress], IR_PIN, key
    Gosub ConvertKeyCodeToValue
  Loop Until key <= 9
  Return

NoKeyPress:
  key = $FF
  return

ConvertKeyCodeToValue:
  If key <= 9 Then
    ; Digit key
    ; "1" == 0 -> 1   "2" == 1 -> 2   "3" == 2 -> 3
    ; "4" == 3 -> 4   "5" == 4 -> 5   "6" == 5 -> 6
    ; "7" == 6 -> 7   "8" == 7 -> 8   "9" == 8 -> 9
    ; "0" == 9 -> 10 // 10 -> 0
    key = key + 1 // 10
  Else
    ; Not a digit key
    key = $FF
  End If
  Return
 

kfjl

Member
Hi,
My interpretation of the question is:
given the Sony protocol doesn't have a toggle bit, like Philips, or a repeat code, like NEC, how do you distinguish between a button held down and a button pressed several times?

On the receiving end, the Sony protocol is as sloppy as orphanage porridge, so with some rough measuring of the time between successive codes, you might be able to tell the difference.

Here's a picture of the code sent by pressing the number 8 key on Rev-Ed's TVR010. The time between the last rising edge of the first burst and the last rising edge of the second is about 62-18 = 44ms, so anywhere near that between successive receptions means you held the button down.

The rest is compromise. You'll need a maximum time between button presses for them to be counted as part of one number and a minimum time for them to be counted as separate numbers.

I haven't actually done this, but Sony must have, because Sony TVs have more than ten channels like all the others.

25882
 

Jim-TX

New Member
"So, pressing "1" will perform a certain function and pressing "12" will perform something else, and pressing "123" will perform something else entirely."

I have worked a lot with IR controllers (Sony protocol).
My first question is why are you wanting to do the 1-2-3 keypad entry? Why not use '1' for one command, '2' for another, and '3' for, yet another. Much simpler to code.

In my case, I used the keypad for various things, but one feature in my LED lighting was to use the numeric keypad to activate an 'Off Delat'. If I pressed '1', it would wait one second before switching off the LEDs. If I pressed '9', it would count down and turn off the LEDs after 9 seconds.

I _did_ use multiple keypad entries, but needed to add a 'delay' between key presses as the Sony protocol (as mentioned above) has an auto-repeat feature that can screw with your results (I.E. it will see 3 '9' entries when you only press '9' once.)

I found using an IR remote quite handy to enter data to the Picaxe processor.
 

kfjl

Member
My first question is why are you wanting to do the 1-2-3 keypad entry? Why not use '1' for one command, '2' for another, and '3' for, yet another. Much simpler to code.
Yeah. Over 100 commands to a picaxe. My imagination stops at: forwards, backwards, left, right, start, stop, faster and slower.

Probably the easiest way to increase the number of commands available would be to use other buttons to send the program to different sub programs where 10, 20, 30, etc would be added to the following button presses.

I would be interested to know what the 123+ commands are.
 

inglewoodpete

Senior Member
Just a thought but...
Could the program be written to ignore any double key codes: Eg. Ignore 11 but accept 12, 13, 14, 15, 16, 17, 18, 19, 121, 123, 124, etc etc
 

Jim-TX

New Member
RE: Could the program be written to ignore any double key codes:

It would be easier to put in a delay of... say... half a second - before scanning for more codes.
To make sure all codes have been received before processing, require the 'Enter' key to also be pressed.
So, the user would enter
'1' 'Enter' for 1
'12' 'Enter' for 12
'123' 'Emter' for 123
 

OLDmarty

Senior Member
Just a thought but...
Could the program be written to ignore any double key codes: Eg. Ignore 11 but accept 12, 13, 14, 15, 16, 17, 18, 19, 121, 123, 124, etc etc
No, i can't miss any codes, it must decode 1 to 512 on a remote control to copy what the external equipment expects on its keypad entry.
 

OLDmarty

Senior Member
The requirement is no different my to TV, where channel 1 is whatever tv station and 12 is some other station, and 123 is some digital radio station etc etc.
 

OLDmarty

Senior Member
I would use a word variable which I multiplied by 10 and added the new button value to on each key so, at the end of 1, 12 or 123 it would automatically contain that value. Something like -
Code:
w1 = 0
Do
  IrIn IR_PIN, b0
  w1 = w1 * 10 + b0
  SerTxd("Pressed so far : ", #w1, CR, LF)
Loop
You would need to convert the key code to a digit value 0-9, and also handle a cancel or abort or whatever. You can use a timeout so you can tell when a key hasn't been pressed to action whatever value has been accumulated.
Thanks Hippy for your input, but i'm not entirely sure why you multiply by 10 to create large numbers.

what is the reason for doing that? (just so i can get my head around it lol).
 

OLDmarty

Senior Member
A more complete version ...
Code:
Symbol IR_PIN     = C.3

Symbol reserveW0 = w0 ; b1:b0
Symbol number    = w1 ; b3:b2
Symbol key       = b4

Main:
  Do
    Gosub GetFirstKey
    number = key
    Do
      Gosub GetNextKey
      If key <= 9 Then
         number = number * 10 + key
      End If
    Loop While key <= 9 And number < 100
    SerTxd("Command is ", #number, CR, LF)
  Loop

GetFirstKey:
  Do
    IrIn IR_PIN, key
    Gosub ConvertKeyCodeToValue
  Loop Until key <= 9
  Return

GetNextKey:
  Do
    IrIn [5000, NoKeyPress], IR_PIN, key
    Gosub ConvertKeyCodeToValue
  Loop Until key <= 9
  Return

NoKeyPress:
  key = $FF
  return

ConvertKeyCodeToValue:
  If key <= 9 Then
    ; Digit key
    ; "1" == 0 -> 1   "2" == 1 -> 2   "3" == 2 -> 3
    ; "4" == 3 -> 4   "5" == 4 -> 5   "6" == 5 -> 6
    ; "7" == 6 -> 7   "8" == 7 -> 8   "9" == 8 -> 9
    ; "0" == 9 -> 10 // 10 -> 0
    key = key + 1 // 10
  Else
    ; Not a digit key
    key = $FF
  End If
  Return
Thanks again Hippy,

I'll definitely look into this and see how it goes for my project.
 

OLDmarty

Senior Member
"So, pressing "1" will perform a certain function and pressing "12" will perform something else, and pressing "123" will perform something else entirely."

I have worked a lot with IR controllers (Sony protocol).
My first question is why are you wanting to do the 1-2-3 keypad entry? Why not use '1' for one command, '2' for another, and '3' for, yet another. Much simpler to code.

In my case, I used the keypad for various things, but one feature in my LED lighting was to use the numeric keypad to activate an 'Off Delat'. If I pressed '1', it would wait one second before switching off the LEDs. If I pressed '9', it would count down and turn off the LEDs after 9 seconds.

I _did_ use multiple keypad entries, but needed to add a 'delay' between key presses as the Sony protocol (as mentioned above) has an auto-repeat feature that can screw with your results (I.E. it will see 3 '9' entries when you only press '9' once.)

I found using an IR remote quite handy to enter data to the Picaxe processor.
The commands are emulating a keypad code entry, so 1 to 512 will be needed.

Yes, it's a lot of data to store either in the picaxe or external eeprom.
 

OLDmarty

Senior Member
RE: Could the program be written to ignore any double key codes:

It would be easier to put in a delay of... say... half a second - before scanning for more codes.
To make sure all codes have been received before processing, require the 'Enter' key to also be pressed.
So, the user would enter
'1' 'Enter' for 1
'12' 'Enter' for 12
'123' 'Emter' for 123
Yes, that's exactly the goal and a small timeout delay would be used, much like a regular TV remote control, you either type in the complete channel number "23"or it defaults to channel "2" if that was all i pressed within the small delay window.
 

Aries

New Member
Thanks Hippy for your input, but i'm not entirely sure why you multiply by 10 to create large numbers.

what is the reason for doing that? (just so i can get my head around it lol).
For example, if you read in key presses of "6" and "9" (in that order), and you want therefore to receive "69", it is

6*10 + 9
 

hippy

Technical Support
Staff member
i'm not entirely sure why you multiply by 10 to create large numbers.
It's simply so you can have the number you entered in a single and easy to use variable. To expand on Aries's comment, with 'number' initially set to zero ...

Entering 1 : 0 * 10 + 1 => 1
Entering 2 : 1 * 10 + 2 => 12
Entering 3 : 12 * 10 + 3 => 123
 

Jim-TX

New Member
Doing a bit of brief thinking on this...
Almost everything you need is already built into the IRIN command that you should use for the Infrared input.

I spent a few minutes and cobbled together how I think I would approach your predicament.
For those of you who are experts, please go easy on me... I consider myself a code-hacker - not an expert.

Anyway... here's the code - after the code, I will try to explain my coding...

IR_Input ' Infrared Input Pin on Picaxe
Infrared ' Variable used to store value
Code_Value ' Keypad Number

I = 0
main:
I = I + 1

irin [1000, Continue_Processing], IR_Input, Infrared

pause 250 ' Delay 250ms to eliminate multiple hits

Select Case Infrared
case 0
Infrared = 9
case 1 to 9
Infrared = Infrared -1
end Select

select case I
case 1
Code_Value = Infrared
case 2
Code_Value = Code_Value + (Infrared * 10)
case 3
Code_Value = Code_Value + (Infrared * 100)
Case 4
' There should NEVER be a Case 4 condition.
' Add code here to disallow Case 4
end select
goto main:

Continue_Processing:

So - IRIN is setup to have a timeout - which is used to branch to a different part of the program if it does not receive any input after a period of time - which we set to 1000ms (or 1 second).
We also define the Input pin for the Infrared device and the variable to store the value
There is a 250ms pause to eliminate the auto-repeat
The first Case statement adjusts the Infrared value
Then there is a Case statement that hopefully creates your Input number.
The only exit from this loop is when the user does not enter any digits on the keypad and the IRIN timeout kicks in.
Continue_Processing is where you decide what to do with your keypad entry value

...or something like that. It isn't perfect, and the variable 'I' needs to get reset to zero before entering the next keypad entry, but these things are minor.
 

erco

Senior Member
Late to this party. I'd say you can go 2 ways easily.

1) Require 3 digits, such as 1=001, 23=023 etc. PITA.
2) Give yourself a certain time to enter the digits, using IRIN's timeout feature. Like so many modern TVs, if you only enter 1 then there's a pause for the timeout, then the value is one. If you enter 2 then shortly after 3, there's a pause then the value is 23.

Either way you would benefit from some feedback (either a beep or better seeing the number onscreen) to know when a number has been received.
 

wapo54001

Senior Member
Now very late to the game, but I had this problem when I was designing an IR control system for an audio preamp. I did not want the volume control to continue to increase/decrease after I let go of the up/down button on the remote because of commands left in the buffer. The way I solved it was to receive the IR code, have the software do the task one time, then clear the buffer then wait for the next key press after a very small delay. That way, if I held the key down the volume would increase at a fixed rate and if I let go after any point in time the volume would stop increasing immediately.

You could use that technique to avoid unintended multiple 'repeat' keystrokes by using an appropriate delay after clearing the buffer. Regarding the entry of "1" "12" "123" the approach on cable boxes is to use the keypad to enter the number and then have the software execute that number only after a pause that indicates no more numbers are going to be entered. You can also speed the process by using a separate "execute" key after the number has been entered.
 
Top