Recommendations for Arduino and ESP interface

Background
I am automating an industrial process, it's very specific and relatively simple (some relays, some actuators... basically ON/OFF signals) so I am using a microcontroller instead of a PLC. At the moment I am using an ESP32, which has the added benefit of submitting sensor data to a cloud server. For added safety, I also use a industrial PID controller so that the ON/OFF signals need both the ESP and the PID to agree. It works fine but I'd like to add more outputs and possibly inputs.

Upgrades
This was the first time I built anything related to ESPs and IoT, and the ESP32 has truly been a great platform to work with. However, compared to say an Arduino Mega it has it's limitations. Initially I didn't care, because there were not many things to control, however the project was not as successful as I wanted and I will need to add more output signals. This upgrade will require more I/O pins, and the Arduino Mega feels like the logical choice.

Question
What would you recommend so that I can control the system with the MEGA but still output sensor data to my cloud server?

I initially thought of coupling the Arduino with the ESP through serial communication. However in the small number of tests I've done the communication is not reliable. For example I did the typical 5V voltmeter using the Mega and a potentiometer, sending data through serial to the ESP. This was just to test the idea and the ESP received a lot of crazy values and was not very responsive.

I was also considering one of those Arduinos that have an ESP8266 module in the board, like this one: https://robotdyn.com/mega-wifi-r3-atmega2560-esp8266-flash-32mb-usb-ttl-ch340g-micro-usb.html

I also thought about using other communication methods, like I2C or SPI. I even thought of sending the data as bit code through digital pins haha (Ben Eater has a great video on that). But I would like to hear recommendations, because I feel I am overthinking this and there are some simple solutions out there.

Yes, overthinking.

A 5V based Arduino board such as the Arduino Uno or Mega is often very handy. They can output 20mA with their pins without problem.

However, running two Arduino boards that communicate with each other makes things often worse. Each Arduino board must deal with its own problems and then you also need to worry about the communication.

The I2C bus is ten times more complex than the Serial/UART communication.

If you would have done the Serial/UART correctly, then you would have used a level shifter between the 5V Mega and the 3.3V ESP32. With the right sketch, it should always work 100% and be very responsive. If it works 99.999%, that is not acceptable, then there is something very wrong.

The boards with a ESP8266 for Wifi are in my opinion Frankenstein boards. The firmware of the ESP8266 might be outdated, and the communication between the ATmega chip and the ESP8266 is a bottleneck and puts you in a corset.

Try to do everything with a ESP32. Then you have the freedom to use everything of the ESP32. For extra I/O use for example a I2C I/O expander (it must be 3.3V compatible).

Note: In my opinion, there is a situation where a Arduino Uno or Mega is a great extension for extra I/O. That is when using a Raspberry Pi board. If the Uno or Mega is connected to the USB port of the Raspberry Pi, then a Python script can communicate via Serial (over USB) with the Arduino board.

1 Like

If you just need more digital IO pins consider an I2C expander like the MCP23008 (8 bits) or MCP23017 (16 bits) or their SPI cousins MCP23S08 or MCP23S17.

2 Likes

Thanks for the recommendations. I have decided to use the MCP23017 to expand my IO pins, however I am having an issue while experimenting with the chip on an ESP8266 NodeMCU 12E.

Using a 5V relay module (4 relays), when using the digital outputs from the ESP8266 to activate the relays I can successfully energize two at the same time. However, when using the MCP23017 outputs, it can only energize one relay at a time, but not two at the same time.

Here's how I have it set up, I have an external 5v power supply powering the relay module and instead of the Arduino Uno in the figure I am using pins D5 and D6 from the ESP8266 or pins B0 and A0 from the MCP23017.

And of course, the code. First the code that only uses the ESP8266 and then the one that uses the MCP23017:

#define relay1 D5
#define relay2 D6

// SETUP
void setup(){
  Serial.begin(9600);
  Serial.println("NODEMCU (Digital Only) Relay Test");
    
  // configure pin as outputs
  pinMode(relay1, OUTPUT);
  pinMode(relay2, OUTPUT);
  // set them high so relays are off
  digitalWrite(relay1,HIGH);
  digitalWrite(relay2,HIGH);
}

// MAIN LOOP
void loop(){
  // start flickering
   Serial.println("Relay 1 ON");
   digitalWrite(relay1,LOW); // relay1 is energized
   delay(2500);
   Serial.println("Relay 2 ON");  
   digitalWrite(relay2,LOW); // relay2 is energized 
   delay(2500);  
   Serial.println("Relay 1 OFF");
   digitalWrite(relay1,HIGH); // relay1 is de-energized
   delay(2500);
   Serial.println("Relay 2 OFF");  
   digitalWrite(relay2,HIGH); // relay2 is de-energized 
   delay(2500);   
}

#include "Wire.h"
#include <Adafruit_MCP23X17.h>

Adafruit_MCP23X17 mcp;
#define relay1 0 //A0
#define relay2 8 //B0
// SETUP
void setup(){
  Serial.begin(9600);
  Serial.println("NODEMCU and MCP23017 Relay Test");

  if (!mcp.begin_I2C()) {
    Serial.println("I2C Error.");
    while(1);
  }
    
  // configure pin as outputs
  mcp.pinMode(relay1, OUTPUT);
  mcp.pinMode(relay2, OUTPUT);
  // set them high so relays are off
  mcp.digitalWrite(relay1,HIGH);
  mcp.digitalWrite(relay2,HIGH);
}

// MAIN LOOP
void loop(){
  // start flickering
   Serial.println("Relay 1 ON");
   mcp.digitalWrite(relay1,LOW); // relay1 is energized
   delay(2500);
   Serial.println("Relay 2 ON");  
   mcp.digitalWrite(relay2,LOW); // relay2 is energized 
   delay(2500);  
   Serial.println("Relay 1 OFF");
   mcp.digitalWrite(relay1,HIGH); // relay1 is de-energized
   delay(2500);
   Serial.println("Relay 2 OFF");  
   mcp.digitalWrite(relay2,HIGH); // relay2 is de-energized 
   delay(2500);   
}