CrowPanel ESP32 2.8-inch with ESP-IDF¶
Overview¶
The example tutorial is an environmental monitoring project, demonstrate how to create a UI and use a DHT20 sensor to obtain the environment temperature and humidity and display it on the screen; and how to control the LED on and off by the buttons on the screen.
In this tutorial, we will show you how to design the UI with SquareLine Studio, and show you how to upload the code with ESP-IDF.
Hardware Preparation¶
CrowPanel ESP32 2.8'' HMI | Crowtail-DHT20 | Crowtail-LED | Dupont-wire |
---|---|---|---|
Design UI file with SquareLine Studio¶
Get Started with SquareLine Studio¶
Please click the card below to learn how to download the SquareLine Studio, and how to export the demo UI file.
Design UI file with SquareLine Studio¶
Let's start learning how to create our own UI after getting an initial understanding of SquareLine Studio.
-
In the earlier version of SLS, select "Arduino"->"Arduino with TFT_eSPI".
Note:
After using SLS to generate UI code, we then use different graphics libraries according to different hardware and modify the corresponding code to display the content you design.
Set the name of the project, set the screen resolution to 320*240, set the color depth to 16bit, and keep other default settings. After setting, click CREATE to create the project.
- 16-bit color depth: can represent 65,536 colors through RGB 5:6:5 sub-pixel representation, that is, each RGB channel occupies 5 bits and 1 bit (a total of 16 bits) to represent colors.
-
After creation, enter the following interface with a blank background.
-
In the "Assets" area, click "ADD FILE TO ASSETS" to add custom images or icons.
Please click to download the custom images used in this tutorial.
Note:
Images only support PNG format. The pixels of the image need to be smaller than the pixel size of the screen used in your project. The size of each image should not exceed 100k, preferably within 30k, to provide a smooth display effect.
-
Add background.
Find "Inspector"->"STYLE SETTING", click to expand "STYLE(MAIN)", then click the 2nd "Background". Check the "Bg Image" and select the background image.
-
Add Label widget to display temperature and humidity.
Click "Label" in the "Widgets" area, and "Label1" will be added to the current Screen.
The position and size of the label can be adjusted by dragging the mouse. You can also directly enter numbers in the Inspector→LABEL→Transform to adjust.
You can set the font colour and other attributes in STYLE SETTING→STYLE(MAIN).
Add a Label2 to display the humidity value in the same way. You can also directly right-click the Label1 to duplicate it.
Then set different positions for the Label2.
Modify the text content to display a default value.
-
Add Button widget to control the LED.
Click "Button" in the "Widgets" area, and "Button1" will be added to the current Screen.
The position and size of the label can be adjusted by dragging the mouse. You can also directly enter numbers in the Inspector→BUTTON→Transform to adjust.
Add an identification symbol to the button. The button in this tutorial controls the LED switch, so you only need to mark the button "on" and "off". You can add LABEL widgets or add a background images to the button. This tutorial will demonstrate how to add a background image to a button.
Click the Button1, then find Inspector->STYLE SETTINGS ->STYLE(MAIN) ->Background, and select the image.
In the same way, duplicate a Button widget. And drag it to the corresponding position to modify different background image.
Set the status of the button to identify different states.
In "Inspector"->"STYLE SETTINGS"->"STATE", set display white background color by DEFAULT and red when on the PRESSED state.
Make the same settings for the "OFF" button.
-
Add events to buttons.
Note: Because the button controls the on and off of the LED, we can add any event here to generate the code framework for the button event when exporting the UI file. We will modify the code of the button event to control the LED latter.
Select the button and click "ADD EVENT".
Select "clicked" as the trigger condition, select a trigger event in "Action". It will be modified in the generated program to achieve the LED control function.
Complete the event. Here I choose to change the screen, and the screen to be switched is Screen1.
Add event to Button2 (OFF) in the same way.
-
Export UI files.
Click "File" -> "Project Settings" and make settings for the exported file.
Set the export path of the file (set the path according to your own file).
Fill in lvgl.h in LVGL Include Path. Check "Flat export(exports all files to one folder )".
Then click "APPLY CHANGES".
Tips: After selecting the flat export, the output files will be in the same folder, so that the output code does not need to modify the path in the program. If not, the output files will be classified and placed in different folders. The compiler may not be able to recognize different paths, which will cause some trouble. In this case, the user needs to modify it manually, so it is recommended to select all files to be output to the same folder.
Export UI files. The exported files will be in the path we set earlier.
Build the Project with ESP-IDF¶
Get Started with ESP-IDF¶
Please click the card below to learn how to install ESP-IDF. Create a blank project according to the "Get Started with ESP-IDF".
You can click to download the complete project we provided. This project can be used directly. You can also create the project by following the tutorial.
Add Libraries¶
Create a new folder and name the folder 'components'. Add the libraries we provided to this folder.
Please click to download the libraries we provided.
Setup UI file¶
Add the UI file we exported earlier in Squareline.
The CMakeList.txt file in the UI file needs to be modified as follows:
Before modification
SET(SOURCES ui_comp_button2.c
ui_comp.c
ui_Screen1.c
ui.c
ui_comp_hook.c
ui_helpers.c
ui_events.c
ui_img_background_png.c
ui_img_on_png.c
ui_img_off_png.c)
add_library(ui${SOURCES})
After modification
Define a variable in the ui.h file. In the main program by judging the value of this variable, control the LED light on and off.
Locate the FUNCTION location in the ui.c file. This is the code we generated when we added events to squareline. We modify the event implementation function to what we need.
Delete the code in the red circle in the image above. Add new code to assign values to led variables.
When the key 1 (ON key) is pressed, set the LED value to 1.
When key 2 (OFF key) is pressed, set the LED value to 0.
Setup main file¶
The CMakeList.txt file contains the Settings for the library. All required libraries should be included by directory address. The CPP file of DHT20 has an additional column.
The main program is written in CrowPanel_ESP32_2.8.cpp file.
Library introduction¶
In this project, we will use the following libraries:
#include <lvgl.h>
#include <DHT20.h>
#include <TFT_eSPI.h>
#include <demos/lv_demos.h>
#include<Arduino.h>
#include "ui.h"
#include <lvgl.h>
: Library for UI interaction#include <DHT20.h>
: The library of temperature and humidity sensors#include <TFT_eSPI.h>
: Screen driven library.#include <demos/lv_demos.h>
: lvgl example library#include "ui.h"
: Library files generated by Squareline Studio****
Code Explanation¶
Basic Definition
-
Screen resolution definition, 2.8 inch resolution is 320*240. Touch calibration data and led variables.
-
Define a buffer variable to initialize the display driver of LVGL and prepare a buffer to store pixel data that will be rendered to the screen. The size of this buffer should be around 1/10 of the product of screen pixel values, which can balance the main control performance and the smoothness of screen display. Taking 8 as an example, the display will be smoother.
-
Initialize the T/H sensor and the TFT_eSPI library
Function
-
Screen refresh function, this code is for the refresh function driven by the display in the LittlevGL (LVGL) graphics library. LVGL is an open-source graphics library for embedded systems, used to create graphical user interfaces (GUIs). This function my_disp_flush is a user-defined callback function used to refresh the content of the graphical interface onto the display device.
/* Display Refresh */ void my_disp_flush( lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p ) { uint32_t w = ( area->x2 - area->x1 + 1 ); uint32_t h = ( area->y2 - area->y1 + 1 ); lcd.startWrite(); lcd.setAddrWindow( area->x1, area->y1, w, h ); lcd.pushColors( ( uint16_t * )&color_p->full, w * h, true ); lcd.endWrite(); lv_disp_flush_ready( disp ); }
-
A simple touch input device reading function, which is used to convert touch events into the input device data format required by the LVGL library, and output the coordinate information of touch points through serial communication.
600 indicates the timeout period (in milliseconds). That is, the maximum waiting time for a touch screen input. When the lcd.getTouch function is called, it attempts to read the input status and coordinate information of the touch screen. If the input is successfully read within 600 milliseconds, the function returns true, indicating that the touch screen was touched. If the input is not read within 600 milliseconds, the function returns false, indicating that the touch screen was not touched. This timeout can be adjusted as needed. A short timeout may result in not accurately capturing all coordinate points when swiping quickly on the touch screen, while a longer timeout may increase response time. You can adjust the timeout period based on application scenarios and requirements.
uint16_t touchX, touchY; /*Read Touchpad*/ void my_touchpad_read( lv_indev_drv_t * indev_driver, lv_indev_data_t * data ) { bool touched = lcd.getTouch( &touchX, &touchY, 600); if ( !touched ) { data->state = LV_INDEV_STATE_REL; } else { data->state = LV_INDEV_STATE_PR; /*Setting the coordinates*/ data->point.x = touchX; data->point.y = touchY; Serial.print( "Data x " ); Serial.println( touchX ); Serial.print( "Data y " ); Serial.println( touchY ); } }
Set Up Part
extern "C" void app_main()
{
Serial.begin( 115200 ); /*Initializing the Serial Port*/
Serial2.begin( 9600 ); /*Initialize Serial Port 2*/
//IO Port Pins
pinMode(25, OUTPUT);
digitalWrite(25, LOW);
//initialization of DHT20 pins(I2C)
Wire.begin(22, 21);
dht20.begin();
uint16_t calData[5] = { 189, 3416, 359, 3439, 1 };
lv_init(); // LVGL initialization
lcd.begin();
lcd.fillScreen(TFT_BLACK);
delay(300);
//Backlight Pins
pinMode(27, OUTPUT);
digitalWrite(27, HIGH);
lcd.setRotation(1);
lcd.setTouch(calData);
lv_disp_draw_buf_init(&draw_buf, disp_draw_buf, NULL, screenWidth * screenHeight / 8);
/*Initializing the display*/
static lv_disp_drv_t disp_drv;//A static lv_disp_drv_t variable disp_drv is defined to store the configuration and information about the display device driver
lv_disp_drv_init( &disp_drv );
/*Change the following line to display resolution*/
disp_drv.hor_res = screenWidth;
disp_drv.ver_res = screenHeight;
disp_drv.flush_cb = my_disp_flush;
disp_drv.draw_buf = &draw_buf;
lv_disp_drv_register( &disp_drv );
/*Initialize the (virtual) input device driver*/
static lv_indev_drv_t indev_drv;//Define the input device driver structure
lv_indev_drv_init( &indev_drv );//Initialize the input device driver
indev_drv.type = LV_INDEV_TYPE_POINTER;//Setting the input device type
indev_drv.read_cb = my_touchpad_read;//Define the read callback function
lv_indev_drv_register( &indev_drv );//Registering Input Device Drivers
ui_init();
while (1)
{
Serial.print(led);
char DHT_buffer[6];
int a = (int)dht20.getTemperature();
int b = (int)dht20.getHumidity();
snprintf(DHT_buffer, sizeof(DHT_buffer), "%d", a);
lv_label_set_text(ui_Label1, DHT_buffer);
snprintf(DHT_buffer, sizeof(DHT_buffer), "%d", b);
lv_label_set_text(ui_Label2, DHT_buffer);
if(led == 1)
digitalWrite(25, HIGH);
if(led == 0)
digitalWrite(25, LOW);
lv_timer_handler();
Serial.println("Setup done");
}
}
Main Program Part
while (1)
{
/*① obtain temperature and humidity data and store it in a char array. First, use two integer variables a and b to store the obtained temperature and humidity separately*/
char DHT_buffer[6];
int a = (int)dht20.getTemperature();
int b = (int)dht20.getHumidity();
/*Then store the values in the array and display them on the label label through conversion*/
snprintf(DHT_buffer, sizeof(DHT_buffer), "%d", a);
lv_label_set_text(ui_Label1, DHT_buffer);
snprintf(DHT_buffer, sizeof(DHT_buffer), "%d", b);
lv_label_set_text(ui_Label2, DHT_buffer);
/*To determine the value of the LED, in the ui. c program, press the "ON" button to set the LED to 1, and control the LED light to turn on.*/
if(led == 1)
digitalWrite(25, HIGH);
/*In the ui. c program, press the "OFF" button to set the LED to 0, and at this time, control the LED to turn off.*/
if(led == 0)
digitalWrite(25, LOW);
lv_timer_handler(); /* let the GUI do its work, only by executing this function can the entire animation run. */
delay( 10 );
}
Setup board¶
Press "Enter"
Menuconfig Setup section¶
Click Menuconfig to enter the Settings
Flash memory setting
Partition table setting.
TFT_eSPI setting
LVGL setting, uncheck
Save the setting
Download the program¶
Connect the ESP32 Display to the PC and compile the program.
After confirming the serial port, select the UART mode.
After the program is successfully downloaded, connect the DHT20 sensor to the IIC port and the LED to GPIO_D, the temperature and humidity values will be displayed on the screen. Click the ON button on the screen and the LED will turn on. Click the OFF button and the LED will turn off.