Decoding NEC Infrared Signals with PIC Microcontrollers

I recently had a need to implement remote control of a device for a project I was working on, and not having sufficient experience of the subject has made the task everything but a trivial one.

NEC protocol is relatively simple, there's a 9ms high pulse followed by a 4.5ms low one after which the 8-bit address/command is encoded using a set of high and low pulses - 565.5uS high followed by a 565.5us low indicating 0, and 565.5uS high followed by ~1.7mS (3x 565.5uS) low indicating 1.

NEC Signal
NEC Signal

Implementation of an algorithm for decoding NEC on a PIC18F4550 was quite a ride. Initially, I attempted to use the "__delay_us" function which allowed me easily to detect the lead signal and the non-inverted address. Unfortunately, the additional delays caused by code execution have made the method unreliable and I decided to go with another route.

Luckily, PIC microcontrollers have an "interrupt on change" feature which sets a flag any time a digital signal changes on a certain port - port B in my particular case. Combining that feature with one of the available timers allowed me to reliably decode the signal with a minimal amount of code.

Timer 0 was configured to tick every 100uS and used for measuring the duration of the pulses once the lead was detected.

if (TMR0IF == 0x1) {
    
    if (edge_detected == 0x1) {
        ticks ++;
    }
    
    TMR0H = // PREFILL_VALUE_HIGH
    TMR0L = // PREFILL_VALUE_LOW
    
    TMR0IF = 0x0;
}

After I've solved that problem, I used interrupt on change feature to process the signal with only a few lines of code.

if (RBIF == 0x1) {
    
    if (PORTBbits.RB5 == 0x1) { // Set Edge Flag To Start Measuring Pulse Intervals 
        edge_detected  = 0x1;
    }

    temp = (uint8_t)(ticks / 6);
    
    if (PORTBbits.RB5 == 0x1) {
        
        if (temp > 4) { // Assume Lead (Low)
	        // BUFFER LEAD LOW
        } else if (temp > 1) { // Assume Bit 0 (Two Low Pulses)
	        // BUFFER TWO ZEROS
        }
    } else {

        if (temp > 4) { // Assume Lead (High)
	        // BUFFER LEAD HIGH
        }
    }

    // BUFFER 1 or 0
    
    RBIF = 0x0;
}

Orce buffering was sufficiently reliable, writing a few functions for extracting the address/command was easy.

if (nec_decode(app_buffer) == NEC_SUCCESS) {
    
    if (nec_get_address() == 0x1 && nec_get_command() == 0x58) { // On Command
        PORTCbits.RC6 = 0x1;
    } else if (nec_get_address() == 0x1 && nec_get_command() == 0x48) { // Off Command
        PORTCbits.RC6 = 0x1;
    }
}

Contact

If you don't want to contact me via office@djordjejocic.com, please use the form bellow. All fields are required.