Make a Universal Arduino IR Remote with Seeeduino XIAO!

Make your very own universal Arduino IR Remote with Seeeduino XIAO! This is a simple project that will allow you to create an infrared (IR) remote to control any appliance with an IR receiver in your house, such as your TV or music player.

Follow today’s tutorial for a step-by-step guide on how to build this project for yourself!

Building with Seeeduino XIAO & Grove

To tackle this project, we can make use of the Seeeduino XIAO and it’s Seeeduino XIAO Expansion Board!

The expansion board features convenient Grove connectors which we can use to plug-and-play with compatible Grove modules without soldering or messy wiring. The pinout of the Seeeduino XIAO’s expansion board is shown below. As we can see, it packs a great variety of connectors and even has an onboard LED display!

Things You’ll Need:

  • Household appliance with an IR receiver that you want to control
  • The IR remote for that household appliance

Parts You’ll Need:

What is “Infrared”?

Infrared light is similar to the light that we see all of us, except it has a different frequency and wavelength. Since it lies outside the visible light spectrum, it’s invisible to humans and great for achieving discreet wireless transmission!

Source: Circuit Basics

However, because infrared is a type of light, it will require a clear line between the transmitter and the receiver for communication to work. This means that unlike BLE or WiFi, our IR signals cannot pass through walls or other opaque materials.

How does Infrared Communication work?

Infrared communication is achieved by transmitting a pattern of infrared light from an infrared emitter to an infrared receiver.

Infrared signals consist of a series of modulated pulses of light waves with “HIGH” and “LOW” states. In IR communication, the specific pattern of HIGHs and LOWs are used to create the ‘message’ that we want to send, similar to morse code. Infrared signals typically have a header to mark the beginning of the signal, such as a long mark followed by a space.

IR light is emitted by anything that produces heat, including the sun, our light bulbs, and us! In order to tackle the issue of IR signal noise, this series of light pulses are only transmitted at a specific frequency. For most transmitters, this frequency is defined to be 38 kHz, since this frequency of IR light is rarely found in nature and thus distinguishable from noise. IR receivers usually equipped with a filter to only receive 38kHz signals.

IR Communication: Transmission Protocols

Because storing the precise timing of the entire signal as 16 bit integers takes up too much memory, IR signals are usually stored as binary numbers of up to 32 bits. At transmission, an IR emitter converts this binary number into the actual IR signal, whereas on the other hand, an IR receiver will decode the received IR signal into the corresponding binary number.

The pattern through which the IR signal is converted to and from binary is known as the transmission protocols. Some of the more common protocols include Sony, NEC, Matsushita, and RC5.

In the NEC protocol, for example, logical ‘1’ starts with a 562.5 µs long HIGH pulse of 38 kHz, followed by a 1687.5 µs long LOW pulse. Meanwhile, logical ‘0’ is transmitted with a 562.5 µs long HIGH pulse followed by a 562.5 µs long LOW pulse:

Arduino IR Remote Receiver Tutorial - NEC Protocol
Source: Circuit Basics

IR Communication: Hexadecimal Codes

Each button we press on our IR remote corresponds to a unique hexadecimal code. This is what is converted into the IR signal and transmitted from our remote to the receiver on the target device.

Since we are building our very own IR remote today, we need to obtain and store the specific IR codes used to control our target device in our program. This information may be included in the datasheet that comes with the device that you want to control.

If not, however, we can simply use an IR Receiver with our Seeeduino XIAO to read the IR codes for our remote controls directly.

Universal Arduino IR Remote: Hardware Setup

First, set up your Seeeduino XIAO, the expansion board, and its Grove modules according to the schematic below. If this is your first time working with the Seeeduino XIAO, I highly recommend you first quickly go through the getting started guide on the Seeed Wiki.

Next, connect your Seeeduino XIAO to your PC via the USB Type-C cable and that’s all we have to do for the hardware! Thanks to the Grove Ecosystem, there’s really no need to fuss over the hardware wiring for our projects any longer. Simply plug, program, and play!

Installing the Required Libraries

Today’s tutorial will make use of the following libraries, which you can download from their respective repositories:

If you are new to installing Arduino libraries, please follow the detailed visual guide on the Seeed Wiki.

Finding the IR Codes for our Target Device

The first official step for our project is to determine the codes that we should be sending to our target device. Fortunately, the Seeed Arduino IR library that we just installed already comes with code to help us do that!

Setting Up Our Seeeduino XIAO as an IR Signal Decoder

In your Arduino IDE, navigate to File > Examples > Seeed Arduino IR, and open the comboDump example. The Arduino code should open in a new window. What you see before you is a short program that will allow your Seeeduino XIAO to receive IR signals that you transmit to it, decode them and display them in your serial monitor.

Before we use the code, we have to edit the pin for our IR receiver. Edit the IRrecv declaration line to the pin number that your IR receiver is attached to. For us, since we are using D5, we will use 5.

#include <IRLibRecv.h>
IRrecv myReceiver(5);  //pin number for the receiver <- Change this to our pin number

Then, change the parameter in the myDecoder.dumpResults() function to false. This will reduce the amount of detail that is displayed to us by the IR signal decode, since we won’t need that today.


Finally, upload the code to your Seeeduino XIAO with the button shown below.

Then, open the Arduino Serial Monitor with the magnifying glass button on the right. If all goes well, you should see “Ready to receive IR signals” printed out. This indicates that our serial connection between the Seeeduino XIAO and the computer has been established.

Getting the IR Codes from our Base Remote

By this point, I hope you’ve decided on a device that you want your universal Arduino IR remote to control. Whatever it is, grab it’s original remote – For example, if you want to control your music player, you will need to use the music player’s remote to get the IR codes.

With the program on your Seeeduino XIAO still running and the Serial Monitor open, press the button that you want to get the IR code for on the remote. Make sure to direct it straight at your IR receiver for the best results!

On your Serial Monitor, the following may be printed out:

Decoded NEC(1): Value:FD807F (32 bits)

The letters that come immediately after “Decoded” indicate the protocol used. In the example above, the protocol is NEC. The “Value” is the hex code of the IR signal received by our receiver, which is “FD807F” in this case.

In essence, if this was the result from us pressing the power button on our music player’s remote, then this is the same hex code that we must transmit on our Seeeduino XIAO IR remote to turn our music player on. Quite straightforward, right?

Now, all you have to do is to repeat the steps until you have the hex codes for all the controls that you want to have on your Seeeduino remote.

This is an example of what you should end up with. Your own codes will almost certainly be different!

Play / Pause40BFF20D
Volume Up40BFA05F
Volume Down40BFF00F

Note: For the best results, ensure that there are no other IR signals being actively sent around your room. Otherwise, the hex codes obtained may not be accurate.

Writing the Remote Program

Now that we’ve collected the hex codes that we want to transmit for each button, we will have to write our Arduino code for our Seeeduino XIAO. The basic idea is that upon each button press, the Seeeduino XIAO will transmit a given IR signal based on a predefined hex code.

First, copy the entire code below into a new Arduino sketch.

// Set Up Display Libraries
#include <Arduino.h>
#include <U8x8lib.h>
U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);

// Function for printing callbacks 
void displayScreen(String message) {
    u8x8.setCursor(0, 0);

// Set Up Key Control Libraries
#include "SoftwareSerial.h"
#if defined(ARDUINO_ARCH_AVR)
#define SERIAL Serial
SoftwareSerial mySerial(2,3);
#define TRANS_SERIAL mySerial
#elif defined(ARDUINO_ARCH_SAMD)
#define SERIAL SerialUSB
#define TRANS_SERIAL Serial

// Set Up IR Libraries
#include <IRLibSendBase.h>    // First include the send base
//Now include only the protocols you wish to actually use.
//The lowest numbered protocol should be first but remainder 
//can be any order.
#include <IRLib_P01_NEC.h>
#include <IRLib_P02_Sony.h>   
#include <IRLibCombo.h>     // After all protocols, include this
// All of the above automatically creates a universal sending
// class called "IRsend" containing only the protocols you want.

// Now declare an instance of that sender.
IRsend mySender;

#define IR_SEND_PWM_PIN D0

void setup() {
    // Setup Display

    // Setup UART Serial for Buttons


void loop() {

void sendControls() {
    while(TRANS_SERIAL.available()) {
        uint8_t data =;
        switch(data) {
            case 0xE1 :
                mySender.send(NEC, 0x40bf12ed, 20);
            case 0xE2 :
                mySender.send(NEC, 0x40bff20d, 20);
            case 0xE3 :
                mySender.send(NEC, 0x40bfa05f, 20);
                displayScreen("Volume Up");
            case 0xE4 :
                mySender.send(NEC, 0x40bff00f, 20);
                displayScreen("Volume Down");

If you connected your IR transmitter differently from the previously shown schematic, you’ll have to edit your IR emitter’s pin declaration.

#define IR_SEND_PWM_PIN D0

Then, to edit this code to work on your Seeduino XIAO for your target device, you will have to edit the sendControls() function.

void sendControls() {
    while(TRANS_SERIAL.available()) {
        uint8_t data =;
        switch(data) {
            case 0xE1 :
                My_Sender.send(NEC, 0x40bf12ed, 20);
            case 0xE2 :
                My_Sender.send(NEC, 0x40bff20d, 20);
            case 0xE3 :
                My_Sender.send(NEC, 0x40bfa05f, 20);
                displayScreen("Volume Up");
            case 0xE4 :
                My_Sender.send(NEC, 0x40bff00f, 20);
                displayScreen("Volume Down");

Each case represents the behaviour that we want our remote to have for each button press. 0xE1 represents button number 1 on our Grove 12-Channel Capacitive Touch Keypad, 0xE2 for 2, 0xE3 for 3 and so on.

Let’s take the first case as an example:

When the “1” button on our keypad is pressed, we will trigger case 0xE1. First, the corresponding IR signal is sent!

mySender.send(NEC, 0x40bf12ed, 20);

The mySender.send() function takes in 3 parameters: Protocol, Command, No. of Bits. This protocol should correspond to the one you’ve found earlier while decoding your original remote’s IR codes.

You’ll also notice that our hex codes have an additional “0x” appended at the head. This is for Arduino to recognise that the code is in hexadecimal format. Finally, the final input refers to the number of bits that a protocol uses. In general, 20 is okay and you can leave it as is.

Flash the Final Program!

Once you’re done editing the code, remember to flash the final product to your Seeeduino XIAO! You’ll now have a working universal Arduino IR remote in your hands. If you find that your remote doesn’t control your target devices as intended, you may have to repeat the decoding process to obtain the hex codes, taking care to avoid external IR noise this time.

In this example, I’ve only used 4 of the 12 keys on the touchpad, so you can definitely add more commands to your remote! What’s interesting is that you could add different hex codes for controlling different devices into your program. That way, your Seeeduino XIAO IR remote can be used to control multiple devices!


And that wraps up our tutorial on how to create a universal Arduino IR remote with Seeeduino XIAO! You’ll find that the Seeeduino XIAO, even with its expansion board, still provides a great form factor for small electronics like this IR remote project. In addition, the expansion board offers a JST 2.0 connector, so you can add a 3.7V LiPo battery to make this project mobile!

What will you control with your brand new remote? Let us know in the comments!

For more Seeeduino XIAO project ideas, check out the following links:

Also be sure to take a look at our Seeeduino XIAO 2021 Recap and Update!

About Author


February 2021