Due Serial Communication & Relay control

Hello everyone,

In the last days I'm confronting with a problem in my code that I can't solve. Before I start explaining, I'm new to coding and arduino, or any controllers. I've spend some weeks, learning and adding parts to a code that I try to make it work.

Brief explanation of what I want to do: I have Home Assistant on a old PC, that speak to an esp32 via MQTT, exp32 needs to relay information's from and to an arduino due, that need to grab sensors data and controlling relays.

This is a "cutout" from my main code, for debug purpose, also it's made from an example found here serial-input-basics-updated. And this must receive commands from esp32, process them and execute, turn relay, corresponding to relay pin, on or off. As shown in the screenshot, commands from esp32 via MQTT are coming as it should, so I think the problem is laying in this code.

[code]
// Example 3 - Receive with start- and end-markers

#define NUM_ELEMENTS(x)  (sizeof(x) / sizeof((x)[0]))
// Serial
const byte numChars = 32;
char receivedChars[numChars];
boolean newData = false;

int relayPins [2][8] {
  {53, 52, 51, 50, 49, 48, 47, 46},              // 8 Chan Relay Board: [1] = Cooling box fan, [2] = Valve, [3] = Valve, [4] = Mixing jars, [5] = Presure pomp(water to plants);
  {45, 44, 43, 42}                               // 4 Chan Relay Board: [1] = Presure pomp, [2] = In res mix pomp, [3] = UV pomp, [4] = UV lamp(+2000 over 'UV pomp');
};

void setup() {
  Serial.begin(9600);
  Serial3.begin(9600);
  Serial.println("<Due is ready!>");
  delay(500);
  for (int i = 0; i <= 1; i++) {
    for (int j = 0; j <= NUM_ELEMENTS(relayPins[i]); j++) {
      pinMode(relayPins[i][j], OUTPUT);
      digitalWrite(relayPins[i][j], HIGH);
    }
  }
}
void loop() {
  recvWithStartEndMarkers();
  processSerialData();
  showNewData();
}

void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;

  while (Serial3.available() > 0 && newData == false) {
    rc = Serial3.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      }
      else {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }

    else if (rc == startMarker) {
      recvInProgress = true;
    }
  }
}

void showNewData() {
  if (newData == true) {
    Serial.println(receivedChars);
    newData = false;
  }
}

void processSerialData() {
  while (newData == true) {
    char cmdChar = receivedChars[0];
    switch (cmdChar) {
      case 'R':                                                     // Message starts with "R" = relays. Format is "Relay:<BOARD#>:<RELAY#>:<STATUS>". Example: "Relay:0:4:1"
        {
          int boardNumber;
          int relayNumber;
          int relayPower;
          char* strtokIndx;
          char buff[20];

          strtokIndx = strtok(receivedChars, ":");                    // Skip the first segment which is the 'R' character
          strtokIndx = strtok(NULL, ":");                             // Get the board number
          boardNumber = atoi(strtokIndx);
          strtokIndx = strtok(NULL, ":");                             // Get the relay number
          relayNumber = atoi(strtokIndx);
          strtokIndx = strtok(NULL, ":");                             // Get the relay power state
          relayPower = atoi(strtokIndx);

          triggerRelay(boardNumber, relayNumber, relayPower);

          sprintf(buff, "<Relay FB:%d:%d:%d>", boardNumber, relayNumber, relayPower);
          Serial3.println(buff);
          Serial.println(buff);
          break;
        }
    }
  }
  newData = false;
}

void triggerRelay(int boardNumber, int relayNumber, int relayTrigger) {
  char buff[50];
  sprintf(buff, "Triggering board:%d, relay:%d, state: %d", boardNumber, relayNumber, relayTrigger);
  Serial.println(buff);
  if (relayTrigger == 1) {
    digitalWrite(relayPins[boardNumber][relayNumber], LOW); // Turn relay ON
  }
  else if (relayTrigger == 0) {
    digitalWrite(relayPins[boardNumber][relayNumber], HIGH); // Turn relay OFF
  }
}
[/code]

After some debugs, it seems playing with delay and removing both "for", from the setup(), give different outcomes.
Adding delay make the text <Due is ready!> to appear in serial monitor but nothing is showing up from esp32, no commands, nothing. First 2 lines from the screenshot, show this.

Deleting the delay make due only printing first character from the message "<Due is ready!>", that's "<", as show in the third line from the screenshot.

Removing this:

  for (int i = 0; i <= 1; i++) {
    for (int j = 0; j <= NUM_ELEMENTS(relayPins[i]); j++) {
      pinMode(relayPins[i][j], OUTPUT);
      digitalWrite(relayPins[i][j], HIGH);
    }
  }

Makes due to work almost properly, when it starts, the message <Due is ready!> appear and when I send a command to turn 1 relay on, the command is coming in and the feedback line, "Triggering board...." it's working as it should, problem is right after this when due keeps printing a command and it's keep triggering that relay. But as in every case the actual relay it's never turning on or off.

Also I didn't made a debug code from esp32, it's keep running the main one, I don't think it matter as the commands to turn relay on or off are coming in as they should, but thought it's good to point this out as well.

Your for loops in setup look dodgy: I suspect that you're setting pinmode on sixteen pins, not twelve as you intend.

Relay coils pull more current that you might expect so if the Due is trying to power them, that may explain why they're not switching.

Well I was not so sure how to set pins to output and write them high so I came with that work around, I will search more and try to come with a better method.

Relays are powered from a 12v power supply with a 5v voltage drop module, so there are no faults in there. Even so I'm testing now with a 2 relay module and it not even turn on the lights that show if relay is on or off( from the relay module). I've been testing Due with a relay test code, and indeed there is no fault in the board, all 8 relays where turning on/off as they should...uploading this code and everything is going south.

[code]
// Example 3 - Receive with start- and end-markers

#define NUM_ELEMENTS(x)  (sizeof(x) / sizeof((x)[0]))
// Serial
const byte numChars = 32;
char receivedChars[numChars];
boolean newData = false;

int relayPins[2][12] = { 46, 47, 48, 49, 50, 51, 52, 53};

void setup() {
  Serial.begin(9600);
  Serial3.begin(9600);
  Serial.println("<Due is ready!>");
  pinMode(46, OUTPUT);
  pinMode(47, OUTPUT);
  pinMode(48, OUTPUT);
  pinMode(49, OUTPUT);
  pinMode(50, OUTPUT);
  pinMode(51, OUTPUT);
  pinMode(52, OUTPUT);
  pinMode(53, OUTPUT);
  digitalWrite(46, HIGH);
  digitalWrite(47, HIGH);
  digitalWrite(48, HIGH);
  digitalWrite(49, HIGH);
  digitalWrite(50, HIGH);
  digitalWrite(51, HIGH);
  digitalWrite(52, HIGH);
  digitalWrite(53, HIGH);
  //  pinMode(Pins[12], OUTPUT);
  //  delay(500);
  //  for (int i = 0; i <= 1; i++) {
  //    for (int j = 0; j <= NUM_ELEMENTS(relayPins[i]); j++) {
  //      pinMode(relayPins[i][j], OUTPUT);
  //      digitalWrite(relayPins[i][j], LOW);
  //    }
  //  }
}
void loop() {
  recvWithStartEndMarkers();
  processSerialData();
  showNewData();}

void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;

  while (Serial3.available() > 0 && newData == false) {
    rc = Serial3.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      }
      else {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }

    else if (rc == startMarker) {
      recvInProgress = true;
    }
  }
}

void showNewData() {
  if (newData == true) {
    Serial.println(receivedChars);
    newData = false;
  }
}

void processSerialData() {
  while (newData == true) {
    char cmdChar = receivedChars[0];
    switch (cmdChar) {
      case 'R':                                                     // Message starts with "R" = relays. Format is "Relay:<BOARD#>:<RELAY#>:<STATUS>". Example: "Relay:0:4:1"
        {
          int boardNumber;
          int relayNumber;
          int relayPower;
          char* strtokIndx;
          char buff[20];

          strtokIndx = strtok(receivedChars, ":");                    // Skip the first segment which is the 'R' character
          strtokIndx = strtok(NULL, ":");                             // Get the board number
          boardNumber = atoi(strtokIndx);
          strtokIndx = strtok(NULL, ":");                             // Get the relay number
          relayNumber = atoi(strtokIndx);
          strtokIndx = strtok(NULL, ":");                             // Get the relay power state
          relayPower = atoi(strtokIndx);

          triggerRelay(boardNumber, relayNumber, relayPower);

          sprintf(buff, "<Relay FB:%d:%d:%d>", boardNumber, relayNumber, relayPower);
          Serial3.println(buff);
          Serial.println(buff);
          break;
        }
    }
  }
  newData = false;
}

void triggerRelay(int boardNumber, int relayNumber, int relayTrigger) {
  char buff[50];
  sprintf(buff, "Triggering board:%d, relay:%d, state: %d", boardNumber, relayNumber, relayTrigger);
  Serial.println(buff);
  if (relayTrigger == 1) {
    digitalWrite(relayPins[boardNumber][relayNumber], LOW); // Turn relay ON
  }
  else if (relayTrigger == 0) {
    digitalWrite(relayPins[boardNumber][relayNumber], HIGH); // Turn relay OFF
  }
  newData = false;
}
[/code]

I did this and now everything is working as it should, problem with the constant "Trigger relay...." message was solved by adding a "newData = false;" at the end of void triggerRelay.
May i ask if there is a way to declare pinMode and digitaWrite as a whole and not to each and every pin as I did now?

Put all pins in one array

uint8_t relayPins = {53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42}  ;

and

    for (uint8_t pinCnt = 0; pinCnt <= NUM_ELEMENTS(relayPins); pinCnt++) {
      pinMode(relayPins[pinCnt], OUTPUT);
      digitalWrite(relayPins[i][j], HIGH);
    }

You might want to put the digitalWrite() before the pinMode() to prevent glitches at startup.

The problem with the two-dimensional array in your original post is that it's basically this:

int relayPins [2][8] {
  {53, 52, 51, 50, 49, 48, 47, 46},              // 8 Chan Relay Board: [1] = Cooling box fan, [2] = Valve, [3] = Valve, [4] = Mixing jars, [5] = Presure pomp(water to plants);
  {45, 44, 43, 42, 0, 0, 0, 0}                               // 4 Chan Relay Board: [1] = Presure pomp, [2] = In res mix pomp, [3] = UV pomp, [4] = UV lamp(+2000 over 'UV pomp');
};

So you're setting the pin mode of pin 0.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.