Introduction: How to Use the ESP8266-01 Pins

Picture of How to Use the ESP8266-01 Pins


ESP8266-01 is a very low cost WiFi enabled chip. But it has very limited I/O. At first glance, once you configure it for programming all the pins are used.

This instructiable builds on Using ESP8266 GPIO0/GPIO2/GPIO15 pins to show you how you can get four (4) usable inputs/outputs for you next ESP8266-01 project and how to use IC2 to get even more inputs.

The code here assumes you are programming the module using the Arduino IDE setup as described on under Installing With Boards Manager. When opening the Boards Manager from the Tools → Board menu and select Type Contributed and install the esp8266 platform.

These instructions are also available from at ESP8266-01 Pin Magic

Step 1: ESP8266-01 Pins

Picture of ESP8266-01 Pins

The ESP8266-01 is the smallest ESP8266 module and only has 8 pins. Of these VCC, GND, RST (reset) and CH_PD (chip select) are not I/O pins but are needed the operation of the module. This leaves GPIO0, GPIO2, TX and RX available as possible I/O pins, but even these have pre-assigned functions. The GPIO0 and GPIO2 determine what mode the module starts up in and the TX/RX pins are used to program the module and for Serial I/O, commonly used for debugging. GPIO0 and GPIO2 need to have pull-up resistors connected to ensure the module starts up correctly.

Step 2: ESP8266 Programming Tips (espcomm Failed)

When programming the ESP8266 using the Arduino IDE (see ESP8266-01 Wifi Shield) you sometimes (often) get an error messages in the Arduino IDE like:-
esp_com open failed
error: Failed to open COM33
error: espcomm_open failed
error: espcomm_upload_mem failed

In that case follow these steps to get it working:-

  1. Check you have ESP8266 board selected in the Arduino Tools menu
  2. Check you have selected a COM port in the Arduino Tools menu
  3. Power cycle the ESP8266 with GPIO0 grounded (clean power application, see below)
  4. If 3) does not fix it, unplug the USB cable from the computer wait few secs and plug it back in
  5. If 4) does not fix it, uplug USB cable from PC, close Arduino IDE, open Arduino IDE, plug USB cable back in.

When you apply power to the ESP8266, after grounding GPIO0, make sure it is applied cleanly. Don't jiggle the connection. The ESP8266 led should just come on and stay on without any flashes.

Step 3: Best Trick – Use I2C

Picture of Best Trick – Use I2C

The best trick to get extra inputs into the ESP8266-01 is to use an I2C interface.

One choice is to use GPIO0 and GPIO2 as the I2C bus.

The pullup resistors needed to get the module to start up correctly can double as the I2C bus pull-up resistors and the other, slave, components on the bus are open collector and so should not pull the bus down on power-up. However in some cases slaves, particularly those with battery backup, can become stuck and hold the bus down. In those cases you will need to isolate the bus until the ESP8266 gets through its boot stage.

You can avoid this issue by using TX and RX for the I2C bus

A few things to note:

  1. GPIO1 (TX) is used as the Data line, because you will always get some debug output on GPIO1 on power up. There is no way to suppress this output, but the Clock line (RX) will be held high so none of this data will be clocked to the slaves
  2. When programming the ESP8266, the RX line is connected to the programmer's output. At the end of the programming the ESP8266 reboots and 330 Protection resistor prevents RX shorting the programmer's output drive.
  3. The I2C series resistors provide similar protection for the TX, RX from shorts on the I2C bus

The ESP8266 is 3.3V device so preferably use 3.3V I2C slaves. Many, but not all, I2C devices are are 3.3V these days. “In general, in a system where one device is at a higher voltage than another, it may be possible to connect the two devices via I2C without any level shifting circuitry in between them. The trick is to connect the pull-up resistors to the lower of the two voltages.” (SparkFun I2C tutorial) For a mixture of 5V and 3.3V devices connect the pullup resistors to the 3.3V line, as shown above.

Using I2C is a great way to add a multi-channel A-to-D converter to the ESP8266-01 which does not expose the single ADC input of the underlying module. For example using Adafruit 12bit I2C 4 channel ADC or for analog output SparkFun's I2C DAC Breakout – MCP4725 board. Many other types of sensors are also available with I2C buses.

See for more information of overcoming I2C problems. Also see Reliable Startup for I2C Battery Backed RTC for a short method to help clear the bus

Step 4: Using the GPIO0 /GPIO2 for OUTPUT and RX for INPUT

Picture of Using the GPIO0 /GPIO2 for OUTPUT and RX for INPUT

While can send debug messages over the WiFi connection it is often convenient to use the TX connection. The next example show how to use GPIO0 and GPIO2 as outputs and RX as an input.

allows you to use RX as a general purpose input (or another output), while still writing debug messages to Serial. Again the 330 ohm resistor in the RX lead to the Flash programmer protects against shorting out the programmer's driver. NOTE: S1 will have to be open in order to program the ESP8266.

The TX pin can be accessed from the sketch as GPIO1 and RX is GPIO3

Step 5: Another Trick – Driving a Relay and Reading a Push Button Using GPIO0 / GPIO2

Picture of Another Trick – Driving a Relay and Reading a Push Button Using GPIO0 / GPIO2

Here is another way of configuring the pins. Note: This trick only works if you have a relay module with an isolated input (N1 and N1-com). Because of this limitation and the complexity of the supporting code, the previous example, using RX as an input, is preferable.

Using ESP8266 GPIO0/GPIO2/GPIO15 pins has already covered how to use GPIO0/GPIO2 together to get an extra input. Here that example will be extended to use GPIO0 as an relay driver output and GPIO0/GPIO2 as an input.

Here is the schematic as a pdf.

Here GPIO0 is used as an output to drive the relay and GPIO0/GPIO2 is used as an input to read the momentary push button which is used as a manual override to turn the relay on and off, in addition to the remote control over the WiFi connection. The momentary push button is also used to enable the config mode if it is press when power is applied.

The trick here is to do all this while still keeping GPIO0 and GPIO2 high when the ESP8266 module is initializing.

The pull-up resistors, R1 and R3, provide the necessary High for these two pins, but you have to ensure that any extra circuitry attached to GPIO0 and GPIO2 cannot not pull pins low. The optically isolated relay is connected between +3.3V and GPIO0. This keeps GPIO0 high on start up but allows GPIO0 to be made an output, after startup, and ground the relay input to operate the relay. It does not matter if the momentary push button is operated while the module is initializing, as that just connects GPIO0 to GPIO2 and connect both of these to their pullup resistors.

Detecting Config Mode

Using the ESP8266 as a temporary access point you can configure it via a web page as described here. Part of that process is to use a push button, or shorting link, on power-up to indicate to the software that you want to enter config mode.

Once the ESP8266 module has initialized, it runs the setup() code. In that code, to detect if the momentary push button is pressed, you need not make GPIO0 low to supply a GND to push button and then check the GPIO2 input to see if it low. A side affect of this check is that the relay will always be operated when the unit is being put into config mode. Once you see the relay operate you can can release the push button, because its input will have been detected by then. Here is some sample code to do this in the setup()

boolean configMode = false;  // not in config mode normally
void setup() {
  pinMode(0, OUTPUT);
  digitalWrite(0, LOW); // make GPIO0 output low
  // check GPIO2 input to see if push button pressed connecting it to GPIO0
  configMode = (digitalRead(2) == LOW);
  if (configMode) {
    // start AP and get ready to serve config web page
    // leave relay on to indicate in config mode
  } else {
    // normal usage
    // make GPIO0 HIGH to turn off the relay
    digitalWrite(0, HIGH);
  // rest of setup()

Detecting the Manual Override Push Button

The previous section covered detecting when the push button was pressed on power up to enable config mode. We also want to use that push button as a manual override for turning the relay on and off in addition to being able to control the relay via the WiFi link.

The WiFi control of the relay is not covered here, but can easily be done using pfodApp. See OLIMEX Menu Generator for how to generate Arduino code with pfodDesigner for ESP8266 modules.

This section will deal with how to detect when the push button is pushed, indicating the user wants to toggle the relay, i.e. turn it OFF is it on or turn it ON if it is off. The schematic is the same as above, all the tricks are in the code. There are two case to consider:-

  1. The relay is OFF and the user wants to turn it on using the push button,
  2. The relay is ON and the user wants to turn it off using the push button.

The relay is OFF and the user wants to turn it on using the push button.

In this case the output of GPIO0 is HIGH. Actually GPIO0 can be an input in this case as the pull up resistor R1 will ensure the relay does not turn on. That is the trick. In this case make GPIO0 an Input and make GPIO2 Output LOW and then when the user presses the push button, two things will happen:- a) the relay will turn on due to the ground provided by GPIO2 via the push button and b) the Input GPIO0 will go low. The code checks the state of the Input GPIO0 and when it goes LOW the code knows the use has pressed the push button and wants the relay to be on. The code then makes GPIO0 an Output LOW to keep the relay on when the push button is released.

The relay is ON and the user wants to turn it off using the push button.

In this case, following on from the case above, GPIO0 is an Output LOW holding the relay ON. Now for this case make GPIO2 an Input (pulled up by R3) and then when the user presses the push button the Input GPIO2 is pulled LOW by the LOW Output on GPIO0. When the use releases the push button the code detect the LOW to HIGH transition and then makes GPIO0 an Input, which releases the relay due to the pull up resistor, R1, and makes GPIO2 an Output LOW to set up for case i) above.

One more trick. For case ii) we need GPIO2 as an Input which detects a LOW to HIGH transition to turn the relay OFF. But if we make GPIO2 and input at the end of case i) then we will get a LOW to HIGH transition as the user releases the push button they just pressed to turn the relay ON. To avoid turning the relay off again immediately, the first LOW to HIGH transition after turning the relay will be ignored as it is just the user releasing the push button they pressed to turn the relay ON.

Sample loop() Code for Relay Manual Over-ride

In this code I am ignoring switch debounce for simplicity. The inputs should be debounced in any real application.

The sample code is here, ESP8266_01pinMagic_1.ino

Again this leaves the TX / RX pins available for Serial debugging or use as other I/O


This page shows how to get the most out the limited pins available on the ESP8266-01. Using GPIO0 / GPIO2 as an I2C bus gives the biggest expansion, but if you project does not use I2C, you can still drive a relay and detect a push button input using GPIO0 / GPIO2. In either case TX / RX are also available for Serial debugging or if you send debug print statements over the WiFi link, these pins are available for general I/O as well..


drmpf (author)2017-09-26

Hi MRezaN, sorry for the delay in replying, but for some reason Instructables is not sending me notifications of comments :-(

Anyway checkout the reply to lotekjunky below. Looks like you need to add a Fet between GPIO0 and IN to fix the problem.

MRezaN made it! (author)2017-06-14

Hi, Great tutorial.

I have a SSY-2330 relay with one IN, The problem is when I connect it to GPIO0 it causes the ESP to go in program mode. It works fine with GPIO2.

How can I solve this issue?

mozalm (author)2017-04-20

can the giop consider as a digital pins by defualt ?

drmpf (author)mozalm2017-04-21

GPIO-0 and GPIO-2 default to inputs. You need to use the mode command to change their mode to something else.

mozalm (author)drmpf2017-04-21

So can i connect my dht22 sensor to the gpio 2

drmpf (author)mozalm2017-04-21

Sorry I have not used dht22 sensor, but provided you can keep GPIO-2 pulled high while powering up the ESP8266, you can use GPIO-2 as you like.

lotekjunky (author)2017-01-01

I've learned a lot from your instructables, but I'd like to make a request. Would you mind making an instruction on how to use GPIO-0 or GPIO-2 as an output via a transistor or mosfet? i'm trying to drive an IR LED off of an ESP-01 and it is giving me all sorts of problems. I'm using a 2n2222a with c @ 3v3, base is coming from GPIO-0 with r3k3. Emitter is going to anode of IR LED, IR LED Cathode is going through R100 to ground. This seems to work... sometimes. Other times, the ESP just hangs with rst 2, boot 3,7 after turning the circuit on, or boot 3,6 after I hit the reset button.

drmpf (author)lotekjunky2017-01-01

A 3k3 resistor on GPIO-0 to a transistor base is problematic. A P-Fet would be much better. Here is a circuit you can use a relay (or with a suitable limiting resistor an IR LED). The SI2333DS fet is specified down to 1.8v and works well at 3V. The relay needs to have a 3V coil. The second circuit uses the 3V fet to drive an opto-isolated 5V relay module. See the instructable above for how to drive a 5V relay module from 3V.

lotekjunky (author)drmpf2017-01-01

Thank you for the response, I truly appreciate it. I've only chosen GPIO-0 as I'm a newb. I'm not using GPIO-2 for anything. Would my original ckt work better if I switch from 0 to 2? Or, do you think the best path forward is to follow your instructions with the coil / relay solution?

drmpf (author)lotekjunky2017-01-01

You can use either GPIO-0 or GPIO-2, both have similar limiation, i.e. they must be in pulled to +3V3 with a <10K resistor when booting normally.

Here is revised circuit that drives an IR led as your original question asked.

(Also the instructable referred to in my previous reply as was my Home Automation - How to Add Relays to Arduino )

lotekjunky (author)drmpf2017-01-13

So I got a couple of those SI2333DS PFETs in. Holy cow! I've never realized how small SMD stuff could be. I think I have soldered on some legs properly so I can move it around. So, I'm looking at your diagram and the P-FET symbol you have on there looks like there is a Zener symbol in the FET. None of the spec sheets I can find on this FET has that symbol. Is that just because it was the symbol you grabbed for your diagram, or am I to put a zener connecting those 2 pins (I think D and S)? Sorry if this is a dumb question.

drmpf (author)lotekjunky2017-01-13

You get that diode across EVERY fet for free. It is an artifact of the construction of the semiconductor layers. It is shown on the datasheet symbol,

Well worth working your way through the data sheet and trying to understand the limits and graphs. The diode is listed under "Diode Forward Voltage" ~0.7V on page 2.

For our purposes the important value is the "Gate Threshold Voltage" -- max -1V, which is when the fet just starts to turn on.

You need to also be aware of the maximum breakdown voltages and the "Drain-Source On Resistance" Also for the on resistance you need to check the graphs carefully to see what will happen at your particular gate drive and drain-source current.

For mounting I usually solder it to the lands on a vero board.

lotekjunky (author)drmpf2017-01-16

Thank you so much for your help, and that picture of the fet on a board is incredibly helpful. i was able to get my project completed this weekend :)

lotekjunky (author)drmpf2017-01-02

Thank you for the further instructions. I don't have any p fets in my kit, so I'll try and post back in a few weeks after they show up in the mail and let you know how it went. I also ordered a couple of esp-12 modules as trying to get these 01s to work as an IR blaster might just be over my head at this stage. I think I can still get them to work as an IFTTT button, so nothing is wasted :) Thanks again!

iTECHKING (author)2017-01-09


Thanks for sharing the such an info. After following your steps, finally I became success to Control Relays through Web.

But the problem I am facing is that the 5V Relay, I am using in my project, works when I connect IN1 or IN2 pin to Low (ground) but the digital output of the GPIO0 and GPIO2 is high (positive). And it causes the relay ON when I click to OFF button on Web and OFF when I click ON.

In case of LED it works fine bcoz no matter what the output GPIO pin is providing, the second LED pin will be connected accordingly (either to high or low).

Kindly provide any suggestion.


drmpf (author)iTECHKING2017-01-09

some options

i) change to a relay module that lets you choose active High or active LOW seeStep 7: High/Low Triggered Relays for Use with 3.3V boards (e.g. ESP8266) in my Home Automation - How to Add Relays to Arduino

ii) edit the web page html to change OFF to ON and ON to OFF
iii) invert the signal from the web that is driving the relay in the ESP code.

drmpf (author)2016-10-08

Corrected schematic for using TX/RX as SDA/SCL
Thanks to diy_bloke for catching the error

drmpf (author)2016-10-07

Using the 4 pins of the ESP8266-01 has an example of using I2C

diy_bloke (author)drmpf2016-10-08

thanks. for the link. Indeed, 4 pins can do a lot. I still have a PCF8591 ADC coming and a PCF8574 I/O expander and BH1750 sensor I want to try to put all on 1 bus

drmpf (author)2016-09-29

Added ESP8266 Programming Tips (espcomm failed) section

zasf (author)2015-09-20

I'm trying to drive a relay with GPIO0 as described in step 4. To activate the relay, GPIO0 must be driven LOW (Active LOW). This leads me to use COM + NC for connecting my device to the mains, instead of COM + NO as I would normally do.

Using COM + NC has the side effect that in case of failure of the ESP8266, my device will be triggered On. How do I deal with this?

drmpf (author)zasf2015-09-20

The trick is to use an isolated relay driver That is a relay that has In+ and In- and then connect In- to GPIO0 as shown in the circuit.

If on the other hand, you have a relay that only has one input, IN, and the relay IN input is Active High, (so normally no voltage on the input to upset the ESP8266 3.3V output.)

Then you need to use either TX (GPIO1) or RX (GPIO3) as an output to drive the relay

Note GPIO1 will be toggled up and down on power up as it sends the initial debug output, so GPIO3 seems to be the best choice

I have not actually tried this yet, but believe it should work

zasf (author)drmpf2015-09-20

My relay driver has only one input IN.

GPIO3 does work. It doesn't have all the annoyances of GPIO0 and GPIO2 (pull up resistors, Active Low, etc) and since I don't need to receive serial input, it seems to be suitable.

Thanks for the advice and this very good instructable.

MattG14 (author)zasf2016-08-29

is there a trick for getting gpio3 as output. I had gpio2 working but with the pull up at boot I need to use gpio3. but for some reason it is always outputting high

MattG14 (author)MattG142016-08-30

I figured this out. I had a serial print line in the code which was keeping the pin high. I took this out and it works.

drmpf (author)MattG142016-08-29

I have a circuit that uses RX (GPIO3) as an output. Here is my setup() code

const int cmd_A_pin = 3;
// name the output pin for 'Relay '
int cmd_A_var = 0;
// output for 'Extension Power is ' is initially LOW,

void setup() {
pinMode(cmd_A_pin, OUTPUT);
// set as output

digitalWrite(cmd_A_pin, cmd_A_var); // set LOW

Check the TX output, your ESP2866 may just be rebooting continually due to some other issue.

diy_bloke (author)2016-04-06

great article. Just a question I have an ESP8266-01 as well and when using it to give an atmega328 WiFi capabilities, I always connected Rx to Tx and Tx to Rx. and that worked.
Yet, I seem to see a lot of circuits connecting Tx-Tx and Rx-Rx. did in later versions something change in the labelling of the pins (with e.g. 'Tx' now meaning 'connect to Tx from other device).
you still advice Rx as input and Tx as (debug) output which is as one expects it to be, but can so many other people be wrong?

drmpf (author)diy_bloke2016-04-06

Tx to Rx and Rx to Tx is correct. All serial connections work like this. The confusion in other cases may arise if the builder marks the lead with 'where it should be connected to' instead of what its function is.

Here is an introductory link to Serial Communications

diy_bloke (author)drmpf2016-04-06

yes exactly my thoughts. I was just wondering if maybe the namesof the pins had changed in later ESP' s, indeed from say Tx to 'this one should go to Rx'

diy_bloke (author)diy_bloke2016-08-28

i think the confusion comes from people using the FDTI interface of an UNO to communicate with the esp8266. The Rx of the interface (basically the atmega8) goes to the Tx of the Atmega328 so to pick up that Rx signal the ESP8266 Tx connects to the Arduino pin labelled 'Tx' (which is where the Atmega8 Rx goes to).... and vice versa

drmpf (author)diy_bloke2016-04-06

not to my knowledge

diy_bloke (author)drmpf2016-04-07

thanks. I knew I wasnt crazy :-)

diy_bloke (author)2016-08-28

very good article

arpruss (author)2016-06-17

Dumb question: Which pin is the GPIO15?

drmpf (author)arpruss2016-06-17

The ESP8266-01 does not bring GPIO15 out to a connector. Other ESP8266 modules do. Check out ESP8266 module types

Hamids (author)2016-05-04

hi and thanks for great job with ESP, actually I disassemble the in-market PIR sensor to monitor the motion, I've tried to read the digital input with ESP but as the ESP is to weak for sink or source the current input pin, I've attempt to use the open collector method but some guys told me the using optocoupler IC have much advantage than PNP transistor , I really appreciated to have your comment to how read digital isolated pin with ESP-01 or else


drmpf (author)Hamids2016-05-04

First measure how many volts the digital output is switching between.

If it is >3.3V then you need some isolation.

For modest voltages say <24dc an open collector switch is good.

Drive base of an NPN transistor eg 2N3903 / BC548 via a resistor and connect the collector to the EPS-01 input. Set the EPS-01 input as pullup. Select the resistor so that <1mA or less flows through the base.

If you need to use an optical isolator then here is a circuit I use to detect Mains voltage

Hamids (author)drmpf2016-05-04

hi , thanks for quick reply , right now I made opto IC to monitor change Level of device , but I don't fully understand for your idea to use the NPN transistor, I made following schematic from your comment please let me know which way is the best to digitaRead of device conected to ESP


drmpf (author)Hamids2016-05-05

Your NPN circuit is correct and either will do.

As I mentioned above if the +V is large then you should use an opto, otherwise the choice is yours. If you have the opto working then keep on with it.

In both circuits the resistor is to limit the current so that the NPN base/emitter or the opto Led does not burn out.

Hamids (author)drmpf2016-05-11

thanks Drmpf for your comments , actually I bought the PIR sensor and rip it off to find the signal to monitor it by ESP, I tried to hack the sensor LED so monitor its blinking however after couple of tried I find the sensor is too week(about uA) and can't trigger the opto IC, I was wonder if you have special opto or transistor schematic to use for such week current


drmpf (author)Hamids2016-05-12

try replacing the sensor LED with the opto coupler, Otherwise you could try a fet instead to drive the opto. Fet runs on volts not current. Say one like 2n7002 which needs about 3.5V to turn on or a BSS138 which needs less say 3V

Hamids (author)drmpf2016-05-15

Thanks Drmbf for the tip , however as you well know most sensor and module come to old Arduino fashion 5 volt supply or TTL , I know I should divide the analogue sensor voltage to 1 volt for ESP ADC , but what is your suggestion when we have digital device with 5 volt supply , how about the I2c output device?


drmpf (author)2015-11-16

Updated 17th Nov 2015 to include using TX/RX as I2C bus and using RX as an input while keeping TX for debug output.

About This Instructable




More by drmpf:Adafruit Feather NRF52 Custom Controls, No Coding RequiredRemote Controlled Light Switch -- Retrofit. Light Switch Still Works, No Extra Writing.Redbear BLE Nano V2 Custom Controls With PfodApp -- No Coding Required
Add instructable to: