Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Recognition of the signal from the IR remote control without libraries

Joined
Mar 13, 2023
Messages
5
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
19
I need to recognize a signal from an IR remote, not to use a library for working with IR remotes/receivers. How can when the button is clicked to display its name. I have PIC12F615 microcontroller with this code: code and 5 buttons connected to him and I need recognise which button pressed. I have some code but it gives different hex codes if I pressed the same button. code:

C++:
const byte IRpin = 2;

volatile boolean remote = false;
volatile unsigned long irCode = 0;

void remoting ()
{
  if ( remote )
  {
    remote = false;
    unsigned long T;
    for ( byte n = 0; n < 32; n ++ )
    {
      do
      {
        T = pulseIn ( IRpin, HIGH, 2200 );
      }
      while ( T < 64 );
      bitWrite ( irCode, n, T > 1120 );
    }
  }
}

void setup ()
{
  Serial.begin ( 9600 );
  Serial.println ( "\n\tReady for keyboard reading!\n" );
  pinMode ( IRpin, INPUT_PULLUP );
  attachInterrupt ( digitalPinToInterrupt ( IRpin ), remoting, FALLING );
}

void loop ()
{
  if (irCode)
  {
    Serial.println (irCode, HEX);
    irCode = 0;
  }
  delay (40);
  remote = true;
}

schema:
a0adee3382000794d06951c16499e6de00ec273b.jpeg
 
Hello!
First, what you call remote is a remote control, right?
I'm not sure of what you want to do. At least you have reinvented the wired remote control.
As for regular remote control, they are all variants of a single working process:
- Send 38 kHz burst of different length
- One of the levels has 2 different widths, one width for 1, one width for 0.
- The other level has a constant width.
- There might be a prefix and a suffix.

What I did:
- Detect the signal from an IR reciever (a 3 legs device, power, ground, output).
- Measure the width duration of all the bursts
- Process the array of widths to extract each bit
- Generate the code.

In any case, you need to use interrupts, and you don't in the present code.

Dora
 
Hello!
First, what you call remote is a remote control, right?
I'm not sure of what you want to do. At least you have reinvented the wired remote control.
As for regular remote control, they are all variants of a single working process:
- Send 38 kHz burst of different length
- One of the levels has 2 different widths, one width for 1, one width for 0.
- The other level has a constant width.
- There might be a prefix and a suffix.

What I did:
- Detect the signal from an IR reciever (a 3 legs device, power, ground, output).
- Measure the width duration of all the bursts
- Process the array of widths to extract each bit
- Generate the code.

In any case, you need to use interrupts, and you don't in the present code.

Dora
here it is, but it doesn't work, it prints infinity zeros:
C++:
volatile uint8_t inputCaptureData[32];
volatile uint8_t receiveCounter = 0;  //Receiver Counter
volatile uint8_t receiveComplete = 0; //Receive Complete Flag
int IR_PIN  = 2;

void handleIR() {
  uint32_t currentMicros = micros();
    inputCaptureData[receiveCounter] = (currentMicros - inputCaptureData[receiveCounter-1]);  //Calculate the time period between the falling edges
    if (inputCaptureData[receiveCounter] >  2500) {  // if the value is greater than 2500us (~2.5ms), then
      receiveCounter = 0; //reset "receiveCounter"
      receiveComplete = 0;  //reset "receiveComplete"
    } else {
      receiveCounter++;
      if (receiveCounter == 32) { //if all the bits are detected,
        receiveComplete = 1;  //then set the "receiveComplete" flag to "1"
      }
  }
}

void setup() {
  Serial.begin(9600);
  pinMode(IR_PIN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(IR_PIN), handleIR, CHANGE);
}

void loop() {
  if (receiveComplete) {  //If receive complete, start decoding process
    uint32_t receiveStream = 0; //To store decoded value
    for (int i = 0; i < 32; i++) {  //Decode all 32 bits receive as time periods
      if (inputCaptureData < 1300 && inputCaptureData > 1000 && i != 31) {  //if the time period t* -> 1.0ms < t < 1.3ms
        receiveStream = (receiveStream << 1); //Only bit shift the current value
      } else if (inputCaptureData < 2500 && inputCaptureData > 2000) {  //if the time period t* -> 2.0ms < t < 2.5ms
        receiveStream |= 0x0001;  //increment value by 1 using Logic OR operation
        if (i != 31) {  //Only shift the bit unless it is the last bit of the captured stream
          receiveStream = (receiveStream << 1); //Only bit shift the current value
        }
        receiveComplete = 0;  //Set the receive complete to 0 for next data to be captured
      }
    }
    Serial.println(receiveStream, HEX); //Print the value in serial monitor for debugging
  }
}
 
Last edited:
Comments:
1. you only look for at most 16 '1's and '0's because the interrupt is triggered on rising and falling edges.
2. if this was a generic decoder instead of just the codes you prepare, it's important to understand there are three commonly used standards: fixed 'high' with variable 'low', fixed 'low' with variable 'high' and RC5.
3. it is quite likely that the IR receiver you use has a built-in noise filter that limits the duration of output pulses. You need to look at them on an oscilloscope or logic analyzer to see what lengths they really are.
4. check the IR receiver is for 38KHz, most are but 56KHz is sometimes used as well.
5. you might have to find the average timings and then decode based on whether the received bit is longer or shorter than average.

Brian.
 
Hi,

there are several issues.

The first one is that nobody knows your "IR coding scheme".
--> specify what signal you expect for each key

The next is, that I guess you did not draw a flow chart, nor did you really consider variable sizes....
(Every professional needs to do this, thus a "less experienced one" should not consider other people do this for them.

Code:
    inputCaptureData[receiveCounter] = (currentMicros - inputCaptureData[receiveCounter-1]);  //Calculate the 
time period between the falling edges
Several issues here:
* receiveCounter is initialized to 0.
so what will happen on the first event when you read (inputCaptureData[-1])?

* This calculation makes no sense to me.
--> please use paper and pencil, write down the values you expect

Code:
if (receiveCounter == 32)
The problem is, that you never limit receiveCounter to be below 32. If there is an erroneous glitch, then there will be more than 32 edges (and those errors will happen!) then you overwrite data in your SRAM, which most probably will lead to software misfunction.

Code:
if (inputCaptureData[receiveCounter] >  2500)
How can it be ">2500" while the register is only 8 bits wide?

***
I didn´t look further through your code.

***
You need to learn how to debug your code.
* either use a simulator
* or a debugger
* or - good old style - use paper and pencil (for sure you may use Excel, too) and write down your register values step by step.

You may say it is time consuming ... but the "-1" issue will be found out within the first seconds.

Klaus
 
Comments:
1. you only look for at most 16 '1's and '0's because the interrupt is triggered on rising and falling edges.
2. if this was a generic decoder instead of just the codes you prepare, it's important to understand there are three commonly used standards: fixed 'high' with variable 'low', fixed 'low' with variable 'high' and RC5.
3. it is quite likely that the IR receiver you use has a built-in noise filter that limits the duration of output pulses. You need to look at them on an oscilloscope or logic analyzer to see what lengths they really are.
4. check the IR receiver is for 38KHz, most are but 56KHz is sometimes used as well.
5. you might have to find the average timings and then decode based on whether the received bit is longer or shorter than average.

Brian.
I change to this, but it doesn't set nec_ok to true:
boolean nec_ok = 0;
byte i, nec_state = 0, command, inv_command;
unsigned int address;
unsigned long nec_code;
Code:
void setup() {
  Serial.begin(9600);
  // Timer1 module configuration
  TCCR1A = 0;
  TCCR1B = 0;                                    // Disable Timer1 module
  TCNT1  = 0;                                    // Set Timer1 preload value to 0 (reset)
  TIMSK1 = 1;                                    // enable Timer1 overflow interrupt
  attachInterrupt(digitalPinToInterrupt(2), remote_read, CHANGE);       // Enable external interrupt (INT0)
}
 
void remote_read() {
unsigned int timer_value;
  if(nec_state != 0){
    timer_value = TCNT1;                         // Store Timer1 value
    TCNT1 = 0;                                   // Reset Timer1
  }
  switch(nec_state){
   case 0 :                                      // Start receiving IR data (we're at the beginning of 9ms pulse)
    TCNT1  = 0;                                  // Reset Timer1
    TCCR1B = 2;                                  // Enable Timer1 module with 1/8 prescaler ( 2 ticks every 1 us)
    nec_state = 1;                               // Next state: end of 9ms pulse (start of 4.5ms space)
    i = 0;
    return;
   case 1 :                                      // End of 9ms pulse
    if((timer_value > 19000) ||   (timer_value < 17000)){         // Invalid interval ==> stop decoding and reset
      nec_state = 0;                             // Reset decoding process
      TCCR1B = 0;                                // Disable Timer1 module
    }
    else
      nec_state = 2;                             // Next state: end of 4.5ms space (start of 562µs pulse)
    return;
   case 2 :                                      // End of 4.5ms space
    if((timer_value > 10000) ||   (timer_value < 8000)){
      nec_state = 0;                             // Reset decoding process
      TCCR1B = 0;                                // Disable Timer1 module
    }
    else
      nec_state = 3;                             // Next state: end of 562µs pulse (start of 562µs or 1687µs space)
    return;
   case 3 :                                      // End of 562µs pulse
    if((timer_value > 1400) ||   (timer_value < 800)){           // Invalid interval ==> stop decoding and reset
      TCCR1B = 0;                                // Disable Timer1 module
      nec_state = 0;                             // Reset decoding process
    }
    else
      nec_state = 4;                             // Next state: end of 562µs or 1687µs space
    return;
   case 4 :                                      // End of 562µs or 1687µs space
    if((timer_value > 3600) ||   (timer_value < 800)){           // Time interval invalid ==> stop decoding
      TCCR1B = 0;                                // Disable Timer1 module
      nec_state = 0;                             // Reset decoding process
      return;
    }
    if( timer_value > 2000)                      // If space width > 1ms (short space)
      bitSet(nec_code, (31 - i));                // Write 1 to bit (31 - i)
    else                                         // If space width < 1ms (long space)
      bitClear(nec_code, (31 - i));              // Write 0 to bit (31 - i)
    i++;
    if(i > 31){                                  // If all bits are received
      nec_ok = 1;                                // Decoding process OK
      detachInterrupt(0);                        // Disable external interrupt (INT0)
      return;
    }
    nec_state = 3;                               // Next state: end of 562µs pulse (start of 562µs or 1687µs space)
  }
}
 
ISR(TIMER1_OVF_vect) {                           // Timer1 interrupt service routine (ISR)
  nec_state = 0;                                 // Reset decoding process
  TCCR1B = 0;                                    // Disable Timer1 module
}
 
void loop() {
  Serial.println(nec_ok);
  if(nec_ok){                                    // If the mcu receives NEC message with successful
    nec_ok = 0;                                  // Reset decoding process
    nec_state = 0;
TCCR1B = 0;                                  // Disable Timer1 module
    address = nec_code >> 16;
    command = nec_code >> 8;
    inv_command = nec_code;
   
   
    attachInterrupt(digitalPinToInterrupt(2), remote_read, CHANGE);     // Enable external interrupt (INT0)
  }
}
[edit - code tags added by Betwixt]
 
Last edited by a moderator:
Hi,

there are several issues.

The first one is that nobody knows your "IR coding scheme".
--> specify what signal you expect for each key

The next is, that I guess you did not draw a flow chart, nor did you really consider variable sizes....
(Every professional needs to do this, thus a "less experienced one" should not consider other people do this for them.

Code:
    inputCaptureData[receiveCounter] = (currentMicros - inputCaptureData[receiveCounter-1]);  //Calculate the
time period between the falling edges
Several issues here:
* receiveCounter is initialized to 0.
so what will happen on the first event when you read (inputCaptureData[-1])?

* This calculation makes no sense to me.
--> please use paper and pencil, write down the values you expect

Code:
if (receiveCounter == 32)
The problem is, that you never limit receiveCounter to be below 32. If there is an erroneous glitch, then there will be more than 32 edges (and those errors will happen!) then you overwrite data in your SRAM, which most probably will lead to software misfunction.

Code:
if (inputCaptureData[receiveCounter] >  2500)
How can it be ">2500" while the register is only 8 bits wide?

***
I didn´t look further through your code.

***
You need to learn how to debug your code.
* either use a simulator
* or a debugger
* or - good old style - use paper and pencil (for sure you may use Excel, too) and write down your register values step by step.

You may say it is time consuming ... but the "-1" issue will be found out within the first seconds.

Klaus
PIC12F615 microcontroller with this code: code and irlink have 38kHz
 

LaTeX Commands Quick-Menu:

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top