Arduino - PC817 Optocoupler: Monitor 12V/24V DC Input Signal
An Arduino input pin is built for 5V and nothing more, so wiring a 12V or 24V line straight to it will destroy the pin. The PC817 optocoupler solves this the safe way: it passes the signal across an insulating gap as light, so Arduino can tell whether the external voltage is present without ever touching it electrically.
The easiest way to use it is a ready-made PC817 optocoupler isolation module: the resistor and a status LED are already on the board, and the external wires go into screw terminals. This tutorial uses the module as the main path.
In this tutorial, we are going to learn:
- How the PC817 optocoupler works
- How to choose the right module for a 3.3V, 5V, 12V or 24V signal
- How to wire the module to Arduino
- How to tap a device in parallel to see whether it is running
- How to tell whether your module reads active-LOW or active-HIGH
- How to program Arduino to read the isolated input

This is the standard way to safely detect a 12V DC signal or monitor a 24V PLC output with a low-voltage board. It is also the simplest answer to a question that comes up all the time in a workshop or a machine room: is that pump, heater, lamp or motor actually running right now? Arduino only has to see whether power is reaching the device, and the PC817 lets it see that from a safe distance.
Hardware Required
Or you can buy the following kits:
| 1 | × | DIYables STEM V3 Starter Kit (Arduino included) | |
| 1 | × | DIYables Sensor Kit (18 sensors/displays) |
Additionally, some links direct to products from our own brand, DIYables .
You only need ONE module: the one that matches the voltage of the signal you want to watch.
About PC817 Optocoupler
The PC817 is a 4-pin optocoupler, also called a photocoupler or opto-isolator. Inside it there is an infrared LED facing a phototransistor across an insulating gap: when current flows through the LED, its light switches the transistor on, so the signal crosses as light instead of electricity, which is why the two sides stay electrically separate.
That gap is rated for 5000 Vrms of isolation for one minute, so a fault on the 12V or 24V side cannot reach Arduino.
A PC817 optocoupler isolation module is that chip on a small PCB with the series resistor already fitted, a status LED, screw terminals for the external signal, and pin headers for Arduino. Modules come in 1, 2, 4 and 8 channel versions.
The useful numbers from the PC817 datasheet:
- LED forward voltage (Vf): about 1.2V typical, 1.4V max
- LED forward current (If): 20mA continuous max, 5mA to 20mA is the normal range, 10mA is a good target
- Output collector-emitter voltage (VCEO): 35V max
- Output collector current (IC): 50mA max
- Collector power dissipation: 150mW
- Isolation voltage: 5000 Vrms for 1 minute
- Current Transfer Ratio (CTR): 50% to 600% depending on the rank (rank A 80-160%, B 130-260%, C 200-400%, D 300-600%)
- Switching speed: rise time about 4us, fall time about 3us
- Operating temperature: -30 to +100 degrees Celsius
Which Optocoupler Module Do I Need?
This is the one decision you have to get right before you buy. The resistor on the module is already fitted, and it is sized for one input voltage, so the module is sold as three separate variants. Look at the signal you want to watch, then buy the matching one:
| Signal you want to watch | Module to buy |
|---|---|
| 3.3V or 5V logic | 3-5V module |
| 12V DC | 12V module |
| 24V DC | 24V module |
With a module you never calculate a resistor. Choosing the variant IS the resistor decision, already made for you.
WARNING
Do not run a module on the wrong voltage. A 12V module fed from a 24V line gets roughly double the intended current through its internal LED and will be damaged. A 24V module fed from a 12V line is underdriven, so the output may switch late, switch unreliably, or never switch at all. Neither mistake announces itself: you simply end up with a dead module or a reading you cannot trust.
※ NOTE THAT:
A 5V or a 3.3V signal is worth isolating too. Isolation is about breaking the ground path, not only about high voltage, so it earns its place whenever the two circuits run from separate power supplies, sit at opposite ends of a long cable, or one of them is electrically noisy, such as a motor driver or the low-voltage control board inside a mains-powered appliance. That is the job of the 3-5V module.
How It Works
- When the external signal is present at the input terminals, current flows through the module's resistor and the internal LED. The LED lights up and switches the phototransistor on, and the module's OUT pin changes state.
- When the external signal is absent, the LED is off, the phototransistor is off, and OUT goes back to its resting state.
The status LED on the module lights up together with the internal LED, so you can see the input side working with your own eyes.
The PC817 does not measure the voltage. It only tells Arduino whether the external signal is there or not. If you need the actual value instead of a yes/no answer, see Arduino - Measure Voltage.
Wiring Diagram
Wiring the PC817 Optocoupler Module to Arduino
The module has two sides, and that is the whole point: the screw terminals belong to the external circuit, the pin header belongs to Arduino, and nothing crosses between them.
- The external 12V/24V signal needs to be connected to the IN+ screw terminal
- The ground of the external circuit needs to be connected to the IN- screw terminal
- The module's VCC pin needs to be connected to the Arduino 5V pin
- The module's GND pin needs to be connected to the Arduino GND pin
- The module's OUT pin needs to be connected to the Arduino D2 pin

This image is created using Fritzing. Click to enlarge image
There is no series resistor to add anywhere in this wiring. The module already carries it.
※ NOTE THAT:
Do NOT connect the ground of the 12V/24V circuit to the Arduino GND. The IN- terminal and the module's GND pin must stay separate, and that separation is exactly what protects Arduino. If you tie them together the module still switches, but the isolation is gone and there is no point in using an optocoupler at all.
Connecting the PC817 in Parallel With the Device You Want to Monitor
Most of the time nobody hands you a spare signal wire. You have a device that is already wired and already working, and you want Arduino to know when it is on. In that case the module input goes across the device, in parallel with it, the same way a voltmeter would sit across it. Nothing in the existing circuit gets cut, moved or rerouted.
Take a 12V relay coil as the example, which makes this a job for the 12V module. The coil already has a positive terminal that goes live when the relay is energised, and a negative terminal that returns to the ground of the 12V supply. The tap is just two extra wires:
- From the coil's positive (switched) terminal to the module's IN+ terminal.
- From the coil's negative (return) terminal to the module's IN- terminal.
- VCC, GND and OUT still go to Arduino 5V, Arduino GND and Arduino D2, exactly as in the wiring above.
The tap draws about 10mA. A 12V relay coil pulls somewhere around 30 to 80mA on its own, so the extra 10mA changes nothing and the relay carries on working exactly as before. This is a read-only measurement: the PC817 watches the coil, it does not switch it.
WARNING
Never put the module in series with the device. In series, the whole load current of the relay coil, lamp or motor would have to pass through the tiny LED inside the PC817, which is rated for 20mA, and the optocoupler would be destroyed the moment you switch the device on. The input always goes across the device, never in line with it.
Because the tap sits across the coil instead of in an Arduino output wire, the reading follows what the device is really doing. If a thermostat, a timer, a PLC or a person switches the relay on, Arduino sees it. If the relay is commanded on but never energises because a fuse blew or a wire came loose, Arduino sees that too. That is what makes this worth building for run-hour counters, idle-time logs and "did it actually start?" alerts. Be honest about what it measures, though: it tells you the device is energised, not that it is doing its job, so a seized motor or a burnt-out heater element still draws power and still reads as ON.
Three things to check before you power the tap up:
- Polarity. The input side is an LED, so it conducts in one direction only. If IN+ and IN- are swapped, the module simply never turns on. Work out which side of the tap is the positive one before you wire it.
- Leaky outputs. Some PLC transistor outputs, triac outputs and LED lamp drivers let a small current through even when they are switched off. That leakage can partly light the PC817 LED, and Arduino then reports the device as ON while it is really OFF. The symptom is easy to recognise: the reading never goes back to ABSENT. The fix is a bleeder resistor of about 4.7 kohm to 10 kohm across the IN+ and IN- terminals, so the leakage flows through the resistor instead of through the LED.
- AC lines. The PC817 input is a single LED, so it responds to one polarity only and is the wrong part for sensing an AC line, which needs an optocoupler whose input stage has two back-to-back LEDs.
WARNING
A relay coil is an inductive load. When it switches off, its collapsing magnetic field produces a reverse voltage spike across the coil many times bigger than the 12V that was driving it, and the PC817 input LED is rated for only 6V in reverse. Fit an ordinary diode in reverse-parallel directly across the IN+ and IN- terminals: the diode cathode to IN+, the diode anode to IN-. In normal operation that diode is reverse-biased and does nothing at all, but when the spike arrives it conducts and clamps the reverse voltage to well under a volt. A 1N4148 is enough for a small tap like this one, a 1N4007 for heavier ones. The same goes for solenoids, contactors, valves and motors.
Is Your Optocoupler Module Active-HIGH or Active-LOW?
On the bare chip this is settled physics. With the internal pull-up enabled, the phototransistor pulls the pin down when the LED is lit, so:
- External signal PRESENT: the Arduino pin reads LOW
- External signal ABSENT: the Arduino pin reads HIGH
Modules are not so predictable. Most of them behave exactly like the bare chip, but some manufacturers invert the output on the board so that OUT follows the input instead. Both kinds are on sale and you cannot tell them apart by looking, so check yours. It takes under a minute:
- Wire the module as above and upload the sketch below without changing anything.
- With nothing connected to the input terminals, look at the Serial Monitor and note what it prints.
- Now apply the external signal and note what it prints.
- Whatever the pin reads while the signal is present is your module's active level.
- Cross-check with the module's status LED: it lights while the input side is energised. If that LED is on but the Serial Monitor still says ABSENT, your module is the other kind.
If the readings come out the wrong way round, do not rewrite anything. Change the single line const bool MODULE_ACTIVE_LOW = true; at the top of the code to false and upload again.
The active-LOW case is the same pattern you get from a button or a limit switch wired with a pull-up.
Optional: Building It From the Bare PC817 Chip
If you would rather build the input yourself, the bare 4-pin chip does the same job for a few cents, but the series resistor is now yours to size. Pin 1 is marked by a dot or a notch on the chip.
- Pin 1 - Anode (A): the external signal needs to be connected here through the series resistor
- Pin 2 - Cathode (K): it needs to be connected to the ground of the external circuit, NOT to the Arduino GND
- Pin 3 - Emitter (E): it needs to be connected to the Arduino GND
- Pin 4 - Collector (C): it needs to be connected to the Arduino D2 pin

Size the resistor for about 10mA with R = (Vin - 1.2) / 0.01, which gives 220 ohm for 3.3V, 390 ohm for 5V, 1 kohm for 12V and 2.2 kohm for 24V. A 1/4W resistor is fine up to 12V, use 1/2W at 24V.
Everything else on this page - the parallel tap, the clamp diode, the code - works the same way.
How To Program For PC817
- Configures an Arduino's pin to the digital input mode with the internal pull-up by using pinMode() function. For example, pin 2:
- Reads the state of that pin by using digitalRead() function:
- Turns that reading into a yes/no answer. A single constant decides which way round it goes, so you can match your own module without touching anything else:
No library is needed for this project.
Arduino Code - PC817 Optocoupler
Quick Steps
- Connect Arduino to PC via USB cable
- Do wiring as the module wiring diagram above
- Open Arduino IDE, select the right board and port
- Copy the above code and open with Arduino IDE
- Click Upload button on Arduino IDE to upload code to Arduino
- Switch the external 12V/24V signal on and off
- See the result on Serial Monitor.
If PRESENT and ABSENT come out swapped, your module is the active-HIGH kind: set MODULE_ACTIVE_LOW to false and upload again.
From here the same circuit covers a lot of ground: watching a 24V machine running or fault lamp line, checking whether a 12V vehicle circuit such as the ignition or the headlights is live, or seeing when a 24V solenoid coil gets energised. Once Arduino knows the state, you can act on it with a relay, a buzzer, or a log entry: count the run hours of a pump, raise an alert when a machine was told to start but did not, or log how long a production line stood idle.
Video Tutorial
We are considering to make the video tutorials. If you think the video tutorials are essential, please subscribe to our YouTube channel to give us motivation for making the videos.