1. 1. 实物
    1. 1.0.1. 界面预览
    2. 1.0.2. 天气温度
      1. 1.0.2.1. WIFI连接任务
      2. 1.0.2.2. 获取网络时间任务
      3. 1.0.2.3. 获取天气信息任务
    3. 1.0.3. 平衡计
    4. 1.0.4. 屏幕亮度更改
    5. 1.0.5. MP3音乐播放
      1. 1.0.5.1. 初始化spiffs
      2. 1.0.5.2. 配置es8311
      3. 1.0.5.3. MP3播放器初始化
      4. 1.0.5.4. 摄像头
      5. 1.0.5.5. 个人信息显示
    6. 1.0.6. partitions(分区表)
    7. 1.0.7. LVGL
      1. 1.0.7.1. 1. 任务 & 定时
      2. 1.0.7.2. 2. 显示驱动(lv_disp_drv_t)
      3. 1.0.7.3. 3. 输入设备驱动(触摸屏)
      4. 1.0.7.4. 4. 对象(Widgets)
      5. 1.0.7.5. 5. 样式(Style)
      6. 1.0.7.6. 6. 动画
      7. 1.0.7.7. 7. 事件
      8. 1.0.7.8. 8. 其他常见工具
  2. 1.1. 其他

实物

LVGL界面使用Gui Guider制作,使用LVGL 8.3;图标库来自iconfont

iconfont-阿里巴巴矢量图标库

界面预览

其他功能参考立创和官方例程制作,使用ESP-IDF环境。

天气温度

和风天气作为服务端,配置相关端口号,实现WIFI获取。

首先配置WIFI

1
2
CONFIG_EXAMPLE_WIFI_SSID="WIFI名称"
CONFIG_EXAMPLE_WIFI_PASSWORD="WIFI密码"

任务创建:连接WiFi任务、获取网络时间任务、获取每日天气信息任务、获取实时天气信息任务、获取实时空气质量任务、主界面任务(从前往后依次执行)

需要创建一个lv_timer定时器,每隔1s判断更新已有数据,比如网络时间是1s更新一次,室外温度和天气图标是30min更新一次,每日温度范围和空气质量是1h更新一次。

WIFI连接任务

WIFI会有AP和STA两种状态,AP是客户,STA是类似基站,还有AP+STA;这里设置为AP模式

创建了一个任务组,可同时通知几个任务进行更新操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#define WIFI_CONNECTED_BIT          BIT0
#define WIFI_GET_SNTP_BIT BIT1
#define WIFI_GET_DAILYWEATHER_BIT BIT2
#define WIFI_GET_RTWEATHER_BIT BIT3
#define WIFI_GET_WEATHER_BIT BIT4

// WIFI连接 任务函数
static void wifi_connect_task(void *pvParameters)
{
my_event_group = xEventGroupCreate();

ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(example_connect());
ESP_LOGI(TAG, "Successfully Connected to AP");

if(reset_flag == 1) // 如果是刚开机
{
lv_label_set_text(label_wifi, "WiFi连接成功");
lv_label_set_text(label_sntp, "正在获取网络时间");
}
// 使得WIFI_CONNECTED_BIT满足
xEventGroupSetBits(my_event_group, WIFI_CONNECTED_BIT);

vTaskDelete(NULL);
}

获取网络时间任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 获得日期时间 任务函数
static void get_time_task(void *pvParameters)
{
// 等待满足WIFI_CONNECTED_BIT,才会向下运行
xEventGroupWaitBits(my_event_group, WIFI_CONNECTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY);

// 设置网络时间的服务器,并连接服务器获取时间。
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("pool.ntp.org");
esp_netif_sntp_init(&config);
// wait for time to be set
int retry = 0;
const int retry_count = 6;
while (esp_netif_sntp_sync_wait(2000 / portTICK_PERIOD_MS) == ESP_ERR_TIMEOUT && ++retry < retry_count) {
ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count);
}

if(retry > 5)
{
esp_restart(); // 没有获取到时间的话 重启ESP32
}

esp_netif_sntp_deinit();
// 设置时区(北京)
setenv("TZ", "CST-8", 1);
tzset();
// 获取系统时间
time(&now);
localtime_r(&now, &timeinfo);

if(reset_flag == 1) // 如果是刚开机
{
lv_label_set_text(label_sntp, "√ 网络时间获取成功");
lv_label_set_text(label_weather, "正在获取天气信息");
}
// 使得WIFI_GET_SNTP_BIT满足
xEventGroupSetBits(my_event_group, WIFI_GET_SNTP_BIT);

vTaskDelete(NULL);
}

获取天气信息任务

获取和风天气相关URL

1
2
3
#define QWEATHER_DAILY_URL   "https://devapi.qweather.com/v7/weather/3d?&location=xxx&key=xxx"
#define QWEATHER_NOW_URL "https://devapi.qweather.com/v7/weather/now?&location=xxx&key=xxx"
#define QAIR_NOW_URL "https://devapi.qweather.com/v7/air/now?&location=xxx&key=xxx"

主要参考:第16章 桌面天气助手 | 立创开发板技术文档中心

登录 | 和风天气

和风天气图标官方链接:https://icons.qweather.com/install/

icon:Temperature Three Quarters Classic Solid Icon | Font Awesome

平衡计

使用QMI8658姿态传感器,通过加速度计算各个角度,并通过LVGL显示数据。

屏幕亮度更改

实质是利用PWM控制LCD的亮度bsp_display_backlight_on()

不能太亮,也不能太暗;通过设置阈值进行控制。

MP3音乐播放

使用DAC es8311实现音频输出,mp3格式,借助SPIFFS文件系统存放(在 SPI Flash里划分作为文件系统)

初始化spiffs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
esp_err_t bsp_spiffs_mount(void)
{
esp_vfs_spiffs_conf_t conf = {
.base_path = SPIFFS_BASE,
.partition_label = "storage",
.max_files = 5,
.format_if_mount_failed = false,
};

esp_err_t ret_val = esp_vfs_spiffs_register(&conf);

ESP_ERROR_CHECK(ret_val);

size_t total = 0, used = 0;
ret_val = esp_spiffs_info(conf.partition_label, &total, &used);
if (ret_val != ESP_OK) {
ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)", esp_err_to_name(ret_val));
} else {
ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used);
}

return ret_val;
}

配置es8311

配置采样率、位宽、通道

采样率:1s采集多少个采样点

位宽:每个采样点用多少位二进制表示

1
2
3
4
5
6
7
8
9
10
11
12
13
#define CODEC_DEFAULT_SAMPLE_RATE          (16000)
#define CODEC_DEFAULT_BIT_WIDTH (16)
#define CODEC_DEFAULT_CHANNEL (2)

esp_err_t bsp_codec_init(void)
{
play_dev_handle = bsp_audio_codec_speaker_init();
assert((play_dev_handle) && "play_dev_handle not initialized");
// 设置采样率、位宽和通道数
bsp_codec_set_fs(CODEC_DEFAULT_SAMPLE_RATE, CODEC_DEFAULT_BIT_WIDTH, CODEC_DEFAULT_CHANNEL);

return ESP_OK;
}

MP3播放器初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void mp3_player_init(void)
{
// 获取spiffs中的文件
file_iterator = file_iterator_new(SPIFFS_BASE);
assert(file_iterator != NULL);

player_config.mute_fn = _audio_player_mute_fn;
player_config.write_fn = _audio_player_write_fn;
player_config.clk_set_fn = _audio_player_std_clock;
player_config.priority = 1;

ESP_ERROR_CHECK(audio_player_new(player_config));
ESP_ERROR_CHECK(audio_player_callback_register(_audio_player_callback, NULL));

music_ui();
}

【立创·实战派ESP32-S3】文档教程 | 立创开发板技术文档中心

摄像头

GC0308,像素30W,用的是DVP接口

ESP32S3是一款双处理器的XTensa,可以使用xTaskCreatePinnedToCore将摄像头获取的画面和LCD显示分别放在不同的处理器进行处理,提升整体性能。

【立创·实战派ESP32-S3】文档教程 | 立创开发板技术文档中心

个人信息显示

简单的展示

partitions(分区表)

Name Type SubType Offset Size Flags
nvs data nvs 0x9000 24k
phy_init data phy 0xf000 4k
factory app factory 8M
storage data spiffs 3M

常见分区说明

nvs → Non-Volatile Storage,存储键值对(比如 Wi-Fi 配网信息)。

otadata → OTA 升级信息区(存哪个固件是当前运行的)。

phy_init → PHY 校准数据。

factory → 固件(App)分区,烧录的程序在这里。

ota_0 / ota_1 → OTA 备用分区,用来放升级的固件。

spiffs / littlefs / fatfs → 文件系统分区,存配置、网页、图片资源等。

LVGL

lvgl_port_lock/unlock 是 ESP-IDF 提供的封装,方便多任务安全调用 LVGL。

1. 任务 & 定时

  • lv_timer_create(cb, period, user_data)
    创建定时器,周期性执行回调(GUI 动画/状态刷新常用)。
  • lv_timer_del(timer) / lv_timer_reset(timer)
    删除/复位定时器。
  • lv_tick_inc(ms)
    系统 tick 增加(ESP32S3 通常用 esp_timer 每 1ms 调一次)。
  • lv_timer_handler()
    LVGL 主循环处理(通常在 GUI 任务里 while(1) 调用)。

2. 显示驱动(lv_disp_drv_t

  • lv_init()
    初始化 LVGL 库。
  • lv_disp_drv_init(&drv)
    初始化显示驱动结构体。
  • lv_disp_draw_buf_init(&buf, buf1, buf2, size)
    初始化绘图缓冲。
  • lv_disp_drv_register(&drv)
    注册显示驱动。
  • lv_disp_flush_ready(drv)
    刷新结束回调(DMA 传输完成后必须调用)。

ESP32S3 上一般会自己写 flush_cb,再通过 lv_disp_drv_register 绑定到 LCD(SPI/RGB)驱动。


3. 输入设备驱动(触摸屏)

  • lv_indev_drv_init(&drv)
    初始化输入设备驱动结构体。
  • lv_indev_drv_register(&drv)
    注册输入设备。
  • lv_indev_drv_update(indev, &new_drv)
    更新输入设备驱动参数。
  • lv_indev_set_group(indev, group)
    将输入设备加入某个 group(键盘/焦点管理)。

4. 对象(Widgets)

  • 容器类
    • lv_obj_create(parent) → 创建通用容器
    • lv_obj_del(obj) → 删除对象
    • lv_obj_align(obj, LV_ALIGN_*, x_ofs, y_ofs) → 对齐
    • lv_obj_center(obj) → 居中
    • lv_obj_set_size(obj, w, h)
    • lv_obj_add_style(obj, style, part)
  • 常用组件
    • Label: lv_label_create, lv_label_set_text, lv_label_set_text_fmt
    • Button: lv_btn_create, lv_obj_add_event_cb
    • List: lv_list_create, lv_list_add_btn
    • Textarea: lv_textarea_create, lv_textarea_get_text, lv_textarea_set_password_mode
    • Keyboard: lv_keyboard_create, lv_keyboard_set_textarea
    • Spinner: lv_spinner_create
    • Msgbox: lv_msgbox_create, lv_msgbox_close
    • Chart: lv_chart_create, lv_chart_add_series, lv_chart_set_next_value

5. 样式(Style)

  • lv_style_init(&style)
  • lv_style_reset(&style)
  • lv_style_set_bg_color(&style, lv_color_make(...))
  • lv_style_set_text_font(&style, &lv_font_montserrat_20)
  • lv_style_set_pad_all(&style, n)
  • lv_obj_add_style(obj, &style, part)

6. 动画

  • lv_anim_init(&a)
  • lv_anim_set_var(&a, obj)
  • lv_anim_set_exec_cb(&a, cb)
  • lv_anim_set_values(&a, start, end)
  • lv_anim_set_time(&a, ms)
  • lv_anim_start(&a)

ESP32-S3 用动画要注意刷新频率(避免卡顿,LCD 带宽有限)。


7. 事件

  • lv_obj_add_event_cb(obj, cb, LV_EVENT_CLICKED, user_data)
  • lv_event_get_target(e) → 获取事件目标对象
  • lv_event_get_code(e) → 获取事件类型
  • lv_event_get_user_data(e) → 获取用户数据

8. 其他常见工具

  • lv_group_create() / lv_group_add_obj(group, obj)
    焦点组管理(键盘/旋钮/遥控器)。
  • lv_color_make(r, g, b)
    构造颜色(RGB565/888 取决于配置)。
  • lv_pct(n)
    百分比尺寸。

其他

ESP32S3的FreeRTOS自带的,但是STM32的FreeRTOS是移植的

项目 官方 FreeRTOS ESP32-S3 的 FreeRTOS(ESP-IDF)
来源 AWS / FreeRTOS 官方 基于 FreeRTOS,Espressif 定制
支持内核数 通常单核 支持多核(SMP)
硬件集成 不集成硬件 集成 Wi-Fi / BLE / 外设等
任务调度 单核调度器 双核调度器(支持亲和性)
功耗管理 需手动实现 支持 Tickless Idle,低功耗优化
API 接口 标准 FreeRTOS API 支持标准 + Espressif 自定义 API
文件系统/网络等 ESP-IDF 提供完整网络、文件系统支持
配置方式 FreeRTOSConfig.h menuconfig 菜单配置(Kconfig)