I have found communications can be one of the most challenging aspects of life; serial communications is no exception. This article focuses on Universal Asynchronous Receiver-Transmitter (UART) communications, using an ARDBOX Relay HF+ WiFi PLC and an M-Duino GPRS/GSM 21+ PLC.

USB

I know I promised to talk UARTs, but let’s just introduce the most popular serial communications link today – the Universal Serial Bus (USB). The Raspberry Pi 4 (found on both the PLCs and Panel PCs) provides four USB sockets (2x USB 2.0 Type A and 2x USB 3.0 Type A) available during development and at run-time. Unfortunately, the Arduino-based PLCs do not provide any USB sockets available at run-time; each has one available (either a Type B or a Micro B) but its use is limited to programming, debugging, etc. For more details on this new industry standard, take a look at the Wiki’s USB article.

UARTs

Now, on to the UARTs – the old industry standards. The two most common UART standards are the RS-485, and the RS-232, which has been around since 1960!

RS-485

Let’s start with the arguably (for us) less complicated of the two – the RS-485. The standard defines only the electrical characteristics of the system – the physical layer. There are two signals, indicated by A+ and B- on the PLC boxes, which form a single differential line for half-duplex operation (see the RS-485 Wiki article for all the details). Two lines can be combined to provide full-duplex operation, in which case the two additional signals are indicated by Y+ and Z- on the PLC box. Or, in the case of the Raspberry Pi PLCs, both are half-duplex lines, both labelled A+ and B-. The RS-485 features are accessible through the RS-485.h header file and related library.

RS-485 pin potentials for transmission of 0xD3 (least significant bit first) using an asynchronous start-stop method.
(Thanks to Royvegard at the English-language Wikipedia)

In order to successfully communicate between two devices using the RS-485 lines, it is necessary to properly configure the environment. First, the Arduino IDE must be configured for the development board family and model. For example, I am using the ARDBOX WiFi/BT family, and the ARDBOX Relay HF+ w/ HW RS-485 WiFi/BT model. Next, I must enable the RS-485 lines, which means I must disable other features that share those lines, by the switches in the left zone and top zone (see User Guide sections 8.2 and 10.2) Finally, jumpers in Jumper Zone 1 (enable Y+ and Z-) and Jumper Zone 3 (enable RS-485 Rx and Tx) must be properly set (see User Guide sections 9 and 10.2). In order to set the jumpers, you must (carefully) open the PLC box, set the jumpers, and close up the box – see the Industrial Shields videos on these topics here (note that while the videos are for the 10 I/Os PLC, the steps are the same for the ARDBOX PLCs.

If you are using the M-Duino GPRS/GSM family, due to a defect in the board library, for the time being it is necessary to select the “M-Duino family” when configuring the Arduino IDE. Also, note the M-Duino PLCs require neither switch nor jumper settings that need to be changed for RS-485 communications.

The final steps in this process are connecting the wires and loading the software. For half-duplex lines, connect the A+ to the A+ signals, and B- to the B- signals; configure system one as the transmitter, and the other as the receiver. For full-duplex lines, connect the A+ to the Y+ signals, and the B- to the Z- signals. For long distances (for RS-485, up to 1200 meters), special twisted pair wiring is recommended, but for short distances (under a few meters, simple bell or stranded wire should suffice (I’ve used 20 AWG and smaller). Be sure the 12-24Vdc Power is connected. Example sketches can be found in your Arduino IDE Examples drop-down list; select the RS-485 option under the selected PLC, then select the sketch you’d like to try – the FullDuplex sketch for example.

RS-232

The Arduino PLCs provide a variety of lines that can be used for serial “RS-232” communications, but you need to be aware of the differences between these lines. First up are the actual RS-232 lines – these are accessible through the RS232.h header file and related library. These lines are marked with an RS232 on the PLC box, and an Rx and Tx to indicate direction. Second are the hardware serial lines – these are accessible through the HardwareSerial.h header file and related library. These are marked with TTL (transistor-transistor logic) on the PLC box, with an Rx and Tx to indicate direction. Finally, the third are the software serial lines, (accessible through the SoftwareSerial.h header file and related library) which are shared with other features on the PLC, typically the SPI lines.

If you don’t learn anything else from this article, know this – these lines are not entirely interoperable on the Industrial Shields PLCs or with other devices!

Generally speaking, the TTL lines and software serial lines play well with each other, but the RS232 lines will not work with either of them. This is due to the fact that while the TTL lines and software serial lines are 5Vdc (as are the Arduino RS-232 lines), the Industrial Shields PLCs RS232 lines use a MAX232 integrated circuit (IC) to boost the RS232 voltage to 12Vdc. So, let me reiterate, the RS232 lines are incompatible with the TTL lines and serial software lines. When you design a system using “RS-232” to connect your PLCs, be sure to take that into account. Another potential issue occurs when you try to connect a third-party “RS-232” device to your system. I learned all about this when I tried to connect an Adafruit Ultimate GPS receiver to my M-Duino Relay HF+ GPRS/GSM 21+ PLC. I couldn’t get it to work with the RS-232 lines, but it works great with TTL and software serial lines. That’s because the GPS receiver uses 3.3Vdc or 5Vdc lines which are not compatible with the 12Vdc MAX232 lines.

Diagrammatic oscilloscope trace of voltage levels for an ASCII “K” character (0x4B) with 1 start bit, 8 data bits (least significant bit first), 1 stop bit.
(Thanks to Ktnbn at the English-language Wikipedia)

There are no RS-232 lines on the Raspberry Pi PLCs, and at most one (often none) on the Arduino PLCs. As mentioned above, these are indicated by the RS-232 label. There is one hardware serial (TTL) line on the Raspberry Pi, and at most two lines on an Arduino PLC. One (if available) is the Serial line, which is used by the Arduino IDE Serial Monitor and for software uploads. Using the Serial line may cause conflicts. The other one (if available) is the Serial1 line, which is free for you to use as you wish. Note that the Arduino Mega2560 board has two additional hardware lines (Serial2 and Serial3), but neither of those is made available on the PLCs. The software serial lines are most often shared with the SPI lines – MOSI, MISO, and SCK. The pin numbers vary by controller board and PLC, but are usually either 14, 15, and 16 (Leonardo), or 51, 52, and 53 (Mega2560).

As with the RS-485 lines, in order to successfully communicate between two devices using the RS-232 lines, it is necessary to properly configure the environment. First, the Arduino IDE must be configured for the development board family and model. For example, I am using the ARDBOX WiFi/BT family, and the ARDBOX Relay HF+ w/ HW RS-485 WiFi/BT model. Next, I must enable the “RS-232” lines, which means I must disable other features that share those lines, by the switches in the left zone and top zone (see User Guide sections 8.3 and 10.1) Finally, jumpers in Jumper Zone 2 (enable software serial Rx and Tx) and Jumper Zone 3 (enable RS-232 Rx and Tx) must be properly set (see User Guide sections 9 and 10.1). In order to set the jumpers, you must (carefully) open the PLC box, set the jumpers, and close up the box – see the Industrial Shields videos on these topics here (note that while the videos are for the 10 I/Os PLC, the steps are the same for the ARDBOX PLCs.

As mentioned above for the RS-485, if you are using the M-Duino GPRS/GSM family, due to a defect in the board library, for the time being it is necessary to select the “M-Duino family” when configuring the Arduino IDE. Also, note the M-Duino PLCs require neither switch nor jumper settings that need to be changed for RS-232 communications.

Again, the final steps in this process are connecting the wires and loading the software. For full-duplex RS-232 lines, connect the Tx to the Rx signals. For long distances (for RS-232, up to only 15 meters), special twisted pair wiring is recommended, but for short distances (under a few meters, simple bell or stranded wire should suffice (I’ve used 20 AWG and finer). Be sure the 12-24Vdc Power is connected. Example sketches can be found in your Arduino IDE Examples drop-down list; select the RS-232 option under the selected PLC, then select the sketch you’d like to try – the Send and Receive sketches for example.

Here is a sketch that you can use to test out a variety of the serial interfaces. Simply leave one SERIAL_TEST defines uncommented. If you select the HARDWARE_SERIAL_TEST, you can connect the RX to the TX on the same box, and verify that interface works. Likewise, you can do the same for the RS232_SERIAL_TEST and the RS485_SERIAL_TEST. This will not work for the SOFTWARE_SERIAL_TEST – it must be connected to a different device.

Remember, do not connect a SOFTWARE_SERIAL_TEST line (or any 5Vdc line) to an RS232 line (or any line with voltage greater than 5Vdc) as it could damage the Arduino controller board!

Also, be sure to check the configuration – IDE board and model, switches, and jumpers.

/*
   Copyright (c) 2021 Daedalus Logic Systems Corporation All rights reserved

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

// Include only one library!
//#define RS485_SERIAL_TEST      /* RS485 A+ B- Y+ Z- */
//#define RS232_SERIAL_TEST      /* RS232 RX and TX */
//#define HARDWARE_SERIAL_TEST   /* TTL0 and TTL1 */
#define SOFTWARE_SERIAL_TEST   /* MOSI, MISO, SCK */

#if defined( RS485_SERIAL_TEST )

#include <RS485.h>

#elif defined( RS232_SERIAL_TEST )

#include <RS232.h>

#elif defined( HARDWARE_SERIAL_TEST )

#include <HardwareSerial.h>

//#define HWSerial Serial      /* RX0 / TX0 - these are used for Serial Monitor and sketch uploads, so expect interference */
#define HWSerial Serial1       /* NC / NC */
  
#elif defined( SOFTWARE_SERIAL_TEST )

#include <SoftwareSerial.h>

// The first value is the RX pin; the second value is the TX pin.
// The RX pin must be MOSI, MISO, or SCK. The TX pin may be MOSI, MISO or SCK.
// The TX pin may also be any available 5Vdc pin, such as 3 or 18.
//
// !!! Do NOT connect a 5Vdc pin to an RS-232 line as this may damage the Arduino controller !!!

SoftwareSerial SWSerial( 14, 3 ); /* Leonardo - MOSI (14), MISO (16), SCK (15) */
//SoftwareSerial SWSerial( 51, 18 ); /* M-Duino - MOSI (50), MISO (51), SCK (52) */

#endif
//// IMPORTANT: check switches configuration

////////////////////////////////////////////////////////////////////////////////////////////////////
void setup()
{
  // Begin serial port
	Serial.begin(9600);
  while (!Serial);  // Wait until Serial is ready

  // Begin selected serial interface
  
#if defined( RS485_SERIAL_TEST )

  Serial.println( "RS485 SERIAL TEST" );
  RS485.begin(9600);
  
#elif defined( RS232_SERIAL_TEST )

  Serial.println( "RS232 SERIAL TEST" );
  RS232.begin(9600);

#elif defined( HARDWARE_SERIAL_TEST )

  Serial.println( "HARDWARE SERIAL TEST" );
  HWSerial.begin(9600);

#elif defined( SOFTWARE_SERIAL_TEST )

  Serial.println( "SOFTWARE SERIAL TEST" );
  SWSerial.begin(9600);

#endif

}

////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() 
{
  byte rx;
  char tx;
  
  // Transmit input byte from Serial Monitor to selected serial interface when available
  if( Serial.available() )
  {
    tx = Serial.read();
    
#if defined( RS485_SERIAL_TEST )

    RS485.write( tx );
    
#elif defined( RS232_SERIAL_TEST )

    RS232.write( tx );

#elif defined( HARDWARE_SERIAL_TEST )

    HWSerial.write( tx );
    
#elif defined( SOFTWARE_SERIAL_TEST )

    SWSerial.write( tx );

#endif

  }

  // Read byte from the selected serial interface when available
  
#if defined( RS485_SERIAL_TEST )

  if( RS485.available() )
  {
    rx = RS485.read();

#elif defined( RS232_SERIAL_TEST )

  if (RS232.available())
  {
    rx = RS232.read();

#elif defined( HARDWARE_SERIAL_TEST )

  if( HWSerial.available() )
  {
    rx = HWSerial.read();

#elif defined( SOFTWARE_SERIAL_TEST )

  if (SWSerial.available())
  {
    rx = SWSerial.read();

#endif

    // Print received byte when available
    if( rx != 0 )
    {
      // Human readable representation
      Serial.print( char(rx) );
      
      // Hexadecimal representation
      Serial.print( " HEX: " );
      Serial.print( rx, HEX );
  
      // Decimal representation
      Serial.print( ", DEC: " );
      Serial.println( rx, DEC );
    }
  }
}

Where does this leave us? Well, for the Arduino PLCs, hopefully all of your questions are answered, and you’re good to go. For the Raspberry Pi PLCs and Panel PCs, probably not so much. I hope to have another article that covers those subjects in the very near future. But if you have any questions (about Arduino or Raspberry Pi products) don’t hesitate to contact me!