Arduino Nano 33 IoT - PC817 Optocoupler: Monitor 12V/24V DC Input Signal

This tutorial instructs you how to use Arduino Nano 33 IoT to watch an isolated 12V or 24V signal through a PC817 optocoupler module - for instance a 24V compressor run-signal, or a 12V access-control strike being energised - so the machine side and the board share no wiring at all. In detail, we will learn:

Arduino Nano 33 IoT PC817 optocoupler isolated 24V input

The Arduino Nano 33 IoT is a board people deploy to report things - over Wi-Fi, over BLE, into a broker or a database. That makes an isolated input especially useful: the run-signal of a 24V pump, or the coil of a 12V door strike, becomes something the node can log and publish without any wire running from the machine into the board. Tapped across the machine itself, the input answers a better question than "is there a voltage here?" - it answers whether that machine is running, which is what a run-hour total, an idle-time log or a "the pump never started" alert is built on.

We suggest:

Hardware Preparation

1×Arduino Nano 33 IoT
1×Micro USB Cable
1×PC817 Optocoupler Module (12V input variant)
1×PC817 Optocoupler Module (3-5V input variant)
1×Breadboard
1×Jumper Wires
1×Recommended: Screw Terminal Expansion Board for Arduino Nano
1×Recommended: Breakout Expansion Board for Arduino Nano
1×Recommended: Power Splitter for Arduino Nano

Or you can buy the following kits:

1×DIYables Sensor Kit (18 sensors/displays)
Disclosure: Some of the links provided in this section are Amazon affiliate links. We may receive a commission for any purchases made through these links at no additional cost to you.
Additionally, some of these links are for products from our own brand, DIYables .

Overview of PC817 Optocoupler

The PC817 is a photocoupler - also written opto-isolator or optocoupler. Inside its little 4-pin body 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. That is the whole trick, and it is why the two sides of the part stay electrically separate: nothing conductive joins them.

A PC817 optocoupler module is that chip with its series resistor - and usually a status LED - already fitted and brought out to screw terminals. It is what this tutorial is built around, because a screw terminal is where a field wire coming off a machine actually belongs. The modules are sold as 1, 2, 4 and 8 channel boards.

For the Arduino Nano 33 IoT this means a 12V or 24V line can be sensed as a plain digital input. The board never sees 12V or 24V; it only ever sees a transistor opening and closing on its own 3.3V side.

PC817 Optocoupler
Package 4-pin DIP, pin 1 marked by a dot or a notch
Input LED forward voltage (Vf) about 1.2V typical, 1.4V max
Input LED forward current (If) 20mA max continuous, 5-20mA normal, 10mA a good target
Output collector-emitter voltage (VCEO) 35V max
Output collector current (IC) 50mA max
Collector power dissipation 150mW
Isolation voltage 5000Vrms for 1 minute
Current Transfer Ratio (CTR) 50% to 600% depending on rank
Switching speed about 4us rise time, 3us fall time
Operating temperature -30°C to +100°C

Which PC817 Optocoupler Module Do I Need?

Because that resistor is soldered on at the factory, it is sized for one input voltage range and one only. This is why the modules are sold as three separate variants, and why the only purchase decision that matters here is which of the three you order. Read the voltage of the signal you intend to watch, then buy the board that matches it:

Signal you want to watch Module variant to buy
24V DC - contactor and relay coils, PLC outputs, most machine and panel wiring the 24V optocoupler module
12V DC - door strikes and maglocks, alarm panels, automotive and marine circuits the 12V optocoupler module
5V or 3.3V logic - another microcontroller, a sensor board, an appliance's own control PCB the 3-5V optocoupler module

Mixing them up costs you either the module or an afternoon. Feed a 12V module from a 24V line and roughly twice the intended current goes through its internal LED, which damages it. Feed a 24V module from a 12V line and the LED is underdriven instead - the output may switch late, switch unreliably, or never switch at all, which is the more annoying of the two failures because nothing looks broken. With a module there is nothing to calculate; getting the variant right is the module equivalent of getting the resistor value right.

The 3-5V variant deserves a word of its own, because a 5V or 3.3V signal is worth isolating far more often than people expect: any time the two circuits run from separate supplies, sit at opposite ends of a long cable, or one of them shares a board with something noisy like a motor driver or the control electronics inside a mains-powered appliance. Isolation is about breaking the ground path, not about the size of the voltage.

The PC817 Optocoupler Module Pinout

The module's terminals split into an input side, which belongs to the machine, and an output side, which belongs to the Arduino Nano 33 IoT:

  • IN+ (or +) - the positive input terminal. The + side of the 12V/24V signal must be connected to here, with no resistor of your own: the module already carries the one its variant is built around.
  • IN- (or -) - the negative input terminal. It must be connected to the ground of the 12V/24V circuit, never to the board ground.
  • VCC - the output-side supply. It must be connected to the 3.3V pin on the Arduino Nano 33 IoT, not to 5V.
  • GND - the output-side ground. It must be connected to GND on the Arduino Nano 33 IoT.
  • OUT (or DO) - the switched output. It must be connected to a digital input pin on the Arduino Nano 33 IoT.

※ NOTE THAT:

The bare chip's pin order is fixed, but the pin and terminal arrangement on a ready-made PC817 optocoupler module varies between manufacturers - VCC, GND and OUT are not always in the same order, and the input terminals may be labelled + / - or IN+ / IN-. Always read the silkscreen on the board in front of you rather than copying a photo, and check the voltage printed on it while you are there, because the three variants look identical.

Active LOW or Active HIGH? Test the Module Before You Trust It

On the bare chip, wired with a pull-up on the collector, the logic runs backwards from what you might expect, and this part is settled physics:

  • External 12V/24V signal PRESENT - the LED lights, the transistor conducts, and the pin is pulled down to GND, so it reads LOW
  • External 12V/24V signal ABSENT - the LED is dark, the transistor is off, and the pull-up holds the pin up, so it reads HIGH

A module is not that predictable. Some pass that inverted output straight to OUT, while others invert it a second time on-board so that OUT simply follows the input. Both kinds are sold, often under the same description, so the only trustworthy answer is the one your own module gives you. Getting it takes under a minute:

  • Wire the module as shown below and upload the sketch from this tutorial unchanged.
  • Leave the input terminals with no signal on them, open the Serial Monitor, and note the state being printed.
  • Apply the 12V/24V signal to IN+ and IN-, and note what is printed now.
  • Whichever value appears while the signal is present is your module's active level.
  • Cross-check it against the module's own status LED, which lights whenever the input side is energised: the LED and the reported state must agree with each other.

If they disagree, the fix is one edit rather than a rewrite - set MODULE_ACTIVE_LOW to false at the top of the sketch and upload again. On a node whose whole purpose is reporting, that minute is worth spending, because a module read the wrong way round does not fail loudly: it publishes ENERGIZED all night while the compressor sits idle, and every run-hour total, duty cycle and alert built on that data is quietly wrong.

Keep the Two Grounds Apart

This is the one rule the whole project rests on: do not connect the ground of the 12V or 24V circuit to the Arduino Nano 33 IoT's GND. The 12V/24V supply keeps its own ground, the board keeps its own, and the only thing bridging them is light inside the PC817. If you tie the grounds together the circuit still switches and the Serial Monitor still shows the right thing - but the isolation is gone, and with it the protection you installed the part for.

Wiring Diagram

The Arduino Nano 33 IoT runs its SAMD21 at 3.3V and its pins are not 5V tolerant, so it matters where the output side of the optocoupler gets its supply. Powered from the board's own 3.3V rail, the input pin swings between 0V and 3.3V and can never go higher - whatever the isolated side happens to run at, 12V, 24V, or anything else inside the PC817's ratings. This is also why no level shifter appears anywhere in this project.

In the wiring options below, D2 is used as the isolated digital input. Any of D2 to D13 would do; D2 is simply a plain digital pin with a usable internal pull-up, and it is not shared with the built-in LED (D13) or the Serial pins (D0 and D1).

Wiring the PC817 Optocoupler Module

Arduino Nano 33 IoT PC817 optocoupler isolation module 12V input wiring

This image is created using Fritzing. Click to enlarge image

Module terminal/pin Connects to
IN+ (or +) the + of the 12V/24V signal
IN- (or -) the ground of the 12V/24V circuit only
VCC 3.3V on the Arduino Nano 33 IoT
GND GND on the Arduino Nano 33 IoT
OUT (or DO) D2 on the Arduino Nano 33 IoT

Power the module's output side from the board's 3.3V pin, not from 5V. The OUT pin idles at whatever VCC you feed it, so taking VCC from 3.3V is what keeps D2 inside the Arduino Nano 33 IoT's limits. Nothing goes in series with IN+ either: the variant you bought already contains the resistor for that voltage. Which way round OUT reports is the module's business rather than the board's, so run the one-minute check from the section above before you believe the first reading.

The same isolation rule applies: the wires going into IN+ and IN- belong to the 12V/24V circuit, and the wires going into VCC, GND and OUT belong to the board. The two groups must never meet.

Optional - Building the Same Input From the Bare PC817 Chip

If you would rather solder the raw chip than buy a module, the 4-pin part does the same job once you fit the series resistor yourself.

Arduino Nano 33 IoT PC817 optocoupler pinout
image source: diyables.io
  • Pin 1 - Anode (A) and Pin 2 - Cathode (K) are the input LED. The + of the 12V/24V signal must be connected to pin 1 through the series resistor, and pin 2 must be connected to the ground of that circuit only.
  • Pin 3 - Emitter (E) must be connected to GND on the Arduino Nano 33 IoT.
  • Pin 4 - Collector (C) must be connected to D2 on the Arduino Nano 33 IoT, with INPUT_PULLUP doing the pulling up.

Size the resistor with the ordinary LED formula, taking Vf as 1.2V and aiming for 10mA: R = (Vin - 1.2) / 0.01. That gives 220 ohm at 3.3V, 390 ohm at 5V, 1 kohm at 12V and 2.2 kohm at 24V, the 24V one wanting a 1/2W part. Wired like this the reading really is inverted, so leave MODULE_ACTIVE_LOW at true.

Wiring the PC817 in Parallel With the Machine, Never in Series

Everything above assumes the 12V or 24V signal is simply sitting there waiting to be read. On a real installation it belongs to something - the run-signal of the compressor, the coil that pulls its contactor in - and the module has to join a circuit that is already working. It joins that circuit across the device, in parallel with it, and never in line with it. A PC817 wired in series carries the machine's whole load current through a 20mA infrared LED, and the part is destroyed the moment the machine is switched on. Nothing in the existing wiring is cut, opened or rerouted; two wires are added to terminals that are already there.

Tap point on the machine Connects to
The + side of the run-signal (its switched or live terminal) the module's IN+ terminal
The - side of the run-signal (its return terminal) the module's IN- terminal

On a module the tap lands straight on the input screw terminals and needs no series resistor of its own; on the bare chip the same two wires go to the resistor and then pin 1, and to pin 2. Either way the tap draws only the small LED current the input side allows, which is nothing worth measuring beside a contactor coil, a lamp, a valve or a motor, so the compressor carries on behaving exactly as it did before the optocoupler arrived - this is a read-only measurement, not an alteration of the machine. Polarity, on the other hand, has to be right: IN+ and IN- are the two ends of an LED and conduct in one direction only, so a tap wired the wrong way round never turns on at all, with no other symptom to go by. Establish which side of the tap is positive before the wires go on.

※ NOTE THAT:

A contactor coil, relay, solenoid valve or motor throws a large reverse-voltage spike back down its own wires the instant it is de-energised, and the PC817's input LED is rated for only 6V in reverse. Fit an ordinary diode in reverse-parallel directly across the module's input terminals - diode cathode to IN+, diode anode to IN- - or across pins 1 and 2 on the bare chip. While the machine runs, that diode is reverse-biased and does nothing whatsoever; when the coil lets go, it conducts and clamps the reverse voltage to well under a volt. A 1N4148 is enough for a small tap, a 1N4007 for heavier ones.

One failure mode is worth knowing before you meet it, because it reads like a bug in the sketch. Transistor and triac outputs on a PLC, and a good many LED-lamp drivers, leak a small current even when they are switched off - enough to keep the PC817's LED faintly lit, so the input reports the machine as running and never falls back. The symptom is unmistakable: the state goes ENERGIZED and then never returns to IDLE. The cure is a bleeder resistor of about 4.7 kohm to 10 kohm fitted in parallel with the input, across the module's IN+ and IN- terminals, so the leakage runs harmlessly through the resistor instead of the LED while the genuine signal still has current to spare.

There is one limit on where this tap can go: the PC817's input is a single LED and answers to one polarity, so it is a DC part only. Sensing an AC line calls for an optocoupler whose input stage is built from two back-to-back LEDs instead.

Monitoring Whether the Machine Is Actually Running

Because the tap sits across the device rather than in whatever commands it, the reading follows the machine's real state. If a pressure switch, a timer or somebody's hand starts the compressor, the Arduino Nano 33 IoT sees it, even though nothing announced it to the board. If the command goes out and the contactor never pulls in, the board sees that too - the state that should have gone ENERGIZED stays IDLE, and that silence is the reading worth acting on.

That is what turns this from a wiring exercise into a monitor, and it is the job this particular board is built for. Every transition the sketch prints is a timestamped event, and a Nano 33 IoT is meant to send events onward rather than keep them: publish each ENERGIZED/IDLE change to a broker, an HTTP endpoint or a database, and the receiving side can total the run hours for the week, chart the duty cycle, count starts per hour to catch a pump short-cycling, or raise a message when a machine that should have started an hour ago still has not. Reporting on change rather than on a timer keeps the traffic tiny, and because the record accumulates at the far end, a reset of the board costs nothing but the seconds it was off the network.

One honest limitation is worth stating plainly: this tells you the device is energised, not that it is doing its job. A seized pump or a burnt-out heater element still draws power, and will still be reported as running.

How To Program Arduino Nano 33 IoT for PC817 Optocoupler

  • The first step is to define the digital pin that the module's OUT pin - or the bare chip's collector - is wired to
#define PC817_PIN D2 // The Arduino Nano 33 IoT pin D2 connected to the PC817 output
  • Configure that pin as an input with the internal pull-up enabled, so the output transistor has something to pull down against
pinMode(PC817_PIN, INPUT_PULLUP);
  • Declare one constant for the module's output polarity, so that a module of either kind is a single edit away
const bool MODULE_ACTIVE_LOW = true;
  • Read the pin, then turn the raw reading into a state through that constant instead of hard-coding the inversion
int raw = digitalRead(PC817_PIN); bool signal_active = MODULE_ACTIVE_LOW ? (raw == LOW) : (raw == HIGH);
  • Compare each reading with the previous one, so the sketch can act at the moment the state changes rather than on every pass through the loop
  • No external library is required for this project - a PC817 is read with plain digitalRead()

Arduino Nano 33 IoT Code for PC817 Optocoupler

/* * This Arduino Nano 33 IoT code was developed by newbiely.com * * This Arduino Nano 33 IoT code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-nano-iot/arduino-nano-33-iot-pc817-optocoupler-monitor-12v-24v-dc-input-signal */ #define PC817_PIN D2 // The Arduino Nano 33 IoT pin D2 connected to the PC817 collector (or the module's OUT pin) // Most PC817 modules pull the output LOW when the input signal is present. // If your module works the other way round, change this to false. const bool MODULE_ACTIVE_LOW = true; int prev_state = HIGH; // the previous reading of the isolated input (HIGH = 12V/24V signal absent) void setup() { // Initialize the Serial to communicate with the Serial Monitor Serial.begin(9600); // The PC817 pulls the pin down when the 12V/24V signal is present, // so the pin needs a pull-up to sit HIGH the rest of the time pinMode(PC817_PIN, INPUT_PULLUP); } void loop() { int pin_state = digitalRead(PC817_PIN); // the constant above decides which raw reading means "the isolated 12V/24V signal IS present" bool signal_active = MODULE_ACTIVE_LOW ? (pin_state == LOW) : (pin_state == HIGH); Serial.print("["); Serial.print(millis() / 1000); Serial.print("s] 24V run-signal: "); Serial.println(signal_active ? "ENERGIZED" : "IDLE"); if (pin_state != prev_state) { // The state just changed. This is the point where a connected board would // publish the new state to a broker, a web dashboard or a database. if (signal_active) Serial.println(" >> transition: STOPPED -> RUNNING"); else Serial.println(" >> transition: RUNNING -> STOPPED"); prev_state = pin_state; } delay(1000); }

Detailed Instructions

  • Check that the module in your hand is the variant that matches your signal - the 24V module on a 24V line, the 12V module on a 12V line, the 3-5V module on logic.
  • Wire the PC817 optocoupler module to the Arduino Nano 33 IoT as shown in the module wiring diagram above, leaving the 12V/24V supply switched off for now.
  • Check once more that no wire runs between the 12V/24V ground and the board's GND before any power is applied.
  • Connect the Arduino Nano 33 IoT board to your computer using a Micro USB cable.
  • Open the Arduino IDE on your computer.
  • Select the correct board: go to ToolsBoardArduino SAMD BoardsArduino NANO 33 IoT.
  • Select the correct COM port: go to ToolsPort and choose the port associated with your Arduino Nano 33 IoT.
  • Copy the code above and paste it into the Arduino IDE.
  • Click the Upload button to compile and upload the code to the board.
  • Open the Serial Monitor: go to ToolsSerial Monitor, and set the baud rate to 9600.
  • Switch the 12V/24V signal on and off a few times and watch the reported state follow it, with the module's status LED as your cross-check.

Serial Monitor Output

Newbiely | Arduino IDE 2.3.8
──
File
Edit
Sketch
Tools
Help
Arduino Nano 33 IoT
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'Arduino Nano 33 IoT' on 'COM15')
New Line
9600 baud
[3s] 24V run-signal: IDLE [4s] 24V run-signal: IDLE [5s] 24V run-signal: ENERGIZED >> transition: STOPPED -> RUNNING [6s] 24V run-signal: ENERGIZED [7s] 24V run-signal: ENERGIZED [8s] 24V run-signal: ENERGIZED [9s] 24V run-signal: IDLE >> transition: RUNNING -> STOPPED [10s] 24V run-signal: IDLE
Ln 11, Col 1
Arduino Nano 33 IoT on COM15
2

If the two states come out the wrong way round - the module's status LED lit while the Serial Monitor still says IDLE - your module inverts on-board. Set MODULE_ACTIVE_LOW to false at the top of the sketch and upload again.

Additional Knowledge

Bare PC817 chip or ready-made optocoupler module? The honest answer depends less on the part itself than on where the finished node is going to live.

On the bench, while you are still working things out, the bare chip wins on flexibility. It drops into a breadboard, the series resistor is a component you can swap in seconds, and moving from a 12V trigger to a 24V one costs you one resistor rather than one board. It is also far cheaper when you need several channels, and it takes almost no room. The price is that every input needs its own resistor calculation and its own tidy wiring, and a chip leg pushed into a breadboard is not a joint you want a field wire from a machine hanging off.

Once the Arduino Nano 33 IoT is installed somewhere and expected to keep reporting, that flexibility stops being worth anything - and that is exactly why the module's fixed variant is not the drawback it first looks like. A reporting node bolted to the frame beside a 24V compressor is wired to a 24V line for the rest of its working life; it is never going to wake up one morning watching 5V logic. The input voltage is a property of the installation, not of the project, so ordering the 24V variant is a decision you get right once, at install, and then never think about again. Everything else a permanent install wants comes along with it: screw terminals that hold a real field wire properly, a status LED that turns "is my code wrong or is my wiring wrong?" into a one-second question, and multi-channel versions that let a single Nano 33 IoT watch four or eight isolated signals from one tidy board - which is exactly the shape of the problem when the node's job is to publish the state of a whole panel. Order the variant that matches the line you are bolting it to, and order a spare of the same one while you are at it.

It is evident that neither form is simply better than the other: prototype with the bare PC817 while the trigger voltage is still an open question, then buy the optocoupler module variant that matches the line the finished node will be permanently wired to, and screw that one to the wall.

Video Tutorial

※ OUR MESSAGES

  • As freelancers, We are AVAILABLE for HIRE. See how to outsource your project to us
  • Please feel free to share the link of this tutorial. However, Please do not use our content on any other websites. We invested a lot of effort and time to create the content, please respect our work!