本帖最后由 云天 于 2025-8-14 00:25 编辑
【项目背景}
在当今的智能硬件开发领域,ESP32-P4 开发板凭借其强大的性能和丰富的功能接口,成为了众多创客和开发者的热门选择。FireBeetle 2 ESP32-P4结合 MIPI-DSI 屏幕,我们可以实现各种精彩的交互式项目。本文将详细介绍如何利用FireBeetle 2 ESP32-P4开发板和 MIPI-DSI 屏幕,实现一个支持触屏交互和定时切换显示内容的创意项目。
【项目准备】
1.硬件准备- ESP32-P4 开发板:确保你有一个 FireBeetle 2 ESP32-P4开发板。
- MIPI-DSI 屏幕: 7寸树莓派TFT触摸屏,800*480分辨率,支持MIPI-DSI 接口,自带电容式触摸面板,支持5点触控,并且兼容树莓派 4B 的 DSI 线序。
- 连接线:将屏幕连接到FireBeetle 2 ESP32-P4的 MIPI-DSI 接口。
2. 软件准备- ESP-IDF:安装最新版本的 ESP-IDF,这是 Espressif 官方的开发框架。
- ESP32_Display_Panel:克隆 ESP32_Display_Panel 仓库,并将其作为组件添加到你的 ESP-IDF 项目中。(ESP32_Display_Panel\examples\esp_idf\lvgl_v8_port,VSC打开文件夹)
3.配置项目
打开 ESP-IDF 的配置菜单,选择目标开发板为“FIREBEETLE-ESP32-P4-LCD-5”,完成项目的初始配置。
Board——Select a target board——FIREBEETLE-ESP32-P4-LCD-5
【编写程序】以下是项目的主程序代码,它实现了屏幕的初始化、LVGL 图形库的初始化,并展示了如何使用 LVGL 创建简单的用户界面。
- /*
- * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
- *
- * SPDX-License-Identifier: CC0-1.0
- */
-
- #include "esp_check.h"
- #include "esp_display_panel.hpp"
- #include "esp_lib_utils.h"
- #include "lvgl.h"
- #include "lvgl_v8_port.h"
- #include "lv_demos.h"
-
- #define EXAMPLE_LCD_USE_EXTERNAL_INIT_CMD (0)
-
- using namespace esp_panel::drivers;
- using namespace esp_panel::board;
-
- static const char *TAG = "example";
- #if EXAMPLE_LCD_USE_EXTERNAL_INIT_CMD
- static const esp_panel_lcd_vendor_init_cmd_t external_init_cmd[] = {
- // {cmd, { data }, data_size, delay_ms}
- // {0xFF, (uint8_t []){0x77, 0x01, 0x00, 0x00, 0x13}, 5, 0},
- // {0xEF, (uint8_t []){0x08}, 1, 0},
- // {0xFF, (uint8_t []){0x77, 0x01, 0x00, 0x00, 0x10}, 5, 0},
- // ...
- };
- #endif // EXAMPLE_LCD_USE_EXTERNAL_INIT_CMD
-
- extern "C" void app_main()
- {
- Board *board = new Board();
- assert(board);
-
- ESP_LOGI(TAG, "Initializing board");
- ESP_UTILS_CHECK_FALSE_EXIT(board->init(), "Board init failed");
-
- #if LVGL_PORT_AVOID_TEARING_MODE
- {
- auto lcd = board->getLCD();
- // When avoid tearing function is enabled, the frame buffer number should be set in the board driver
- lcd->configFrameBufferNumber(LVGL_PORT_DISP_BUFFER_NUM);
- # if ESP_PANEL_DRIVERS_BUS_ENABLE_RGB && CONFIG_IDF_TARGET_ESP32S3
- auto lcd_bus = lcd->getBus();
- /**
- * As the anti-tearing feature typically consumes more PSRAM bandwidth, for the ESP32-S3, we need to utilize the
- * "bounce buffer" functionality to enhance the RGB data bandwidth.
- * This feature will consume `bounce_buffer_size * bytes_per_pixel * 2` of SRAM memory.
- */
- if (lcd_bus->getBasicAttributes().type == ESP_PANEL_BUS_TYPE_RGB) {
- static_cast<BusRGB *>(lcd_bus)->configRGB_BounceBufferSize(lcd->getFrameWidth() * 10);
- }
- # endif
- }
- #endif // LVGL_PORT_AVOID_TEARING_MODE
-
- #if EXAMPLE_LCD_USE_EXTERNAL_INIT_CMD
- ESP_LOGI(TAG, "Using external LCD init command");
- {
- auto lcd = board->getLCD();
- ESP_UTILS_CHECK_FALSE_EXIT(
- lcd->configVendorCommands(external_init_cmd, sizeof(external_init_cmd) / sizeof(external_init_cmd[0])),
- "LCD init failed"
- );
- }
- /**
- * In addition, you can also get handles to any other devices (like touch) and use `config*()` functions to
- * configure or replace default parameters, but this must be completed before `board->begin()`
- */
- #endif // EXAMPLE_LCD_USE_EXTERNAL_INIT_CMD
-
- ESP_UTILS_CHECK_FALSE_EXIT(board->begin(), "Board begin failed");
-
- ESP_LOGI(TAG, "Initializing LVGL");
- ESP_UTILS_CHECK_FALSE_EXIT(lvgl_port_init(board->getLCD(), board->getTouch()), "LVGL init failed");
-
- ESP_LOGI(TAG, "Creating UI");
- /* Lock the mutex due to the LVGL APIs are not thread-safe */
- lvgl_port_lock(-1);
-
- // lv_demo_widgets();
- // lv_demo_benchmark();
- lv_demo_music();
- //lv_demo_stress();
- /* Release the mutex */
- lvgl_port_unlock();
- }
-
复制代码

5.显示文字
在项目中,我们可以通过 LVGL 图形库轻松实现文字和图片的显示。以下是具体的代码示例:
- // Create a label to display text
-
- lv_obj_t *label = lv_label_create(lv_scr_act());
- lv_label_set_text(label, "Hello, FireBeetle2 ESP32-P4!");
-
- // Set the font size
- static lv_style_t style_text;
- lv_style_init(&style_text);
- lv_style_set_text_font(&style_text, &lv_font_montserrat_34); // 设置字体大小为 34
-
- lv_obj_add_style(label, &style_text, LV_PART_MAIN | LV_STATE_DEFAULT);
-
- lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); // Center the label on the screen
复制代码
6.显示图片
首先,使用工具将图片处理为适合屏幕分辨率的格式,并通过 LVGL 提供的工具将其转换为 C 代码格式。然后在代码中加载图片。
(1)处理图片
使用Macromedia Fireworks 8将图片处理成分辨率800*400的jpg格式。
(2)转换格式
lv_img_conv 是 LVGL 提供的一个工具,用于将图片文件(如 PNG、JPG、BMP 等)转换为 LVGL 支持的格式(如 C 数组或二进制文件),以便在嵌入式系统中使用。以下是 在线版lv_img_conv 的使用方法:
访问在线工具:打开 LVGL Online Image Converter。
- 选择图片文件:点击“Image file(s)”按钮,选择要转换的图片文件。
- 设置输出文件名:在“File name(s)”中输入输出文件的名称(例如 background_img)。
- 选择颜色格式:根据目标硬件选择合适的颜色格式(如 RGB565 或 True Color)。
- 选择输出格式:选择输出格式,通常是 C array(生成 C 代码)或 Binary(生成二进制文件)。
- 点击转换:点击“Convert”按钮,下载转换后的文件。
将生成文件background_img.c,放入项目文件夹中。
- // 背景图片已经转换为 C 代码格式
- extern const lv_img_dsc_t background_img;
- // 创建背景图片
- lv_obj_t *background = lv_img_create(lv_scr_act());
- lv_img_set_src(background, &background_img); // 设置图片源
- lv_obj_align(background, LV_ALIGN_CENTER, 0, 0); // 将图片居中显示
复制代码
7.触屏功能
通过 LVGL 的事件回调机制,我们可以实现点击屏幕按钮切换图片的功能。以下是代码示例:
- void switch_image(lv_event_t * e) {
- lv_obj_t *img = (lv_obj_t *)e->user_data;
- static bool switch_state = false;
- if (!switch_state) {
- lv_img_set_src(img, &background_img);
- } else {
- lv_img_set_src(img, &background_img1);
- }
- switch_state = !switch_state;
- }
-
- lv_obj_t *btn = lv_btn_create(lv_scr_act());
- lv_obj_set_size(btn, 100, 50);
- lv_obj_align(btn, LV_ALIGN_CENTER, 0, 100); // 将按钮放置在屏幕下方
-
- lv_obj_add_event_cb(btn, switch_image, LV_EVENT_CLICKED, background);
复制代码

8.定时切换
我们还可以通过 LVGL 的定时器功能实现图片的定时切换,代码如下:
- void switch_image(lv_timer_t *timer) {
- lv_obj_t *img = (lv_obj_t *)timer->user_data;
- static bool switch_state = false;
-
- static lv_anim_t a;
- lv_anim_init(&a);
- lv_anim_set_var(&a, img);
-
- if (!switch_state) {
- lv_anim_set_exec_cb(&a, [](void *img, int32_t v) {
- lv_img_set_src((lv_obj_t *)img, &background_img);
- });
- } else {
- lv_anim_set_exec_cb(&a, [](void *img, int32_t v) {
- lv_img_set_src((lv_obj_t *)img, &background_img1);
- });
- }
-
- lv_anim_set_time(&a, 3000); // 动画持续时间 3000 毫秒
- lv_anim_set_playback_time(&a, 1000); // 回放时间 1000 毫秒
- lv_anim_set_repeat_count(&a, 1); // 重复一次
- lv_anim_set_path_cb(&a, lv_anim_path_ease_in_out); // 使用缓动函数
-
- lv_anim_start(&a);
-
- switch_state = !switch_state;
- }
-
- lv_timer_t *timer = lv_timer_create(switch_image, 5000, background);
- lv_timer_set_repeat_count(timer, LV_ANIM_REPEAT_INFINITE);
复制代码
【演示视频】
|