A simple IR Tx Rx system - Packet Errors

Hello.

I have tried to make my own little IR transmitter with an ATtiny85 with a 16Mhz external crystal.
I am using a Nano with a TSOP Rx.

I have various TSOP packages…I am lost as to what may be what. I have the following ones available (labels on the back of the package):225 ,386,233,148,322 and currently have a 41 in my breadboard.

They all have a green band (I assume 38Khz) except for the 233 which has a brown/orange band.

I am using my code here to send bytes 0-255 in a loop with a 10ms delay.

My code uses a High then Low period to denote a “1” and a Low Low to denote a “0”.
This was to give the Rx a “rest” so it does not over saturate (as per the data sheet).

TSOP41

I have it so a burst is 600us long at 38Khz giving ~23 cycles per burst.
Each burst is followed by at least a 600us low period.

The datasheet says:
“Minimum burst length 6 cycles/burst”
“After each burst of length A gap time is required of 6 to 70 cycles ≥ 10 cycles”
“For bursts greater than a minimum gap time in the data stream is needed of 70 cycles > 1.2 x burst length”
“Maximum number of continuous short bursts/second 2000”

I thought I had satisfied the above by having always at least a 23 cycle gap after every 23 cycles.

I.e.

When I run my code as shown, it mainly works. I noticed some packets were causing issues, they were not the expected +1 over the last value. I started to log them and collected ~50,000 bytes which occurred ~900 errors.

I plotted a frequency table and can see that the ones that seem to be “wrong” are not random and there seems to be a sway toward ones that had previous numbers with a lot of 1s had a higher failure rate.

How can I eliminate this issue?

Code TX:

int baud = 600;
byte packsize = 8;

void setup() {
  CLKPR = 0     // Clock Pre-scale Register = 0. Clock division factor = 1
          ;

  DDRB = 0
         | (1 << PB1); //Set pin PB1 as output

  OCR1C = 12;    // Counter Max...clock cycles before pin is toggled.
  PLLCSR = 0;

}
void loop() {
  // send the numbers 0 to 256.
  for (byte i = 0; i < 16000; i++) {

    senddata(i);
    delay(10);
  }
}
void senddata(int x) {
  int compare_bits = 0b10000000;
  highbit(); // Startbit.

  for (byte i = 0; i < packsize; i++) {
    if (compare_bits & x) { // if the last bit in x == 1...
      highbit();                   // send a highbit.
    }
    else {
      lowbit();
    }
    compare_bits = compare_bits >> 1; //shift the compare along for the next bit...
  }
}

void highbit() {
  //Turn the 38-40Khz pin ON, delay (baud) and then turn it off.
  // A high bit is 1 adn then 0.


  TCCR1 = 0
          | (1 << CTC1)
          | (1 << COM1A0) //Bits 5 and 4 of TCCR1 (COM1A0 and COM1A1) indicate what to do when comparator == counter
          | (0 << COM1A1)  // When A0 is 1 and A1 is 0, the pin is toggled on a compare.
          | (0 << CS13)
          | (1 << CS12)  // Table 12-5. Timer/Counter1 Prescale Select. Divides the Clock by an amount.
          | (0 << CS11)
          | (1 << CS10);
  delayMicroseconds(baud);
  TCCR1 = 0;
  delayMicroseconds(baud);

}

void lowbit() {
  // Low bit is 00;
  delayMicroseconds(baud);
  delayMicroseconds(baud);
}

Code Rx:

int baud = 600;
int doublebaud = baud * 2;
unsigned int rxd = 0;
byte state;
byte packsize = 8;
long errors = 0;
int last_num = 0;
long total_bytes = 0;

void setup() {
  // put your setup code here, to run once:
  pinMode(8, INPUT);
  Serial.begin(115200);
}

void loop() {
  // put your main code here, to run repeatedly:
  if (!digitalRead(8)) {                 // Hit a start bit...
    delayMicroseconds(1400);

    for (int i = packsize; i > 0; i--) {
      state = !digitalRead(8);
      Serial.print(state);
      rxd = rxd << 1;
      rxd += state;
      delayMicroseconds(doublebaud);

    }
    if (rxd != last_num + 1 && rxd > 0) {
      errors++;
      Serial.print(",E");
    }
    else {
      Serial.print(",O");
    }
    last_num = rxd;
    total_bytes++;
    Serial.print(",");
    Serial.print(rxd);
    Serial.print(",");
    Serial.print(total_bytes);
    Serial.print(",");
    Serial.println(errors);
    rxd = 0;

  }
}

Thank you for any help!

Oh and before I forget, the TSOP has a 0.1uF cap across its Vs and GND and a 100ohm resistor between the supply voltage and the TSOP Rx Voltage Supply pin.

The IRremote library mentions a time shift of up to 100µs(?) between raising and falling edges of the received signal. I'd use that library for a first test, to verify that everything works with a standard protocol. You also can add your own protocol to that library.

Thanks for the suggestion.

Issue being I am using the ATtiny85's Counter to pulse the LED at 38Khz, so the library will not be compatible.

I am guessing I may need to re-think my method somewhat? Maybe the code is causing unwanted delays...maybe interrupts or like like on the Rx side may be a better idea?

Use a scope or logic analyzer, to find out more about the transmitted and received signal shapes. Then you can adjust the transmitter pulse timing to compensate for eventual receiver distortions.

DrDiettrich: Use a scope or logic analyzer, to find out more about the transmitted and received signal shapes. Then you can adjust the transmitter pulse timing to compensate for eventual receiver distortions.

I wish I had the money for one :P.

I have an old HAMEG 20MHz scope...

I am attempting a variation of the Rx code using an interrupt pin.

Feeling a solution may be to read a global variable that reflects if there was a transition (indicating a 1) on the pin from LOW->HIGH.

Made a very quick sketch to test the “theory”. The TSOP output is reversed…it is default HIGH…goes LOW when data is received…

volatile boolean pin_state = false;

void setup() {

  attachInterrupt(digitalPinToInterrupt(3), inter_func, FALLING);
  Serial.begin(115200);
}

void loop() {
  // put your main code here, to run repeatedly:
  for (byte i = 0; i < 100; i++) {
    Serial.print(pin_state);
    pin_state = false;
    delayMicroseconds(600);
  }
  Serial.println("");
}

void inter_func() {

  pin_state = true;
}

Getting this in my monitor :):

1100010110000000000000000000000101000101001000000000000000001001010100000000000000000000000010010101
0000000000000000000000001000010100000100000000000000000010001101000001010000000000000000100010010001
0000000000000000000010001011000100010000000000000000100010100001010000000000000000001000101010010101
0000000000000000100010101000000000000000000000001000101010100001000000000000000010001010101001000000
0000000000001000101010100101000000000000000001001010101010000000000000000000010010101010100000000000
0000000001001010101010100000000000000000010000101010101010000000000000000101000000000000000000000000
0000010100000000000010000000000000000101000000000010000000000000000001010000000000101000000000000000
0101000000001000000000000000000001010000000000001000000000000000010100000000011000000000000000000011
0000000001001000000000000000001000000001000000000000000000000010100000010000010000000000000000101000
0001000100000000000000000010100000010001010000000000000000101000000101000000000000000000001010000001
0100010000000000000000101000000101010000000000000000001010000000010101000000000000000010100000100000
0000000000000000001010000010000001000000000000000000100000100000000000000000000000010000001000001000
0000000000000001000000100010000000000000000000010100001000100010000000000000000101000010001010000000
0000000000010100001000101010000000000000000101000000100000000000000000000001010000011000001000000000
0000000101000001000010000000000000000001010000010100101000000000000000010100000101000000000000000000
0001010000010101001000000000000000000100000101010000000000000000000010000001010101100000000000000000
1000010000000000000000000000000010100100000000010000000000000000101001000000010000000000000000001010
0000000001010000000000000000101000100001000000000000000000001010001000010001000000000000000010100010
0001010000000000000000001010001000010101000000000000000010100010001000000000000000000000001000100010
0001000000000000000001100010001000100000000000000000010000100010001000000000000000000101001000101000
0000000000000000010100100010100010000000000000000101000000101010000000000000000001010001001010101000
0000000000000101000100000000000000000000000001010001010000001000000000000000010100010100001000000000
0000000001010001010000101000000000000000010100010100000000000000000000000001000101000100100000000000
0000000100010100010000000000000000000010000101000101000000000000000000101001010100000000000000000000
0010100101010000010000000000000000101001010100010000000000000000001010000101000101000000000000000010
1000110101000000000000000000001010001001010001000000000000000010100010110101000000000000000000101000
1010010101000000000000000010101000000000000000000000000000101010000000000100000000000000000010100000

Which must be a good start?

Tweaked my code again…sorry…had a moment and may have answered this myself :|. Still open to suggestions!

10000000 0
10000001 2
10000010 4
10000011 6
10000100 8
10000101 10
10000110 12
10000111 14
10001000 16
10001001 18
10001010 20
10001011 22
10001100 24
10001101 26

Looks like you transmit 7 bits only, LSB missing.

Got it!

I was not resetting the boolean flag back to false at the end of the main() so it automatically re-ran it causing a bit to be missed/dropped.

volatile boolean pin_state = false;

byte f = 0;

void setup() {

  attachInterrupt(digitalPinToInterrupt(3), inter_func, FALLING);
  Serial.begin(115200);
}

void loop() {
  f = 0;
  while (!pin_state) {}
  pin_state = false;
  delayMicroseconds(1300);

  for (byte i = 0; i < 7; i++) {
    Serial.print(pin_state);
    Serial.print(" ");
    f += pin_state;
    f = f << 1;
    pin_state = false;
    delayMicroseconds(1200);
  }

  Serial.print(pin_state);
  f += pin_state;
  pin_state = false;
  Serial.print(" ");
  Serial.println(f);

}

void inter_func() {
  pin_state = true;
}
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 1
0 0 0 0 0 0 1 0 2
0 0 0 0 0 0 1 1 3
0 0 0 0 0 1 0 0 4
0 0 0 0 0 1 0 1 5
0 0 0 0 0 1 1 0 6
0 0 0 0 0 1 1 1 7
0 0 0 0 1 0 0 0 8
0 0 0 0 1 0 0 1 9
0 0 0 0 1 0 1 0 10
0 0 0 0 1 0 1 1 11
0 0 0 0 1 1 0 0 12
0 0 0 0 1 1 0 1 13
0 0 0 0 1 1 1 0 14
0 0 0 0 1 1 1 1 15
0 0 0 1 0 0 0 0 16
0 0 0 1 0 0 0 1 17
0 0 0 1 0 0 1 0 18
0 0 0 1 0 0 1 1 19
0 0 0 1 0 1 0 0 20
0 0 0 1 0 1 0 1 21
0 0 0 1 0 1 1 0 22
0 0 0 1 0 1 1 1 23
0 0 0 1 1 0 0 0 24
0 0 0 1 1 0 0 1 25
0 0 0 1 1 0 1 0 26

Thank you very much for the input. I may be back mind! Going to test the hell out of this now.