To isolate a UART TX line using a PC817 optocoupler, wire the LED anode to the microcontroller's VCC (3.3V or 5V) and the cathode to the TX pin. Wire the phototransistor emitter to the receiving ground and the collector to the RX pin with a 4.7kΩ pull-up resistor. This non-inverting configuration maintains the UART idle-HIGH state. However, the PC817’s ~4µs rise and fall times strictly cap your reliable baud rate at 19,200 bps. For 115,200 bps or higher, you must upgrade to a high-speed optocoupler like the 6N137 or a silicon digital isolator.
UART Bus Mechanics and Protocol Selection
Before designing the isolation circuit, it is critical to understand where UART fits in the broader ecosystem of embedded communication protocols. UART (Universal Asynchronous Receiver-Transmitter) is a point-to-point, asynchronous protocol. It lacks a clock line, meaning both devices must agree on a baud rate beforehand. While excellent for short-distance, chip-to-chip debugging and sensor communication, standard unisolated UART is highly vulnerable to ground loops and voltage spikes when connecting disparate systems.
If your application requires long distances or multi-drop networking, isolated UART becomes impractical, and you should pivot to RS-485 or CAN. The table below outlines which protocol fits your specific distance, speed, and device count requirements.
| Protocol | Wires Required | Max Speed (Typical) | Addressing / Topology | Max Distance |
|---|---|---|---|---|
| UART (Isolated) | 2 (TX, RX) + 2 isolated grounds | 19.2 kbps (PC817) / 1 Mbps (Digital) | Point-to-Point (No addressing) | ~15 meters (with RS-232 transceivers) |
| RS-485 | 2 (A, B) + Ground | 10 Mbps (short) / 100 kbps (long) | Multi-drop bus (Software addressing) | 1,200 meters |
| CAN Bus | 2 (CAN_H, CAN_L) + Ground | 1 Mbps (40m) / 125 kbps (500m) | Multi-master (Hardware ID arbitration) | 40 meters @ 1Mbps / 1km @ 125kbps |
| I2C | 2 (SDA, SCL) + Ground | 400 kbps (Fast) / 3.4 Mbps (High) | Multi-master (7/10-bit hardware address) | ~1 meter (highly capacitance limited) |
PC817 Physical Wiring and Baud Rate Limitations
The PC817 is a general-purpose optocoupler designed for low-frequency signal isolation and power supply feedback loops, not high-speed data. Its internal phototransistor suffers from high Miller capacitance, which severely limits its switching speed. If you attempt to push 115,200 baud through a PC817, the 8.6µs bit window will be entirely consumed by the optocoupler's rise and fall times, resulting in severe signal sloping, jitter, and framing errors.
| Component | Type | Typical CTR | Propagation Delay / Rise Time | Max Reliable UART Baud | Approx. Cost (USD) |
|---|---|---|---|---|---|
| PC817 | Standard Phototransistor | 80% - 160% | ~4µs rise / ~3µs fall | 19,200 bps | $0.10 |
| 6N137 | High-Speed (Logic Output) | N/A (Logic gate) | ~75ns max propagation | 1,000,000 bps (1 Mbps) | $0.65 |
| Si8621 | Capacitive Digital Isolator | N/A (Digital) | ~13ns propagation | 150,000,000 bps (150 Mbps) | $1.20 |
Non-Inverting Wiring Configuration
UART lines idle in a logic HIGH state. A standard common-emitter optocoupler circuit (Anode to TX, Cathode to GND) will invert this signal: when TX is HIGH, the LED turns on, pulling the RX line LOW. To prevent having to invert the signal in software or use a secondary logic gate, use this non-inverting wiring topology:
- Isolated Side 1 (Transmitting MCU): Connect the PC817 Anode (Pin 1) to VCC (e.g., 3.3V). Connect the Cathode (Pin 2) to the MCU's TX pin via a current-limiting resistor.
- Isolated Side 2 (Receiving MCU): Connect the Emitter (Pin 4) to the receiving system's GND. Connect the Collector (Pin 3) to the RX pin, and add a pull-up resistor between the Collector and the receiving system's VCC.
The PC817 LED has a forward voltage (Vf) of ~1.2V. For optimal Current Transfer Ratio (CTR), aim for 10mA of LED current. If your TX MCU operates at 3.3V logic: R = (3.3V - 1.2V) / 0.010A = 210Ω. Use a standard 220Ω resistor. If operating at 5V logic: R = (5V - 1.2V) / 0.010A = 380Ω. Use a 390Ω resistor. When the TX pin drives LOW (0V), the LED turns on. When TX is HIGH (3.3V), the voltage differential is zero, the LED turns off, and the RX pull-up holds the line HIGH.
Minimal Working Exchange and Pin Mapping
Below is the physical pin mapping for an ESP32 transmitting isolated UART data to an Arduino Uno receiving it. This setup assumes the ESP32 is powered by a 3.3V regulator and the Arduino by a separate 5V supply, with no common ground between the two systems.
| PC817 Pin | Function | ESP32 (TX Side) | Arduino Uno (RX Side) |
|---|---|---|---|
| 1 (Anode) | LED Positive | ESP32 3V3 Pin | - |
| 2 (Cathode) | LED Negative | GPIO 17 (UART1 TX) via 220Ω | - |
| 3 (Collector) | Phototransistor Output | - | Pin 0 (RX) + 4.7kΩ pull-up to 5V |
| 4 (Emitter) | Phototransistor GND | - | Arduino GND |
Because we are capping the baud rate at 9600 bps to ensure clean edges through the PC817, the code requires no special high-speed interrupts or hardware tweaks. Here is the minimal working exchange using the ESP32's HardwareSerial library.
#include <HardwareSerial.h>
// Use UART1 on ESP32 (GPIO 16 for RX, GPIO 17 for TX)
HardwareSerial IsolatedSerial(1);
void setup() {
// Initialize standard debug serial on USB
Serial.begin(115200);
// Initialize isolated UART at 9600 baud (safe for PC817)
// Parameters: baud, config, rxPin, txPin
IsolatedSerial.begin(9600, SERIAL_8N1, 16, 17);
Serial.println("Isolated UART TX initialized at 9600 baud.");
}
void loop() {
// Transmit a heartbeat message every 2 seconds
IsolatedSerial.println("ISOLATED_PING: Sensor Node OK");
// Check for isolated RX data (if a second optocoupler is used for RX)
if (IsolatedSerial.available()) {
String response = IsolatedSerial.readStringUntil('\n');
Serial.print("Received from isolated side: ");
Serial.println(response);
}
delay(2000);
}
Debugging the Isolated Bus and Classic Failures
When an isolated UART bus fails to communicate, the issue is almost always rooted in the physical layer rather than the software. While protocols like I2C or RS-485 frequently suffer from address clashes or termination resistor errors, isolated UART presents a unique set of hardware-specific failure modes.
The Classic Failure Modes
- Defeating the Isolation (The Ground Loop Trap): The most common mistake is accidentally tying GND1 and GND2 together on the breadboard or oscilloscope probe ground clip. If you connect your oscilloscope's ground clip to the isolated side while the scope is earth-grounded via its power cord, you will bypass the optocoupler entirely and potentially blow the PC817 or the microcontroller's ground plane.
- Missing or Weak Pull-Up Resistor: If you omit the pull-up resistor on the collector (Pin 3), the RX line will float when the phototransistor is off. The microcontroller's internal pull-up (often 20kΩ to 50kΩ) is usually too weak to overcome the stray capacitance of the breadboard and wiring, leading to slow rise times and phantom start bits. Always use an external 4.7kΩ or 2.2kΩ resistor.
- Baud Rate Mismatch and Signal Sloping: If you set the baud rate to 38,400 bps or higher on a PC817, the receiver will see a triangle wave instead of a square wave. The receiver's UART peripheral will sample the sloped voltage at the wrong threshold, triggering continuous framing errors.
How to Sniff and Debug the Bus
To debug isolated UART, you must use tools that respect the isolation boundary. A standard USB logic analyzer (like the popular $15 24MHz 8-channel clones or a Saleae Logic Pro) is ideal, but you must ensure the logic analyzer's ground is tied only to the specific side of the circuit you are probing.
Use a dual-channel oscilloscope to view both the TX pin (before the optocoupler) and the RX pin (after the optocoupler) simultaneously. Note: You cannot use standard grounded oscilloscope probes on both sides simultaneously unless your scope supports isolated channels or you use differential probes. A safer, cheaper alternative is to use two separate battery-powered logic analyzers, one on each side of the isolation barrier, and compare the decoded serial streams in software.
If the RX signal shows a sharp fall time but a sluggish, curved rise time, your pull-up resistor value is too high for the phototransistor's junction capacitance. Drop the pull-up from 10kΩ to 4.7kΩ to sharpen the rising edge. For deep dives into serial protocol timing and framing, refer to the SparkFun Serial Communication Guide or the Texas Instruments Digital Isolator Overview to understand when it is time to abandon the PC817 and move to capacitive isolation.






