感谢EEPW提供的“换取逻辑分析仪”活动。本次分享一下ESP32结合LVGL设计的音频数据动态显示系统。
系统设计核心模块:
用FireBeetle-E (ESP32)开发板作为控制单元 (下图所示),搭配显示屏移植lvgl 8.3图形库,动态显示声音传感器(SEN0487)采集到的数据并在显示屏上进行展示。
这里采用的屏幕仍然是之前测评STM32F412的时候使用的ILI9341驱动的电阻触摸屏 (NUCLEO-F412驱动TFT屏幕 https://forum.eepw.com.cn/thread/384041/1)。
下图是FireBeetle-E开发板的Pinout:
具体的硬件连线:
根据系统设计指标, 分解成三个子任务:
Sub-1:移植LVGL 8.3图形库
Sub-2:声音传感器SEN0487数据采集
Sub-3:使用Sub-1中的LVGL组件动态显示Sub-2中的传感器数据
下面分别介绍各模块的实现方法。
Sub-1:移植LVGL 8.3图形库
在开始移植LVGL8.3图形库之前,需要确保LCD屏幕可以被正常驱动,此处我们使用的是TFT_eSPI这个Arduino库。手头的一块带电阻触摸的屏幕驱动芯片是ILI9341,在TFT_eSPI的适用范围内。这块屏幕是2.4寸彩屏,支持16BIT RGB 65K色显示,显示色彩丰富 320X240高清分辨率,可选触摸功能 采用SPI串行总线,只需几个IO即可点亮显示。
下面先安装这个触摸屏的驱动库TFT_eSPI,在IDE中打开库管理器,然后搜索:“TFT_eSPI”,选择合适的版本,点击安装即可。
之后安装FireBeetle-ESP32主板相关的驱动库。这部分操作可以参考DFROBOT官网7.1 Arduino环境配置,不过Arduino->文件->首选项->附件开发板管理器****输入的是: http://download.dfrobot.top/FireBeetle/package_esp32_index.json
更新板卡,打开“工具” -> 开发板管理,待自动更新完成后,会在列表中看到FireBeetle-ESP32主板(现已更新至0.1.1版本),点击安装:
根据屏幕驱动来修改库文件中的User_Setup.h文件,库里面内置了很多种屏幕的驱动,具体可以到TFT_Drivers目录下查看。
这个User_Setup.h里面定义了相关的硬件接口,包括屏幕显示和屏幕触摸部分。需要结合屏幕的引脚进行准确的分配。比如下面TFT_CS定义了屏幕的片选引脚,TOUCH_CS定义了触摸部分SPI接口的片选引脚。
安装LVGL库,此处选择的是lvgl 8.3.0
移植LVGL到Arduino平台还是非常方便的!下面是移植步骤:
官方参考文档: https://docs.lvgl.io/latest/en/html/get-started/arduino.html#configure-lvgl
在Arduino ide中,项目 -> 显示项目文件夹,在文件管理器中打开当前项目文件夹,然后向上一级目录,找到libraries文件夹并进入,进入lvgl文件夹,复制lv_conf_template.h文件,向上一级目录,粘贴并重命名为lv_conf.h。此时lv_conf.h在libraries文件夹中。
修改如下内容:
第10行,将其设为1。
#if 1 /*Set it to "1" to enable content*/
第32行,设置自己显示器的颜色深度,笔者对自己显示器的颜色深度也不是很了解,故使用的默认值16。
第303行,将LV_TICK_CUSTOM设为1
#define LV_TICK_CUSTOM 1
第384行,将列出的字体全部设为1,在lv_examples中,用到了很多不同的字体大小。
#define LV_FONT_MONTSERRAT_8 1 #define LV_FONT_MONTSERRAT_10 1 #define LV_FONT_MONTSERRAT_12 1 #define LV_FONT_MONTSERRAT_14 1 #define LV_FONT_MONTSERRAT_16 1 #define LV_FONT_MONTSERRAT_18 1 #define LV_FONT_MONTSERRAT_20 1 #define LV_FONT_MONTSERRAT_22 1 #define LV_FONT_MONTSERRAT_24 1 #define LV_FONT_MONTSERRAT_26 1 #define LV_FONT_MONTSERRAT_28 1 #define LV_FONT_MONTSERRAT_30 1 #define LV_FONT_MONTSERRAT_32 1 #define LV_FONT_MONTSERRAT_34 1 #define LV_FONT_MONTSERRAT_36 1 #define LV_FONT_MONTSERRAT_38 1 #define LV_FONT_MONTSERRAT_40 1 #define LV_FONT_MONTSERRAT_42 1 #define LV_FONT_MONTSERRAT_44 1 #define LV_FONT_MONTSERRAT_46 1 #define LV_FONT_MONTSERRAT_48 1
之后运行LVGL的Btn例程后,发现触摸Button的位置,没有什么反应,即不会进入cbk。后面阅读手册,发现需要先运行
执行完屏幕校准程序“lvgl_demo_Touch_calibrate_240x320.ino”后,串口监视器有如下的输出,然后将下面两行代码拷贝到自己的项目中,覆盖默认的屏幕校准数据。
uint16_t calData[5] = { 403, 3530, 292, 3483, 3 }; tft.setTouch(calData);
这个屏幕校准是非常重要的一个步骤,如果跳过这个步骤,后面的屏幕触摸将不能正常工作。下面展示的是校准后的,触摸屏幕上的LVGL中的“Button”类小组件,颜色发生变化,说明触摸正常工作。
相关核心代码:
void setup() { pinMode(LED_BUILTIN, OUTPUT);//将LED引脚设置为输出模式 Serial.begin( 115200 ); /* prepare for possible serial debug */ String LVGL_Arduino = "Hello Arduino! "; LVGL_Arduino += String('V') + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch(); Serial.println( LVGL_Arduino ); Serial.println( "I am LVGL_Arduino" ); lv_init(); tft.begin(); /* TFT init */ tft.setRotation( 1 ); /* Landscape orientation, flipped */ /*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] = { 403, 3530, 292, 3483, 3 }; 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 ); /*Change the following line to your display resolution*/ disp_drv.hor_res = screenHeight; disp_drv.ver_res = screenWidth; 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 ); lv_obj_t* mySwitch = lv_btn_create(lv_scr_act()); lv_obj_align( mySwitch, LV_ALIGN_CENTER, 0, 0 ); lv_obj_set_size(mySwitch, 30, 30); lv_obj_set_style_bg_color(mySwitch, lv_color_hex(0x17a1a5), 0); lv_obj_add_event_cb(mySwitch, myCbk, LV_EVENT_ALL, NULL); lv_obj_add_flag(mySwitch, LV_OBJ_FLAG_CHECKABLE); /* Create simple label */ lv_obj_t *label = lv_label_create( lv_scr_act() ); lv_label_set_text( label, "Hello MOTOR" ); lv_obj_align_to(label, mySwitch, LV_ALIGN_OUT_BOTTOM_MID, 30, 0); Serial.println( "Setup done" ); } void loop() { lv_timer_handler(); /* let the GUI do its work */ delay( 5 ); } static void myCbk(lv_event_t* e) { Serial.println("call back func entered"); lv_event_code_t code = lv_event_get_code(e); if(code == LV_EVENT_CLICKED) { LV_LOG_USER("Clicked"); digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); } else if(code == LV_EVENT_VALUE_CHANGED) { LV_LOG_USER("Toggled"); } }//end-static-void-myCbk
Sub-2:声音传感器SEN0487数据采集
声音传感器数据采集使用的传感器型号是Fermion MEMS Microphone Sensor SKU:SEN0487 Fermion: 全向MEMS麦克风模块 简介 https://wiki.dfrobot.com.cn/_SKU_DFR0654_FireBeetle_Board_ESP32_E#target_0
Fermion MEMS Microphone Sensor https://wiki.dfrobot.com.cn/_SKU_SEN0487_Fermion_MEMS_Microphone_Sensor
测试代码也是非常的简单,可以参考上述DFROBOT的wiki:
void setup() {
Serial.begin(115200);
}
void loop() {
// read the value from the sensor:
Serial.println(analogRead(A0));
delay(10);
}
执行后,打开Arduino IDE自带的串口绘图工具。可以看到没有声音输入的时候,传感器ADC值在1600左右(1920/4095 * 3.3 v = 1.54 v,这与DFROBOT官网描述一致:这是一款超小体积的MEMS麦克风。放大器增益为66,当没有检测到声音时,输出电压在1.5V左右浮动),有声音输入的时候,波形非常明显。
Sub-3:使用Sub-1中的LVGL组件动态显示Sub-2中的传感器数据
这部分的工作主要是把声音传感器采集到的模拟数据经过ADC处理后,显示在屏幕上,这里使用到了LVGL的组件有:
chart: 用柱状图的形式显示声音数据
bar: "进度条"组件用于动态显示ADC数值并且ADC数值越大,Bar的指示器(Indicator)的宽度越宽。
结果展示:
下图是没有声音输入的时候,采样值会维持在1920(ADC最大4095)
下图是对着声音传感器吹气,可以明显的看到chart和bar这两个lvgl的小组件可以动态的准确显示ADC数值。
主要的代码如下,完整代码可以参考附件:
static void add_data(lv_timer_t * timer) { LV_UNUSED(timer); tempVal = analogRead(A0); lv_chart_set_next_value(chart1, ser1, tempVal>>6); String mySensorValueADC = "Voice Sensor: " + String(tempVal); lv_textarea_set_text(mySensorValue, mySensorValueADC.c_str()); lv_bar_set_value(myBar, tempVal, LV_ANIM_OFF); } void lv_lvgl_chart2(void) { //add a text for chart to show the sensor adc value mySensorValue = lv_textarea_create(lv_scr_act()); //lv_obj_align_to(mySensorValue, chart1, LV_ALIGN_TOP_LEFT, 0, 0); lv_obj_align(mySensorValue, LV_ALIGN_TOP_MID,0,0); lv_obj_t * myLabelforBar = lv_label_create(lv_scr_act()); lv_obj_align(myLabelforBar, LV_ALIGN_BOTTOM_LEFT,0,-10); lv_label_set_text(myLabelforBar, " Voice Sensor: "); // Bar Related Part Start: static lv_style_t style_indic; lv_style_init(&style_indic); lv_style_set_bg_opa(&style_indic, LV_OPA_COVER); lv_style_set_bg_color(&style_indic, lv_palette_main(LV_PALETTE_RED)); lv_style_set_bg_grad_color(&style_indic, lv_palette_main(LV_PALETTE_BLUE)); lv_style_set_bg_grad_dir(&style_indic, LV_GRAD_DIR_VER); myBar = lv_bar_create(lv_scr_act()); lv_obj_add_style(myBar, &style_indic, LV_PART_INDICATOR); //lv_obj_align(myBar, LV_ALIGN_BOTTOM_MID,0, -10); lv_obj_align_to(myBar, myLabelforBar, LV_ALIGN_OUT_RIGHT_MID, 5, 0); lv_obj_add_event_cb(myBar, myBar_event_cb, LV_EVENT_DRAW_PART_END, NULL); lv_obj_set_size(myBar,180, 20); lv_bar_set_range(myBar, 0, 4095); // Bar Related Part End. /*Create a chart1*/ chart1 = lv_chart_create(lv_scr_act()); lv_obj_set_size(chart1, 200, 150); lv_obj_center(chart1); lv_chart_set_type(chart1, LV_CHART_TYPE_BAR); /*Show lines and points too*/ lv_chart_set_div_line_count(chart1, 5, 7); lv_obj_add_event_cb(chart1, draw_event_cb, LV_EVENT_DRAW_PART_BEGIN, NULL); //lv_chart_set_update_mode(chart1, LV_CHART_UPDATE_MODE_CIRCULAR); lv_chart_set_update_mode(chart1, LV_CHART_UPDATE_MODE_SHIFT); /*Comment out the 2nd data serie, only leave the 1st data serie*/ ser1 = lv_chart_add_series(chart1, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_PRIMARY_Y); //ser2 = lv_chart_add_series(chart1, lv_palette_main(LV_PALETTE_BLUE), LV_CHART_AXIS_SECONDARY_Y); uint32_t i; for (i = 0; i < 10; i++) { lv_chart_set_next_value(chart1, ser1, lv_rand(20, 90)); //lv_chart_set_next_value(chart1, ser2, lv_rand(30, 70)); } lv_timer_create(add_data, 1, NULL); }
总结:
DFROBOT的这款FIREBEETLE-E ESP32开发板是一款高性能、易上手开发的物联网开发板。结合LVGL 可以设计出精美的UI!
附上自己收集的相关资料链接:
DFROBOT官方论坛:https://wiki.dfrobot.com.cn/_SKU_DFR0654_FireBeetle_Board_ESP32_E#target_0
Fermion MEMS Microphone Sensor https://wiki.dfrobot.com.cn/_SKU_SEN0487_Fermion_MEMS_Microphone_Sensor