一、项目要求及简介
1、项目要求
本次活动我选择的是:任务二:lvgl图形库和应用。
官方要求:
用FireBeetle-E开发板作为控制单元,搭配显示屏移植lvgl图形库,动态显示任意一个及以上传感器采集到的数据,或者使用触摸屏对执行器进行控制。
2、使用的模块
①主控:DFRobot的FireBeetle ESP32-E IOT开发板
②声音传感器:DFRobot的Analog Sound Sensor
③ 温湿度传感器模块 DHT11
④ 显示模块:ST7789v2 240*240 IPS液晶屏
3、具体完成的项目
通过lvgl在LCD上面分成四块区域,分别显示标题、环境声音强度、环境温度、环境湿度;其中除标题外,其余部分背景色分别是蓝、绿、红。下图为ui展示,具体的详见第五部分(实物展示)。
二、开发环境搭建
1、Arduino开发环境
去官网https://www.arduino.cc/en/software下载Arduino2.0.3,这个开发环境相较于 Arduino1.x来说,增加了代码提示和跳转功能,开发起来更加的方便。
2、DFRobot官方资料
官方中文Wiki地址https://wiki.dfrobot.com.cn,大部分资料可以通过左侧的索引找到。但根据个人经验,FireBettle ESP32-E IOT开发板需要手动搜索货号:DFR0654才能找到。下面附加用到的资料链接。
开发板资料:https://wiki.dfrobot.com.cn/_SKU_DFR0654_FireBeetle_Board_ESP32_E
声音传感器资料:https://wiki.dfrobot.com.cn/_SKU_DFR0034_%E6%A8%A1%E6%8B%9F%E5%A3%B0%E9%9F%B3%E4%BC%A0%E6%84%9F%E5%99%A8_V2
DHT11温湿度传感器资料:https://wiki.dfrobot.com.cn/_SKU_DFR0067_DHT11%E6%95%B0%E5%AD%97%E6%B8%A9%E6%B9%BF%E5%BA%A6%E4%BC%A0%E6%84%9F%E5%99%A8V2
ST7789 240*240分辨率LCD资料:https://wiki.dfrobot.com.cn/1.54_240x240_IPS_LCD_SKU_DFR0649
3、TFT-eSPI资料
本次活动采用的LCD是ST7789v2控制器,用官方资料无法正常驱动,所以采用第三方的TFT-eSPI驱动库。链接地址:https://github.com/Bodmer/TFT_eSPI
3、LVGL资料
lvgl源码:https://github.com/lvgl/lvgl/tree/release/v8.2
lvgl Arduino移植教程:https://docs.lvgl.io/master/get-started/platforms/arduino.html
lvgl Arduino简易Demo:https://github.com/lvgl/lvgl/blob/master/examples/arduino/LVGL_Arduino/LVGL_Arduino.ino
三、外设驱动及LVGL移植
1、添加驱动到libraries文件夹下
根据Arduino的安装位置(比如默认安装目录下,库目录为:C:\Users\xxx\AppData\Local\Arduino15\packages\DFRobot\hardware\esp32\0.2.1\libraries)将前面下载的zip驱动包解压至此根目录即可。注:LVGL要将lv_conf.h单独复制到此目录下。
2、修改驱动
首先根据LCD的信息修改TFT-eSPI的User_Setup.h文件,如下:
// Only define one driver, the other ones must be commented out
//#define ILI9341_DRIVER // Generic driver for common displays
//#define ILI9341_2_DRIVER // Alternative ILI9341 driver, see https://github.com/Bodmer/TFT_eSPI/issues/1172
//#define ST7735_DRIVER // Define additional parameters below for this display
//#define ILI9163_DRIVER // Define additional parameters below for this display
//#define S6D02A1_DRIVER
//#define RPI_ILI9486_DRIVER // 20MHz maximum SPI
//#define HX8357D_DRIVER
//#define ILI9481_DRIVER
//#define ILI9486_DRIVER
//#define ILI9488_DRIVER // WARNING: Do not connect ILI9488 display SDO to MISO if other devices share the SPI bus (TFT SDO does NOT tristate when CS is high)
//#define ST7789_DRIVER // Full configuration option, define additional parameters below for this display
#define ST7789_2_DRIVER // Minimal configuration option, define additional parameters below for this display
//#define R61581_DRIVER
//#define RM68140_DRIVER
//#define ST7796_DRIVER
//#define SSD1351_DRIVER
//#define SSD1963_480_DRIVER
//#define SSD1963_800_DRIVER
//#define SSD1963_800ALT_DRIVER
//#define ILI9225_DRIVER
//#define GC9A01_DRIVER
// For ST7789, ST7735, ILI9163 and GC9A01 ONLY, define the pixel width and height in portrait orientation
// #define TFT_WIDTH 80
// #define TFT_WIDTH 128
// #define TFT_WIDTH 172 // ST7789 172 x 320
#define TFT_WIDTH 240 // ST7789 240 x 240 and 240 x 320
// #define TFT_HEIGHT 160
// #define TFT_HEIGHT 128
#define TFT_HEIGHT 240 // ST7789 240 x 240
// #define TFT_HEIGHT 320 // ST7789 240 x 320
// #define TFT_HEIGHT 240 // GC9A01 240 x 240
// For NodeMCU - use pin numbers in the form PIN_Dx where Dx is the NodeMCU pin designation
// #define TFT_CS PIN_D8 // Chip select control pin D8
// #define TFT_DC PIN_D3 // Data Command control pin
// #define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line)
#define TFT_MISO 19
#define TFT_MOSI 23
#define TFT_SCLK 18
#define TFT_CS 27
#define TFT_DC 25
#define TFT_RST 26
根据官方教程修改lv_conf.h文件
/* clang-format off */
#if 1 /*Set it to "1" to enable content*/
#ifndef LV_CONF_H
#define LV_CONF_H
#include <stdint.h>
/*====================
COLOR SETTINGS
*====================*/
/*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/
#define LV_COLOR_DEPTH 16
/*Swap the 2 bytes of RGB565 color. Useful if the display has an 8-bit interface (e.g. SPI)*/
#define LV_COLOR_16_SWAP 1
需要使能文件,修改颜色深度为16,并使能字节交换(SPI是8位传输,颜色数据是16位)
四、业务代码
1、添加lvgl底层显示函数
static const uint16_t screenWidth = 240;
static const uint16_t screenHeight = 240;
static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[screenWidth * 10];
TFT_eSPI tft = TFT_eSPI(screenWidth, screenHeight); // Create object "tft"
dht11 dht;
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.pushColors((uint16_t*)&color_p->full, w * h, false);
tft.endWrite();
lv_disp_flush_ready(disp);
}
此函数是lvgl需要底层显示的时候回调的
2、初始化屏幕、lvgl等
Serial.begin(115200);
lv_init();
tft.init();
tft.setRotation(3);
pinMode(15, ANALOG);
lv_disp_draw_buf_init( &draw_buf, buf, NULL, screenWidth * 10 );
static lv_disp_drv_t disp_drv;
lv_disp_drv_init( &disp_drv );
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 );
3、lvgl设置区域,分别显示标题、声音大小、温度和湿度,每块区域都有不同的背景色。
title = lv_obj_create(lv_scr_act());
lv_obj_set_style_bg_color(title, lv_color_hex(0xFFFFFF), LV_STATE_DEFAULT);
lv_obj_set_size(title, 240, 20);
title_label = lv_label_create(title);
static String title_str = "Funpack2.3";
lv_label_set_text( title_label, title_str.c_str() );
lv_obj_align( title_label, LV_ALIGN_CENTER, 0, 0 );
/*声音传感器*/
sound = lv_obj_create(lv_scr_act());
lv_obj_set_style_bg_color(sound, lv_color_hex(0xFF0000), LV_STATE_DEFAULT);
lv_obj_set_size(sound, 240, 60);
lv_obj_set_pos(sound, 0, 40);
sound_label = lv_label_create(sound);
lv_label_set_text( sound_label, sound_str.c_str() );
lv_obj_align( sound_label, LV_ALIGN_CENTER, 0, 0 );
/*温度*/
temp = lv_obj_create(lv_scr_act());
lv_obj_set_style_bg_color(temp, lv_color_hex(0x00FF00), LV_STATE_DEFAULT);
lv_obj_set_size(temp, 240, 60);
lv_obj_set_pos(temp, 0, 110);
temp_label = lv_label_create(temp);
lv_label_set_text( temp_label, temp_str.c_str() );
lv_obj_align( temp_label, LV_ALIGN_CENTER, 0, 0 );
/*湿度*/
humi = lv_obj_create(lv_scr_act());
lv_obj_set_style_bg_color(humi, lv_color_hex(0x0000FF), LV_STATE_DEFAULT);
lv_obj_set_size(humi, 240, 60);
lv_obj_set_pos(humi, 0, 180);
humi_label = lv_label_create(humi);
lv_label_set_text( humi_label, humi_str.c_str() );
lv_obj_align( humi_label, LV_ALIGN_CENTER, 0, 0 );
4、主循环中每隔5毫秒调用一次lvgl处理函数,每隔1000ms读取一次传感器的值(声音传感器及DHT11为慢速设备,读取过快会造成读取错误或者数值不准确)并更新lvgl显示。
volatile uint32_t tickms = 0;
void loop()
{
while (1)
{
lv_timer_handler();
delay(5);
tickms += 5;
if (tickms % 1000 == 0)
{
int val = analogRead(15);
Serial.println(val, DEC);
sound_str = "sound: ";
sound_str += val;
lv_label_set_text( sound_label, sound_str.c_str() );
int status = dht.read(2);
if (status == DHTLIB_OK) {
temp_str = "temp: ";
temp_str += dht.temperature;
lv_label_set_text( temp_label, temp_str.c_str() );
humi_str = "humi: ";
humi_str += dht.humidity;
lv_label_set_text( humi_label, humi_str.c_str() );
} else {
Serial.println("dht error");
}
}
}
}
五、实物演示
1、正常状态
如上图所示,此为上电2分钟后的稳定状态,此时环境声音强度为0,温度为29.5度,湿度为29%。符合冬天有暖气的室内温度和相对干燥的环境湿度。
2、有外部噪音
如上图所示,这是存在外部噪音的显示状况,此时环境声音强度由0变为了834。环境温湿度不受影响。
3、手动影响温湿度传感器测试
如上图所示,这是用手手动干预温湿度传感器后的结果。此时温度上升到30.8℃,湿度变化更明显,上升到95%。而环境声音强度未受影响。
六、心得体会
这次活动深刻感受到了esp32的arduino环境下的开发速度与便捷。也对dfrobot的各种模块好评,开发简单,资料齐全。