I have tried to make my own IR transmitter and receiver code.
Currently, the Tx is an ATtiny85 with the IR led on PB1 with a 16Mhz crystal.
Here is the code. It uses Timer1 to make a square wave signal with a set period (38Khz).
The LED is turned on and off using the TCCR1A register.
/*
8Mhz internal clock = 1/(8E6) period = 1.25e-7 seconds = 0.125uS
38Khz period = 1/38E3 = 26.3uS
26.3us / 0.125us = 210.4 ticks per period
half period = 105 ticks...
16Mhz external clock = 1/(16E6) period = 6.25E-8 seconds = 0.0625uS
38Khz period = 1/38E3 = 26.3uS
26.3us / 0.125us = 420 ticks per period
half period = 210 ticks...
*/
#define crystal 16
// Byte value for TCCR1A register to turn LED on with 38Khz carrier.
#define on B00010001
# define off 0
void setup() {
DDRB = 0
| (1 << PB1); //Set pin PB1 as output
if (crystal == 16) {
OCR1A = 210; // Counter Max...clock cycles before pin is toggled.
}
else if (crystal == 8) {
OCR1A = 105;
}
}
void loop() {
for ( unsigned int num = 0; num < 64000; num++) {
send_uint(num);
delay(100);
}
}
void send_uint(unsigned int x) {
unsigned int mask = 0b1000000000000000;
// Use the mask to shift bits out...
TCCR1 = on;
delayMicroseconds(300);
TCCR1 = off;
delayMicroseconds(900);
while (mask) {
if (mask & x) { // A 1 bit = A High, Low, High, Low.
TCCR1 = on;
delayMicroseconds(300);
TCCR1 = off;
delayMicroseconds(300);
TCCR1 = on;
delayMicroseconds(300);
TCCR1 = off;
delayMicroseconds(300);
}
else { // A 0 bit = A High followed by nada.
TCCR1 = on;
delayMicroseconds(300);
TCCR1 = off;
delayMicroseconds(900);
}
mask = mask >> 1;
}
}
Here is my Rx Code using a TSOP38238 IR receiver.
TSOP Datasheet
I noticed the required "cycles" being 10 per burst. So set the ON time for the LED on the Tx as 300us...giving a small headway over the datasheet 264ish uS.
#define bits 16
static unsigned long timeout_time = (bits+1) * 2000;
unsigned long data = 0;
volatile boolean iflag = false;
unsigned long t_start = 0;
unsigned long t_now = 0;
boolean timeout = false;
void setup() {
pinMode(2, INPUT);
pinMode(13, OUTPUT);
Serial.begin(115200);
attachInterrupt(digitalPinToInterrupt(2), fallISR, FALLING);
}
void loop() {
timeout = false;
unsigned long data = 0;
iflag = false;
byte count = 0;
while (!iflag) {} // Wait for an initial start bit...
t_start = micros(); // timeout reference time.
iflag = false; // Reset the interrupt flag.
while (!timeout && (count < bits)) { // While the timeout is false ...(packet is of set time length)
count++;
while (!iflag) {} //wait for a signal
iflag = false;
delayMicroseconds(1050); // wait for the second pulse...
if (iflag) { // If there was a second pulse...
data += 1; //Add 1 to end of data.
iflag = false; // Reset the flag ready for next detection...
}
data = data << 1; // shift left ready for next reading...
if (micros() - t_start > timeout_time) {
timeout = true;
}
}
data = data >> 1;
Serial.print(data);
Serial.print(" ");
Serial.println(data, BIN);
}
void fallISR() {
iflag = true;
}
Example Serial output I get when using 16Mhz:
5756 1011001111100
5757 1011001111101
5758 1011001111110
5759 1011001111111
5760 1011010000000
5761 1011010000001
5762 1011010000010
5763 1011010000011
5764 1011010000100
5765 1011010000101
5766 1011010000110
5767 1011010000111
5768 1011010001000
5769 1011010001001
5770 1011010001010
5771 1011010001011
5772 1011010001100
5773 1011010001101
5774 1011010001110
5775 1011010001111
5776 1011010010000
5777 1011010010001
5778 1011010010010
My issues are as follows:
- On using the 8Mhz internal oscillator of the ATtiny85...I get rubbish. I DO get data...but it is all crap.
- I can not seem to use any speed faster than sending data every 100ms. I tried "50ms" delay between sends and get no Serial Output at all.
I think it may have something to do with over saturating the reciever.
Worst case is I send about 30 cycles every 1 bit. I send 16 bits...so about 30 x 16 = 480 cycles in a packet transmission.
If I send 10 packets (100ms delay) I am already pushing the TSOP over its spec? That is 4800 cycles a second...the data sheet says this: