How to Interface STONE HMI with ESP32

In this tutorial we will see how to interface the Stone HMI Display with ESP32 using the ESP-IDF. We will control a LED connected to the ESP32 using the buttons on the display, also we will print some numerical value on the display.

For this tutorial I am going to use the ESP32 WROOM controller. The HMI Displays generally communicates using the UART, so in order to control the display, all we need is a controller with UART peripheral, which is actually very common to find.

We have already covered How to use UART in ESP32 using the ESP-IDF. So If you haven’t seen it yet, I would advise you to check it out.

Let’s start with the connection

The Connection

The Stone HMI Display have the connector header in order to connect to the microcontrollers. But the spacing between the pins is too wide, and I couldn’t find any male header which can fit it. The display comes along with a USB-UART board which can also be used to power the display.

After doing some continuity testing I have found that the pins of this USB-UART board can also use used as the TX and RX pins. The diagram for the same is shown below

The HMI Display communicates in the RS232 format and in order to convert it to the TTL, I am using a RS232 to TTL converter.

The MCU is connected to the display via this converter as shown below.

Note that between the MAX232 converter and the USB-UART board, there is a cross connection, TX->RX and RX->TX. But between the MCU and MAX232 converter, there is a straight connection, TX->TX and RX->RX.

The MAX232 needs to be supplied 5V, as it will misbehave at 3.3V.

Also the ESP32 board have a on board LED connected to the pin GPIO2.



The Design

Below is the image from the Stone designer including all the elements used in the Design.

There are 3 Labels

  • Label 1 indicates the LED State
  • Label 2 have the fixed string, “VALUE =”, and it does not change
  • Label 3 is going to be updated with the value from the Integer Variable.

There are 2 buttons, LED01 is the ON button and we will program it to turn ON the LED. LED02 is the OFF button and it will turn the LED OFF.


We will first create a project using the examples provided in the IDE by default. Later we will modify it according to our need.

  • Fist we will create a new Espressif IDF project
  • Then give some name to this project and click next

  • check “Create project using one of the templates”
  • goto Peripherals -> uart and select the “uart_async_rxtxtasks”
  • The name of the project will be modified after this, so make sure you change it back
  • Click finish to generate the project

The example we chose above is simplest method of sending and receiving data, i.e using the blocking mode.



The Code

On Pressing the button on the display, it sends the data via the UART. The data sent by the HMI Display is shown below:

Basically we get the 12 bytes of fixed data, and the rest depends on what name have we set for the button. As per this tutorial, I have set the button names as LED01 and LED02, so the total data sent by the display would be 12 Bytes + 5 Bytes for button name + 1 byte for the value = 18 Bytes.

We can write a simple UART receive task to receive the data, and then check for the button name in the received data. This task should run every 200ms so that we don’t get much delay after the button has been pressed.

const int rxBytes = uart_read_bytes(UART_NUM_2, data, RX_BUF_SIZE, 200 / portTICK_RATE_MS);

If we have received the data successfully, we will check for the button names present in the data received.


if (strncmp((char *)(data+7), "LED01", 5) == 0)
{
  gpio_set_level(LED, 1);
  TxData = (char *)malloc(100);
  int len = sprintf(TxData, "ST<{\"cmd_code\":\"set_text\",\"type\":\"label\",\"widget\":\"label1\",\"text\":\"LED ON\"}>ET");
  uart_write_bytes(UART_NUM_2, TxData, len);
  free(TxData);
}
  • Here we will check if the received data contains the string “LED01“, which is actually the name of the ON button
    • Note that we are checking the button name from the 7th position, as I explained above that the first 7 bytes remains constant, so button name starts at 7th position itself.
  • If the string is found, means that the ON button was pressed, we will proceed further.
  • We will first Set the LED pin HIGH.
  • Then send the text “LED ON” to the label 1 indicating that the LED is ON.

In order to send the text to the label, we used the command given in the instruction manual of the display. Below is the image from the manual showing this command.

This image has an empty alt attribute; its file name is 2-1024x93.jpg

The sprintf is just used to copy the string to the TxData buffer, which is then sent via the UART.

Similar to ON button, we also check for the OFF button, and then proceed accordingly. Below is the full code related to the buttons.

else if (strncmp((char *)(data+7), "LED02", 5) == 0)
{
  gpio_set_level(LED, 0);
  TxData = (char *)malloc(100);
  int len = sprintf(TxData, "ST<{\"cmd_code\":\"set_text\",\"type\":\"label\",\"widget\":\"label1\",\"text\":\"LED OFF\"}>ET");
  uart_write_bytes(UART_NUM_2, TxData, len);
  free(TxData);
}

We also need to send the Integral value to another label we created on the display. In order to do so, I am going to increment a variable and then convert its value to the Ascii format and send to the label.

I have assigned the Tx Task for this purpose as shown below.

static void tx_task(void *arg)
{
	   while (1)
	    {
	  	  TxData = (char *)malloc(100);
	  	  int len = sprintf(TxData, "ST<{\"cmd_code\":\"set_text\",\"type\":\"label\",\"widget\":\"label3\",\"text\":\"%d\"}>ET", num++);
	  	  uart_write_bytes(UART_NUM_2, TxData, len);
	  	  free(TxData);
	      vTaskDelay(500 / portTICK_PERIOD_MS);
	    }
}
  • Here we will first allocate the memory for the TX data buffer
  • Then store the command into the TxData buffer with the text field as the format specifier of the integral value (%d)
    • The value to be stored in this identifier is that of the num variable.
  • We will then send the data to the u art using the uart_write_bytes function.
  • This task will run every 500 ms.

The main function is shown below

void app_main(void)
{
    gpio_set_direction(LED, GPIO_MODE_OUTPUT);
    init();
    xTaskCreate(rx_task, "uart_rx_task", 1024*2, NULL, configMAX_PRIORITIES, NULL);
    xTaskCreate(tx_task, "uart_tx_task", 1024*2, NULL, configMAX_PRIORITIES-1, NULL);
}
  • Here we will first set the direction of the LED as output
  • Then initialise the UART
  • Then we will create two tasks, one for receiving the data (RX Task) and another one for sending the data (TX Task)
  • Once created, these tasks will start executing.


Result

Below are the images of the LCD and the ESP32

  • In the image above, the LED is turned on after pressing the ON button
  • The LED state shows the the LED is ON
  • Also note the value = 49, it is the value of the num variable that we incremented in the code

  • In the image above, the LED is turned off after pressing the OFF button
  • The LED state shows the the LED is OFF
  • Also note the value = 53, it is the value of the num variable that we incremented in the code

Check out the Video Below




Info

You can help with the development by DONATING
To download the code, click DOWNLOAD button and view the Ad. The project will download after the Ad is finished.

Subscribe
Notify of

0 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
keyboard_arrow_up