I have tried to follow along/reproduce the results from several sources for emulating the Nikon infrared remote trigger:

I can read the signal from my remote trigger, but I cannot reproduce it with my Arduino setup. The signal I can receive (w/ TSOP38238 receiver diode) matches all of the signals given by the links above (there is some expected variance in pulse durations).

I don't think my hardware is at fault:

  • TSOP38238 receives @ 950 nm
  • my IR LED is 940-950 nm per datasheet
  • my IR LED works (I can see it emitting when I point it at my phone camera)


simulate this circuit – Schematic created using CircuitLab

My Code:

I have tried the code given in the links above, most don't use Port Manipulation and instead trial-and-error the delay durations to account for the overhead in Arduino functions. I have experimented with different values of the wait variable (8-13 microseconds) but have not gotten it working so far. I prefer to have my code versatile like this (no hard coded durations) so I can use it with other remotes in the future.

uint16_t Signal[] = [2050, 27800, 430, 1650, 430, 3650, 430, 65000]; // ON & OFF pulse durations (microseconds)
uint8_t wait = 13; // duration (microseconds) between pin state changes

// the setup function runs once when you press reset or power the board
void setup() {
    DDRB = B00000001; // set digital pin 8 to output
    PORTB = B00000000; // set digital pin 8 LOW
    Serial.begin(9600); // start serial monitor

// the loop function runs over and over again forever
void loop() {
    delay(1500); // wait a bit between sending signal
    // send signal twice, this is what the actual remote does
    Serial.println("Signal sent"); // message saying signal was sent

// function that sends the signal
void sendSignal(void) {
    for (int i = 0; i < sizeof(Signal)/sizeof(Signal[0]); i++) { // for each element in Signal array
        if (i%2 > 0) { // odd numbered index, is an OFF pulse
            PORTB = B00000000; // set digital pin 8 LOW
            delayMicroseconds(Signal[i]); // delay for OFF pulse duration
        } else { // even numbered index (including i=0), is an ON pulse, 38 kHz (26.3 usec period), 50% duty cycle
            unsigned long currentTime = micros(); // get current time
            while (micros() - currentTime < (unsigned long)Signal[i]) { // while still in ON pulse duration
                PORTB = B00000001; // set digital pin 8 HIGH
                delayMicroseconds(wait); // leave ON for time
                PORTB = B00000000; // set digital pin 8 LOW
                delayMicroseconds(wait); // leave OFF for time

I hold my camera in direct line of sight of the LED (not blocking the receiver on the camera) from distances of ~2in to ~3ft away without success.

Has anyone tried this before? Is there a mistake in my approach or code?

  • 1
    generating an 38kHz signal with delayMicroseconds doesn't result in a very accurate frequency. It's probably lower due to the while loop taking some time to execute. The code provided in you second to last link actually uses 7µs of delay, and uses a simpler for-loop. It also uses a 810µs delay after the first pulse, where your code uses 27800µs
    – Gerben
    Jul 29, 2021 at 15:54
  • @Gerben That link uses delay(27) and delayMicroseconds(810) for a total delay of 27810 microseconds. It also uses digitalWrite instead of port manipulation which is slower. Jul 29, 2021 at 16:35
  • But the delayMicroseconds documentation does say "the largest value that will produce an accurate delay is 16383" so I will try to combine delay w/ delayMicroseconds like that link does. Jul 29, 2021 at 16:41
  • one if the links you posted includes code ... why are you not using it?
    – jsotola
    Jul 29, 2021 at 22:28
  • @jsotola none of the provided code worked for me Aug 8, 2021 at 20:52

1 Answer 1


Got it working. The problems were the delayMicroseconds input being too large (see comments) and the frequency mismatches.

I set up a script to time the code segments of interest and that allowed me to select the best wait duration. It looks like this:

while (i < 256) {
    /* your code to time here */
i = 0;
unsigned long time = 10000000 + micros();

Make sure to time the empty loop and subtract that from your readings w/ code. Take the difference between time read outs, subtract the printing statement overhead (which is dependent on how many digits it is printing, hence the 10000000 + micros() to keep # of digits constant) and divide by 256.

I measured 4 different combinations to find the closest frequency match:

Command Type: Wait duration (micro seconds): Frequency (Hz): % difference from 38 kHz
Port Manipulation 14 36990 -2.7 %
Port Manipulation 13 39960 5.2 %
digitalWrite 11 35980 -5.3 %
digitalWrite 10 38790 2.1 %

The final code ended up looking a lot like the one from this link; counting off cycles of the on-off 38 kHz pulse.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.