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 |
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;
}
}