Using ESP-01 RX and TX pins as additional GPIO pins

Hello,

I am trying to maximize the use of the ESP-01 by enabling it to control 4 relays using its normal GPIO pins 0 and 2, but additionally convert its RX and TX pins as two extra GPIO pins. I researched online and i found some specific code which i included into my final sketch: esp8266 - How to I make the Tx and Rx pins on an ESP-8266-01 into GPIO pins? - Arduino Stack Exchange
I commented out all the serial.print lines to make sure they were not interfering. But none of the relays are working. I am wondering if i need to pull certain pins HIGH in the void setup() function?

/* 
 * ESP-01 WiFi relays controller via local network
 * version 1.2 
 * Testing RX and TX as extra GPIO pins
 */

#include <ESP8266WiFi.h>

const char* ssid = "****"; // enter Service Set Identifier
const char* password = "*****";  // enter WiFi network password

int relayPin1 = 0; // GPIO0 of ESP-01
int relayPin2 = 1; // GPIO1 of ESP-01 (TX)
int relayPin3 = 2; // GPIO2 of ESP-01
int relayPin4 = 3; // GPIO3 of ESP-01 (RX)

int relay1_status = 0;  // status of relay 1 initialised to 0 or OFF
int relay2_status = 0;  // status of relay 2 initialised to 0 or OFF
int relay3_status = 0;  // status of relay 3 initialised to 0 or OFF
int relay4_status = 0;  // status of relay 4 initialised to 0 or OFF

WiFiServer ESPserver(80); //Service Port

void setup() 
{
//********** CHANGE PIN FUNCTION  TO GPIO **********
//GPIO 1 (TX) swap the pin to a GPIO.
pinMode(1, FUNCTION_3); 
//GPIO 3 (RX) swap the pin to a GPIO.
pinMode(3, FUNCTION_3); 
//**************************************************

//Serial.begin(115200); //Default Baud Rate for ESP-01
pinMode(relayPin1, OUTPUT);  // Connect relay 1 to ESP-01's GPIO 0
pinMode(relayPin2, OUTPUT);  // Connect relay 2 to ESP-01's GPIO 1
pinMode(relayPin3, OUTPUT);  // Connect relay 3 to ESP-01's GPIO 2
pinMode(relayPin4, OUTPUT);  // Connect relay 4 to ESP-01's GPIO 3

digitalWrite(relayPin1, LOW);  // set initial status to LOW
digitalWrite(relayPin2, LOW);  // set initial status to LOW
digitalWrite(relayPin3, LOW);  // set initial status to LOW
digitalWrite(relayPin4, LOW);  // set initial status to LOW

/*Serial.println();
Serial.println();
Serial.print("Connecting to WiFi: ");
Serial.println(ssid);
*/
WiFi.begin(ssid, password);
delay(5000);

// The following 5 lines of code assign static IP address to ESP-01. Otherwise, comment out to get automatic IP.
  IPAddress ip(192,168,8,233);
  IPAddress gateway(192,168,1,1);
  IPAddress subnet(255,255,255,0);
  WiFi.config(ip, gateway, subnet);
  delay(5000);

while (WiFi.status() != WL_CONNECTED) 
{
  delay(100);
  //Serial.print("*");
}
//Serial.println("");
//Serial.println("WiFi connected");

// Start the server
ESPserver.begin();
//Serial.println("Server started");
 
// Print the IP address
/*
Serial.print("The URL to control ESP-01: ");
Serial.print("http://");
Serial.println(WiFi.localIP());
Serial.println("");
*/
}

void loop() 
{
// Check if a client has connected
WiFiClient client = ESPserver.available();
if (!client) 
{
  return;
}

// Wait until the client sends some data
//Serial.println("Client connected");
while(!client.available())
{
  delay(1);
}

// Read the first line of the request
String request = client.readStringUntil('\r');
//Serial.println(request);
client.flush();

// Match the request
if (request.indexOf("/RELAY1ON") != -1)
{
  //Serial.println("Relay 1 is ON");
  digitalWrite(relayPin1, HIGH);
  relay1_status = 1; // ON
}
else if (request.indexOf("/RELAY1OFF") != -1)
{
  //Serial.println("Relay 1 is OFF");
  digitalWrite(relayPin1, LOW);
  relay1_status = 0; // OFF
}
else if (request.indexOf("/RELAY2ON") != -1)
{
  //Serial.println("Relay 2 is ON");
  digitalWrite(relayPin2, HIGH);
  relay2_status = 1; // ON
}
else if (request.indexOf("/RELAY2OFF") != -1)
{
  //Serial.println("Relay 2 is OFF");
  digitalWrite(relayPin2, LOW);
  relay2_status = 0; // OFF
}
else if (request.indexOf("/RELAY3ON") != -1)
{
  //Serial.println("Relay 3 is ON");
  digitalWrite(relayPin3, HIGH);
  relay3_status = 1; // ON
}
else if (request.indexOf("/RELAY3OFF") != -1)
{
  //Serial.println("Relay 3 is OFF");
  digitalWrite(relayPin3, LOW);
  relay3_status = 0; // OFF
}
else if (request.indexOf("/RELAY4ON") != -1)
{
  //Serial.println("Relay 4 is ON");
  digitalWrite(relayPin4, HIGH);
  relay4_status = 1; // ON
}
else if (request.indexOf("/RELAY4OFF") != -1)
{
  //Serial.println("Relay 4 is OFF");
  digitalWrite(relayPin4, LOW);
  relay4_status = 0; // OFF
}
else
{
  //Serial.println("Invalid request");
  relay1_status = 2; // Invalid request
  relay2_status = 2; // Invalid request
  relay3_status = 2; // Invalid request
  relay4_status = 2; // Invalid request
  //client.stop();
  //Serial.println("Client disconnected");
  //Serial.println();
  //return;
}

// Send a standard http response header
client.println("HTTP/1.1 200 OK");  // start the web response that is sent to the web browser
// The 200 OK is a HTTP response code and in this case is 200 which means the request is OK
client.println("Content-Type: text/html");  // tell the browser that the response content type is text/html
client.println("Connection: close");
// the connection will be closed after completion of the response
client.println(); // need to have a space here after http response header
client.println("<!DOCTYPE HTML>");  // HTML web site template
client.println("<html lang=\"en\">");
client.println("<head>");
client.println("<meta charset=\"utf-8\">");
client.println("<title>ESP-01 WiFi relay controller</title>");
client.println("</head>");
client.println("<body>");

// Prints text in web browser
client.println("<h3>ESP-01 WiFi relay controller</h3>");

client.print("<p><b>Relay 1 (GPIO 0):</b> ");
client.println("<a href='/RELAY1ON' target='_self'>ON</a>");
client.println("<a href='/RELAY1OFF' target='_self'>OFF</a></p>");
client.print("<p>Status of relay 1: ");
if (relay1_status == 1)
{
  client.println("<font color=\"red\"><b>ON</b></font></p>");
}
else if (relay1_status == 0)
{
  client.println("<font color=\"blue\"><b>OFF</b></font></p>");
}
else if (relay1_status == 2)
{
  client.println("Invalid request</p>");
}

client.print("<p><b>Relay 2 (GPIO 1 / TX):</b> ");
client.println("<a href='/RELAY2ON' target='_self'>ON</a>");
client.println("<a href='/RELAY2OFF' target='_self'>OFF</a></p>");
client.print("<p>Status of relay 2: ");
if (relay2_status == 1)
{
  client.println("<font color=\"red\"><b>ON</b></font></p>");
}
else if (relay2_status == 0)
{
  client.println("<font color=\"blue\"><b>OFF</b></font></p>");
}
else if (relay2_status == 2)
{
  client.println("Invalid request</p>");
}

client.print("<p><b>Relay 3 (GPIO 2):</b> ");
client.println("<a href='/RELAY3ON' target='_self'>ON</a>");
client.println("<a href='/RELAY3OFF' target='_self'>OFF</a></p>");
client.print("<p>Status of relay 3: ");
if (relay3_status == 1)
{
  client.println("<font color=\"red\"><b>ON</b></font></p>");
}
else if (relay3_status == 0)
{
  client.println("<font color=\"blue\"><b>OFF</b></font></p>");
}
else if (relay3_status == 2)
{
  client.println("Invalid request</p>");
}

client.print("<p><b>Relay 4 (GPIO 3 / RX):</b> ");
client.println("<a href='/RELAY4ON' target='_self'>ON</a>");
client.println("<a href='/RELAY4OFF' target='_self'>OFF</a></p>");
client.print("<p>Status of relay 4: ");
if (relay4_status == 1)
{
  client.println("<font color=\"red\"><b>ON</b></font></p>");
}
else if (relay4_status == 0)
{
  client.println("<font color=\"blue\"><b>OFF</b></font></p>");
}
else if (relay4_status == 2)
{
  client.println("Invalid request</p>");
}

client.println("</body>");
client.println("</html>");

// give the web browser time to receive the data
delay(1);

// close the connection:
//Serial.println("Client disconnected");
//Serial.println();
}

I also found this link while searching for a solution: https://www.roboremo.com/simple-wifi-rc-car.html although i’m not sure if it is applicable. According to that web page, the GPIO0 and GPIO2 must be pulled up and a 1N4148 diode must be added??

1 Like

http://www.forward.com.au/pfod/ESP8266/GPIOpins/ESP8266_01_pin_magic.html

ieee488:
ESP8266-01 Pin Magic How to use the ESP8266-01 pins

That's interesting, but it's a solution involving I2C. I am looking for a more direct way of using RX and TX pins as GPIO pins.

The author of that page is very knowledgeable.

If you think you know more than him, write him.

does the relay on io 2 or io 0 work?

If you never invoke serial.begin, then Tx and Rx are just I/O pins.

You do need to use active-LOW relay modules of course since the GPIO0 and GPIO2 must be pulled high on power-up.

And the common active-LOW relay modules must have VCC connected to 5 V, not 3.3 V since they have a LED and optocoupler in series and require more than 3.3 V to operate.

ESP01 works perfect with PCF8574. Don’t just run away of it.
For relay module, you turn it ON with LOW. Here is a great video:

Juraj:
does the relay on io 2 or io 0 work?

OK, to make troubleshooting easier, i went back to a simpler version of the code and switched the relay with a simple LED. I also tested the GPIO 2 pin of the ESP-01 instead of engaging in more advanced RX/TX to GPIO conversions.

Here is the code:

#include <ESP8266WiFi.h>

const char* ssid = "*****"; // enter Service Set Identifier
const char* password = "*****";  // enter WiFi network password

int ledPin = 2; // GPIO pin of ESP-01
int led_status = 0;  // status of LED initialised to 0 or OFF

WiFiServer ESPserver(80); //Service Port

void setup() 
{ 
Serial.begin(115200); // Default Baud Rate for ESP-01
pinMode(ledPin, OUTPUT);  // set ESP-01's GPIO as output
digitalWrite(ledPin, LOW);  // set initial GPIO pin status to LOW
 
Serial.println();
Serial.println();
Serial.print("Connecting to WiFi: ");
Serial.println(ssid);
 
WiFi.begin(ssid, password);
delay(5000);

// The following 5 lines of code assign static IP address to ESP-01. Otherwise, comment out to get automatic IP.
 IPAddress ip(192,168,8,233);
 IPAddress gateway(192,168,1,1);
 IPAddress subnet(255,255,255,0);
 WiFi.config(ip, gateway, subnet);
 delay(5000);
 
while (WiFi.status() != WL_CONNECTED) 
{
  delay(100);
  Serial.print("*");
}
Serial.println("");
Serial.println("WiFi connected");
 
// Start the server
ESPserver.begin();
Serial.println("Server started");
 
// Print the IP address
Serial.print("The URL to control ESP-01: ");
Serial.print("http://");
Serial.println(WiFi.localIP());
Serial.println("");
}

void loop() 
{
// Check if a client has connected
WiFiClient client = ESPserver.available();
if (!client) 
{
  return;
}

// Wait until the client sends some data
Serial.println("Client connected");
while(!client.available())
{
  delay(1);
}

// Read the first line of the request
String request = client.readStringUntil('\r');
Serial.println(request);
client.flush();

// Match the request
if (request.indexOf("/LEDOFF") != -1)
{
  Serial.println("LED is OFF");
  digitalWrite(ledPin, LOW);
  led_status = 0; // OFF
}
else if (request.indexOf("/LEDON") != -1)
{
  Serial.println("LED is ON");
  digitalWrite(ledPin, HIGH);
  led_status = 1; // ON
}
else
{
  Serial.println("Invalid request");
  led_status = 2; // Invalid request
}

// Send a standard http response header
client.println("HTTP/1.1 200 OK");  // start the web response that is sent to the web browser
// The 200 OK is a HTTP response code and in this case is 200 which means the request is OK
client.println("Content-Type: text/html");  // tell the browser that the response content type is text/html
client.println("Connection: close");
// the connection will be closed after completion of the response
client.println(); // need to have a space here after http response header
client.println("<!DOCTYPE HTML>");  // HTML web site template
client.println("<html lang=\"en\">");
client.println("<head>");
client.println("<meta charset=\"utf-8\">");
client.println("<title>ESP-01 WiFi LED controller</title>");
client.println("</head>");
client.println("<body>");

// Prints text in web browser
client.println("<h2>ESP-01 WiFi LED controller</h2>");
client.print("<p>Control LED: ");
client.println("<a href='/LEDON' target='_self'>ON</a>");
client.println("<a href='/LEDOFF' target='_self'>OFF</a></p>");

client.print("<p>Status of the LED: ");
if (led_status == 0)
{
  client.println("<font color=\"blue\"><b>OFF</b></font></p>");
}
else if (led_status == 1)
{
  client.println("<font color=\"red\"><b>ON</b></font></p>");
}
else if (led_status == 2)
{
  client.println("Invalid request</p>");
}
client.println("</body>");
client.println("</html>");

// give the web browser time to receive the data
delay(1);

// close the connection:
Serial.println("Client disconnected");
Serial.println();
}

In my setup, i have the GPIO 2 pin of the ESP-01 connected directly to the positive pin of an LED and the negative pin connected to ground, which is common for the ESP and Arduino. But it’s not working.

Here is the output on the Serial Monitor after using ON and OFF links on the web page hosted on the ESP server:

Client connected
GET /LEDON HTTP/1.1
LED is ON
Client disconnected

Client connected
GET /LEDOFF HTTP/1.1
LED is OFF
Client disconnected

Paul__B:
If you never invoke serial.begin, then Tx and Rx are just I/O pins.

You do need to use active-LOW relay modules of course since the GPIO0 and GPIO2 must be pulled high on power-up.

And the common active-LOW relay modules must have VCC connected to 5 V, not 3.3 V since they have a LED and optocoupler in series and require more than 3.3 V to operate.

dekip:
ESP01 works perfect with PCF8574. Don’t just run away of it.
For relay module, you turn it ON with LOW. Here is a great video:
#18 Add a Relay Module to your Arduino project - Hints, Tips & Traps - YouTube

Thank you for the advice. I will try to implement these in the next version of the code after i troubleshoot some basic GPIO control issues.

LED without a resistor?

Juraj:
LED without a resistor?

I was in a hurry and skipped on it. My bad. I added a 330 Ohms resistor in series with the LED. But it does not turn on. I think maybe i destroyed the LED... I will check and come back.

You are most unlikely to damage the LED with an ESP8266’s output drive capability.

Note however that if you pull GPIO2 down with a red LED (with or without resistor) at boot, you put it in a different mode and it will not run your program. Same for GPIO0. That’s why I suggested the opto-isolated relay module - you connect the device you wish to control between the GPIO and supply.

So connect your red LED and 470 Ohm resistor between the GPIO and 3.3 V to test.

Paul__B:
You are most unlikely to damage the LED with an ESP8266's output drive capability.

Note however that if you pull GPIO2 down with a red LED (with or without resistor) at boot, you put it in a different mode and it will not run your program. Same for GPIO0. That's why I suggested the opto-isolated relay module - you connect the device you wish to control between the GPIO and supply.

So connect your red LED and 470 Ohm resistor between the GPIO and 3.3 V to test.

Thanks for this helpful information. I don't know much about that type of relay but i will investigate about it. For now, i'm just using LEDs instead of relays to make it easier to prototype and understand how to work with the ESP-01's 4 GPIO pins (including RX and TX pins). I connected each of the 4 GPIO pins to a different LED via its own 330 Ohms resistor. But is it better to use 470 Ohms instead?

The program was not running with the 4 GPIOs already connected at boot up. So, i tried disconnecting each GPIO and reset the ESP-01 to see which one was blocking the boot-up and normal program running mode. I found that the program ran normally by disconnecting the GPIO 2 cable from its LED, rebooted the ESP-01, waited a few seconds and now the other 3 GPIOs work. What is this special mode called when GPIO 2 is connected to an LED? I know that GPIO 0 when grounded sets the ESP-01 in programming mode, so is this another programming mode?

From my testing, GPIO 0 can be left connected to an LED and the boot-up proceeds normally. Did i miss anything?

This is my setup. Sorry, the ESP-01 is out of frame.

Is it possible to solve this issue by setting certain specific GPIO pins to LOW/HIGH in void setup()?

//Serial.begin(115200); // Default Baud Rate for ESP-01
pinMode(led0Pin, OUTPUT);  // set ESP-01's GPIO 0 as output
//digitalWrite(led0Pin, LOW);  // set initial GPIO 0 status to LOW
pinMode(led1Pin, OUTPUT);  // set ESP-01's GPIO 1 as output
//digitalWrite(led1Pin, LOW);  // set initial GPIO 1 status to LOW
pinMode(led2Pin, OUTPUT);  // set ESP-01's GPIO 2 as output
//digitalWrite(led2Pin, LOW);  // set initial GPIO 2 status to LOW
pinMode(led3Pin, OUTPUT);  // set ESP-01's GPIO 3 as output
//digitalWrite(led3Pin, LOW);  // set initial GPIO 3 status to LOW

DryRun:
The program was not running with the 4 GPIOs already connected at boot up. So, i tried disconnecting each GPIO and reset the ESP-01 to see which one was blocking the boot-up and normal program running mode. I found that the program ran normally by disconnecting the GPIO 2 cable from its LED, rebooted the ESP-01, waited a few seconds and now the other 3 GPIOs work. What is this special mode called when GPIO 2 is connected to an LED? I know that GPIO 0 when grounded sets the ESP-01 in programming mode, so is this another programming mode?

Yes, apparently it is. Something to do with the EEPROM I think Can't find a ready reference here but this describes the requirement, I don't fancy digging deeper at this point.

The point remains - whatever you connect to GPIOs 0 and 2, LED or relay driver, you connect it between that pin and at least 3.3 V, not ground. A (visible colour) LED has a voltage drop that prevents it pulling the voltage up above 3.3 V when connected to 5 V so you can use 5 V for a LED.

I said 470 Ohms to be cautious. Let's see, red LED at 2.0 V, 1.3 V across resistor, 330 Ohms, yeah, 4 mA fine at 3.3 V but at 5 V (because I suggested connection to 5 V) would be 9 mA and max is IIRC, 12 mA for the ESP.


DryRun:
Is it possible to solve this issue by setting certain specific GPIO pins to LOW/HIGH in void setup()?

No, because setup() runs after booting. You must as I explain, connect those GPIO to something that will by default, pull them to the specified state - for GPIO 0 and 2, that is a HIGH level. Perfectly easy to do. If a CMOS input to a chip, a 10k (or 22k, 47k) pull-up to 3.3 V which works just fine as things like the MAX7219 and 74HC595 are active LOW.

Thank you, Paul__B for this great explanation. It definitely helped me a lot to understand those ‚Äústrange‚ÄĚ boot-up behaviors of the ESP-01.

Paul__B:
You must as I explain, connect those GPIO to something that will by default, pull them to the specified state - for GPIO 0 and 2, that is a HIGH level. Perfectly easy to do. If a CMOS input to a chip, a 10k (or 22k, 47k) pull-up to 3.3 V which works just fine as things like the MAX7219 and 74HC595 are active LOW.

But how to achieve the temporary pull-up state for GPIO 0 and 2 at boot-up in an automatic setup? I have been thinking about it for a while and maybe i could use a 555 timer IC? But i’m not sure if that would work.

esp01pullups.png

DryRun:
But how to achieve the temporary pull-up state for GPIO 0 and 2 at boot-up in an automatic setup? I have been thinking about it for a while and maybe i could use a 555 timer IC? But I'm not sure if that would work.

It is dead simple as I just explained in that paragraph, there is no such problem. :roll_eyes:

Do not connect them to anything that pulls them down. You will basically never have a need to do so. The relay module I cited is active LOW - so it only ever acts as a pull-up (but because of the LED thresholds, it does not pull up to 3.3 V so you may need a 10k pull-up to ensure the state on initialisation).

Paul__B:
Do not connect them to anything that pulls them down. You will basically never have a need to do so. The relay module I cited is active LOW - so it only ever acts as a pull-up (but because of the LED thresholds, it does not pull up to 3.3 V so you may need a 10k pull-up to ensure the state on initialisation).

I followed your instructions and i connected GPIO 0 and 2 to 10kOhms pull-up resistors and now it works! :slight_smile:

withpullups1.jpg withpullups2.jpg

withpullups1.jpg

withpullups2.jpg