Tags: ,

In this tutorial we will see how to address each relay individually with a NodeMCU32S microcontroller and 74HC595 shift registers. At the end of this tutorial you will also be able to control each relay using the serial monitor. This tutorial follows on from the project Pilot 8 relays using an ESP32 and a shift register.

Ce tutoriel peut être appliqué à n’importe quel microcontrôleur. Il faudra faire attention à modifier le schéma de connexion et le code pour qu’ils correspondent à votre usage.

Material

  • NodeMCU 32S
  • Breadboard
  • Jumper cable
  • 8 relay module
  • Shift register 74hc595

Principle

In the previous tutorial, we saw how to manage 8 relays using a shift register. We will now come to address each relay independently using the Arduino IDE’s serial monitor. It is possible to communicate with the microcontroller via the USB port using the serial port. We will therefore define a message structure to tell the microcontroller which relay to switch on.

Schematic

As a reminder, here is the connection diagram of the project

  • GND integrated circuit ground
  • Vcc power supply pin. Usually connected to 5V
  • SH_CP or RCLK connected to pin 33
  • ST_CP or SRCLK connected to pin 32
  • DS or SER connected to pin 25
esp32_74HC595x1_8relays_bb-1280x1082 Control 8 relays using ESP32 and serial monitor

Code

We are going to take the code from the previous tutorial and add the functions to receive messages from the serial monitor and recover the relay control commands. For the command messages, we choose the form “YYxZ”, with YY, the relay identifier, a number from 0 to 7; and Z, the relay status 0-open, 1-close.

The readSerialPort function, retrieves the characters sent by the serial monitor in the character string “msg”.

the convertMsgToCmd function will translate the string into a relayId identification number and the status of the relayState.

void readSerialPort() {
  while (Serial.available()) {
    delay(10);
    if (Serial.available() > 0) {
      char c = Serial.read();  //gets one byte from serial buffer
      msg += c;
    }
  }
}

void convertMsgToCmd() {
  relayId = -1;
  relayState = -1;
  if (msg.length() > 0) {
    Serial.println(msg);
    sep = msg.indexOf('x');
    if (sep > 0) {
      m1 = msg.substring(0, sep); //get servo id
      m2 = msg.substring(sep + 1, msg.length()); //get servo pos

      char carray1[6]; //magic needed to convert string to a number
      m1.toCharArray(carray1, sizeof(carray1));
      relayId = atoi(carray1);

      char carray2[6];
      m2.toCharArray(carray2, sizeof(carray2));
      relayState = atoi(carray2);

      relayState = 1 - relayState;
      Serial.print(F("Set relay n° ")); Serial.print(relayId); Serial.print(F(" to ")); Serial.println(!relayState ? "HIGH" : "LOW");
    }

    sep = msg.indexOf("reset");
    if (sep == 0) {
      m1 = "reset";
    }

    sep = msg.indexOf("states");
    if (sep == 0) {
      m1 = "states";
    }
    msg = "";
  }
}

Once the values relayId and relayState have been retrieved, they can be set as the input for the setRegisterPin function (relayId, relayState); in order to activate or deactivate the relay. It is possible to create as many messages as you wish. Here, for example, I have added the “reset” command to open all the relays and the “states” command to display the states of each relay.

//Constants
#define number_of_74hc595s 1
#define numOfRegisterPins number_of_74hc595s * 8
#define SER_Pin 25
#define RCLK_Pin 33
#define SRCLK_Pin 32

//Variables
boolean registers[numOfRegisterPins];
String msg, m1, m2;
int sep, relayId, relayState;

void setup() {
  delay(100);
  //Init Serial USB
  Serial.begin(115200);
  Serial.println(F("Initialize System"));
  //Init register
  pinMode(SER_Pin, OUTPUT);
  pinMode(RCLK_Pin, OUTPUT);
  pinMode(SRCLK_Pin, OUTPUT);
  clearRegisters();
  writeRegisters();
  delay(500);
  Serial.println(F("Enter Relay ID ans state (IDxSTATE):"));
}

void loop() {
  readSerialPort();
  convertMsgToCmd();
  if (relayId >= 0 and relayState >= 0) {
    setRegisterPin(relayId, relayState);
    writeRegisters();
  }
  if (m1 == "reset") {
    Serial.println(F("Reset all relays"));
    clearRegisters();
    writeRegisters();
  }
  if (m1 == "states") {
    Serial.println(F("print relays states"));
    printRegisters();
  }
  m1 = "";
}

void clearRegisters() { /* function clearRegisters */
  //// Clear registers variables
  for (int i = numOfRegisterPins - 1; i >=  0; i--) {
    registers[i] = HIGH;
  }
  printRegisters();
}

void writeRegisters() { /* function writeRegisters */
  //// Write register after being set
  digitalWrite(RCLK_Pin, LOW);
  for (int i = numOfRegisterPins - 1; i >=  0; i--) {
    digitalWrite(SRCLK_Pin, LOW);
    digitalWrite(SER_Pin, registers[i]);
    digitalWrite(SRCLK_Pin, HIGH);
  }
  digitalWrite(RCLK_Pin, HIGH);
}

void setRegisterPin(int index, int value) { /* function setRegisterPin */
  ////Set register variable to HIGH or LOW
  registers[index] = value;
}

void printRegisters() { /* function clearRegisters */
  //// Clear registers variables
  for (int i = 0; i < numOfRegisterPins; i++) {
    Serial.print(registers[i]); Serial.print(F(" ,"));
  }
  Serial.println();
}

void readSerialPort() {
  while (Serial.available()) {
    delay(10);
    if (Serial.available() > 0) {
      char c = Serial.read();  //gets one byte from serial buffer
      msg += c;
    }
  }
}

void convertMsgToCmd() {
  relayId = -1;
  relayState = -1;
  if (msg.length() > 0) {
    Serial.println(msg);
    sep = msg.indexOf('x');
    if (sep > 0) {
      m1 = msg.substring(0, sep); //get servo id
      m2 = msg.substring(sep + 1, msg.length()); //get servo pos

      char carray1[6]; //magic needed to convert string to a number
      m1.toCharArray(carray1, sizeof(carray1));
      relayId = atoi(carray1);

      char carray2[6];
      m2.toCharArray(carray2, sizeof(carray2));
      relayState = atoi(carray2);

      relayState = 1 - relayState;
      Serial.print(F("Set relay n° ")); Serial.print(relayId); Serial.print(F(" to ")); Serial.println(!relayState ? "HIGH" : "LOW");
    }

    sep = msg.indexOf("reset");
    if (sep == 0) {
      m1 = "reset";
    }

    sep = msg.indexOf("states");
    if (sep == 0) {
      m1 = "states";
    }
    msg = "";
  }
}

Result

Once the code has been loaded into the microcontroller, open the serial monitor. You can enter the relay ID (0 – 7) and the desired state (0-open, 1-closed). For example, to close relay 2, type 2×1 and then “enter” or “send”.

nodemcu32s-74hc595-16relays-monitor-control Control 8 relays using ESP32 and serial monitor

Next Steps

Sources