Hi. I need a few more digital output pins than the Nano ESP32 has available, and my reading led me to the 74HC595 shift register. So far it works with a Mega but not with the Nano ESP32, so perhaps you can help me figure out why.
I am testing with code taken from one of several nearly identical tutorials online, but I'll post it at the end. The specific tutorial I found is here: https://lastminuteengineers.com/74hc595-shift-register-arduino-tutorial/ but I have cross-checked the pin assignments with other tutorial versions at Adafruit and elsewhere.
Application: I eventually need to control an 8-outlet AC power bar which is apparently built with Omron G2R-1 relays. My full application may have two such power bars and other pins are busy with a clock, SD card, temperature sensors, some small solid-state relays, and a display. Speed of output is not an issue, as one state change per second is fast enough. Current for the relays could be an issue, but at the moment I just want to get the tutorial to work. The eventual goal is an updated version of the system described here: The Coral Bleaching Automated Stress System (CBASS): A low‐cost, portable system for standardized empirical assessments of coral thermal limits
I wired up the tutorial on a breadboard, using some old LEDs and resistors as outputs. The first time I ran the code I just got 7 bright LEDs instead of the progressive lighting that was expected (all off, 1 on, 1 and 2 on, etc.).
After checking the wiring with no change in behavior, here are some of the things I tried.
- Ran exactly the same code on an Arduino Mega, wiring it to the same breadboard. This worked as expected, so there is nothing grossly wrong with the code or wiring, at least when using a Mega.
Back on the Nano ESP32 none of this helped:
- Verified that the pin numbers in the sketch were controlling the pins I wired to.
- Added some blinks of the onboard LED and serial monitor prints of the "leds" variable, just to see that the code was running.
- Put a 100 nanofarad capacitor between the clockPin and ground. Also one across the power input at pin 16.
- Put capacitors on the output pins. It didn't help and in retrospect I don't think it was a good idea.
- Added a 2 millisecond delay before shiftOut() to allow for the rise time of the latchPin and 2 milliseconds after for no good reason.
- Tried reducing the processor clock speed with setCpuFrequencyMhz(), since that's one big difference between the two Arduinos. At 40 and 20 MHz the output changed to have one LED on, but it still wouldn't switch. After setting 10 MHz I could not load another sketch until I reset the bootloader and uninstalled and reinstalled the Arduino IDE and drivers!
- Connected 5V to the chip Vcc pin, since that's what the Mega has. Pin 10, SRCLR bar, was also connected to 5V. This was probably doomed to fail, since interpolating between datasheet points for Vcc and the high input voltage suggests that a 5V Vcc would require nearly 3.5 V to switch the inputs. Of course I'm only working with 3.3V or so.
- Unplugged most of the LEDs in case there was a total current issue.
Some general observations on the state of the LEDs. Usually they start all off or all on, but occasionally in some other pattern. That state sometimes changes once in the first second of a run, but never again. Briefly unplugging the USB cable tends to restore the previous state, but leaving it out for 10 seconds or so seems more likely to show a new starting state. Hitting the reset button does not change the state.
I'm much more of a programmer than an electronics person, but I have one of those little pocket oscilloscopes (DSO Nano V3). The latch pin sits at 3.3V and drops to ground for about 8 microseconds at each update. The transitions aren't square, but they are pretty steep with no noticeable overshoots. This seems reasonable.
The data and clock pin just sit at zero volts all the time! This could simply be that my skills with the oscilloscope are not good enough for the more rapid signals. I tried the full range of time scales, but I could be missing something.
Speculation:
There are two big differences between the Mega and ESP32 that are likely to matter here. First is 3.3V logic versus 5V, but note that the 74HC595 data sheet allows a 2V to 6V supply.
Second, the Mega CPU clock is 16 MHz and the ESP32 is 240 MHz. The data sheet values for the 74HC595 interpolate to about 20 MHz at 3.3 V. This is where my internet searches failed me. I don't know how fast the clock and data pins are actually being switched by the shiftOut() function. I can see that the clock is set high for a very short time for each bit with no delay or other code between two digitalWrite() calls.
digitalWrite(clockPin, HIGH);
digitalWrite(clockPin, LOW);
In the 8 microseconds between latch changes shiftOut() does 24 digitalWrite() calls, 16 of which are the clockPin changes in the code snippet above. In the unlikely event that all 24 calls are evenly spaced that should mean 0.33 * 10-6 seconds per call or a frequency around 3 MHz. Because I don't actually know how the calls are spaced I still don't know whether something there will violate the 20 MHz frequency limit of the chip.
Question time:
- Should I be doing this a whole different way?
- If it's a clock issue is there a way to set the rate without slowing down the whole CPU?
- Is there anything else I should check?
- Are there other Mega vs. ESP32 differences that I should be allowing for (and how)?
Thanks for anything!
int dataPin = 4; // Data pin of 74HC595 is connected to Digital pin 4 (SER, chip pin 14)
int latchPin = 5; // Latch pin of 74HC595 is connected to Digital pin 5 (RCLK, chip pin 12)
int clockPin = 6; // Clock pin of 74HC595 is connected to Digital pin 6 (SRCLK, chip pin 11)
byte leds = 0; // Variable to hold the pattern of which LEDs are currently turned on or off
void setup()
{
delay(500);
// Set all the pins of 74HC595 as OUTPUT
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
}
void loop()
{
leds = 0; // Initially turns all the LEDs off, by giving the variable 'leds' the value 0
updateShiftRegister();
delay(2000);
for (int i = 0; i < 8; i++) // Turn all the LEDs ON one by one.
{
bitSet(leds, i); // Set the bit that controls that LED in the variable 'leds'
updateShiftRegister();
delay(500);
}
}
/*
* updateShiftRegister() - This function sets the latchPin to low, then calls the Arduino function 'shiftOut' to shift out contents of variable 'leds' in the shift register before putting the 'latchPin' high again.
*/
void updateShiftRegister()
{
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, LSBFIRST, leds);
digitalWrite(latchPin, HIGH);
}