Issue Sending IR Signals with Arduino Mega 2560 and IRLib2

Hi all,

I’m struggling with the IR libraries and have tried both IRRemote and IRLib2. I am using an Arduino Mega 2560 board.

I am able to successfully receive IR signals using the "Arduino remote controller" with IRLib2 and the Rawrecv.ino example. However, I am unable to send IR signals with the RawSend example.

To send the signal, I’m using an IR LED, with its anode connected to 5V through a 100-ohm resistor and the cathode connected to ground via an NPN transistor.

I believe the issue lies in the transistor not turning on, as the digital pins on the Mega seem to be inactive. Specifically, I have tried connecting the base of the NPN transistor to each of the available PWM pins (2 to 13) but nothing happens. However, when I connect the base of the transistor to 5V through a resistor, the transistor turns on and the IR LED successfully transmits signals.

Could anyone advise what I might be doing wrong?

Thanks in advance for any help!

What transistor?

The transistor is 2N2222A

I believe the default send pin for mega is 9.
If your transistor worked on your "manual" test, it should work with correct pin.
Use series resistor for base.

Wired like this it should work, but 100 ohm might be a bit low, depending on the max current for the IR LED.

You could check it by replacing the IR LED with a visible light output LED, change R2 to a few 100 ohms, and write a simple LED blink sketch to see if it flashes.

Well, you would run the sketch you're testing with to see if the visible LED flashes. The first question is whether anything is being sent. If it is, then we can deal with what is it sending.

What version of IRRemote are you using? Do your example sketches come from that same version of the library?

i'm currently experimenting with both the IRLib2 (GitHub - cyborg5/IRLib2: Library for receiving, decoding, and sending infrared signals using Arduino) and IRRemote v 4.4.1.

i've successfully managed to send IR signals using the IRLib2 library with the following sketch:

#include <IRLibRecvPCI.h> 
#include <IRLibSendBase.h>    //We need the base code
#include <IRLib_HashRaw.h>    //Only use raw sender

IRsendRaw mySender;
IRrecvPCI myReceiver(2);//pin number for the receiver


void setup() {
  Serial.begin(9600);
  delay(2000); while (!Serial); //delay for Leonardo
  myReceiver.enableIRIn(); // Start the receiver
  Serial.println(F("Ready to receive IR signals"));
}


#define RAW_DATA_LEN 68
uint16_t rawData[RAW_DATA_LEN]={
	9022, 4598, 542, 570, 534, 602, 534, 606, 
	534, 602, 534, 602, 534, 606, 566, 570, 
	530, 606, 538, 1734, 546, 1682, 566, 1682, 
	566, 1682, 566, 1678, 570, 1682, 566, 1706, 
	542, 1706, 542, 1682, 566, 570, 534, 1714, 
	566, 570, 510, 630, 530, 606, 534, 1718, 
	562, 570, 538, 602, 562, 1710, 542, 570, 
	566, 1682, 566, 1706, 542, 1706, 542, 570, 
	542, 1730, 542, 1000};


void loop() {
  //Continue looping until you get a complete signal received
 

    mySender.send(rawData,RAW_DATA_LEN,38);//Pass the buffer,length, optionally frequency
  
    

  if (myReceiver.getResults()) { 
    Serial.println(F("Do a cut-and-paste of the following lines into the "));
    Serial.println(F("designated location in rawSend.ino"));
    Serial.print(F("\n#define RAW_DATA_LEN "));
    Serial.println(recvGlobal.recvLength,DEC);
    Serial.print(F("uint16_t rawData[RAW_DATA_LEN]={\n\t"));
    for(bufIndex_t i=1;i<recvGlobal.recvLength;i++) {
      Serial.print(recvGlobal.recvBuffer[i],DEC);
      Serial.print(F(", "));
      if( (i % 8)==0) Serial.print(F("\n\t"));
    }
    Serial.println(F("1000};"));//Add arbitrary trailing space
    myReceiver.enableIRIn();      //Restart receiver

}

}

The solution was removing BJT base resistance.

This works well for sending signals; however, the raw data I receive is slightly different in length and pattern compared to the original transmission. For example, the received data might look like:

#define RAW_DATA_LEN 100
uint16_t rawData[RAW_DATA_LEN]={
	9106, 4754, 498, 658, 522, 658, 522, 686, 
	522, 666, 518, 682, 522, 670, 566, 626, 
	526, 670, 538, 1810, 530, 1786, 522, 1786, 
	550, 1786, 550, 1750, 562, 1786, 522, 1814, 
	522, 1786, 526, 1786, 550, 630, 526, 1810, 
	550, 638, 490, 714, 498, 714, 490, 1814, 
	550, 630, 522, 686, 550, 1794, 514, 666, 
	542, 1766, 546, 1814, 522, 1782, 526, 634, 
	522, 1814, 522, 1070, 9222, 4706, 518, 630, 
	522, 662, 522, 690, 490, 686, 494, 686, 
	498, 682, 550, 634, 522, 658, 522, 1814, 
	522, 1762, 546, 1750, 534, 1790, 522, 1766, 
	542, 1754, 530, 1000};

Do you have any clue on that?

I also attempted to use the IRRemote library. However, I encountered confusion regarding which pin should control the BJT (even though I tried various PWM pins on the Arduino Mega).
Could you please help me?

For you reference, here is the sketch I'm using with the IRRemote library:


#include "IRremote.h"

int receiver = 2; // Signal Pin of IR receiver to Arduino Digital Pin 11

/*-----( Declare objects )-----*/
IRrecv irrecv(receiver);     // create instance of 'irrecv'
IRsend mySender;

//vairable uses to store the last decodedRawData
uint32_t last_decodedRawData = 0;

/*-----( Function )-----*/
void translateIR() // takes action based on IR code received
{
  // Check if it is a repeat IR code 
  if (irrecv.decodedIRData.flags)
  {
    //set the current decodedRawData to the last decodedRawData 
    irrecv.decodedIRData.decodedRawData = last_decodedRawData;
    Serial.println("REPEAT!");
  } else
  {
    //output the IR code on the serial monitor
    Serial.print("IR code:0x");
    Serial.println(irrecv.decodedIRData.decodedRawData, HEX);
  }
  //map the IR code to the remote key
  switch (irrecv.decodedIRData.decodedRawData)
  {
    case 0xBA45FF00: Serial.println("POWER"); break;
    default:
      Serial.println(" other button   ");
  }// End Case
  //store the last decodedRawData
  last_decodedRawData = irrecv.decodedIRData.decodedRawData;
  delay(500); // Do not get immediate repeat
} //END translateIR


void setup()  
{
  Serial.begin(9600);
  Serial.println("IR Receiver Button Decode");
  irrecv.enableIRIn(); // Start the receiver


}


void loop()  
{

  mySender.sendNEC(0xBA45FF00, 32);

  if (irrecv.decode()) // have we received an IR signal?
  {
    translateIR();
    irrecv.resume(); // receive the next value
  }
}

What value did you remove?
You shouldn't really connect the arduino output pin to the base. A value of 1k should be fine. That would give you about (5v-0.7v) = 4.3V into 1K which will be 4.3mA. If your transistor has a current gain of 10 in saturation then you'd be able to get up to 43mA through the collector.
Assuming the IR LED has a forward voltage of about 1.5V and allowing 0.5V for the saturated transistor, then you'd have 3V across your 100 ohm resistor which would give 30mA through the LED.

Is there a reason why you have to use raw data? I find it easier to look at the decoded output consisting of 3 items: Protocol (e.g. NEC), Address, and Command. Then use the appropriate send function which accepts those parameters.
I can't remember whether or not there's a fourth parameter (length in bits) required for some protocols.
Small variations in the raw protocol values are (AFAIK) just minor timing differences between samples of the same key press.

The typical IR receiver's output is just whether it detects 38KHz carrier or not. But the receiver may not detect aquisition of carrier as rapidly as it detects loss of carrier. So that would result in the On times being shorter than the Off times even though in the transmission they were equal. Even so, the total On+Off time for a bit should be right.

In NEC protocol, the times are actually 562.5us On and Off for a zero bit, and 562.5 and 1687.5us (exactly three times as much) for a one bit. So the total time is 1125us for a zero, and 2250us for a one.

Since the device being controlled only has to distinguish a short Off time from a long one, there can be a good bit of jitter and it will still work.

But I agree with @Dave_Lowther about using address/command if possible. I think a large part of the IRRemote re-write was intended to promote that usage as opposed to the hex strings used before. Also, the old versions dealt with NEC as MSB-first whereas it actually is LSB-first, so LSB-first codes obtained elsewhere wouldn't work.

Edit: Forgot to say - IRRemote doesn't use timer-based PWM unless you tell it to. It bit-bangs the PWM, so you can use any pin for output. I believe the default output pin is D3, but could be misremembering that. In any case, you can specify the input and output pins.

1 Like

Thank you for your valuable feedback and suggestions!

Regarding the use of HEX, I was attempting to read the signal from the Arduino remote controller (for example, the power button is 0xBA45FF00), save it, and then send the same signal again via Arduino.

Currently, I am using the following code to send and receive the signal:

void translateIR() // takes action based on IR code received
{
  
    //output the IR code on the serial monitor
    Serial.print("IR code:0x");
    Serial.println(irrecv.decodedIRData.decodedRawData, HEX);
  irrecv.decodeNEC()
  delay(500); // Do not get immediate repeat
} //END translateIR

void loop()  
{
  mySender.sendNEC(0xBA45FF00, 32);

  if (irrecv.decode()) // have we received an IR signal?
  {
    translateIR();
    irrecv.resume(); // receive the next value
  }

delay(2000);
}

Here’s the behavior I’m observing:

  • When i send 0xBA45FF00, i get 0xFFA25D.
  • When I send 0xFFA25D, I get back 0xBA45FF00.

It seems like these are different codes, possibly because of variations in the protocol being used.I suspect that the issue lies in the receiving/sending protocol mismatch.

Could you advise me on what steps I can take to ensure I receive the exact same signal that I send?

Thanks a lot again

They are the same number. 0xBA45FF00 is probably most-significant-bit first, and 0x[00]FFA25D is the same number, least-significant-bit first.

Back in the day, we dealt with NEC as hex strings, MSB-first, primarily because it just naturally worked out that way since we read and write numbers from left(MS) to right (LS). But in reality the NEC spec calls for just the opposite.

IRRemote.h now deals with hex strings as LSB-first unless you say otherwise. You can call:

IrSender.sendNECMSB()

to use the old-style MSB-first hex strings.

Here's a sketch you can load into a spare Arduino that converts either format into the other.

/*

This sketch converts the bit order of a hex value you type in.
It can convert MSB-first to LSB-first, or vice versa.
Set Serial Monitor line ending to Newline.

*/

unsigned long pointer, output, inverse;
char buff [11];
char d;
int buffSize, i, j;
byte c;

void setup () {
  Serial.begin (9600);
  Serial.println ("Convert between MSB and LSB, both HEX.");
  Serial.println ("Enter up to 8 HEX digits:");
}
void loop() {

  if (Serial.available()) {              // process input from Serial Monitor

    d = Serial.read();                   // set end-line option to Newline or CR
    if ((d == 13) || (d == 10)) {
      buff[buffSize] = 0;
      parse_cmd();
      buffSize = 0;
      buff[0] = 0;
      delay(200);
      if (Serial.available()) Serial.read();  // dump second line end char if present
    }
    else {
      buff[buffSize] = d;
      buffSize++;
    }
  }
}

void parse_cmd() {
  output = 0;
  for (i = 0; i < buffSize; i++) {
    c = buff[i];
    if (c > 0x39) c -= 7;
    c &= 0xF;
    output <<= 4;
    output |= c;
  }
  i = buffSize << 2;

  pointer = 1;
  inverse = 0;

  for (j = 0; j < i; j++) {
    inverse <<= 1;
    if (output & pointer) inverse |= 1;
    pointer <<= 1;
  }

  Serial.print (output,HEX);
  Serial.print ("  ");
  Serial.println (inverse,HEX);
  Serial.println();
}
2 Likes

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.