Sending long AC Signals from Flash with IRremote

One of the most popular projects involving Infrared remote control, is to use an Arduino to control an Air conditioner (AC) system. However, AC signals are usually very long and take up a lot of SRAM on a standard Arduino. Experienced users will go about reverse engineering the AC protocol to make the sketch fit within the 2K Bytes of SRAM. Many hobbyists will struggle, even with the help of tools like AnalysIR to guide them. In this post we cover sending long AC Signals from Flash with IRremote. IRremote (along with IRLib) is a popular open-source library for sending and receiving IR remote control signals with Arduino. The demo code covered in this sketch extends our previous sendRAW example by demonstrating how to store many long AC signals in Flash with little or no SRAM overhead.

AnalysIR screen-shot showing the signals captured from the sendRAW_Flash sketch
AnalysIR screen-shot showing the signals captured from the sendRAW_Flash sketch (click or more detail)

Standard Arduinos (aka Genuinos) typically have 32kB of Flash and 2kB of SRAM and one AC signal can use up all of the available SRAM – leaving little or no SRAM for the rest of the application. In the example sendRAW sketch (IRremote), it is not possible to compile 2 of these long AC signals with the SRAM available. Our example sketch (sendRAW_Flash) takes a different approach by storing the signals in Flash memory and using some IRremote internals to send the signals direct from Flash, instead of SRAM. This allows storage of many more long  AC signals. Of course, experienced users may chose to reverse engineer the AC protocol and write a dedicated sketch that also uses less SRAM and Flash and there are several examples of these approaches to be found by searching our blog.

Sending long AC Signals from Flash with IRremote

Below we step thru the main components of the example sketch and provide a download link for the complete source code. We plan to submit this example for inclusion in the IRremote library which will complement the sendRAWdemo we contributed previously.

#include <IRremote.h>

IRsend irsend;

//Example signals from various Hitachi AC units (very long signals)
const unsigned int AC_irSignal1[] PROGMEM = {3344,1672,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,1254,418,1254,418,418,418,418,418,418,418,1254,418,418,418,418,418,1254,418,418,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,418,418,1254,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,1254,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,1254,418,418,418,1254,418,418,418,418,418,418,418,418,418,1254,418,418,418,1254,418,418,418,1254,418,1254,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,418,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418}; //AnalysIR Batch Export (IRremote) - RAW
const unsigned int AC_irSignal2[] PROGMEM = {3344,1672,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,1254,418,1254,418,418,418,418,418,418,418,1254,418,418,418,418,418,1254,418,418,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,418,418,1254,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,1254,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,1254,418,418,418,1254,418,418,418,418,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,418,418,1254,418,418,418,418,418,1254,418,418,418,418,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,418,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418}; //AnalysIR Batch Export (IRremote) - RAW
const unsigned int AC_irSignal3[] PROGMEM = {3344,1672,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,1254,418,1254,418,418,418,418,418,418,418,1254,418,418,418,418,418,1254,418,418,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,418,418,1254,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,1254,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,1254,418,418,418,1254,418,418,418,418,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,418,418,1254,418,418,418,418,418,1254,418,418,418,418,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,418,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418}; //AnalysIR Batch Export (IRremote) - RAW
const unsigned int AC_irSignal4[] PROGMEM = {3344,1672,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,1254,418,1254,418,418,418,418,418,418,418,1254,418,418,418,418,418,1254,418,418,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,418,418,1254,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,1254,418,418,418,418,418,1254,418,418,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,418,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,418,418,1254,418,418,418,418,418,1254,418,418,418,418,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,418,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418}; //AnalysIR Batch Export (IRremote) - RAW
const unsigned int AC_irSignal5[] PROGMEM = {3344,1672,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,1254,418,1254,418,418,418,418,418,418,418,1254,418,418,418,418,418,1254,418,418,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,418,418,1254,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,1254,418,1254,418,418,418,418,418,1254,418,418,418,418,418,1254,418,418,418,418,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,418,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,1254,418,1254,418,1254,418,1254,418,1254,418,1254,418}; //AnalysIR Batch Export (IRremote) - RAW


void setup() {
  //insert your own setup code here
}

We start off by including the IRremote library and creating an irsend instance to use later on. Next we define a number of long AC signals using “PROGMEM” and “const” to ensure they are stored in flash and not SRAM. For our example we do not need to place any code in the setup function, but most users should place their own setup code here as is normal. As a minimum you should configure your IR send pin as output & LOW. Feel free to change the signal names to suit your application, but remember to change the names everywhere in your sketch. You should be able to fit a large number of signals into FLASH on a standard Arduino and even more on an Arduino Mega 1280/2560.

void loop() {
  //replace this with your own code.
  while (true){ //loop forever sending the test signals, with 5 second gaps
  sendRAW_Flash(AC_irSignal1, sizeof(AC_irSignal1)/sizeof(int),33); //send AC signal #1 @ 33kHz
  delay(5000); //a good idea to have gaps between signals
  
  sendRAW_Flash(AC_irSignal2, sizeof(AC_irSignal2)/sizeof(int),36); //send AC signal #2 @ 36kHz
  delay(5000); //a good idea to have gaps between signals
  
  sendRAW_Flash(AC_irSignal3, sizeof(AC_irSignal3)/sizeof(int),38); //send AC signal #3 @ 38kHz
  delay(5000); //a good idea to have gaps between signals
  
  sendRAW_Flash(AC_irSignal4, sizeof(AC_irSignal4)/sizeof(int),40); //send AC signal #4 @ 40kHz
  delay(5000); //a good idea to have gaps between signals
  
  sendRAW_Flash(AC_irSignal5, sizeof(AC_irSignal5)/sizeof(int),56); //send AC signal #3 @ 56kHz
  delay(5000); //a good idea to have gaps between signals
  }
}

Next we see the “loop” function where we simply create an endless loop to send each of our 5 example signals directly from flash. You will note how we automatically calculate the size of the signal buffer using the compiler (sizeof). In addition, every signal is sent at different carrier frequencies representing each of the standard IR frequencies – i.e. 30, 33, 36, 38, 40 & 56 kHz. Individual signals are sent using our “sendRAW_Flash” function call, which passes the signal buffer, the signal length and carrier frequency as parameters. Users should replace our example code and signals with their own. Tip: you can use AnalysIR to record longer signals than can be recorded with libraries. You will also find an example sketch on our blog which records longer AC signals more accurately.

void sendRAW_Flash(const unsigned int * signalArray, unsigned int signalLength, unsigned char carrierFreq) {

  irsend.enableIROut(carrierFreq); //initialise the carrier frequency for each signal to be sent
  
  for (unsigned int i=0;i<signalLength;i++){
    if (i & 1) irsend.space(pgm_read_word_near(&signalArray[i]));
    else irsend.mark(pgm_read_word_near(&signalArray[i]));
  }
  irsend.space(1);//make sure IR is turned off at end of signal

}

Finally, we see the “sendRAW_Flash” function call. First we set the carrier frequency for transmission using the IRremote function “irsend.enableIROut”. Then we iterate through the signal buffer in flash and send the individual marks and spaces using the internal IRremote functions for mark & space. You will also note the use of the special functions to read directly from Flash (aka PROGMEM). If you are not familiar with these you can search online for details. Finally we send a space of 1 microsecond duration to  ensure the IR carrier is turned off at the end of the signal.

The code above is essentially a very simple sketch which makes use of existing libraries and functions to deliver impressive benefits by saving users valuable SRAM in their sketches. Although the motivation for writing this sketch was primarily for AC signals, it could be used for TV style IR protocols or protocols that are not directly supported by IRremote.

If you are unsure of which pin is the output pin for your IR LED then we suggest a search online or use our IRforum for assistance.

Download the sketch

You can download the full source code for the sketch by clicking here.