Sunday, July 10, 2016

Extended NEC IR remote control decoder with PIC18F4550 microcontroller


Extended NEC protocol decoder
 
The NEC protocol uses pulse distance encoding of the bits. Each pulse is a 562.5µs long with carrier frequency of 38KHz. Logic bits are transmitted as follows:
Logic 0: 562.5µs pulse burst followed by a 562.5µs space, with a total transmit time of 1125µs (562.5 x 2).
Logic 1: a 562.5µs pulse burst followed by a 1687.5µs (562.5 x 3) space, with a total transmit time of 2250µs (562.5 x 4).
Extended NEC protocol data send
The complete extended NEC protocol message is started by 9ms burst followed by 4.5ms space which is then followed by the Address and Command. The address is 16-bit length and the command is transmitted twice (8 bits + 8 bits) where in the second time all bits are inverted and can be used for verification of the received message. The following drawing shows an extended NEC message example.
Extended NEC protocol one code message 
NEC Protocol IR remote control decoder with PIC18F4550 microcontroller:
It is easy to decode IR remote control uses NEC protocol using microcontrollers.
Here Microchip PIC18F4550 microcontroller is used to decode IR remote controls which uses NEC and extended NEC protocol. Decoder circuit schematic is shown below.
Extended NEC protocol for IR remote control decoder using PIC18F4550 circuit - CCS PIC C 
In this project PIC18F4550 internal oscillator is used @ 8MHz.
NEC Protocol IR remote control decoder with PIC18F4550 CCS C code:
There are different ways to decode the NEC protocol for example using CCP module and Timer module, using Timer module or using port change interrupt........ In this project I didn't use any interrupt or Timer, I used delay command to make the code as simple as possible with time-out property and the code checks the IR signal with resolution of 50µs.
Programming hints:
From the decoder circuit schematic above the output of the IR receiver is connected to RB0 and when an IR signal is received RB0 pin goes from logic high (+5V) to logic low (0V).
The NEC message has 32 bits which are divided into address (16 bits), command (8 bits) and inverted command (8 bits).
The microcontroller waits until the IR receiver receives an IR signal which makes RB0 goes from logic high to logic low and the command used is:
while(input(PIN_B0));
After that a function named nec_remote_read() is called, this function checks if the received signal has NEC protocol form all the time.
The last function reads the 9ms burst using the following lines and if the pulse is more than 10ms (50µs x 200) or less than 8ms (50µs x 160) the function returns with false result which means the received signal doesn't have NEC protocol form.
while((input(PIN_B0) == 0) && (count < 200)){
    count++;
    delay_us(50);}
if( (count > 199) || (count < 160))
    return false;
The 4.5ms space is checked as the 9ms burst with small differences:
while((input(PIN_B0)) && (count < 100)){
    count++;
    delay_us(50);}
  if( (count > 99) || (count < 60))
    return false;
After that the microcontroller starts reading the 32 bits and keeps checking of NEC protocol form.
The following code is the complete CCS PIC C code written with compiler PCWHD version 5.051.
// Extended NEC Protocol IR remote control decoder using PIC18F4550 CCS C code
// http://ccspicc.blogspot.com/
// electronnote@gmail.com

//LCD module connections
#define LCD_RS_PIN PIN_D0
#define LCD_RW_PIN PIN_D1
#define LCD_ENABLE_PIN PIN_D2
#define LCD_DATA4 PIN_D3
#define LCD_DATA5 PIN_D4
#define LCD_DATA6 PIN_D5
#define LCD_DATA7 PIN_D6
//End LCD module connections

#include <18F4550.h>
#fuses NOMCLR INTRC_IO
#use delay(clock = 8000000)
#include <lcd.c>
#use fast_io(B)

unsigned int32 ir_code;
unsigned int16 address;
unsigned int8 command, inv_command;
short nec_remote_read(){
  unsigned int8 count = 0, i;
  // Check 9ms pulse (remote control sends logic high)
  while((input(PIN_B0) == 0) && (count < 200)){
    count++;
    delay_us(50);}
  if( (count > 199) || (count < 160))        // NEC protocol?
    return FALSE;                          
  count = 0;
  // Check 4.5ms space (remote control sends logic low)
  while((input(PIN_B0)) && (count < 100)){
    count++;
    delay_us(50);}
  if( (count > 99) || (count < 60))          // NEC protocol?
    return FALSE;                         
  // Read message (32 bits)
  for(i = 0; i < 32; i++){
    count = 0;
    while((input(PIN_B0) == 0) && (count < 14)){
      count++;
      delay_us(50);}
    if( (count > 13) || (count < 8))         // NEC protocol?
      return FALSE;                          
    count = 0;
    while((input(PIN_B0)) && (count < 40)){
      count++;
      delay_us(50);}
    if( (count > 39) || (count < 8))         // NEC protocol?
      return FALSE;                           
    if( count > 20)                          // If space width > 1ms
      bit_set(ir_code, (31 - i));            // Write 1 to bit (31 - i)
    else                                     // If space width < 1ms
      bit_clear(ir_code, (31 - i));          // Write 0 to bit (31 - i)
  }
  return TRUE;
}
void main(){
  setup_oscillator(OSC_8MHZ);                // Set internal oscillator to 8MHz
  setup_adc_ports(NO_ANALOGS);               // Configure AN pins as digital
  set_tris_b(1);                             // Configure RB0 as digital input pin
  lcd_init();                                // Initialize LCD module
  lcd_putc('\f');                            // LCD clear
  lcd_gotoxy(3, 1);                          // Go to column 3 row 1
  lcd_putc("NEC Protocol");
  lcd_gotoxy(5, 2);                          // Go to column 5 row 2
  lcd_putc("Decoder");
  delay_ms(2000);
  lcd_putc('\f');
  lcd_gotoxy(1, 1);                          // Go to column 1 row 1
  printf(lcd_putc, "Address:0x0000");
  lcd_gotoxy(1, 2);                          // Go to column 1 row 2
  printf(lcd_putc, "Com:0x00 In:0x00");
  while(TRUE){
    while(input(PIN_B0));                    // Wait until RB0 pin falls
    if(nec_remote_read()){
      address = ir_code >> 16;
      command = ir_code >> 8;
      inv_command = ir_code;
      lcd_gotoxy(11, 1);               
      printf(lcd_putc,"%4LX",address);  
      lcd_gotoxy(7, 2);          
      printf(lcd_putc,"%2X",command); 
      lcd_gotoxy(15, 2);          
      printf(lcd_putc,"%2X",inv_command);
      delay_ms(200);}
  }
}

NEC Protocol IR remote control decoder with PIC18F4550 video:
The following video shows how this decoder works in a hardware circuit.
Reference:
http://www.sbprojects.com/