Projects Research & Design Hub

Build an iPad-Based IR Remote (Part 1)

Written by Brian Millier

The Original Design and IR Code Protocols

Brian built an iPad-based IR “learning” remote, and you can too. In the first part of this series, he presents the original design concepts and sheds some light on the theory behind IR code protocols.

  • How to build an iPad-based IR “learning” remote,

  • How to develop the IR code transmitter

  • How to adapted the iOS  iOS “Mote” app

  • How to do the IR code analysis

  • ESP8266 SMT module and FTDI Friend module from

  • Atmega1284P MCU from Microchip (formerly Atmel)

  • TSMP-1138 IR Receiver and TSAL6400 IR LED from Vishay

  • Mote IOS App from Worried Cat LLC

  • ESP8266 AT Command firmware flasher program (v0.9.2.2 AT Firmware.bin) from XESS

Most of us have many IR remotes associated with what is now referred to as our home media center. Often the IR remote supplied with the cable company’s set-top box or DVR can emulate some of the functions of the other devices. Of course you have to take the time to figure out how to program it to do this. But, in trying to become more universal, these remotes have become larger and loaded with 30 or so small buttons. My eyesight is still pretty good, but I do need reading glasses to identify the function of a lot of these buttons. And, if I am viewing TV in a darkened room, it is difficult or impossible to read these buttons in the dark.

Equally important is the issue of older people who have trouble figuring out how to get their TV to show content from a DVD player, media streaming box, or DVR due to the complexity. I thought that a good way to solve most of these problems would be as follows. You could use a touch screen to display the buttons: not a tiny one as used on some expensive universal IR remotes, but a 4″-to-10″ touchscreen as found on an iPhone or iPad. In addition, make the buttons large and label them with either with an easily-read caption or a standard icon in the case of the “transport” controls associated with DVD players, DVRs, or other devices. You also can group the buttons into different screens. One screen would handle the TV and possibly the home theater receiver. Another screen would be for the DVD player. Another screen would be for a media streaming box. Lastly, eliminate all of the buttons found on the factory-supplied remote that are almost never used. When is the last time you selected a TV channel number by entering the two or three digits on the remote’s numeric keypad?

My first design of such a controller used an “intelligent” 4.3″ touch screen display and an Atmel AVR microcontroller (see Photo 1). It was housed in an extruded aluminum enclosure, which was a bit bigger than a conventional IR remote, but still quite usable. It performed very well, but the cost of 4.3″ touch screens at that time was significant. I was writing a series of articles about these touch screen displays at the time, so their cost was not an issue for me. However, I felt it would discourage many Circuit Cellar readers, so I didn’t write up this project.

photo 1 An early version of my LCD touchscreen IR remote control.
photo 1
An early version of my LCD touchscreen IR remote control.

When I designed a second unit for the bedroom TV, FTDI (who make those USB ICs that we all use) had introduced a new touch screen controller chip, the FT800. The FT800-based 4.3″ touch screen that I used in my second remote controller was only half as expensive as the unit in the first model. This unit is illustrated in Photo 2.

Photo 2 Another version of my LCD touchscreen IR remote control. The FT800 display does not readily support Portrait mode, so this remote looks different than your usual IR remote.
Photo 2
Another version of my LCD touchscreen IR remote control. The FT800 display does not readily support Portrait mode, so this remote looks different than your usual IR remote.

I’m a big fan of Apple’s iPod Touch and iPad, which I’ve had as long as they have been available. The thought had not escaped me that it would be nice to use one of these devices instead of the custom-designed IR remotes mentioned earlier. I always have my iPad with me whenever I am watching TV, if for nothing else than Googling the answer to some question that comes up while watching a show. From this point on in the article, I will refer only to an iPad, but you could use other Apple iOS devices like the iPhone or iPod Touch.

There were three important issues that had to be addressed before this idea could work. One, none of the iOS devices contain an IR LED to transmit the IR codes to the TV and so on. So this must be implemented separately from the iOS device itself. Two, you need the ability to be able to write (or obtain) an iOS app with a user interface containing buttons, sliders, and so on that can be readily tailored to model the appearance/functionality of various IR remote controls. Three, you need to be able to replicate the IR codes coming from all of your various IR remotes. As I’ll outline later in the article, this is not a trivial task. Let’s look at these issues individually.


It is obvious that I needed a separate box containing an IR Led to send the IR codes to the TV and other devices. We also need a method of sending the commands (arising from pressing “buttons” on the iPad’s touchscreen) over to this box. I’ll discuss it in more detail later, but another function of this external box will be to receive the IR codes coming from your various remotes during the initial “learning” phase of operation (which happens only once, during the initial learning phase).

The only practical way to communicate between the iPad and the external IR box is via Wi-Fi. This is basically due to the fact that the iOS application that I wanted to use doesn’t support Bluetooth or Bluetooth LE.

It turns out that implementing the Wi-Fi function in the external IR control box is inexpensive and pretty easy to understand using the recently introduced Adafruit Industries ESP8266 Wi-Fi module. Depending upon the vendor, these modules can be obtained for $2 to $7. While these modules contain a complete ARM-based system on chip (SoC), which can be programmed to act as a stand-alone processor, there is Wi-Fi-to-serial bridge firmware preprogrammed into the module when you get it, and that is what I chose to use for this project. I chose to operate the ESP8266 module in the Station mode. That is, it is configured to connect to the existing wireless access point (router), in your home, and messages from the iPad to the IR transmitter box all go through your router. The button commands sent from the iPad are received by the ESP8266 module and are then sent by the ESP8266 UART port to the microcontroller that I use to control the IR LED emitter.


Unless you are actively involved in writing iOS apps, it is unlikely that you would be able to write a program that would do what this project needs. You would have to download Apple’s Xcode IDE and learn Objective C as well as some APIs. While I am constantly adapting to new microcontrollers and programming languages, I couldn’t quickly come up to speed in this environment. Luckily, there is a low-cost iOS app called “Mote,” which enables you to design various remote control “screens” using a drag and drop interface. After you lay out your remote control, you can “attach” to each button/slider a command string that will be transmitted by the iPad over Wi-Fi. You can select among various transmission protocols such as UDP, TCP/IP, or HTTP. You can design as many “screens” as you wish. I usually use one screen per physical IR remote that I am emulating. There are handy options, like a repeat option which repeats a command at various rates, if you keep a particular button pressed for more than an instant. This is useful for scrolling through menus, adjusting volume, and so on. There are also gesture options available such as the common “swipe” gesture used on iOS devices. Photo 3 shows two of the remote screens I designed for this project. You’ll note that I have not defined buttons for all of those seldom-used buttons on the actual remote, as I mentioned earlier. The Mote iOS app comes with excellent instructions describing how to set up your remote screen layout, so I won’t attempt to explain this in the article.

Photo 3 Here are a couple of remote control layouts as they appear on my iPad screen.
Photo 3
Here are a couple of remote control layouts as they appear on my iPad screen.

I decided to use a very simple command protocol. I assign each button an integer number value, and I send it out as an ASCII string when that button is pressed. I make no distinction as to what IR remote control a button is associated with. I assign each necessary button on each of the IR remotes its own unique number. When I am in the IR code learning mode, I enter that number and then press that button on the remote. The microcontroller firmware then analyzes/saves that IR code into an EEPROM table that is indexed by that button’s number. Later, in operational mode and when that button number is received from the iPad, the firmware merely looks into this table using the button number as an index and sends out the proper IR code. The actual analysis of an IR code is quite involved, and will be described next.


You could write a book about IR codes alone. There are currently many different protocols used, and there will undoubtedly be more introduced in the future. There are several methods that can be used to develop a “universal” IR remote control, not all of which are practical for individuals who are designing their own unit from scratch. Let’s review some these methods.

There are companies like Zilog who sell the CrimZon microcontroller, which is specifically designed for IR remotes and is supported with a large Zilog database of existing protocols. This is not a viable solution for individuals designing a custom remote for their own purposes.

You can access the publicly available IR code database known as the Linux IR Code (LIRC) database. This is a well-established database that is maintained on an ongoing basis by volunteers, in a “crowd-sourced” manner. This database is associated with application programs that were originally designed to run on Linux-based computers. These programs allow you to “record” codes from any IR remote, using an IR receiver module, and then store them in a file using the standardized LIRC format. There are matching firmware programs that run on various microcontrollers and SBCs that use the information from this database to transmit the IR codes via an IR LED connected to a microcontrollers I/O port pin. For the two touchscreen IR remote controllers that I designed and discussed earlier, I used a Raspberry Pi SBC running Linux to record the codes of my various IR remotes into a LIRC database format. Listing 1 shows part of a sample LIRC table for a Sony device. The first section, beginning with name SONY contains 11 attributes of the IR code itself (other remotes can use more attributes than the ones shown). The second section (“begin codes”) contains the actual data pattern that is distinct for each button. Each value can be from 8 to 32-bits in length. Writing code to handle all of the various permutations of this IR code characterization scheme is not trivial in my experience.

Listing 1
This is a printout of a typical LIRC database. In this case it describes the IR code structure used by a Sony RM-VZ950T. Only a few of the button codes are shown here, for space purposes.

# brand:                                      SONY          
# model no. of remote control:                RM-VZ950T
# devices being controlled by this remote:    VDR 1.1.20

begin remote

   name SONY
   bits           11
   eps            30
   aeps          100

   header       2459   551
   one          1260   534
   zero          667   534
   ptrail        668
   gap          44921
   min_repeat      3
   toggle_bit      0

       begin codes
          KEY_POWER                0x0000000000000548        #  Was: POWER
          KEY_1                    0x0000000000000008        #  Was: 1
          KEY_2                    0x0000000000000408        #  Was: 2
          KEY_3                    0x0000000000000208        #  Was: 3
          KEY_4                    0x0000000000000608        #  Was: 4
          KEY_5                    0x0000000000000108        #  Was: 5
          KEY_6                    0x0000000000000508        #  Was: 6
   …... other codes follow 

You can write your own firmware that allows a microcontroller interfaced with an IR receiver module to analyze the various IR codes sent out by all of your remotes. It can then store these codes in basically a “raw” format. That is, you make no assumptions about the actual protocol used by the remote, and instead measure each IR pulse train and spacing interval individually, and store this code as a long list of pulse parameters and inter-pulse space times. Doing it this way requires five to 10 times more memory space than what you could achieve using the fairly comprehensive LIRC code definition structure. However, it is very close to being truly “universal” in terms of what remotes it will work with.

Recently, I found that the IR codes used by my newly installed cable TV set-top box could not be analyzed by the LIRC “record” program running on my Raspberry Pi. This set-top box is a new model that operates as an IP-TV receiver, fed by the telephone company fiber optical cable, run right into my home. The point I am trying to make is that, despite the popularity and wide support of the LIRC database, there are times when it is not yet ready to handle brand-new devices. For this reason I decided to go with the third option for this project, since my earlier LIRC-based touchscreen remotes would not work with my new TV set-top box.


Regardless of the protocol used, all IR remotes operate by sending pulses of IR light separated in time from each other. The “pulse” of IR light is actually amplitude modulated at some carrier frequency—that is, the IR light is not steady throughout the pulse interval. The common carrier frequencies are generally between 35 and 40 kHz, but they can go as low as 25 kHz or as high as 56 kHz. Photo 4a is a screen capture from my oscilloscope connected to the Vishay Intertechnology TSMP-1138 IR receiver that I use in this project. You can see the overall pulses, along with the different spaces between the pulses. It is the inter-pulse spacing, in this case, that defines the data pattern. Photo 4b shows the same IR signal, but I increased the horizontal sweep speed markedly. You can see the individual cycles of the IR carrier. I placed vertical cursors to define one complete cycle, and the actual carrier frequency of 37.04 kHz shows up in measurement window at the lower left of the display. Note that the TSMP-1138 outputs a high logic signal in the absence of a signal, and it drops low when an IR signal is present.

Photo 4 a—This is a typical IR signal as it is presented at the TSMP-1138's output pin. b—This is a portion of the signal shown in Photo 4a at a sweep rate that allows you to see individual cycles of the 37-kHz IR carrier.
Photo 4
a—This is a typical IR signal as it is presented at the TSMP-1138’s output pin. b—This is a portion of the signal shown in Photo 4a at a sweep rate that allows you to see individual cycles of the 37-kHz IR carrier.

Modulating the IR pulse in this way allows the use of an IR receiver module which contains a band-pass filter centered around this carrier frequency. This filter makes the receiver module much more immune to stray light, which is constantly present. You have probably been amazed at how flexible you can be regarding the distance between the remote control and the TV, as well as the latitude in aiming it. This is largely due to both the band-pass filter as well as the automatic gain control (AGC) used in the IR receiver module. Another reason the system works so well is that the IR LED in the remote control puts out a strong IR signal, since is run at a high current level of 50 to 100 mA. Since it operates at such a low duty-cycle, the IR LED can easily handle that high a current without over-heating.

The advantages of using a specific carrier frequency, which can be selectively filtered in the IR receiver module, works against us when trying to design a universal “learning” remote. The common IR receiver modules that are available are specified at a specific carrier frequency which is what their internal band-pass filter is tuned to. The output of such modules is a demodulated signal. That is, it outputs a logic LOW signal during the entire time that the modulated pulse is present, and a logic HIGH signal when no IR light is being detected.

For the purposes of “learning” the different IR codes, these modules present two problems. The first problem: You would have to provide a separate IR receiver module for each carrier frequency that was used by the remotes you were trying to emulate. (Practically speaking, you could get by with three modules—25 to 35 kHz, 35 to 45 kHz, and 45 to 56 kHz—but this still isn’t not a good option.) The second problem: Since their output signal output is a demodulated one, you would have no way of knowing what the carrier frequency was for any particular remote control, nor would you know how many cycles of the carrier frequency were used to make up the various pulse lengths needed for the codes.

I discovered that you have to use special IR receiver modules if you want to implement a “learning” remote. These modules are different from the standard IR receiver modules used in consumer devices, in the following ways. One, they have a broader band-pass filter (typically 30 to 60 kHz). Two, they do not demodulate the signal, so you get a output which is a true representation of the modulated pulse waveform. And three, because of the first two features, they are not nearly as flexible, in terms of aiming and distance, as the standard IR receivers. However, in a “learning” mode, you would be aiming your remote directly at this module, over a small distance range of 1 to 3 feet. Under these conditions, these “learning” IR modules work just fine.

Such “learning” IR receiver modules are less common than the usual IR receiver modules that you see which cost about a dollar. However, I found that Vishay makes a few such devices, and I chose the TSMP-1138 for this project. Photo 5 shows this module. Note from its size relative to a dime that it is much larger than the common IR receiver modules used for “non-learning” purposes. Besides being designed for “learning” remotes, these modules are also used in IR “repeaters”—that is, devices that enable you to extend the range of your IR remote to other rooms in the house. Since the TSMP1138 provides an accurate signal representing the true IR code structure, you can transmit it by wire or wirelessly to another room. In the other room, this signal is then used to drive an IR LED, which is pointed at the device to be controlled.

Photo 5 This is Vishay Intertechnology TSMP-1138 “learning” IR remote receiver, shown next to a dime for a sense of its relatively large size.
Photo 5
This is Vishay Intertechnology TSMP-1138 “learning” IR remote receiver, shown next to a dime for a sense of its relatively large size.

Using a TSMP-1138, the microcontroller can expect to get a TTL level signal that is low when IR light is present, and high when it is not. What the microcontroller must measure is basically a time function. How long is the IR light present and how long is it absent? In the AVR microcontroller, there is a 16-bit timer/counter that has an Input Capture function. If you connect the TSMP-1138 to the Input Capture pin, you can measure these time intervals.

If you look at a typical IR code, you can see that what you need to capture is as follows. Let’s review.

One, what is the carrier frequency? This can be measured by waiting until the TSMP1138 signal goes low, capturing that time, and then waiting until the signal goes low again. The difference between these two times is the carrier period, and the carrier frequency is the inverse of this value. It should be noted that the carrier frequency used by any particular remote will be constant. It doesn’t change within a pulse sequence, or between different code sequences.

Two, how many cycles of this carrier frequency make up each pulse? You do this by measuring the times of subsequent falling edges on the Input Capture pin until you find a time difference that is considerably greater than one carrier cycle (at the lowest expected carrier frequency of 25 kHz, or about 40 µs). The total of these falling edges is the number of cycles of the carrier frequency for this particular pulse.

Three, once you have reached the end of a given carrier-modulated pulse, you then measure the amount of time that elapses until the next pulse starts. This is called the Space interval in the LIRC database. In many IR code schemes, the pulses themselves are only “place-keepers”—it is actually the time between the individual pulses that holds the IR code information. The important thing to note here is that the length of these inter-pulse intervals can be much longer than the length of time for a single carrier cycle.

Four, how many pulses are there in one complete IR code? This is not a simple question. Some IR remotes send repeated copies of the applicable code even when the remote button is just quickly tapped. Some of them send the same code twice with the second instance being a modification of the first in some specific way (by toggling one or more bits of the code). There is no easy way of knowing in advance how any given remote will structure its codes. Therefore, in my “learning” firmware routine, I merely continue to record the values associated with items 2 and 3 above until a 2-s timeout interval has elapsed.

There are a few considerations that must be addressed in implementing a firmware routine to implement the above algorithm. Let’s consider couple of important ones.

If we want to accurately measure the carrier frequency (in the 25 to 56 kHz range), we have to measure the TSPM1138 signal transitions with a fairly high resolution. I used a microcontroller clock of 8 MHz. At this frequency, the ATmega1284’s Input Capture function can provide resolutions of 125 ns, 1 µs, 8 µs, 32 µs, and 128 µs (depending upon the clock prescaler). I chose the 1 µs resolution value, which provides sufficient carrier frequency accuracy.

Given the 1 µs resolution of the Input Capture function, you have to consider the longest period of time that can be measured with the 16-bit counter used. This is 65,535 µs, or 65.535 ms. There may be inter-pulse space times greater than this, and there will definitely be intervals greater than this between the “repeat” code transmissions mentioned above. Therefore, it was necessary to attach an interrupt service routine to the timer overflow and count how many times the 16-bit timer overflowed during the interval being timed. This overflow count is a 16-bit variable, making the maximum time interval that could be measured equal to 4259.8 s, well beyond what we might encounter.

All of these parameters for the various IR codes will end up being stored in external SPI flash memory. But, since we are doing very precise timing measurements here, it is impossible to store these values directly to SPI flash, since its write times are in the millisecond range. Therefore, SRAM memory in the ATmega1284P must be used to store the IR code timing parameters. And after each code is “learned,” this data can be transferred to SPI EEPROM memory. Since I couldn’t predict exactly how many pulses might make up IR codes from the various remote controls, I chose the ATmega1284P with 8 KB of SRAM rather than trying to build the project with the common Arduino ATmega328 with only 2 KB of SRAM. When I completed the coding, the SRAM space required by the variables and arrays in my program would have fit into a 2-K SRAM space. But, there was no easy way for me to know how much stack/buffer/heap space might end up being allocated by the Arduino C compiler, so I was justified in using the higher-end AVR microcontroller for this design.

While the analysis routine outlined above sounds quite simple, the actual firmware routine is quite involved. In my Arduino program, the function analyse_IR_Code takes care of this analysis, as well as saving the resulting information to the AT25256 SPI EEPROM. The IR_Learn_Mode routine repeatedly calls this analysis routine, incrementing the button number variable each time through the loop. To keep the program simple, you have to “learn” each button in sequence. However, if you stop the learning process before doing all buttons of all remotes and then start the process again at a later time, the program will restart, displaying the number of the next button in sequence (that has yet to be “learned”). Because of the varying complexity of different IR code schemes, there is no “fixed” number of IR codes that can be learned/stored, but you can expect to be able to store about 100 buttons worth of average complexity codes in the AT25256 EEPROM.

Because I am basically storing “raw” pulse/space data for the IR codes, I believe the routines should be able to handle anything that an IR remote can throw at it, assuming the following. One, the carrier frequency is in the 30 to 60 kHz range of the TSMP-1138 receiver module. Two, I use three integer variables to define each pulse/space combination and reserve an SRAM integer array of 500 such values. So, the IR code can be up to 166 pulses long, which is longer than any codes I have come across so far. Three, the TSMP-1138 receiver module is reasonably good at discerning the individual carrier cycles, but the data-sheet mentions that it may not perfectly replicate the number of carrier cycles per pulse. In my experience, this has not been a problem, but there may be some IR remote controls/IR receiver modules out there which are particularly critical in this respect. I feel this is unlikely considering the wide range of lighting conditions, aiming flexibility and range of usable distances that are accommodated by modern IR remote controls. This flexibility would be hard to achieve if the signal analysis done by the unit’s IR receiver module was so critical that it took the exact carrier cycle count into consideration.


So far, I have covered most of the theory and some practical considerations involved in designing this project. In the second part of this article series, I will start by taking a detailed look at the ESP8266 Wi-Fi module itself, since it is an important part of the overall design. I’ll also explain the full circuitry used in the design, as well as including a short “user’s manual” for the unit. 

Read Part 2 Here

Pridopia, ESP8266 AT Command Set,

ESP8266 SMT module and FTDI Friend module
Adafruit Industries |
Atmega1284P Microcontroller
Microchip Technology (formerly Atmel) |
TSMP-1138 IR Receiver and TSAL6400 IR LED
Vishay Intertechnology |
Mote IOS App
Worried Cat LLC |
ESP8266 AT Command firmware flasher program (v0.9.2.2 AT Firmware.bin)
XESS Corp. |


Keep up-to-date with our FREE Weekly Newsletter!

Don't miss out on upcoming issues of Circuit Cellar.

Note: We’ve made the Dec 2022 issue of Circuit Cellar available as a free sample issue. In it, you’ll find a rich variety of the kinds of articles and information that exemplify a typical issue of the current magazine.

Would you like to write for Circuit Cellar? We are always accepting articles/posts from the technical community. Get in touch with us and let's discuss your ideas.

Sponsor this Article

Brian Millier runs Computer Interface Consultants. He was an instrumentation engineer in the Department of Chemistry at Dalhousie University (Halifax, NS, Canada) for 29 years.

Supporting Companies

Upcoming Events

Copyright © KCK Media Corp.
All Rights Reserved

Copyright © 2024 KCK Media Corp.

Build an iPad-Based IR Remote (Part 1)

by Brian Millier time to read: 18 min