CrowPanel ESP32 Terminal SPI with Arduino IDE¶
Overview¶
The example tutorial is an environmental monitoring project, demonstrate how to create a UI and use a Humidity&Temperature 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 Arduino IDE.
Hardware Preparation¶
ESP32 Terminal | Crowtail-AM2302 | Crowtail-LED |
---|---|---|
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.
Please click to download the demo for "Example Demonstration" section in "Get Started with SquareLine Studio".
Design UI file with SquareLine Studio¶
Let's start learning how to create our own UI after getting an initial understanding of SquareLine Studio.
-
Open the SquareLine Studio and create a project. Select "Arduino"->"Arduino with TFT_eSPI".
Note:
When select the Arduino framwork, there's only one option "Arduino with TFT_eSPI". By choosing this, the squareline studio will generate a template code suitable for the TFT_eSPI library. However, squareline studio not only supports the TFT_eSPI library, it supports a variety of libraries to suit different hardware and application needs. For example, Adafruit_GFX library, LovyanGFX etc.
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, you can select the folder to save the project. Click CREATE to create the project.
-
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 color 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 "released" 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.
In order to be used with the main program, all UI files generated need to be placed in the same folder as the main program.
Please click to download the main program(and the expert UI is included).
-
Modify the button event code.
Open the main program. And all the UI file in the same folder will open too.
First, define an extern variable in the ui.h file to store the status of the LED. In the main program, the LED light is controlled to turn on and off by judging the status of this variable.
Then find "FUNCTION" in the ui.c file. Here is the corresponding code generated when we add events in SquareLine.
Comment out or delete the code circled in red in the picture above, add new code to assign a value to the LED variable.
- When button 1 (ON button) is pressed, set the LED value to 1.
- When button 2 (OFF button) is pressed, set the LED value to 0.
The UI file export is completed, and the button event function is also modified. Next we're going to learn about the Arduino main program and learn how to upload the code to the board.
Build the Project with Arduino IDE¶
Get Started with Arduino IDE¶
Please click the card below to learn how to install Arduino IDE, and install ESP32 board in the Arduino IDE.
Install Libraries¶
In this project, we will use the following libraries:
#include<Arduino.h>
#include <lvgl.h>
#include <LovyanGFX.hpp>
#include <stdbool.h>
#include "FT6236.h"
#include "ui.h"
#include "DHT.h"
#include <Arduino.h>
: contains the Arduino core library, providing commonly used functions and data types.#include <LovyanGFX.hpp>
: A library for drawing graphics on embedded systems, providing rich graphics functions and APIs.stdbool.h
: is a header file in the C language standard library, which defines the Boolean type bool and related macros.#include "FT6236.h"
: A library for the FT6236 touch chip to handle touch input.#include "ui.h"
: is a custom header file that contain UI-related functions or definitions.#include "DHT.h"
: to read data from the temperature and humidity sensor.
Please click to download the libraries.
Then click "File" -> "Preferences" -> "Setting" to check the sketchbook location. Place the libraries downloaded to the sketchbook location.
Tips:
- If you install the lvgl libraries by Library Manager, you need to copy the demos folder and examples folder and paste them to src folder. And modify the lv_conf_template.h file and rename it to lv_conf.h, and place it in libraries folder.(Please refer to the library provided)
Code Explanation¶
Basic Definition¶
Pin Definition
Touch I2C definition, LCD backlight definition pin, temperature and humidity sensor definition pin and initialization.
const int i2c_touch_addr = TOUCH_I2C_ADD;
#define LCD_MOSI 13
#define LCD_MISO 14 // 12
#define LCD_SCK 12
#define LCD_CS 3
#define LCD_RST -1 // 26
#define LCD_DC 42 // 33
#define LCD_BL 46
#define DHTPIN 40 // Digital pin connected to the DHT sensor
#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321
// Initialize DHT20 sensor
DHT dht(DHTPIN, DHTTYPE);
#define SDA_FT6236 2
#define SCL_FT6236 1
LGFX Class Definition
This part is the definition of a class LGFX
, which is a subclass of lgfx::LGFX_Device
. The main function is to configure and initialize an RGB color panel and then connect it to the SPI bus on the ESP32-S3 microcontroller in order to display graphics on the panel.
class LGFX : public lgfx::LGFX_Device
{
lgfx::Panel_ILI9488 _panel_instance;
lgfx::Bus_SPI _bus_instance;
public:
LGFX(void)
{
{
auto cfg = _bus_instance.config();
cfg.spi_host = SPI3_HOST;
cfg.spi_mode = 0;
cfg.freq_write = 60000000;
cfg.freq_read = 16000000;
cfg.spi_3wire = false;
cfg.use_lock = true;
cfg.dma_channel = 1;
cfg.pin_sclk = LCD_SCK;
cfg.pin_mosi = LCD_MOSI;
cfg.pin_miso = LCD_MISO;
cfg.pin_dc = LCD_DC;
_bus_instance.config(cfg);
_panel_instance.setBus(&_bus_instance);
}
{
auto cfg = _panel_instance.config();
cfg.pin_cs = LCD_CS;
cfg.pin_rst = LCD_RST;
cfg.pin_busy = -1;
cfg.memory_width = 320;
cfg.memory_height = 480;
cfg.panel_width = 320;
cfg.panel_height = 480;
cfg.offset_x = 0;
cfg.offset_y = 0;
cfg.offset_rotation = 0;
cfg.dummy_read_pixel = 8;
cfg.dummy_read_bits = 1;
cfg.readable = true;
cfg.invert = false;
cfg.rgb_order = false;
cfg.dlen_16bit = false;
cfg.bus_shared = true;
_panel_instance.config(cfg);
}
setPanel(&_panel_instance);
}
};
LGFX tft;
Define LED variables and screen resolution parameters
int led;
/*Changing the screen resolution*/
/*Change to your screen resolution*/
static const uint16_t screenWidth = 480;
static const uint16_t screenHeight = 320;
Defining buffer variables
Initialize the LVGL display driver and prepare a buffer to store the pixel data to be rendered on the screen. The size of this buffer should be about 1/10 of the product of the screen pixel value, which can take into account both the main control performance and the smoothness of the screen display. Here, take 5 as an example, the display will be smoother.
Functions¶
my_disp_flush()
This code is a callback function for refreshing the display, usually used with a graphics library. The function is to write pixel data to the display device based on the given area and color data to implement the display refresh operation.
/* Display flushing */
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 );
tft.startWrite();
tft.setAddrWindow( area->x1, area->y1, w, h );
tft.writePixels((lgfx::rgb565_t *)&color_p->full, w * h);
tft.endWrite();
lv_disp_flush_ready( disp );
}
my_touchpad_read()
This code is a callback function for reading touch screen input, usually used with the graphics library. The function is to set the corresponding input data according to the input state and coordinates of the touch screen so that the graphics library can perform subsequent processing and display.
void my_touchpad_read( lv_indev_drv_t * indev_driver, lv_indev_data_t * data )
{
int pos[2] = {0, 0};
ft6236_pos(pos);
if (pos[0] > 0 && pos[1] > 0)
{
data->state = LV_INDEV_STATE_PR;
data->point.x = tft.width()-pos[1];
data->point.y = pos[0];
// data->point.y = pos[1];
// data->point.x = pos[0];
Serial.printf("x-%d,y-%d\n", data->point.x, data->point.y);
}
else {
data->state = LV_INDEV_STATE_REL;
}
}
touch_init()
This code is a function for initializing the touch screen. It is used to initialize the touch screen and detect whether it is successfully connected to the touch screen device.
void touch_init()
{
// I2C init
Wire.begin(SDA_FT6236, SCL_FT6236);
byte error, address;
Wire.beginTransmission(i2c_touch_addr);
error = Wire.endTransmission();
if (error == 0)
{
Serial.print("I2C device found at address 0x");
Serial.print(i2c_touch_addr, HEX);
Serial.println(" !");
}
else if (error == 4)
{
Serial.print("Unknown error at address 0x");
Serial.println(i2c_touch_addr, HEX);
}
}
Set Up Part¶
void setup()
{
Serial.begin( 115200 ); /*Initializing the Serial Port*/
dht.begin(); /*DHT initialization*/
//IO Port Pins
pinMode(11, OUTPUT);
digitalWrite(11, LOW);
tft.begin(); /* TFT init */
tft.setRotation( 3 ); /* Landscape orientation, flipped */
tft.fillScreen(TFT_BLACK);
delay(500);
pinMode(LCD_BL, OUTPUT);
digitalWrite(LCD_BL, HIGH);
touch_init();
lv_init();
/*This code is used to configure and initialize the display driver and input device driver of the LittlevGL (LVGL) graphics library to implement the display and interaction of the graphical interface in the embedded system. The main steps include:
Get the width and height of the screen and initialize the drawing buffer.
Initialize the display driver and set its parameters, including resolution, refresh callback function and drawing buffer.
Register the display driver to the LVGL library.
Initialize the input device driver and set its type and read callback function.
Register the input device driver to the LVGL library.*/
lv_disp_draw_buf_init( &draw_buf, buf, NULL, screenWidth * screenHeight / 5 );
/*Initialize the display*/
static lv_disp_drv_t disp_drv;
lv_disp_drv_init( &disp_drv );
/*Change the following line to your 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 (dummy) input device driver*/
static lv_indev_drv_t indev_drv;
lv_indev_drv_init( &indev_drv );
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = my_touchpad_read;
lv_indev_drv_register( &indev_drv );
/*Initialize the (virtual) input device driver. This code is used to initialize a virtual input device driver and associate it with the LVGL framework to handle the interaction of the input device. It provides the necessary configuration and functions for the input device driver by setting the input device type and defining the read callback function.*/
/* Initialize the (dummy) input device driver */
static lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = my_touchpad_read;
lv_indev_drv_register(&indev_drv);
ui_init(); // UI initialization
lv_timer_handler();
}
Main Program Part¶
void loop()
{
/*Get the temperature and humidity data and use a char array to store it. First, use two integer variables a and b to store the obtained temperature and humidity.*/
char DHT_buffer[6];
int a = (int)dht.readTemperature();
int b = (int)dht.readHumidity();
/*Then the value is stored in an array through conversion and displayed on the label*/
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);
/*udge the value of LED. In the ui.c program, press the "ON" button to set LED to 1, and the LED light will be on.*/
if(led == 1)
digitalWrite(11, HIGH);
/*In the ui.c program, press the "OFF" button to set the led to 0, and then the control turns off the led light.*/
if(led == 0)
digitalWrite(11, LOW);
/*Let the GUI complete its work. Only by executing this function can the entire animation run.*/
lv_timer_handler(); /* let the GUI do its work */
delay( 10 );
}
Upload the Code¶
-
After completing the installation of the ESP32 board according to "Get Started with Arduino IDE" and the installation of the library according to "Install Libraries", open the program and connect the ESP32 Terminal to the computer via a USB-C cable.
-
Select Board: click "Tools" -> "Board" -> "esp32" and select "ESP32S3 Dev Module"
-
Setting: Click "Tool", select "16MB" as the flash size, select "Huge APP..." as the partition scheme, and select the "OPI PSRAM" as the PSRAM.
-
Select Port
Select the serial port corresponding to the ESP32 terminal board.
-
Upload the code
-
After the program is successfully uploaded, connect the sensor to the D2 Port(IO40) port and the LED to D1 Port(IO11), 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.
Examples¶
Please click to download the code for the examples.
Note:
The library used in this section is in the compressed package of the library downloaded above.
Example 1: Switch color screen¶
-
Open and upload the A-LCD.ino
-
The screen will display different colors
Example 2: Display the pictures from TF card¶
- Insert the TF card in to card slot
- Open and upload the A-TF-PIC.ino
- The pictures will show on the screen
Example 3: Touch initialization¶
-
Open and upload the A-TOUCH.ino
-
The XY coordinates of the touch will be displayed when touching different positions
Example 4: Camera initialization¶
-
Open and upload the A-Camera.ino
-
The camera will open
Example 5: LED Blinking and read analog sensor value¶
- Plug the LED into the D port, and plug a sensor to the A port
- Open and upload the A-A_D_PORT.ino
- The LED will blink, and the value of the sensor will show on the serial monitor
Example 6: I2C communication¶
- Plug an OLED screen to the I2C port
- Open and upload the A-IIC.ino
- The OLED screen will display the content sent from the ESP terminal
Example 7: Make sound¶
- Upload the A-BUZZER.ino
- The on-board buzzer will sounds "beep"
Example 8: Microphone initialization¶
-
Upload the A_AUDIO.ino
-
The serial monitor will display the sound waveform
Example 9: UART communication¶
-
Plug a Crowtail-GPS to the UART port
-
Open and upload the A-UART.ino
-
The GPS data will show on the serial monitor