Recommendation for an IC "OR Gate" for ESP8266 Project

I'm looking for an "OR Gate" to trigger a GND signal to the RST pin on an ESP8266.

The project is a remote control consisting of an ESP8266-12E with 5 buttons and a battery, which uses ESPNow to send data to a remote ESP8266-12E which is hard wired to a power source.

I have the button functions and data transmission working well, and am now trying to maximize battery life of the remote. So I starting testing various sleep modes of the 8266.

For the wake function, I'd like it to wake up when any of the 5 buttons are pressed. I have it working fine with one button, but don't see a way in the software to enable more than one GPIO pin for wake up. So I'm looking for a hardware solution.

The 5 buttons are connected to GPIO pins which have been set as INPUT_PULLUP, and the buttons connect GND to the pins when they are pressed. So I'm thinking I can connect the output side of the buttons to both the GPIO signal pins as well as to an OR Gate. So if any of the input signals to the OR gate receive a GND signal, the OR Gate would output a GND signal for the wake functionality.

In researching, I found the 74HC32 IC, but I'm not sure if it'll do what I'm wanting and thought it may be best to ask for advice on an IC to handle this. Or ... would 5 diodes work just as well for this?

Here is a rough drawing of the remote.

As for the code, I can't fit it all in due to the character limitation, but below are the pieces related to the sleep function. I'm using "Light Sleep" right now, and pressing the button connected to GPIO5 wakes it up as expected. Eventually, I'd like to get to Deep Sleep, where I'd need to use the RST pin to wake it up ... but for now, I'll settle with Light Sleep and an assigned wake pin.

If I do find an OR Gate that'll work, I would define a new GPIO pin for waking from Light Sleep, instead of using one of the pins in use by the buttons.

#include <ESP8266WiFi.h>
#include <espnow.h>

// PIN DEFINITIONS ---------------------------------------------------
int Cha_PIN = 5;                                                       // Pin for Channel a's button
int Chb_PIN = 4;                                                       // Pin for Channel b's button
int Chc_PIN = 14;                                                      // Pin for Channel c's button
int Chd_PIN = 12;                                                      // Pin for Channel d's button
int Che_PIN = 13;                                                      // Pin for Channel e's button
  
// VARIABLE DEFINITIONS -----------------------------------------------
int Sleep_Time = 300000;                                              // Variable to set how long to wait with no button push, before going to sleep
bool Sleep = false;                                                    // Variable to track if the ESP8266 should be asleep or not

// ********************************************************* INITIALIZE *********************************************************
void setup() {
  Serial.begin(19200);                                                 // Initialize Serial Monitor
  pinMode (Cha_PIN, INPUT_PULLUP);                                     //Set the pin for connecting to the EasyTouch's channel 1, to Input Pullup
  pinMode (Chb_PIN, INPUT_PULLUP);                                     //Set the pin for connecting to the EasyTouch's channel 2, to Input Pullup
  pinMode (Chc_PIN, INPUT_PULLUP);                                     //Set the pin for connecting to the EasyTouch's channel 3, to Input Pullup
  pinMode (Chd_PIN, INPUT_PULLUP);                                     //Set the pin for connecting to the EasyTouch's channel 4, to Input Pullup
  pinMode (Che_PIN, INPUT_PULLUP);                                     //Set the pin for an additional TBD control, to Input Pullup
  WiFi.mode(WIFI_STA);                                                 // Set device as a Wi-Fi Station
  if (esp_now_init() != 0) {                                           // Initialize ESP-NOW
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);                      // Set the ESPNow role of the ESP8266
  esp_now_register_send_cb(OnDataSent);                                // Register for Send CB to get the status of Trasnmitted packet
  esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);  // Register the receiver MAC as a peer
}

// ********************************************************* MAIN LOOP *********************************************************
void loop() {
  ReadButtons();                                                       // Read the state of the buttons
  if (Sleep == true && Button_Time == 0) {Wakeup();}                   // If coming out of sleep, call the Wakeup function
  if (Button_Time == 0 || Button_Time == 1005) {Send_Data();}          // If a button has been pressed, call the Send Data function
  if (Button_Time == Sleep_Time) {Light_Sleep();}                      // If no button has been pushed for a given time, call the sleep function
  Button_Time = Button_Time + 1;                                       // Increment varibale for tracking time since last button push
}

// *********************************************************  FUNCTION DEFINITIONS *********************************************************
// Put the ESP8266 to sleep ------------------------------------------------------------
void Light_Sleep(){
   Serial.println("Sleep");
   Sleep = true;                                                       // Set Sleep variable to "true", to indicate sleeping
   wifi_station_disconnect();                                          // Disconnect WiFi
   WiFi.mode(WIFI_OFF);
   wifi_set_opmode_current(NULL_MODE);                                 // ?????
   wifi_fpm_set_sleep_type(LIGHT_SLEEP_T);                             // Set sleep type
   gpio_pin_wakeup_enable(GPIO_ID_PIN(5), GPIO_PIN_INTR_LOLEVEL);      // GPIO_ID_PIN(5) corresponds to D7 on ESP8266-12E , GPIO_PIN_INTR_LOLEVEL for a logic low
   wifi_fpm_open();                                                    // Enable force sleep                      
   wifi_fpm_do_sleep(0xFFFFFFF);                                       // Sleep for longest possible time
   delay(10);
 }

// Wakeup actions ---------------------------------------------------------------------------
void Wakeup(){
    Serial.println("Wake Up");
    Sleep = false;                                                     // Set sleet variable to "false", to indicate awake
    Button_Time = 0;                                                   // Reset Button_Time variable
    WiFi.mode(WIFI_STA);                                               // Set device as a Wi-Fi Station
}

Never used one but apparently it has interrupts on almost every I/O pin.

Stoopalini:
I'm looking for an "OR Gate"

No, what you want is an AND gate (*): the output is HIGH when all inputs are HIGH! But 5 diodes will also work, and you don't need R1.

*: Is the same beast as an OR gate with inverted in- and outputs. :wink:

Edit:
PS.: Unless it can be done with interrupts, of course.

You have the wrong idea - an “or” says that if any input pin is HIGH, the output is HIGH. Thus a single switch closure won’t produce any output because all the other gate pins see “HIGH”. You want an “and” gate - if all the input pins are “HIGH” (idle state) then the output is HIGH. If any go LOW, the output goes LOW.

Unfortunately there is no 5 input AND gate available, only the 8-input NAND 74HC30, you can make it an AND by inverting the output with an additional inverter.

That, or use diodes.

Thanks guys, I appreciate the input.

So would five 1A Schottky diodes do the trick here then?

Is IN5817 a good choice?

Thanks again!

You can use the 74HC30 as a 5-input AND gate... just tie the three unused inputs to 5V.

metermannd:
You can use the 74HC30 as a 5-input AND gate... just tie the three unused inputs to 5V.

Perfect, thanks!

So I've ordered some 74HC30 chips, and they'll be here tomorrow. I've been thinking a bit on how to get the output of the 74HC30 to trigger a LOW signal to the RST pin when the ESP8266 is in Deep Sleep, but not when it is up and running.

I think this will work, so long as I can configure one of the 8266 pins to be HIGH when the unit is running, and change to LOW when it goes into Deep Sleep. Then I would connect the pin of the opticoupler (the one with the ? in my diagram)to this identified 8266 pin.

So when the unit is running, and this pin is HIGH ... when one of the 5 buttons are pressed, the output of the AND gate would change from HIGH to LOW, and trigger the opticoupler ... but the output of the opticoupler would pass a HIGH signal and not trigger the RST pin to reboot the 8266.

But when in Deep Sleep, and this pin is LOW ... when one of the 5 buttons are pressed, the output of the AND gate would change from HIGH to LOW, and trigger the opticoupler ... but now the output of the opticoupler would pass a LOW signal, and will trigger the RST pin and reboot the 8266 back to AWAKE mode.

Does this seem a reasonable approach to solve this challenge? I'm definitely open to ideas on how to do this. I'd like the 9v battery to last as long as possible, as the remote won't be used very often (it's for swimming pool and yard control ... lights, waterfall, pump speed, etc ...).

I put R2 in the diagram, to pull the RST pin high and not have a floating signal on it ... not entirely sure if this is needed though ... and if it is, what value resister would be appropriate.

So I just read up on AND vs. NAND ... and realize the output of the 74HC30 will be opposite of what I thought.

So I'll need to connect the Anode pin of the opticoupler to the 74CH30's output, and the Cathode of the opticoupler to GND on the 8266.

The rest should still function as expected though.

Here's the updated diagram reflecting this ...

And here's the truth table I'm using to understand the NAND:

Personally, I would just use one gate of a quad NAND IC as an inverter, to make the HC30 NAND into an AND. Then I would have 3 spare NAND gates to use at will for other purposes.

Or 3 dual Schottky diodes like the BAT51.

aarg:
Personally, I would just use one gate of a quad NAND IC as an inverter, to make the HC30 NAND into an AND. Then I would have 3 spare NAND gates to use at will for other purposes.

Do you mean instead of the opticoupler?

aarg:
Or 3 dual Schottky diodes like the BAT51.

I thought about diodes as well, but went with the HC30 instead. I figured it would be a good opportunity to learn about the gates as I work with it.

Stoopalini:
Do you mean instead of the opticoupler?

Yes. Or, you could use an NPN transistor inverter. R2 is already a pull up for RESET, so all you need is a 1k resistor from the HC30 output to the transistor base, emitter grounded, and collector to RESET.

aarg:
Yes. Or, you could use an NPN transistor inverter. R2 is already a pull up for RESET, so all you need is a 1k resistor from the HC30 output to the transistor base, emitter grounded, and collector to RESET.

I have some BC337 transistors here, which should work well for that. I also have the 814 opticouplers already on hand too ... But the 337 would take up less space inside the remote control casing.

I'll do some testing when the HC30 chips arrive.

Out of curiosity, why would you choose a different approach than the opticoupler? Is there some design concern using an LTV-814 in this way, or is it just a solution preference; and either would work reliably?

Thanks for your help!

The transistor is cheaper, smaller and faster. I think only the first two matter in your case. The opto is just overkill.

For testing, you don't really have to wait - you could temporarily drive the transistor from some ESP I/O pin for that.

aarg:
The transistor is cheaper, smaller and faster. I think only the first two matter in your case. The opto is just overkill.

Gotcha, makes sense.

Another quick question ... about your comment:

aarg:
1k resistor from the HC30 output to the transistor base, emitter grounded, and collector to RESET.

I get this, in that when the HC30 outputs 3.3v to the transistor's base, it'll cause the transistor to switch and send the GND signal from the emitter, through to the collector .. therefore triggering the reset.

But I only want this to happen when the 8266 is in Deep Sleep.

How would it impact the transistor if the 8266 pin the emitter was connected to, was set HIGH (3.3v) when the 8266 was operational, and then changed to LOW (GND) when it went into Deep Sleep?

I think it would be fine, but an not certain. When the 8266 was NOT asleep, and the HC30 sent out 3.3v to the transistor's base ... it just wouldn't switch due to no GND signal being on the emitter .. correct? Or would a 3.3v signal on the emitter damage the transistor?

Thanks again for your help, I appreciate it!

Stoopalini:
How would it impact the transistor if the 8266 pin the emitter was connected to...

Please clarify. The emitter is supposed to be grounded, not connected to any pin.

Did you suddenly realize that with any of the circuits above, any key press will now reset the ESP? :slight_smile: If you want to gate the signal, I suggest using a quad NAND IC since you can use one NAND input as an inverter, the other input of the same gate can enable/disable the RESET signal if connected to an I/O pin.

aarg:
Please clarify. The emitter is supposed to be grounded, not connected to any pin.

I guess there's two challenges I'm trying to solve:

  • Trigger a signal when any one of the buttons are pressed = the NAND gate does this for me
  • Only allow that signal to trigger GND to the RESET pin while the ESP is in Deep Sleep

So to solve for #2, my thought was to toggle an ESP pin from from one state to another.

For example, with the opticoupler approach ... I would set the ESP pin to HIGH in void setup(); and then change it to LOW inside the void sleep(); function. So when the ESP was not in sleep mode, and the opticoupler was activated, it would pass a 3.3v signal through to the RESET pin, and nothing would happen. When the sleep function was executed, and the ESP pin changed to LOW .. now when the opticoupler was activated, it would pass a GND signal through to the RESET pin and cause the ESP to wake up.

For the transistor solution, if the emitter was always connected to GND, anytime a button was pressed, the ESP would reset .. even when not in sleep mode.

So I've been thinking about this some more, and after doing some testing ... I've realized the NAND gate idea actually won't work. The reason is due to the signal pins on the ESP (the ones to which the buttons are connected), drain when the ESP goes into Deep Sleep, and don't retain the 3.3v signal from the INPUT_PULLUP config.

I thought about trying to determine a way to have the pins retain their state when the ESP goes into Deep Sleep, but then I realized I was just over thinking this.

Instead of trying to determine a way to keep a pin in HIGH state when in Deep Sleep, I decided to approach it from the other direction ... set a pin to HIGH when it's awake to gate the signal, and the allow a low signal (when it drains from Deep Sleep) to allow a signal to pass. That led me to a PNP transistor, specifically the BC327.

For the AND logic, I just used 5 opticouplers ... and after a quick test, it works perfectly! When the ESP is running, I write D8 to HIGH in void setup(). When a button is not pressed, I'm guessing since the 327's Base is floating, it's in the Cut-Off region ... so it doesn't pass the signal. When a button is pressed, the 3.3v from D8, routing through the optocouplers into the 327's Base, saturates it and also prevents the Emitter signal (connected to GND) from being passed through to the Collector (connected to RST). But when the ESP goes to sleep, and D8 drains, apparently it's retaining enough current to drive the 327's Base in to the active region, without hitting the saturation region ... so the signal now passes.

The 5 opticouplers are setup to just pass the signal from D8 to the 327's Base when any of the 5 buttons are pressed.

The final challenge I now have to solve is how to read the button push signal when it is also waking up the ESP. When it's awake and running, pressing a button causes a transmission of data to the receiving ESP. But when it's asleep, and a button is pressed ... it's the release of the button which causes the reset action. So by this time, the button state is no longer active ... When the ESP boots back up and reads the button states, they're all open.

I need to figure out a way to retain the signal while the ESP is rebooting, even after releasing the button. Maybe a slow drain capacitor on the signal pins? Not sure, need to think about it some more...

But I'm happy to have solved the 2 issues for now :slight_smile:

More progress ... a 10 uF capacitor with a 10 Kohm drain resistor across it, connected between GND and the transistor's Emitter, did the trick for getting a button press to not only wake up the ESP, but also read the state of the button which was pressed to wake it up. The 10 uF cap charges quicker than a typical press of the button, so before the user lets off the button, the ESP has booted and read the signal pin. Then the drain resistor drains the cap when the user releases the button.

After testing and verifying that, I changed the code to put the ESP into deep sleep after 100000 cycles, which is about one second for the 8266 ... so the ESP stays in Deep Sleep, and when you press a button, it wakes up, reads the button press, transmits it with ESPNow, then goes back to sleep ... all in about 1 second.

I'd think this configuration should allow the 9v battery to last a very long time.