Learn

Arduino relay module: why LOW turns it on, and other surprises

  • 192parts on the bench
  • 25boards running now
  • 1.00xreal time, on every board
Arduino Uno: a four-channel relay boardlive0.000 s 0.00x
Click to open it in the editor
Active LOW inputs on pins 2 to 5, a lamp on each channel. Open it and swap the two setup lines to hear the startup click.

The blue relay module is in almost every Arduino kit, and it produces the same three questions on r/arduino and the Arduino forum every week: why the relay is on when the code says off, why it clicks every time the board starts, and why it does nothing on an ESP32 or a Pico. All three have one-line fixes once you know how the module is built.

The circuit above is a four-channel relay board on an Arduino Uno, with a lamp on each channel’s normally open contact and pins 2 to 5 on the inputs. It chases the lamps round, and it is wired and coded the right way. Open it in the editor and each problem below takes one change to reproduce.

Most relay modules are active LOW

On nearly every cheap relay board, each IN pin goes to the cathode of an LED inside an optocoupler, and the LED’s anode is tied to the board’s VCC through a resistor. Current flows, and the relay pulls in, only when IN is pulled toward ground. So `digitalWrite(pin, LOW)` turns the channel on and `HIGH` turns it off. That is the opposite of an LED on a pin, and it is the single most common reason a relay sketch looks backwards.

We ran a sketch that writes HIGH to mean on against the simulated board. Channel 1 was on whenever the sketch said off, and the three channels the sketch never wrote stayed pulled in the whole time, because a pin set to OUTPUT starts LOW. Set the board’s trigger property to high and the same sketch behaves, which is how the rarer active HIGH boards work. A few boards have a jumper to choose; most do not, so check yours with a wire from IN to GND before writing code.

The cleanest fix is a small function that hides the inversion, so the rest of the sketch can say what it means.

Active LOW, handled once
const int RELAY_PIN = 2;

void relayOn(bool on) {
  digitalWrite(RELAY_PIN, on ? LOW : HIGH);  // LOW switches the relay on
}

void setup() {
  digitalWrite(RELAY_PIN, HIGH);  // off, before the pin is even an output
  pinMode(RELAY_PIN, OUTPUT);
}

void loop() {
  relayOn(true);
  delay(1000);
  relayOn(false);
  delay(1000);
}

It clicks when the board starts

At reset every pin is an input, and an input leaves the optocoupler’s LED with no path to ground, so the relay stays off. The trouble starts with `pinMode(pin, OUTPUT)`. The output latch is LOW after a reset, so that line drives the pin LOW, which on an active LOW board means on. The relay stays on until the sketch gets round to writing HIGH.

How long that is decides whether you hear it. With the two lines back to back, the pin is LOW for a few microseconds; in our run the simulated relay’s arm started to move and fell back without ever touching the other contact, because a relay needs about 10 milliseconds to pull in. Put a `Serial.begin(9600)` and one `Serial.println` between them, as many sketches do while setting things up, and the contacts closed about 10 milliseconds after start and stayed closed for another 10. On a real board that is an audible click and a brief pulse to whatever the relay switches, which matters if it is a pump, a lock or a motor.

The fix in the code above is to write HIGH first and then make the pin an output. Writing HIGH to an input turns on the internal pull-up, which keeps the module off, and the pin goes straight from that to a driven HIGH with no LOW in between. With that order the simulated relay never moved at all, even with the print in the middle.

Two causes are outside the code. On a real Uno the bootloader flashes the L LED on pin 13 after every reset, so a relay on pin 13 can click before your sketch starts; use another pin. On an ESP32, a few pins are strapping pins that the chip reads while it boots, and some of them are driven or pulled during the boot; the ESP32 DevKit help article lists them. Mokxi runs no bootloader, so those two only show up on the bench.

It does not switch at all

Check the supply first. The coil on a standard module is a 5 volt coil and it needs close to 5 volts to pull in. We ran the board with its VCC at 3.3 volts and no channel ever moved, whatever the input said; at 4.2 volts it worked. That is why a 3.3 volt board such as an ESP32 or a Pico should power the module from its 5 V or VBUS pin while its GPIO drives IN.

Driving IN from a 3.3 volt pin while VCC is 5 volts works on many boards, but not all. The optocoupler’s LED sits between 5 volts and your pin, so a 3.3 volt HIGH still leaves a volt or more across it, and on some modules the channel will not turn fully off. Mokxi reads IN as a logic level against half of VCC, so it cannot show that half-on state. If a module will not release on a 3.3 volt board, a module rated for 3.3 volt logic, or a small transistor on each input, fixes it.

Next, ground and wiring. The board’s GND and the module’s GND must be joined, and the load goes on COM and NO, not COM and NC, if it should be off until the relay pulls in. Then check the speed: in our run a sketch that toggled the input every 4 milliseconds left the arm traveling back and forth without ever making contact. Nothing on a relay should change faster than a few times a second.

What the module does for you, and what it does not

The module already carries the transistor, the diode across the coil and the optocoupler, so a pin can drive it directly. A bare relay cannot be driven from a pin: its coil draws far more current than a pin should supply, and switching it off throws a voltage spike back at whatever drove it. The flyback diode page shows that spike, and the relay motor project drives a bare relay through a 2N2222 with a 1N4007 across the coil.

Each coil draws roughly 70 milliamps, so four channels together are more than a USB-powered board likes. Many boards have a JD-VCC jumper that lets the coils run from a separate 5 volt supply. Mokxi does not model supply current or that jumper, so a board that would sag on your desk runs cleanly here.

Keep projects in class on low voltage. The screw terminals are rated for mains, but a breadboard project is no place for it, and a lamp, a fan or a pump on a 12 volt supply teaches exactly the same thing.

Questions

Why is my relay on when I write LOW?

Most relay modules are active LOW: IN pulls an optocoupler’s LED to ground, so LOW switches the channel on and HIGH switches it off. Wrap it in a function such as relayOn(true) so the sketch reads the right way.

How do I stop the relay clicking when the Arduino starts?

Write the pin HIGH before calling pinMode(pin, OUTPUT). The pin then goes from input to a driven HIGH without ever being LOW. Also keep relays off pin 13, which the bootloader blinks on a real Uno.

Can an ESP32 or a Pico drive a 5 V relay module?

Usually, if the module’s VCC comes from the board’s 5 V pin and only IN is driven at 3.3 V. Some modules will not turn fully off from a 3.3 V HIGH; a 3.3 V module or a transistor on the input fixes that.

Do I need a diode with a relay module?

Not with a module, which already has one across each coil. A bare relay needs a diode across its coil and a transistor to drive it.

Build this for real

Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.