内容介绍
内容介绍
Funpack2-3:基于 FireBeetle ESP32-E 实现一个温湿度传感器数据展示面板
一、项目描述
FireBeetle ESP32-E 是一款硬件资源很丰富的物联网模组,MCU主频240MHz,SRAM高达520KB,并且自带蓝牙和WIFI等无线连接功能。DFRobot 为模块的二次开发提供了多种开发平台和详细的开发资料,并且为模组提供了显示屏、扩展板和传感器等多种配件,方便工程师进行项目原型的搭建。本次Funpack活动,我利用 FireBeetle ESP32-E 从传感器获取温度和湿度数据,并通过 TFT 显示屏将传感器数据展示出来,为了更加美观地展示数据,使用LVGL开发了温度、湿度数据的展示面板,并增加了按钮控件进行简单的交互。项目中使用的所有硬件均来自DFRobot。
二、硬件介绍
本次项目使用的硬件如下:
类别 | 名称 | 描述 |
主控 | DFR0654-F | FireBeetle Board ESP32 E |
扩展板 | DFR0762 | 专为FireBeetle 2系列提供的Gravity IO扩展板 |
传感器 | DFR0067 | DHT11 湿度,温度传感器 |
显示屏 | DFR0665 | 2.8" 320x240 TFT电阻触摸显示屏 |
三、设计思路
温湿度数据的采集比较简单,DFRobot提供了简单易用的库函数,采集到的数据如何展示出来就需要使用LVGL丰富的组件,我主要使用了下列三种组件:
- 数据展示使用 LVGL chart 组件,Y轴左侧表示温度范围,Y轴右侧表示湿度范围,红色图表序列表示温度数值,绿色图表序列表示湿度数值;
- Button 组件绑定单击事件,单击start时,创建轮询温湿度数据的任务,单击Stop时,删除轮询温湿度数据的任务;
- Dropdown 组件代表任务的轮询周期;
程序初始化的流程如下:
四、开发环境的搭建
- 开发工具链和驱动库:DFRobot 为 FireBeetle 系列模块提供了简单易用的 Arduino 开发环境,并且为所有的传感器、显示屏等配件都提供了相应的开发库和参考示例程序。关于如何在 Arduino 开发环境中增加 FireBeetle 2 ESP32-E 板卡的开发工具链和驱动库,可以参考DFRobot的官方wiki页面,详见“Arduino环境配置”部分;
- 安装TFT 显示屏的驱动库:TFT_eSPI;
- 安装 LVGL 库:lvgl;
五、各功能对应的主要代码片段及说明
- 屏幕驱动使用TFT_eSPI,在安装好库之后,修改 “Arduino\libraries\TFT_eSPI\User_Setup.h” 中控制显示屏的管脚:
#define TFT_MISO 19
#define TFT_MOSI 23
#define TFT_SCLK 18
#define TFT_CS 14 // Chip select control pin
#define TFT_DC 25 // Data Command control pin
#define TFT_RST 26 // Reset pin (could connect to RST pin)
//#define TFT_RST -1 // Set TFT_RST to -1 if display RESET is connected to ESP32 board RST
// For ESP32 Dev board (only tested with GC9A01 display)
// The hardware SPI can be mapped to any pins
//#define TFT_MOSI 15 // In some display driver board, it might be written as "SDA" and so on.
//#define TFT_SCLK 14
//#define TFT_CS 5 // Chip select control pin
//#define TFT_DC 27 // Data Command control pin
//#define TFT_RST 33 // Reset pin (could connect to Arduino RESET pin)
#define TFT_BL 12 // LED back-light
#define TOUCH_CS 4 // Chip select pin (T_CS) of touch screen
- 安装 LVGL 之后,将 “Arduino\libraries\lvgl\lv_conf_template.h” 拷贝为 “Arduino\libraries\lv_conf.h”,并修改头文件开头处的宏定义,启用 lvgl 功能;
- 注册屏幕显示和触摸的函数代码
/* TFT screen resolution */
static const uint16_t screenWidth = 320;
static const uint16_t screenHeight = 240;
static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[screenWidth * 10];
/* TFT instance */
TFT_eSPI tft = TFT_eSPI();//TFT_eSPI(screenWidth, screenHeight);
#if LV_USE_LOG != 0
/* Serial debugging */
void my_print(const char * buf)
{
Serial.printf(buf);
Serial.flush();
}
#endif
/* 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.pushColors((uint16_t *)&color_p->full, w * h, true);
tft.endWrite();
lv_disp_flush_ready(disp);
}
/*Read the touchpad*/
void my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data)
{
uint16_t touchX, touchY;
bool touched = tft.getTouch(&touchX, &touchY, 600);
if (!touched)
{
data->state = LV_INDEV_STATE_REL;
}
else
{
data->state = LV_INDEV_STATE_PR;
/*Set the coordinates*/
data->point.x = touchX;
data->point.y = touchY;
Serial.print("Data x ");
Serial.println(touchX);
Serial.print("Data y ");
Serial.println(touchY);
}
}
- LVGL组件初始化代码
static lv_obj_t *chart;
static lv_chart_series_t *ser1, *ser2;
void setup()
{
/* prepare for possible serial debug */
Serial.begin(115200);
String LVGL_Arduino = "Hello Arduino! ";
LVGL_Arduino += String('V') + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();
Serial.println(LVGL_Arduino);
Serial.println("A demo of Temperature & Humidity display panel.");
Serial.print("LIBRARY VERSION: ");
Serial.println(DHT11LIB_VERSION);
Serial.println();
lv_init();
#if LV_USE_LOG != 0
lv_log_register_print_cb(my_print); /* register print function for debugging */
#endif
/* TFT init */
tft.begin();
/* Landscape orientation, flipped */
tft.setRotation(3);
/* Set the touchscreen calibration data,
the actual data for your display can be acquired using
the Generic -> Touch_calibrate example from the TFT_eSPI library */
uint16_t calData[5] = { 454, 3307, 496, 3138, 1 };
tft.setTouch(calData);
lv_disp_draw_buf_init(&draw_buf, buf, NULL, screenWidth * 10);
/* Initialize the display */
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);
/* 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);
/* Change the active screen's background color */
lv_obj_set_style_bg_color(lv_scr_act(), lv_color_hex(0x003a57), LV_PART_MAIN);
/* Create a chart title */
lv_obj_t *title = lv_label_create(lv_scr_act());
lv_label_set_text(title, "Funpack2-3: DHT11 Temperature & Humidity");
lv_obj_set_style_text_color(lv_scr_act(), lv_color_hex(0xffffff), LV_PART_MAIN);
lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 0);
/* Create a chart */
chart = lv_chart_create(lv_scr_act());
lv_obj_set_size(chart, 240, 150);
lv_obj_center(chart);
lv_chart_set_type(chart, LV_CHART_TYPE_LINE); /*Show lines and points too*/
lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, -10, 40);
lv_chart_set_range(chart, LV_CHART_AXIS_SECONDARY_Y, 0, 100);
lv_chart_set_point_count(chart, 24);
/*Add ticks and label to every axis*/
// lv_chart_set_axis_tick(chart, LV_CHART_AXIS_PRIMARY_X, 10, 5, 12, 3, true, 40);
lv_chart_set_axis_tick(chart, LV_CHART_AXIS_PRIMARY_Y, 10, 5, 6, 2, true, 50);
lv_chart_set_axis_tick(chart, LV_CHART_AXIS_SECONDARY_Y, 10, 5, 6, 2, true, 50);
/* Zoom in a little in X */
//lv_chart_set_zoom_x(chart, 512);
/*Add two data series*/
ser1 = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_PRIMARY_Y);
ser2 = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_GREEN), LV_CHART_AXIS_SECONDARY_Y);
lv_chart_refresh(chart);
/* Create a drop down list */
lv_obj_t *dropdown = lv_dropdown_create(lv_scr_act());
lv_dropdown_set_options(dropdown, "1\n3\n10\n30\n60\n300\n900\n1800");
lv_obj_set_pos(dropdown, 50, 200);
//lv_obj_align(dropdown, LV_ALIGN_BOTTOM_LEFT, 10, 10);
lv_obj_set_size(dropdown, 100, 40);
lv_obj_add_event_cb(dropdown, dropdown_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
/* Add a Start button */
lv_obj_t *btn = lv_btn_create(lv_scr_act());
lv_obj_set_pos(btn, 170, 200);
//lv_obj_align(btn, LV_ALIGN_BOTTOM_RIGHT, 10, 10);
lv_obj_set_size(btn, 100, 40);
lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_ALL, NULL);
lv_obj_add_flag(btn, LV_OBJ_FLAG_CHECKABLE);
lv_obj_t *label = lv_label_create(btn);
lv_label_set_text(label, "Start");
lv_obj_center(label);
}
- 绑定 dropdown 组件的选择事件 和 button 的单击事件
static uint8_t flag = 0;
static uint32_t interval = 1;
static void btn_event_cb(lv_event_t *e)
{
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t *btn = lv_event_get_target(e);
if (code == LV_EVENT_CLICKED) {
lv_obj_t *label = lv_obj_get_child(btn, 0);
if (flag == 0)
{
lv_label_set_text_fmt(label, "Stop");
lvgl_task = lv_timer_create(lvgl_task_cb, interval * 1000, 0);
flag = 1;
}
else
{
lv_label_set_text_fmt(label, "Start");
lv_timer_del(lvgl_task);
flag = 0;
}
}
}
static void dropdown_event_cb(lv_event_t * e)
{
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t * obj = lv_event_get_target(e);
if(code == LV_EVENT_VALUE_CHANGED) {
char buf[32];
lv_dropdown_get_selected_str(obj, buf, sizeof(buf));
interval = atoi(buf);
LV_LOG_USER("Interval: %d", interval);
}
}
- 轮询温度、湿度数据的任务
static lv_timer_t *lvgl_task = NULL;
static float temperature, humidity;
dht11 DHT;
#define DHT11_PIN 0
int dht11_query(float *temperature, float *humidity)
{
int chk;
Serial.print("DHT11, \t");
chk = DHT.read(DHT11_PIN); // READ DATA
switch (chk){
case DHTLIB_OK:
*temperature = DHT.temperature;
*humidity = DHT.humidity;
Serial.print("OK,\t");
break;
case DHTLIB_ERROR_CHECKSUM:
Serial.print("Checksum error,\t");
break;
case DHTLIB_ERROR_TIMEOUT:
Serial.print("Time out error,\t");
break;
default:
Serial.print("Unknown error,\t");
break;
}
// DISPLAT DATA
Serial.print(DHT.humidity,1);
Serial.print(",\t");
Serial.println(DHT.temperature,1);
return chk;
}
void lvgl_task_cb(lv_timer_t * tmr)
{
int chk = dht11_query(&temperature, &humidity);
//lv_chart_set_next_value(chart, ser1, lv_rand(-10, 40));
//lv_chart_set_next_value(chart, ser2, lv_rand(0, 100));
if (chk == DHTLIB_OK)
{
lv_chart_set_next_value(chart, ser1, temperature);
lv_chart_set_next_value(chart, ser2, humidity);
}
}
六、功能展示及说明
- 上电后,屏幕显示如下
- 选择采集温湿度数据的任务周期,单击“Start”按钮,任务就会周期性地采集温湿度数据并显示在图表中,下图是每15分钟采集一次温湿度数据之后的结果
七、心得体会
FireBeetle系列开发板有丰富的开发配件和多种便利的开发环境,参考官方wiki可以快速上手。另外,使用配套的扩展板,可以不用在面包板上通过飞线去连接外设配件,搭建好的原型也会更加美观。本次项目我只使用了温湿度传感器和屏幕,ESP32-E自带的无线连接功能暂时没有使用,在官方wiki中有不少通过无线连接将采集到的数据上传到云端的示例,以后可以再花些时间去学习。
八、参考链接
软硬件
附件下载
funpack2-3.ino
项目 Arduino 源码
lv_conf.h
lvgl 配置文件
User_Setup.h
TFT_eSPI 配置文件
团队介绍
在职工程师
评论
0 / 100
查看更多
猜你喜欢
Funpack2-3: 基于FireBeetle ESP32和LVGL的声音传感器数据采集和显示设计本设计目标是完成任务二:lvgl图形库和应用
用FireBeetle-E (ESP32)开发板作为控制单元,搭配显示屏移植lvgl 8.3图形库,动态显示声音传感器(SEN0487)采集到的数据并在显示屏上进行展示
littlestudent
1444
Funpack2-3活动ESP32-E采用LVGL显示温湿度及环境声音音量值Funpack2-3活动ESP32-E采用LVGL显示温湿度及环境声音音量值
Snapdragon
2004
Funpack2-3 使用FireBeetle ESP32-E制作物联网温湿度监控平台以FireBettle EPS32-E作为边缘设备,采集温湿度数据并上传自建服务端。
2x3j
1097