This is a Library for receiving and decoding IR signals from remote controls. Perfect for your Arduino projects that need a fast, simple and reliable decoder, but don't require the usage of multiple different protocols at the same time and don't need to send IR signals.
Because no hardware specific instructions are used, it probably works on all Arduino boards (and possibly others, I'm not quite sure, I've only tested it thoroughly on an Arduino Uno and a Mega).
ATtiny 25/45/85/24/44/84 microcontrollers are supported.
If you have problems with this library on some board, please submit an issue here or contact me.
The receiver's output must be connected to one of the Arduino's digital pin that is usable for interrupts and it also must work with the CHANGE mode if the intended protocol uses that mode. One example of a board that does not have CHANGE mode on some of the interrupt pins is the Arduino 101 and one protocol that uses that mode is the RC5 (you can find the modes here).
The following table (adapted from the Arduino Reference) contains the digital pins that can be use to connect the IR receiver to the Arduino board:
[*] - In the Mega family, pins 20 & 21 are not available to use for interrupts while they are used for I2C communication.
[**] - Assuming you're using damellis' ATtiny core or SpenceKonde's ATTinyCore. Other cores may have different pin assignments.
If you're not sure about how to connect the IR receiver to the Arduino, go to: IR receiver connection details at the end of this document.
With the Library Manager
Manually
In the INO file, one of the following directives must be used:
#define IR_SMALLD_NEC
#define IR_SMALLD_NECx
#define IR_SMALLD_RC5
#define IR_SMALLD_SIRC12
#define IR_SMALLD_SIRC15
#define IR_SMALLD_SIRC20
#define IR_SMALLD_SIRC
#define IR_SMALLD_SAMSUNG
#define IR_SMALLD_SAMSUNG32
before the
#include <IRsmallDecoder.h>
Then you need to create one decoder object with the correct digital pin:
IRsmallDecoder irDecoder(2); //IR receiver connected to pin 2 in this example
And also a decoder data structure:
irSmallD_t irData;
Inside the loop(), check if the decoder has new data available. If so, do something with it:
void loop() {
if(irDecoder.dataAvailable(irData)) {
Serial.println(irData.cmd, HEX);
}
}
#define IR_SMALLD_NEC
#include <IRsmallDecoder.h>
IRsmallDecoder irDecoder(2);
irSmallD_t irData;
void setup() {
Serial.begin(250000);
Serial.println("Waiting for a NEC remote control IR signal...");
Serial.println("held \t addr \t cmd");
}
void loop() {
if(irDecoder.dataAvailable(irData)) {
Serial.print(irData.keyHeld,HEX);
Serial.print("\t ");
Serial.print(irData.addr,HEX);
Serial.print("\t ");
Serial.println(irData.cmd,HEX);
}
}
if you are using multiple remotes, with different addresses, in the vicinity of your project, you should also verify the address. You can do something like this:
if (irData.addr == theRightAddr) {
switch (irData.cmd) {
case someCmd:
// do something here
break;
case someOtherCmd:
// do some other things
break;
//etc.
}
}
The dataAvailable(irData)
method combines the functionalities of 3 "fictitious" functions: isDataAvailable(), getData() and setDataUnavailable(). If there is some data available, already decoded, when irDecoder.dataAvailable(irData)
is called:
irData
;If there's no new data, it just returns false.
Note: this library does not use data buffering, if a new signal is received before the available data is retrieved, that previous data is discarded. This may happen if the loop takes to long to check for new data. So, if you want to use repetition codes, try to keep the loop duration below 100ms (for NEC and RC5) and don't use delays. They don't interfere with the decoding, but I don't recommend their usage.
If you want to check if any key was pressed and don't care about the data, you can use the dataAvailable()
method without any parameters. Keep in mind that, if there's new data available, this method will discard that data, before returning true. The ToggleLED example demonstrates this functionality.
If you don't want to receive IR codes when they are not needed or if you want to prevent possible interferences in time critical functions by the decoders' interrupts, you can use the disable()
and enable()
methods. The TemporaryDisable example demonstrates a possible usage for these methods.
The enable()
method also resets the decoder after reenabling it. This is useful if you have to temporarily disable all interrupts or need to use a library that does that. If you don't reset the decoder after re-enabling all interrupts, the next IR signal may not be recognized if the IR receiver detected some signal while the interrupts where disabled.
The protocol data structure is not the same for all protocols, but they all have two member variables in common:
Most of the decoders have the keyHeld variable (which is set to true when a button is being held) and two of the SIRC decoders have the ext variable (see notes for more details);
The following table shows the number of bits used by each protocol and the datatypes of the data structure member variables:
So far, these releases were made without any significant contribution from other developers, but I do have to say that this work was inspired by some of the existing IR Libraries: Arduino-IRremote, IRLib2, IRReadOnlyRemote, Infrared4Arduino and especially the IRLremote, which was almost what I was looking for, but not quite... So I decided to make my own NEC decoder and then an RC5 and a SIRC. Finally I decided to put these decoders in a library, hoping that it will be useful to someone.
If you wish to report an issue related to this library (and don't want to do it on GitHub) you may send an e-mail to: lumica@outlook.com. Suggestions and comments are also welcome.
Copyright (c) 2020 Luis Carvalho
This library is licensed under the MIT license.
See the LICENSE file for details.
The size of this library is, as the name implies, small (about 900 bytes on average, for the Arduino UNO board) and the memory usage is also reduced (around 30 bytes). Keep in mind that these values vary depending on the selected protocol and the board used.
Program memory and static data used (in SRAM) on an Arduino UNO (in bytes):
To keep track of the sizes of this library, I used a sketch, similar to the ToggleLED example, with and without the library. By compiling each of the supported protocols and comparing their sizes with the reference sketch we get the memory used by the library.
Reference sketch | With NEC protocol decoder |
---|---|
```ino
// #define IR_SMALLD_NEC
// #include |
```ino
#define IR_SMALLD_NEC
#include |
Although my main goals are functionality and small size, I believe this library is reasonably fast. I haven't compared it to other libraries (it's not easy to do so), but I was able to compare the speed of the different protocols that I've implemented so far:
Protocol Speed comparisons:
Protocol | Interrupt Mode | Avg. Interrupt Time | Max. Interrupt Time | Interrupts per Keypress | Signal Duration |
---|---|---|---|---|---|
NEC | RISING | 11.35 µs | 13 µs | 34 | 67.5ms |
NECx | RISING | 10.90 µs | 13 µs | 34 | 67.5ms |
RC5 | CHANGE | 10.44 µs | 17 µs | 14 to 28 | 24.9ms |
SIRC12 | RISING | 10.44 µs | 13 µs | 3*13 | 3*(17.4 to 24.6)ms |
SIRC15 | RISING | 10.51 µs | 12 µs | 3*16 | 3*(21 to 30)ms |
SIRC20 | RISING | 11.10 µs | 15 µs | 3*21 | 3*(27 to 39)ms |
SIRC | RISING | 11.70 µs | 17 µs | 39, 48 or 63 | 3*(17.4 to 39)ms |
SAMSUNG | FALLING | 10.99 µs | 13 µs | 2*22 | 2*(32.1 to 54.6)ms |
SAMSUNG32 | FALLING | 10.97 µs | 14 µs | 34 | (54.6 to 72.6)ms |
Notes:
Remote control keys do not "bounce", but the remotes do tend to send more codes than we wish for when we press a button. That's because, after a very short interval, they start sending repeat codes. To avoid those unwanted initial repetitions, this library ignores a few of those repetition codes before confirming that the button is actually being held.
The data sent by the remotes is decoded according to the protocols' specifications and separated into different variables. On most remotes only the 8-bit command matters, so you don't have to work with 16-bit or 32-bit codes, reducing code size and memory usage.
As you've probably seen above, or if you've already tried one of the "Hello..." examples, this library is very simple to use and it's not full of rarely needed features. That's what makes it small and why it uses few resources. Additional features may be added in the future, but only if requested and do not significantly affect the size and/or speed.
The decoding is done asynchronously, which means that it doesn't rely on a timer to receive and process signals, but it uses a hardware interrupt to drive the Finite State Machines that perform the decoding. In fact, they are Statechart Machines (David Harel type) working in a asynchronous mode.
Most of the protocols' Statechart Machines are implemented using switch cases, but I also use the "labels as values" GCC extension (AKA "computed gotos") to implement some of the more complex statecharts. It's not a C++ standard but it should work with all IDEs that use the GCC (like Arduino IDE). If you have problems compiling any of the protocols that use the "labels as values" extension, please submit an issue here or contact me.
I can't say that it's easy to understand how these decoders work, some of the Statechart Machines I designed turned out to be a bit tricky. But if you still want to take a look at the statechart diagrams, they can be found here. Note that they may not be an exact representation of what I actually implemented, but they are a good starting point.
In order to make this library compatible with most of the Arduino boards, I didn't include any hardware specific instructions, but I did use a programming technique in which it's assumed that the microcontroller's endianness is Little-Endian. On some boards you may even get a warning related to this, but it should work anyway.
If you are using a simple IR receiver module, the pinout order will most likely be Out Gnd Vcc
, as in the following examples:
But beware, there are other IR receivers with different pinouts, like these examples:
If you are using a test module, the pinout is usually written on it (sometimes it's DATA, DAT or S instead of OUT).
The connection to the Arduino is very straightforward, just connect:
GND to one of the Arduino's Ground connector.
1. Go to Connecting the IR receiver for more information.
2. Keep in mind that not all IR receivers can operate at low voltages.
Nearly all IR receiver's datasheets recommend the usage of an RC filter (R1, C1) at the power input, but it's not absolutely necessary, (it's meant to suppress power supply disturbances):
Note that most IR receiver test modules already have that RC filter.