IR receive doesn't work prospectively

I'm trying to build some little thing like laser War (Milestag,maybe some guys from western know).
It use IR to simulate fire , you hit someone by IR instead of color ball or bullet.
I make a simple IR sender and receiver program based on IRLib2.
The hardware based on milestag’s design:

The MCU will be replaced with Nano, use the pin9 as PWM out.
I just use 1 pin to send out, not 2 like the original design( is it the reason leading to failure?).

The receiver did receive the signal send by sender,but received info is not same with sent(even think of tolerance).
Package looks like this:
headmark,space,mark,space,mark,space...
I have printed out the received signal,it is not right:

  1. Total counts is not right, less than sent, and there is no regular pattern;
  2. The time interval is not right. E.g. Headmark should be 2400us,but received is far away from that, actually most of the interval is not right.

The source segments:
Send :

void IRsender::send(uint16_t data) {
//try{
digitalWrite(13,HIGH); //debug
mark(headMark);
space(headSpace);

for (uint8_t i = 0; i <numBits; i++) {
if (data & TOPBIT) {
mark(markOne); space(spaceBoth);
}
else {
mark(markZero); space(spaceBoth);
}
data <<= 1;
}
digitalWrite(13,LOW); //debug

};

#define IR_SEND_MARK_TIME(time) IRLibDelayUSecs(time)
void IRLibDelayUSecs(uint16_t time) {
if(time){if(time>16000) {delayMicroseconds(time % 1000); delay(time/1000); } else delayMicroseconds(time);};
}

void IRsender::mark(uint16_t time) {
IR_SEND_PWM_START;
IR_SEND_MARK_TIME(time);
}

void IRsender::space(uint16_t time) {
IR_SEND_PWM_STOP;
delayMicroseconds(time);
}

Receive:

void IRrecv_Handler(){
uint32_t volatile curUs = micros();
uint32_t deltaUs = curUs - recvGlobal.preUs;
value[idx] = deltaUs;
recvGlobal.preUs = curUs;
if(++idx>Max) NotifyDecode();
}

attachInterrupt(intrNum, IRrecv_Handler, CHANGE);

Can't post picture?

The parts I used is very old, at least 7 years ago I bought them :slight_smile:
TSOP4840, and IR LED from vishay, and the wave length should be same.
Have set to 40KHZ in send program.

It should not be so difficult to just receive the right thing indoor.
What caused it? software or hardware?

Anyone have advice?

continue to find reason.

Now, I just send one mark and one space for 5 times:
IR_SEND_PWM_START;
mark(headMark);
space(spaceBoth);
mark(headMark);
space(spaceBoth);
mark(headMark);
space(spaceBoth);
mark(headMark);
space(spaceBoth);
mark(headMark);
space(spaceBoth);
IR_SEND_PWM_STOP;
headMark = 2400us,spaceBoth = 600us.
this is what I received:
->LOW 2140 ->HIGH 700
->LOW 2664 ->HIGH 356
->LOW 472 ->HIGH 412
->LOW 3004 ->HIGH 384
->LOW 2696 ->HIGH 668
->LOW 2364 ->HIGH 996
->LOW 2096 ->HIGH 1268
->LOW 2092 ->HIGH 1272
->LOW 2092 ->HIGH 1272
->LOW 2088 ->HIGH 1172
->LOW 2192 ->HIGH 1268
->LOW 2096 ->HIGH 1268
->LOW 2092 ->HIGH 1224
the value for low(headmark) should be 2400,and high(space) should be 600.
Obviously,space is too long.
why?

Interrupt to receive is much simple:
void IRrecv_Handler(){
long volatile curUs = micros();
long deltaUs = curUs - recvGlobal.preUs;

//------------debug:

if(digitalRead(recvGlobal.recvPin))
{Serial.print(" ->HIGH ");Serial.println(deltaUs);}
else
{Serial.print(" ->LOW ");Serial.print(deltaUs);}

recvGlobal.preUs = curUs;
recvGlobal.recvBuffer[recvGlobal.idx] = deltaUs;
recvGlobal.idx ++;
if(recvGlobal.idx>=31) recvGlobal.idx =0;
//Serial.println(deltaUs);
return;
}

attachInterrupt(digitalPinToInterrupt(recvGlobal.recvPin), IRrecv_Handler, CHANGE);

No one try IR send & receive?

still fail to receive:

40Khz, TSOP4840, mark:600us,space:600us.

send: mark,space,mark,space
receive:
------------1st------
High: 971960
Low: 448
High: 588
Low: 232
-------------2nd-------
High: 2493252
Low: 984
------------3rd-----------
High: 1196384
Low: 752
-------------4th-----------
High: 1273636
Low: 496
High: 488
Low: 232
problems:
1)lost signal ,should get 4 intervals ,just like 1st or 4th;
2)tolerance is too high, 600-496 ,600-488 , 600-232

the distance between TSOP4840 & TSAL6100 LED does any affection?
In my case ,it is very short,1cm.
But I try the long distance, same problems.

For the receive program is so simple, I don't know what to do now ;).

Maybe I touched something right now.

The signal captured is right now: get 4 intervals every time:
High: 31423160
Low: 792
High: 496
Low: 824
High: 2181648
Low: 840
High: 592
Low: 816
High: 1380520
Low: 820
High: 620
Low: 788
High: 2068008
Low: 596
High: 684
Low: 768

How? I decreased the frequency from 40Khz to 30Khz.
So,Nano can't deal with high frequency interrupt or PWM out?
I did not find explanation on max frequency for interrupt,any one knows?
But, for the TSOP4840 just outputs the original signal square wave, the frequency is very low, I don't think Nano can't manipulate the interrupt in time.

And for the sender(Nano too), it output PWM through pin3 controlled by timer2.
It can't deal with 40KHZ square wave?
I have no oscilloscope, can't check the real output.

Anyway, the tolerance is still too high.

Include all your code here and you may get some suggestions.
You can also look at the datasheet for the ATMEGA328P. There you'll see that fast PWM can operate at upto half the clock speed.
Your use of digitalWrite() etc. could slow things down. Use direct port operations.