The NEC IR Protocol: How Most TV Remotes Send Commands
Pick up a TV remote, a DVD player remote, or a set-top box remote and there's a good chance the protocol it speaks is NEC. Developed by NEC Corporation in the 1980s, the NEC IR protocol became the dominant standard for consumer electronics remote controls. It's well-documented, simple to implement, and still widely used in new devices today.
If you've ever wondered what that invisible burst of light from your remote actually looks like at the signal level - how it encodes button presses into timing patterns - this article breaks it down precisely. And if you're working with the BLEShark Nano's IR features, understanding NEC will help you know what you're capturing and why the timing matters.
Table of Contents
- The 38kHz Carrier and Modulation
- NEC Frame Structure
- Pulse-Distance Encoding
- Exact Bit Timings
- Address and Command Bytes
- Repeat Codes
- Extended NEC Protocol
- Which Brands Use NEC
- NEC on the BLEShark Nano
The 38kHz Carrier and Modulation
IR remote controls don't just flash the LED on and off to represent data directly. They modulate the data onto a carrier frequency - typically 38kHz for NEC. The LED rapidly blinks at 38,000 times per second when it's transmitting a "1" in the carrier sense. This is called a burst or mark.
The reason for this carrier is noise rejection. Ambient light - sunlight, fluorescent bulbs, incandescent lamps - all produce infrared radiation. If the receiver just detected any IR light, it would constantly trigger from ambient sources. By filtering for a 38kHz signal, the receiver can ignore all that DC or slowly-varying ambient IR and only respond to intentional remote transmissions.
The receiver demodulates this: when it detects 38kHz modulated IR, it outputs a logic LOW (active low). When there's no 38kHz signal, it outputs a logic HIGH. So from the microcontroller's perspective, it sees active-low pulses. The BLEShark's IR receiver works the same way - it demodulates the carrier and hands the microcontroller the timing of the pulses and spaces.
NEC Frame Structure
An NEC message consists of the following in sequence:
- Lead burst (preamble): 9ms of 38kHz carrier (burst)
- Lead space (preamble): 4.5ms of silence (no carrier)
- 8-bit address (LSB first)
- 8-bit address complement (LSB first)
- 8-bit command (LSB first)
- 8-bit command complement (LSB first)
- Stop bit: 562.5 microsecond burst
The lead burst and space (9ms + 4.5ms) form a distinctive preamble that receivers can quickly identify as an NEC frame beginning. Nothing else in the IR world uses exactly that timing, so false triggers are rare.
The 32 data bits break down into four bytes: address, ~address (bitwise inverse of address), command, ~command. The inverted bytes serve as error checking - the receiver verifies that each byte matches the complement of its pair. If they don't match, the packet is discarded as corrupted.
This gives NEC a total of 256 possible addresses (0x00-0xFF) and 256 possible commands (0x00-0xFF), for 65,536 unique address/command combinations. In practice, many manufacturers share address ranges, which is why a single universal remote database needs to store brand and model alongside the codes.
graph LR
subgraph FRAME["NEC IR Frame (67.5ms total)"]
subgraph LEADER["Leader Code"]
AGC["AGC Burst
9ms pulse
(38kHz carrier)"]
SPACE["Space
4.5ms
(no carrier)"]
end
subgraph DATA["Data Payload (32 bits)"]
ADDR["Address
8 bits
(device ID)"]
ADDR_INV["Address Inverse
8 bits
(error check)"]
CMD["Command
8 bits
(button code)"]
CMD_INV["Command Inverse
8 bits
(error check)"]
end
STOP["Stop Bit
562.5us pulse"]
end
AGC --> SPACE --> ADDR --> ADDR_INV --> CMD --> CMD_INV --> STOP
subgraph ENCODING["Pulse-Distance Encoding"]
ZERO["Logical 0
562.5us pulse
562.5us space
(1.125ms total)"]
ONE["Logical 1
562.5us pulse
1687.5us space
(2.25ms total)"]
end
subgraph REPEAT["Repeat Code (if held)"]
R_AGC["9ms AGC"]
R_SPACE["2.25ms space"]
R_STOP["Stop bit"]
R_AGC --> R_SPACE --> R_STOP
end
DATA -.->|"Each bit uses"| ENCODING
STOP -->|"Button held:
110ms interval"| REPEAT
NEC IR frame structure - a 9ms AGC burst followed by 32 bits of pulse-distance encoded data. The inverse bytes provide simple error detection, and repeat codes fire every 110ms when a button is held.
sequenceDiagram
participant REMOTE as TV Remote
(NEC Encoder)
participant IR as Infrared LED
(38kHz Carrier)
participant SENSOR as IR Receiver
(TV / BLEShark Nano)
participant DECODE as Decoder Logic
Note over REMOTE: User presses "Volume Up"
REMOTE->>IR: Generate 38kHz carrier (9ms)
IR->>SENSOR: AGC burst detected
SENSOR->>DECODE: Start of frame
REMOTE->>IR: No carrier (4.5ms)
SENSOR->>DECODE: Leader space - standard frame
loop 8 Address bits (e.g., 0x04 = Samsung TV)
REMOTE->>IR: 562.5us pulse
REMOTE->>IR: Space (562.5us=0, 1687.5us=1)
SENSOR->>DECODE: Bit decoded by space duration
end
loop 8 Address Inverse bits
REMOTE->>IR: Pulse + space per bit
SENSOR->>DECODE: Verify: must equal NOT(address)
end
loop 8 Command bits (e.g., 0x02 = Vol Up)
REMOTE->>IR: Pulse + space per bit
SENSOR->>DECODE: Command decoded
end
loop 8 Command Inverse bits
REMOTE->>IR: Pulse + space per bit
SENSOR->>DECODE: Verify: must equal NOT(command)
end
DECODE->>DECODE: Validate inversions
DECODE->>DECODE: Output: Addr=0x04, Cmd=0x02
Note over REMOTE: If button still held (110ms gap)
REMOTE->>IR: Repeat code (9ms + 2.25ms + stop)
SENSOR->>DECODE: Repeat last command
NEC protocol sequence - the remote encodes each button press as a 32-bit frame with address and command bytes, validated by their inverses. BLEShark Nano's IR receiver captures and decodes these frames for cloning.
Pulse-Distance Encoding
NEC uses pulse-distance encoding (also called pulse-spacing encoding) to differentiate between 0 and 1 bits. The key thing to understand about this encoding: all pulses (bursts) are the same length. The information is carried entirely by the length of the space (silence) that follows each pulse.
This is different from pulse-width encoding (which Sony SIRC uses, as covered in the next article) where the pulse length carries the information. In NEC:
- A logical 0 is: 562.5 microsecond burst + 562.5 microsecond space (total 1.125ms)
- A logical 1 is: 562.5 microsecond burst + 1,687.5 microsecond space (total 2.25ms)
The total time for a 0 bit is 1.125ms. The total time for a 1 bit is 2.25ms - exactly twice as long. This makes the protocol fairly easy to decode: measure the time from the start of one burst to the start of the next burst. If it's approximately 1.125ms, that's a 0. If it's approximately 2.25ms, that's a 1.
The 562.5 microsecond pulse duration is derived from the carrier period: 1/38000 Hz = 26.3 microseconds per carrier cycle. The 562.5 microsecond burst is 21.4 carrier cycles. This isn't a round number, which is worth noting - NEC's timing is optimized for the specific carrier frequency.
Exact Bit Timings
For reference, here are the exact NEC timings:
- Lead burst: 9,000 microseconds (342 carrier cycles at 38kHz)
- Lead space: 4,500 microseconds
- Bit burst: 562.5 microseconds (21.4 carrier cycles)
- Bit space for 0: 562.5 microseconds
- Bit space for 1: 1,687.5 microseconds
- Stop bit burst: 562.5 microseconds
- Frame gap (between repeat if button held): 40ms from start of frame
Total frame time for a single NEC message: 9ms + 4.5ms + (32 bits * avg ~1.7ms) + stop bit = approximately 67.5ms for a worst case (all 1 bits) or 45ms for best case (all 0 bits). In practice with mixed data, a full NEC frame takes about 67.5ms maximum.
Receiver implementations typically tolerate 20-30% timing variation because IR transmission is noisy - reflections, ambient IR, AGC settling all introduce jitter. When the BLEShark captures an NEC signal, it records the actual measured pulse and space durations, which will deviate from ideal by a few percent depending on the source remote's crystal accuracy.
Address and Command Bytes
The NEC frame transmits bits LSB (least significant bit) first. So if the address byte is 0x04 (binary 00000100), it's transmitted as 0,0,1,0,0,0,0,0 - the 1 appears at position 2 (0-indexed from right).
The address byte identifies the device type or manufacturer's device class. Command byte identifies the specific function. For example, on a typical TV:
- Address 0x04, Command 0x08: Power toggle
- Address 0x04, Command 0x02: Volume up
- Address 0x04, Command 0x03: Volume down
These values are manufacturer-specific and there's no central registry - they're documented through reverse engineering and community databases like IRDB, which now contains tens of thousands of device codes.
The address complement is transmitted immediately after the address. If address is 0x04 = 00000100, the complement is 0xFB = 11111011. The receiver computes the XOR of the received address and complement - if the result is 0xFF (all ones), the address is valid. Same verification for the command byte.
Repeat Codes
When a button is held down, NEC doesn't retransmit the full frame repeatedly. Instead, it sends a repeat code: a 9ms burst followed by a 2.25ms space followed by a 562.5 microsecond stop burst. This compact 11.25ms sequence says "the last command is still active."
Repeat codes are sent every 110ms (from the start of the previous frame or repeat code) as long as the button remains pressed. The receiving device interprets repeated repeat codes as a held button, which typically means repeat the action - hold volume up keeps increasing the volume, for example.
When capturing IR signals with the BLEShark, you'll see this as a short burst of activity after the initial longer frame if you hold the button. The repeat code is stored separately from the frame data and is replayed by the IR transmit feature when you want to simulate a button hold.
Extended NEC Protocol
The original NEC protocol has 256 addresses. When manufacturers started running out of unique addresses, an extended variant was developed. Extended NEC (sometimes called NEC2 or NEC-16bit) uses a 16-bit address instead of 8-bit address plus its complement. This gives 65,536 possible addresses instead of 256.
The frame structure is the same - 9ms lead burst, 4.5ms lead space, 32 data bits, stop bit - but the interpretation of the first 16 bits changes. Instead of 8-bit address + complement, it's a 16-bit address. The second 16 bits remain the 8-bit command plus complement.
You can't tell from looking at a raw NEC capture whether it's standard or extended NEC - the frame length is identical. The difference is in how you interpret the bytes. Many IR code databases distinguish between the two, and universal remote implementations need to handle both.
When the BLEShark captures and stores an NEC signal, it stores the raw timing data rather than interpreting the protocol. This means it can replay the signal accurately regardless of which NEC variant it is - the replay just reproduces the exact timing that was captured.
Which Brands Use NEC
NEC protocol is used by a wide range of manufacturers. Common brands that use NEC or NEC-derived protocols include:
- LG (televisions, monitors)
- Samsung (uses a modified NEC variant, sometimes called Samsung32 or NECx)
- Sharp (televisions)
- Toshiba (televisions, home theater)
- Marantz (AV receivers)
- Denon (AV receivers, similar address space to Marantz - same parent company)
- Many Chinese-branded electronics
Samsung's variant is worth noting specifically. Samsung uses NEC timing but typically has a 16-bit address space (no complement) and some devices use different lead timing. Code databases usually distinguish Samsung32 from NEC, but they're close enough that timing-based capture (like the BLEShark uses) captures both correctly.
Protocols that are NOT NEC include Sony (SIRC - pulse width, 40kHz carrier), Philips RC-5, Philips RC-6, and Panasonic (Kaseikyo/JVC variant). These all require separate protocol handling.
NEC on the BLEShark Nano
The BLEShark Nano captures IR using a TSOP-type IR receiver module that outputs a demodulated signal. The ESP32-C3 timestamps the transitions (mark-to-space and space-to-mark) using a timer peripheral, producing a raw list of pulse and space durations in microseconds.
The Receive app stores this raw timing data. When you replay using the Transmit app, the ESP32 reproduces those exact timings through the IR LED, with the 38kHz carrier modulated onto each mark. Because it's reproducing timing rather than re-encoding a protocol, it works for NEC, extended NEC, Samsung, and any other timing-based IR protocol without needing to know which protocol it is.
The TV-B-Gone feature takes a different approach: it sends pre-coded NEC (and other protocol) frames for known power-off commands across hundreds of TV brands. Those codes are stored as protocol + address + command triplets rather than raw timing, because the code database was built from documented IR codes rather than captured signals.
If you want to capture a NEC remote's codes for replay with the BLEShark, point the remote at the BLEShark's IR receiver from about 30cm away, press and hold the button for one second, and release. The BLEShark will store the frame timing. Hold the button longer if you also want to store repeat code behavior. The Shiver mesh makes this scalable - you can deploy IR nodes across multiple rooms and control them all, with each node capable of transmitting any stored IR code on command.
All IR codes shown are for educational reference. IR code databases are built from community-contributed captures and manufacturer documentation.