I'm trying to make an arduino infrared remote control receiver and I'm getting incorrect results.
I have started with a basic program taken from Sensor tutorials - IR remote receiver/decoder tutorial that runs in a while loop and measures the length of the signals. From its output I understood that the remote key starts with a ON signal of ~9000 us followed by ~4000us OFF signal. I found an IR receiver code based on interrupts, posted by someone on his/her blog that was written to communicate with another arduino through IR. I made some changes to it to support receiving remote control keys.
Since I'm only at the beginning I decided to output every signal trough serial com. I didn't clean up the code since I'm more interested in making it work first. I'm posting the entire code for anyone that would like to help, but also with the idea that would give a starting point for someone that wants to do something similar.
Hardware: IR receiver connected to D2 on the arduino along with a pull-up resistor.
Software:
const byte LED_HIGH = 13;
byte readyToSend = false;
#define IR_PIN_BANK PIND
#define IR_PIN 2
const byte isrBitLen = 80;
unsigned int signalsLen = 0;
unsigned int signals[isrBitLen];
unsigned int signalsOn[isrBitLen];
unsigned int signalsOff[isrBitLen];
void setup()
{
pinMode (LED_HIGH, OUTPUT); // so we can update the LED
pinMode (IR_PIN, INPUT); //read the IR
digitalWrite(IR_PIN, HIGH);
Serial.begin(9600);
Serial.println("Starting");
// TIMSK1|=0x01; // enabled global and timer overflow interrupt;
TCCR1A = 0x00; // normal operation page 148 (mode0);
TCNT1=0x0000; // 16bit counter register, set to 0
TCCR1B = 0x02; // start timer/ set clock 8 prescalar - for 16mhz this means a overflow at every ~40 ms
attachInterrupt (0, pinChange, CHANGE); // attach interrupt handler
}
ISR(TIMER1_OVF_vect) {
TIMSK1&=0x00;
readyToSend = true;
digitalWrite (LED_HIGH, HIGH^digitalRead(LED_HIGH));
}
// helper functions
unsigned long elapsedSince(unsigned long since, unsigned long now)
{
return since < now ? now-since : 0xFFFFFFFFUL - (now - since);
}
unsigned long elapsedSince(unsigned long since)
{
return elapsedSince( since, micros() );
}
// iSOBOT IR protocol timing
#define TimeStartOnJvc 9500
#define TimeStartOffJvc 4000
#define TimeZeroOnJvc 600
#define TimeZeroOffJvc 550
#define TimeOneOnJvc 600
#define TimeOneOffJvc 1600
#define TimeEnd 600
#define IsSignal(t,x) (true) //for testing purpose
#define IsSignalOneOn(t) IsSignal(t,TimeOneOnJvc)
#define IsSignalOneOff(t) IsSignal(t,TimeOneOffJvc)
#define IsSignalZeroOn(t) IsSignal(t,TimeZeroOnJvc)
#define IsSignalZeroOff(t) IsSignal(t,TimeZeroOffJvc)
#define IsSignalStartOn(t) IsSignal(t,TimeStartOnJvc)
#define IsSignalStartOff(t) IsSignal(t,TimeStartOffJvc)
#define IsSignalEnd(t) IsSignal(t,TimeEnd)
enum
{
ISR_IDLE, // nothing is/was happening (quiet)
ISR_START, //ready to receive
ISR_START_ON, // start of sequence, was waiting for a header signal
ISR_START_OFF, // start of sequence, was waiting for a header signal off
ISR_BIT_ONE_ON, // transsmitting a bit (IR carrier turned on)
ISR_BIT_ONE_OFF, // transsmitting a bit (IR carrier turned on) - end of bit 1 transmission
ISR_BIT_ZERO_ON, // in an OFF bit slot (IR carrier turned off)
ISR_BIT_ZERO_OFF // in an OFF bit slot (IR carrier turned off) - end of transmission for bit 0
}
isrState = ISR_IDLE;
unsigned long isrLastTimeStamp;
unsigned long isrRcvCmd;
unsigned long isrNewCmd;
byte isrBitCnt;
void pinChange()
{
TCNT1 = 0; //reset timer1
readyToSend = false;
// receiving a modulated IR signal makes the pin go low (active low)
byte bIrSignalOn = (! (IR_PIN_BANK & _BV(IR_PIN)));/*(PIND & (1<<2)) == 0;*/
unsigned elapsed;
{
unsigned long timeStamp = micros();
elapsed = elapsedSince(isrLastTimeStamp,timeStamp);
isrLastTimeStamp = timeStamp;
}
if (signalsLen < isrBitLen)
{
if (bIrSignalOn)
{
signalsOn[signalsLen] = elapsed;
}
else
{
signalsOff[signalsLen] = elapsed;
}
//signals[signalsLen] = elapsed/100;
switch( isrState )
{
case ISR_IDLE :
if( bIrSignalOn )
{
isrState = ISR_START;
}
break;
case ISR_START:
signals[signalsLen] = elapsed;
isrBitCnt = 0;
isrNewCmd = 0;
if(/*!bIrSignalOn && */IsSignalStartOn(elapsed) )
isrState = ISR_START_ON;
else
isrState = ISR_IDLE;
break;
case ISR_START_ON:
signals[signalsLen] = elapsed;
isrBitCnt = 0;
isrNewCmd = 0;
if(/*bIrSignalOn && */IsSignalStartOff(elapsed) )
isrState = ISR_START_OFF; // bits are now rolling
else
isrState = ISR_IDLE; // wrong timing of start or pin state
break;
case ISR_BIT_ONE_OFF:
case ISR_BIT_ZERO_OFF:
case ISR_START_OFF:
signals[signalsLen] = elapsed;
// if(bIrSignalOn)
// {
if (IsSignalOneOn(elapsed))
{
isrState = ISR_BIT_ONE_ON;
}
else if (IsSignalZeroOn(elapsed))
{
isrState = ISR_BIT_ZERO_ON;
}
else
{
isrState = ISR_IDLE; // bad state
}
// }
// else isrState = ISR_IDLE; // bad state
break;
case ISR_BIT_ONE_ON:
case ISR_BIT_ZERO_ON:
signals[signalsLen] = elapsed;
// if( !bIrSignalOn )
// {
if (isrState == ISR_BIT_ONE_ON && IsSignalOneOff(elapsed))
{
isrState = ISR_BIT_ONE_OFF;
isrNewCmd |= 1;
}
else if (isrState == ISR_BIT_ONE_ON && IsSignalZeroOff(elapsed))
{
isrState = ISR_BIT_ZERO_OFF;
isrNewCmd |= 0;
}
else
{
isrState = ISR_IDLE; // bad state
}
isrNewCmd <<= 1;
isrBitCnt ++;
// }
// else isrState = ISR_IDLE; // bad state
break;
}
TCNT1 = 0; //reset timer1
}
else
{
readyToSend = true;
}
signalsLen++;
TIMSK1|=0x01;
}
void loop()
{
unsigned long rcv = 0;
if (readyToSend)
{
if (signalsLen > 0)
{
TIMSK1&=0x00;
Serial.print("signalsLen = ");
Serial.println(signalsLen);
for (int j = 0 ; j < signalsLen && j < isrBitLen; j++)
{
Serial.print(signals[j]);
Serial.print('.');
}
Serial.println("Cmd = ");
Serial.println(isrNewCmd);
Serial.println("On");
for (int j = 0 ; j < signalsLen && j < isrBitLen; j++)
{
Serial.print(signalsOn[j]);
Serial.print('.');
}
Serial.println('.');
Serial.println("Off");
for (int j = 0 ; j < signalsLen && j < isrBitLen; j++)
{
Serial.print(signalsOff[j]);
Serial.print('.');
}
Serial.println('.');
signalsLen=0;
}
readyToSend = false;
}
}
First output, after reset:
Starting
signalsLen = 1
0.Cmd =
0
On
13616..
Off
0..
signalsLen = 71
8996.4336.644.484.652.484.644.476.640.496.636.1592.636.496.616.1612.656.460.668.1564.640.1592.624.1604.652.1576.656.472.652.1580.672.452.676.1552.632.508.632.488.640.1588.656.1580.652.468.668.472.648.484.652.460.672.1560.668.1568.660.456.672.456.656.1588.640.1580.652.1588.656.1568.668.40160.8992.2152.640.Cmd =
4294967294
On
13616.4336.0.484.0.484.0.476.0.496.0.1592.0.496.0.1612.0.460.0.1564.0.1592.0.1604.0.1576.0.472.0.1580.0.452.0.1552.0.508.0.488.0.1588.0.1580.0.468.0.472.0.484.0.460.0.1560.0.1568.0.456.0.456.0.1588.0.1580.0.1588.0.1568.0.40160.0.2152.0..
Off
8996.0.644.0.652.0.644.0.640.0.636.0.636.0.616.0.656.0.668.0.640.0.624.0.652.0.656.0.652.0.672.0.676.0.632.0.632.0.640.0.656.0.652.0.668.0.648.0.652.0.672.0.668.0.660.0.672.0.656.0.640.0.652.0.656.0.668.0.8992.0.640..
Same remote key pressed the second time:
signalsLen = 1
45976.Cmd =
4294967294
On
45976..
Off
8996..
signalsLen = 67
8976.4352.656.476.640.488.640.484.628.500.668.1572.644.472.644.1600.640.476.612.1616.640.1592.644.1584.648.1584.652.476.628.1600.632.496.640.1588.656.472.648.480.640.1592.652.1576.656.468.656.464.656.484.652.472.692.1540.640.1592.652.472.644.484.652.1568.652.1580.656.1572.664.1576.656.Cmd =
4294967294
On
45976.4352.0.476.0.488.0.484.0.500.0.1572.0.472.0.1600.0.476.0.1616.0.1592.0.1584.0.1584.0.476.0.1600.0.496.0.1588.0.472.0.480.0.1592.0.1576.0.468.0.464.0.484.0.472.0.1540.0.1592.0.472.0.484.0.1568.0.1580.0.1572.0.1576.0..
Off
8976.0.656.0.640.0.640.0.628.0.668.0.644.0.644.0.640.0.612.0.640.0.644.0.648.0.652.0.628.0.632.0.640.0.656.0.648.0.640.0.652.0.656.0.656.0.656.0.652.0.692.0.640.0.652.0.644.0.652.0.652.0.656.0.664.0.656..
The issue here is the one signal command received before the actual key. It has a random length and after it the rest is inverted, meaning that the signal ~9000(first ex: 8996) should be ON and not OFF and so on.
Any input would be appreciated.
Thanks