Build Interactive GUI with Nextion Display and STM32 Using STM32CubeIDE
Getting Started with Nextion Display on STM32: Hardware, Coding & Setup
Introduction
Interfacing a Nextion display with an STM32 microcontroller opens up a world of interactive graphical user interfaces (GUI) for your embedded projects. Whether you want to display sensor data, create control panels, or build smart home interfaces, the Nextion HMI touchscreen makes it simple and visually appealing. In this tutorial, we will guide you step by step on how to connect a Nextion display to an STM32 board using STM32CubeIDE. You’ll learn about hardware connections, setting up the development environment, uploading your HMI project to the display, and writing the STM32 code to communicate seamlessly with Nextion. By the end of this guide, even beginners will be able to create interactive STM32 projects with touch-enabled displays, enhancing both functionality and user experience.
We are using STM32CubeMX and STM32IDE for stm32f103 programming. There are following components we need....
Required Components
- 1 × STM32F103 Board
- 1 × Nextion Display
- 1 × ST-Link Programmer
- 1 × TTL Serial to USB Adapter
- 1 × LED
- 1 × 220 Ω Register
- 10 × Jumper Wires
First, we create the Nextion display screen following the steps shown in our Nextion display tutorial. For a detailed guide, please visit the link below.
We created below scrren for project.
- h0 : (Arduino Uno, Mega, or ESP32)
- t0,t1 :textbox ,( t0 fetch value of h0 slider) (t1 for light title)
- b0, b1: Button for controlling Led.
STM32CubeMX Confugure:
First, we need to receive and transmit data via UART, which can be achieved using three methods: polling, interrupt, or DMA for UART communication. To get started, we create a project in STM32CubeMX to generate the basic configuration code.
Polling Method
HAL_UART_Receive(huart, pData,Size,Timeout)
HAL_UART_Transmit(huart, pData, Size,Timeout)
The polling method is essentially a blocking function being called from the main routine and it does block the CPU so it can’t proceed in the main task execution until a certain amount of UART data bytes are received. After receiving the required amount of data, the function ends and the CPU continues the main code execution. Otherwise, and if the UART peripheral for some reason didn’t receive the expected amount of data, the function will keep blocking the CPU for a certain amount of time “time-out” after which it gets terminated and gives back the control to the CPU to resume the main code.
while(1)
{
HAL_UART_Receive(&huart1, (uint8_t*) Rxbuf,3, 1000);
if (strcmp( Rxbuf, "ON") == 0)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
}
else if (strcmp(Rxbuf, "OFF") == 0)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
}
else if(atoi(Rxbuf))
{
Nextion_Send("t0",(char *)Rxbuf);
}
memset(Rxbuf, 0, sizeof(Rxbuf));
HAL_Delay(100);
}
We created Nextion_Send method to send data to nextion display.
void Nextion_Send(char * Id, char * String)
{
uint8_t Cmd_End[3] = {0xFF,0xFF,0xFF};
char buf[50];
int len = sprintf(buf, "%s.txt=\"%s\"",Id,String);
HAL_UART_Transmit(&huart1, (uint8_t*)buf, len, 1000);
HAL_UART_Transmit(&huart1, Cmd_End, sizeof(Cmd_End), 1000);
}
Interrrupt Method:
Using interrupt signals is a convenient way to achieve serial UART data reception. The CPU initializes the UART receive hardware so that it fires an interrupt signal whenever a new byte of data is received. And in the ISR code, we save the received data in a buffer for further processing.
This way of handling the UART data reception is a non-blocking way. As the CPU initiates the receiving process and it resumes executing the main code. Until an interrupt is received, then it freezes the main context and switches to the ISR handler to save the received byte to a buffer and switches back to the main context and resume the main code.
HAL_UART_Receive_IT(huart, pData,Size)
HAL_UART_Transmit_IT(huart, pData, Size)
The above function initializes the UART receive process in interrupt mode (non-blocking) and upon completion, a callback function is called to notify the application and the processor knows that the received data buffer is now ready.
For interrupt first need change in cubemax file for enable it. As shown in below figure.
In Non-Blocking way interrupt call after complete transmit or receive. After it call function
HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
#include "main.h"
UART_HandleTypeDef huart1;
char Rxbuf[50];
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
HAL_UART_Receive_IT(&huart1, (uint8_t*) Rxbuf, 3);
if (strcmp( Rxbuf, "ON") == 0)
{ HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); }
else if (strcmp(Rxbuf, "OFF") == 0)
{ HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); }
else if(atoi(Rxbuf))
{ Nextion_Send("t0",(char *)Rxbuf); }
memset(Rxbuf, 0, sizeof(Rxbuf));
HAL_Delay(100);
}
void Nextion_Send(char * Id, char * String)
{
uint8_t Cmd_End[3] = {0xFF,0xFF,0xFF};
char buf[50];
int len = sprintf(buf, "%s.txt=\"%s\"",Id,String);
HAL_UART_Transmit(&huart1, (uint8_t*)buf, len, 1000);
HAL_UART_Transmit(&huart1, Cmd_End, sizeof(Cmd_End), 1000);
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
HAL_UART_Receive_IT(&huart1, (uint8_t*) Rxbuf, 3);
while (1)
{
}
}
DMA Method:
This method is a non-blocking one, yet very efficient. However, if you’re receiving a continuous stream of serial data, an insane number of interrupts per second will have to be handled by the CPU which is a huge loading and a waste of time for it. In this situation, even the interrupt method will be inefficient and unnecessarily loading the CPU and consuming too much of the CPU time. And in worst scenarios, there might be some data packets lost or dropped in the way. Now, it comes the time to use the DMA method.
HAL_UART_Receive_DMA(huart, pData, Size)
HAL_UART_Transmit_DMA(huart, pData, Size)
Using the DMA method in order to direct the received serial UART data from the UART peripheral directly to the memory is considered to be the most efficient way to do such a task. It requires no CPU intervention at all, you’ll have only to set it up and go execute the main application code. The DMA will notify back the CPU upon reception completion and that received data buffer will be in the pre-programmed location.
Conclusion
In this tutorial, we successfully interfaced a Nextion display with an STM32 microcontroller using STM32CubeIDE. We covered the complete process—from creating the HMI project in Nextion Editor, wiring the display to STM32, configuring UART communication, to writing code for sending and receiving data. This setup allows you to build interactive and visually appealing GUIs for a variety of applications, from sensor dashboards to control panels. By mastering these steps, you can now enhance your embedded projects with touch-enabled displays and take your STM32 applications to the next level.
It would be useful if you included the code to set up the UART interrupts and DMA.
ReplyDeleteThanks.
Thank you for your time!
Deletehow to change the Nextion display pages using stm32 code. plz healp me
ReplyDelete