feat: 更新项目配置与代码以兼容 ESP-IDF

- 新增 .editorconfig 以统一 C++ 代码格式
- 更新 c_cpp_properties.json 中的编译器路径,适配 Windows 环境
- 修改 settings.json 中的 IDF 设置路径,反映新的环境配置
- 将 dependencies.lock 中的 IDF 版本降级至 6.0.1 以保证稳定性
- 在 CMakeLists.txt 中补充缺失的 esp_driver_ledc 依赖
- 清理 idf_component.yml,移除已注释的依赖项
- 重新整理 main.c 中的头文件包含,提升可读性与结构清晰度
- 在 main.c 中实现 LCD 背光控制,加入 PWM 配置
- 增强 LVGL 集成,更新屏幕刷新与触摸回调函数
- 改进 main.c 中的 WiFi 初始化与事件处理逻辑
This commit is contained in:
雨霖铃
2026-06-29 22:27:07 +08:00
parent 815485fc1a
commit fc03cedf66
7 changed files with 483 additions and 390 deletions
+416 -380
View File
@@ -6,42 +6,48 @@
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/lock.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_timer.h"
#include "driver/gpio.h"
#include "driver/i2c.h"
#include "driver/ledc.h"
#include "driver/spi_master.h"
#include "esp_err.h"
#include "esp_event.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_panel_st7789.h"
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "driver/i2c.h"
#include "esp_err.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_log.h"
#include "lvgl.h"
#include "esp_system.h"
#include "esp_timer.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "freertos/task.h"
#include "lvgl.h"
#include "nvs_flash.h"
#include <stdio.h>
#include <string.h>
#include <sys/lock.h>
#include <sys/param.h>
#include <unistd.h>
#include "lwip/err.h"
#include "lwip/sys.h"
/* The examples use WiFi configuration that you can set via project configuration menu
/* The examples use WiFi configuration that you can set via project
configuration menu
If you'd rather not, just change the below entries to strings with
the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID
#define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD
#define EXAMPLE_ESP_MAXIMUM_RETRY CONFIG_ESP_MAXIMUM_RETRY
#define EXAMPLE_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID
#define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD
#define EXAMPLE_ESP_MAXIMUM_RETRY CONFIG_ESP_MAXIMUM_RETRY
// 在文件顶部定义 PWM 参数
#define EXAMPLE_LCD_BK_LIGHT_CH LEDC_CHANNEL_0
#define EXAMPLE_LCD_BK_LIGHT_TIMER LEDC_TIMER_0
#define EXAMPLE_LCD_BK_LIGHT_FREQ (5000) // 5KHz PWM 频率
#if CONFIG_ESP_STATION_EXAMPLE_WPA3_SAE_PWE_HUNT_AND_PECK
#define ESP_WIFI_SAE_MODE WPA3_SAE_PWE_HUNT_AND_PECK
@@ -78,63 +84,67 @@
#endif
// Using SPI2 in the example
#define LCD_HOST SPI2_HOST
#define LCD_HOST SPI2_HOST
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////// Please update the following configuration according to your LCD spec //////////////////////////////
//////////////////// Please update the following configuration according to your
/// LCD spec //////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define EXAMPLE_LCD_PIXEL_CLOCK_HZ (20 * 1000 * 1000)
#define EXAMPLE_LCD_BK_LIGHT_ON_LEVEL 1
#define EXAMPLE_LCD_PIXEL_CLOCK_HZ (20 * 1000 * 1000)
#define EXAMPLE_LCD_BK_LIGHT_ON_LEVEL 1
#define EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL !EXAMPLE_LCD_BK_LIGHT_ON_LEVEL
// LCD SPI 管脚(根据实际开发板)
#define EXAMPLE_PIN_NUM_SCLK 10
#define EXAMPLE_PIN_NUM_MOSI 13
#define EXAMPLE_PIN_NUM_MISO -1 // LCD 不需要 MISO
#define EXAMPLE_PIN_NUM_LCD_DC 11
#define EXAMPLE_PIN_NUM_LCD_RST 9
#define EXAMPLE_PIN_NUM_LCD_CS 12
#define EXAMPLE_PIN_NUM_BK_LIGHT 14 // 背光 PWM
#define EXAMPLE_PIN_NUM_TOUCH_CS 15
#define EXAMPLE_PIN_NUM_SCLK 10
#define EXAMPLE_PIN_NUM_MOSI 13
#define EXAMPLE_PIN_NUM_MISO -1 // LCD 不需要 MISO
#define EXAMPLE_PIN_NUM_LCD_DC 11
#define EXAMPLE_PIN_NUM_LCD_RST 9
#define EXAMPLE_PIN_NUM_LCD_CS 12
#define EXAMPLE_PIN_NUM_BK_LIGHT 14 // 背光 PWM
#define EXAMPLE_PIN_NUM_TOUCH_CS 15
// 触摸屏 - 改为 I2C 接口
#define EXAMPLE_PIN_NUM_TOUCH_SDA 47
#define EXAMPLE_PIN_NUM_TOUCH_SCL 48
#define EXAMPLE_PIN_NUM_TOUCH_RST 17
#define EXAMPLE_PIN_NUM_TOUCH_INT 21
#define EXAMPLE_PIN_NUM_TOUCH_SDA 47
#define EXAMPLE_PIN_NUM_TOUCH_SCL 48
#define EXAMPLE_PIN_NUM_TOUCH_RST 17
#define EXAMPLE_PIN_NUM_TOUCH_INT 21
// 用户按键和 LED
#define EXAMPLE_PIN_NUM_KEY 4
#define EXAMPLE_PIN_NUM_LED 16
#define EXAMPLE_PIN_NUM_KEY 4
#define EXAMPLE_PIN_NUM_LED 16
#define TOUCH_I2C_MASTER_NUM I2C_NUM_0
#define TOUCH_I2C_MASTER_FREQ_HZ 400000
#define TOUCH_I2C_MASTER_NUM I2C_NUM_0
#define TOUCH_I2C_MASTER_FREQ_HZ 400000
// The pixel number in horizontal and vertical
#define EXAMPLE_LCD_H_RES 240
#define EXAMPLE_LCD_V_RES 320
#define EXAMPLE_LCD_H_RES 240
#define EXAMPLE_LCD_V_RES 320
// Bit number used to represent command and parameter
#define EXAMPLE_LCD_CMD_BITS 8
#define EXAMPLE_LCD_PARAM_BITS 8
#define EXAMPLE_LCD_CMD_BITS 8
#define EXAMPLE_LCD_PARAM_BITS 8
#define EXAMPLE_LVGL_DRAW_BUF_LINES 20 // number of display lines in each draw buffer
#define EXAMPLE_LVGL_TICK_PERIOD_MS 2
#define EXAMPLE_LVGL_DRAW_BUF_LINES \
20 // number of display lines in each draw buffer
#define EXAMPLE_LVGL_TICK_PERIOD_MS 2
#define EXAMPLE_LVGL_TASK_MAX_DELAY_MS 500
#define EXAMPLE_LVGL_TASK_MIN_DELAY_MS 1000 / CONFIG_FREERTOS_HZ
#define EXAMPLE_LVGL_TASK_STACK_SIZE (4 * 1024)
#define EXAMPLE_LVGL_TASK_PRIORITY 2
#define EXAMPLE_LVGL_TASK_STACK_SIZE (4 * 1024)
#define EXAMPLE_LVGL_TASK_PRIORITY 2
// LVGL library is not thread-safe, this example will call LVGL APIs from different tasks, so use a mutex to protect it
// LVGL library is not thread-safe, this example will call LVGL APIs from
// different tasks, so use a mutex to protect it
static _lock_t lvgl_api_lock;
/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_wifi_event_group;
/* The event group allows multiple bits for each event, but we only care about two events:
/* The event group allows multiple bits for each event, but we only care about
* two events:
* - we are connected to the AP with an IP
* - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
#define WIFI_FAIL_BIT BIT1
static const char *TAG = "example";
// static const char *TAG = "wifi station";
@@ -143,348 +153,374 @@ static int s_retry_num = 0;
extern void example_lvgl_demo_ui(lv_disp_t *disp);
static bool example_notify_lvgl_flush_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)
{
lv_display_t *disp = (lv_display_t *)user_ctx;
lv_display_flush_ready(disp);
return false;
/**
* @brief 设置 LCD 背光亮度
* @param brightness 亮度值 0-10230=灭, 1023=最亮)
*/
void lcd_backlight_set_brightness(uint16_t brightness) {
if (brightness > 1023)
brightness = 1023;
ESP_ERROR_CHECK(
ledc_set_duty(LEDC_LOW_SPEED_MODE, EXAMPLE_LCD_BK_LIGHT_CH, brightness));
ESP_ERROR_CHECK(
ledc_update_duty(LEDC_LOW_SPEED_MODE, EXAMPLE_LCD_BK_LIGHT_CH));
}
/* Rotate display and touch, when rotated screen in LVGL. Called when driver parameters are updated. */
static void example_lvgl_port_update_callback(lv_display_t *disp)
{
esp_lcd_panel_handle_t panel_handle = lv_display_get_user_data(disp);
lv_display_rotation_t rotation = lv_display_get_rotation(disp);
switch (rotation) {
case LV_DISPLAY_ROTATION_0:
// Rotate LCD display
esp_lcd_panel_swap_xy(panel_handle, false);
esp_lcd_panel_mirror(panel_handle, true, false);
break;
case LV_DISPLAY_ROTATION_90:
// Rotate LCD display
esp_lcd_panel_swap_xy(panel_handle, true);
esp_lcd_panel_mirror(panel_handle, true, true);
break;
case LV_DISPLAY_ROTATION_180:
// Rotate LCD display
esp_lcd_panel_swap_xy(panel_handle, false);
esp_lcd_panel_mirror(panel_handle, false, true);
break;
case LV_DISPLAY_ROTATION_270:
// Rotate LCD display
esp_lcd_panel_swap_xy(panel_handle, true);
esp_lcd_panel_mirror(panel_handle, false, false);
break;
}
static bool
example_notify_lvgl_flush_ready(esp_lcd_panel_io_handle_t panel_io,
esp_lcd_panel_io_event_data_t *edata,
void *user_ctx) {
lv_display_t *disp = (lv_display_t *)user_ctx;
lv_display_flush_ready(disp);
return false;
}
static void example_lvgl_flush_cb(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map)
{
example_lvgl_port_update_callback(disp);
esp_lcd_panel_handle_t panel_handle = lv_display_get_user_data(disp);
int offsetx1 = area->x1;
int offsetx2 = area->x2;
int offsety1 = area->y1;
int offsety2 = area->y2;
// because SPI LCD is big-endian, we need to swap the RGB bytes order
lv_draw_sw_rgb565_swap(px_map, (offsetx2 + 1 - offsetx1) * (offsety2 + 1 - offsety1));
// copy a buffer's content to a specific area of the display
esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, px_map);
/* Rotate display and touch, when rotated screen in LVGL. Called when driver
* parameters are updated. */
static void example_lvgl_port_update_callback(lv_display_t *disp) {
esp_lcd_panel_handle_t panel_handle = lv_display_get_user_data(disp);
lv_display_rotation_t rotation = lv_display_get_rotation(disp);
switch (rotation) {
case LV_DISPLAY_ROTATION_0:
// Rotate LCD display
esp_lcd_panel_swap_xy(panel_handle, false);
esp_lcd_panel_mirror(panel_handle, true, false);
break;
case LV_DISPLAY_ROTATION_90:
// Rotate LCD display
esp_lcd_panel_swap_xy(panel_handle, true);
esp_lcd_panel_mirror(panel_handle, true, true);
break;
case LV_DISPLAY_ROTATION_180:
// Rotate LCD display
esp_lcd_panel_swap_xy(panel_handle, false);
esp_lcd_panel_mirror(panel_handle, false, true);
break;
case LV_DISPLAY_ROTATION_270:
// Rotate LCD display
esp_lcd_panel_swap_xy(panel_handle, true);
esp_lcd_panel_mirror(panel_handle, false, false);
break;
}
}
static void example_lvgl_flush_cb(lv_display_t *disp, const lv_area_t *area,
uint8_t *px_map) {
// example_lvgl_port_update_callback(disp);
esp_lcd_panel_handle_t panel_handle = lv_display_get_user_data(disp);
int offsetx1 = area->x1;
int offsetx2 = area->x2;
int offsety1 = area->y1;
int offsety2 = area->y2;
// because SPI LCD is big-endian, we need to swap the RGB bytes order
lv_draw_sw_rgb565_swap(px_map,
(offsetx2 + 1 - offsetx1) * (offsety2 + 1 - offsety1));
// copy a buffer's content to a specific area of the display
esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1,
offsety2 + 1, px_map);
}
#if CONFIG_EXAMPLE_LCD_TOUCH_ENABLED
static void example_lvgl_touch_cb(lv_indev_t *indev, lv_indev_data_t *data)
{
uint16_t touchpad_x[1] = {0};
uint16_t touchpad_y[1] = {0};
uint8_t touchpad_cnt = 0;
static void example_lvgl_touch_cb(lv_indev_t *indev, lv_indev_data_t *data) {
uint16_t touchpad_x[1] = {0};
uint16_t touchpad_y[1] = {0};
uint8_t touchpad_cnt = 0;
esp_lcd_touch_handle_t touch_pad = lv_indev_get_user_data(indev);
esp_lcd_touch_read_data(touch_pad);
/* Get coordinates */
bool touchpad_pressed = esp_lcd_touch_get_coordinates(touch_pad, touchpad_x, touchpad_y, NULL, &touchpad_cnt, 1);
esp_lcd_touch_handle_t touch_pad = lv_indev_get_user_data(indev);
esp_lcd_touch_read_data(touch_pad);
/* Get coordinates */
bool touchpad_pressed = esp_lcd_touch_get_coordinates(
touch_pad, touchpad_x, touchpad_y, NULL, &touchpad_cnt, 1);
if (touchpad_pressed && touchpad_cnt > 0) {
data->point.x = touchpad_x[0];
data->point.y = touchpad_y[0];
data->state = LV_INDEV_STATE_PRESSED;
} else {
data->state = LV_INDEV_STATE_RELEASED;
}
if (touchpad_pressed && touchpad_cnt > 0) {
data->point.x = touchpad_x[0];
data->point.y = touchpad_y[0];
data->state = LV_INDEV_STATE_PRESSED;
} else {
data->state = LV_INDEV_STATE_RELEASED;
}
}
#endif
static void example_increase_lvgl_tick(void *arg)
{
/* Tell LVGL how many milliseconds has elapsed */
lv_tick_inc(EXAMPLE_LVGL_TICK_PERIOD_MS);
static void example_increase_lvgl_tick(void *arg) {
/* Tell LVGL how many milliseconds has elapsed */
lv_tick_inc(EXAMPLE_LVGL_TICK_PERIOD_MS);
}
static void example_lvgl_port_task(void *arg)
{
ESP_LOGI(TAG, "Starting LVGL task");
uint32_t time_till_next_ms = 0;
while (1) {
_lock_acquire(&lvgl_api_lock);
time_till_next_ms = lv_timer_handler();
_lock_release(&lvgl_api_lock);
// in case of triggering a task watch dog time out
time_till_next_ms = MAX(time_till_next_ms, EXAMPLE_LVGL_TASK_MIN_DELAY_MS);
// in case of lvgl display not ready yet
time_till_next_ms = MIN(time_till_next_ms, EXAMPLE_LVGL_TASK_MAX_DELAY_MS);
usleep(1000 * time_till_next_ms);
}
}
static void event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
esp_wifi_connect();
s_retry_num++;
ESP_LOGI(TAG, "retry to connect to the AP");
} else {
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
ESP_LOGI(TAG,"connect to the AP fail");
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
}
void wifi_init_sta(void)
{
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
esp_event_handler_instance_t instance_any_id;
esp_event_handler_instance_t instance_got_ip;
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
ESP_EVENT_ANY_ID,
&event_handler,
NULL,
&instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
IP_EVENT_STA_GOT_IP,
&event_handler,
NULL,
&instance_got_ip));
wifi_config_t wifi_config = {
.sta = {
.ssid = EXAMPLE_ESP_WIFI_SSID,
.password = EXAMPLE_ESP_WIFI_PASS,
/* Authmode threshold resets to WPA2 as default if password matches WPA2 standards (password len => 8).
* If you want to connect the device to deprecated WEP/WPA networks, Please set the threshold value
* to WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK and set the password with length and format matching to
* WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK standards.
*/
.threshold.authmode = ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD,
.sae_pwe_h2e = ESP_WIFI_SAE_MODE,
.sae_h2e_identifier = EXAMPLE_H2E_IDENTIFIER,
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
ESP_ERROR_CHECK(esp_wifi_start() );
ESP_LOGI(TAG, "wifi_init_sta finished.");
/* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
* number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
pdFALSE,
pdFALSE,
portMAX_DELAY);
/* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
* happened. */
if (bits & WIFI_CONNECTED_BIT) {
ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
} else if (bits & WIFI_FAIL_BIT) {
ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
} else {
ESP_LOGE(TAG, "UNEXPECTED EVENT");
}
}
void app_main(void)
{
//Initialize NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
if (CONFIG_LOG_MAXIMUM_LEVEL > CONFIG_LOG_DEFAULT_LEVEL) {
/* If you only want to open more logs in the wifi module, you need to make the max level greater than the default level,
* and call esp_log_level_set() before esp_wifi_init() to improve the log level of the wifi module. */
esp_log_level_set("wifi", CONFIG_LOG_MAXIMUM_LEVEL);
}
ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
wifi_init_sta();
ESP_LOGI(TAG, "Turn off LCD backlight");
gpio_config_t bk_gpio_config = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_BK_LIGHT
};
ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));
ESP_LOGI(TAG, "Initialize SPI bus");
spi_bus_config_t buscfg = {
.sclk_io_num = EXAMPLE_PIN_NUM_SCLK,
.mosi_io_num = EXAMPLE_PIN_NUM_MOSI,
.miso_io_num = EXAMPLE_PIN_NUM_MISO,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = EXAMPLE_LCD_H_RES * 80 * sizeof(uint16_t),
};
ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO));
ESP_LOGI(TAG, "Install panel IO");
esp_lcd_panel_io_handle_t io_handle = NULL;
esp_lcd_panel_io_spi_config_t io_config = {
.dc_gpio_num = EXAMPLE_PIN_NUM_LCD_DC,
.cs_gpio_num = EXAMPLE_PIN_NUM_LCD_CS,
.pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ,
.lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS,
.lcd_param_bits = EXAMPLE_LCD_PARAM_BITS,
.spi_mode = 0,
.trans_queue_depth = 10,
};
// Attach the LCD to the SPI bus
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(LCD_HOST, &io_config, &io_handle));
esp_lcd_panel_handle_t panel_handle = NULL;
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = EXAMPLE_PIN_NUM_LCD_RST,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR,
.bits_per_pixel = 16,
};
ESP_LOGI(TAG, "Install ST7789 panel driver");
ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, true, false));
// user can flush pre-defined pattern to the screen before we turn on the screen or backlight
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));
ESP_LOGI(TAG, "Turn on LCD backlight");
gpio_set_level(EXAMPLE_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL);
ESP_LOGI(TAG, "Initialize LVGL library");
lv_init();
// create a lvgl display
lv_display_t *display = lv_display_create(EXAMPLE_LCD_H_RES, EXAMPLE_LCD_V_RES);
// alloc draw buffers used by LVGL
// it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sized
size_t draw_buffer_sz = EXAMPLE_LCD_H_RES * EXAMPLE_LVGL_DRAW_BUF_LINES * sizeof(lv_color16_t);
void *buf1 = spi_bus_dma_memory_alloc(LCD_HOST, draw_buffer_sz, 0);
assert(buf1);
void *buf2 = spi_bus_dma_memory_alloc(LCD_HOST, draw_buffer_sz, 0);
assert(buf2);
// initialize LVGL draw buffers
lv_display_set_buffers(display, buf1, buf2, draw_buffer_sz, LV_DISPLAY_RENDER_MODE_PARTIAL);
// associate the mipi panel handle to the display
lv_display_set_user_data(display, panel_handle);
// set color depth
lv_display_set_color_format(display, LV_COLOR_FORMAT_RGB565);
// set the callback which can copy the rendered image to an area of the display
lv_display_set_flush_cb(display, example_lvgl_flush_cb);
ESP_LOGI(TAG, "Install LVGL tick timer");
// Tick interface for LVGL (using esp_timer to generate 2ms periodic event)
const esp_timer_create_args_t lvgl_tick_timer_args = {
.callback = &example_increase_lvgl_tick,
.name = "lvgl_tick"
};
esp_timer_handle_t lvgl_tick_timer = NULL;
ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer));
ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, EXAMPLE_LVGL_TICK_PERIOD_MS * 1000));
ESP_LOGI(TAG, "Register io panel event callback for LVGL flush ready notification");
const esp_lcd_panel_io_callbacks_t cbs = {
.on_color_trans_done = example_notify_lvgl_flush_ready,
};
/* Register done callback */
ESP_ERROR_CHECK(esp_lcd_panel_io_register_event_callbacks(io_handle, &cbs, display));
#if CONFIG_EXAMPLE_LCD_TOUCH_ENABLED
// 仅在触摸启用时初始化 I2C
ESP_LOGI(TAG, "Initialize I2C for touch");
i2c_config_t i2c_conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = EXAMPLE_PIN_NUM_TOUCH_SDA,
.scl_io_num = EXAMPLE_PIN_NUM_TOUCH_SCL,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = TOUCH_I2C_MASTER_FREQ_HZ,
};
ESP_ERROR_CHECK(i2c_param_config(TOUCH_I2C_MASTER_NUM, &i2c_conf));
ESP_ERROR_CHECK(i2c_driver_install(TOUCH_I2C_MASTER_NUM, I2C_MODE_MASTER, 0, 0, 0));
ESP_LOGI(TAG, "Initialize touch controller CST816");
esp_lcd_touch_handle_t tp = NULL;
esp_lcd_touch_config_t tp_cfg = {
.x_max = EXAMPLE_LCD_H_RES,
.y_max = EXAMPLE_LCD_V_RES,
.rst_gpio_num = EXAMPLE_PIN_NUM_TOUCH_RST,
.int_gpio_num = EXAMPLE_PIN_NUM_TOUCH_INT,
.flags = {
.swap_xy = 0,
.mirror_x = 0,
.mirror_y = 0,
},
};
// CST816 使用 I2C 接口
ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_cst816(
TOUCH_I2C_MASTER_NUM,
&tp_cfg,
&tp
));
static lv_indev_t *indev;
indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
lv_indev_set_display(indev, display);
lv_indev_set_user_data(indev, tp);
lv_indev_set_read_cb(indev, example_lvgl_touch_cb);
#endif
ESP_LOGI(TAG, "Create LVGL task");
xTaskCreate(example_lvgl_port_task, "LVGL", EXAMPLE_LVGL_TASK_STACK_SIZE, NULL, EXAMPLE_LVGL_TASK_PRIORITY, NULL);
ESP_LOGI(TAG, "Display LVGL Meter Widget");
// Lock the mutex due to the LVGL APIs are not thread-safe
static void example_lvgl_port_task(void *arg) {
ESP_LOGI(TAG, "Starting LVGL task");
uint32_t time_till_next_ms = 0;
while (1) {
_lock_acquire(&lvgl_api_lock);
example_lvgl_demo_ui(display);
time_till_next_ms = lv_timer_handler();
_lock_release(&lvgl_api_lock);
// in case of triggering a task watch dog time out
time_till_next_ms = MAX(time_till_next_ms, EXAMPLE_LVGL_TASK_MIN_DELAY_MS);
// in case of lvgl display not ready yet
time_till_next_ms = MIN(time_till_next_ms, EXAMPLE_LVGL_TASK_MAX_DELAY_MS);
usleep(1000 * time_till_next_ms);
}
}
static void event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data) {
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (event_base == WIFI_EVENT &&
event_id == WIFI_EVENT_STA_DISCONNECTED) {
if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
esp_wifi_connect();
s_retry_num++;
ESP_LOGI(TAG, "retry to connect to the AP");
} else {
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
ESP_LOGI(TAG, "connect to the AP fail");
}
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
}
void wifi_init_sta(void) {
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
esp_event_handler_instance_t instance_any_id;
esp_event_handler_instance_t instance_got_ip;
ESP_ERROR_CHECK(esp_event_handler_instance_register(
WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, &instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(
IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, &instance_got_ip));
wifi_config_t wifi_config = {
.sta =
{
.ssid = EXAMPLE_ESP_WIFI_SSID,
.password = EXAMPLE_ESP_WIFI_PASS,
.threshold.authmode = ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD,
.sae_pwe_h2e = ESP_WIFI_SAE_MODE,
.sae_h2e_identifier = EXAMPLE_H2E_IDENTIFIER,
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "wifi_init_sta finished. Connecting to AP in background...");
}
void app_main(void) {
esp_log_level_set("*", ESP_LOG_INFO);
// ESP_LOGI(TAG, "Turn off LCD backlight");
// gpio_config_t bk_gpio_config = {
// .mode = GPIO_MODE_OUTPUT,
// .pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_BK_LIGHT};
// ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));
ESP_LOGI(TAG, "Configure LCD backlight PWM");
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_LOW_SPEED_MODE,
.timer_num = EXAMPLE_LCD_BK_LIGHT_TIMER,
.duty_resolution = LEDC_TIMER_10_BIT, // 10位分辨率 (0-1023)
.freq_hz = EXAMPLE_LCD_BK_LIGHT_FREQ,
.clk_cfg = LEDC_AUTO_CLK,
};
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
ledc_channel_config_t ledc_channel = {
.speed_mode = LEDC_LOW_SPEED_MODE,
.channel = EXAMPLE_LCD_BK_LIGHT_CH,
.timer_sel = EXAMPLE_LCD_BK_LIGHT_TIMER,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = EXAMPLE_PIN_NUM_BK_LIGHT,
.duty = 0, // 初始为 0(关闭)
.hpoint = 0,
};
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
ESP_LOGI(TAG, "Initialize SPI bus");
spi_bus_config_t buscfg = {
.sclk_io_num = EXAMPLE_PIN_NUM_SCLK,
.mosi_io_num = EXAMPLE_PIN_NUM_MOSI,
.miso_io_num = EXAMPLE_PIN_NUM_MISO,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = EXAMPLE_LCD_H_RES * 80 * sizeof(uint16_t),
};
ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO));
ESP_LOGI(TAG, "Install panel IO");
esp_lcd_panel_io_handle_t io_handle = NULL;
esp_lcd_panel_io_spi_config_t io_config = {
.dc_gpio_num = EXAMPLE_PIN_NUM_LCD_DC,
.cs_gpio_num = EXAMPLE_PIN_NUM_LCD_CS,
.pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ,
.lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS,
.lcd_param_bits = EXAMPLE_LCD_PARAM_BITS,
.spi_mode = 0,
.trans_queue_depth = 10,
};
// Attach the LCD to the SPI bus
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(LCD_HOST, &io_config, &io_handle));
esp_lcd_panel_handle_t panel_handle = NULL;
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = EXAMPLE_PIN_NUM_LCD_RST,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR,
.bits_per_pixel = 16,
};
ESP_LOGI(TAG, "Install ST7789 panel driver");
ESP_ERROR_CHECK(
esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, false, false));
// user can flush pre-defined pattern to the screen before we turn on the
// screen or backlight
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));
ESP_LOGI(TAG, "Turn on LCD backlight");
gpio_set_level(EXAMPLE_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL);
// 设置背光亮度为 100%(占空比 1023/1023
// lcd_backlight_set_brightness(1023);
// lcd_backlight_set_brightness(1023);
// while(1) {
// vTaskDelay(pdMS_TO_TICKS(1000));
// }
// ESP_ERROR_CHECK(ledc_set_duty(LEDC_LOW_SPEED_MODE, EXAMPLE_LCD_BK_LIGHT_CH,
// 1023)); ESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE,
// EXAMPLE_LCD_BK_LIGHT_CH));
ESP_LOGI(TAG, "Initialize LVGL library");
lv_init();
// create a lvgl display
lv_display_t *display =
lv_display_create(EXAMPLE_LCD_H_RES, EXAMPLE_LCD_V_RES);
// alloc draw buffers used by LVGL
// it's recommended to choose the size of the draw buffer(s) to be at least
// 1/10 screen sized
size_t draw_buffer_sz =
EXAMPLE_LCD_H_RES * EXAMPLE_LVGL_DRAW_BUF_LINES * sizeof(lv_color16_t);
void *buf1 = spi_bus_dma_memory_alloc(LCD_HOST, draw_buffer_sz, 0);
assert(buf1);
void *buf2 = spi_bus_dma_memory_alloc(LCD_HOST, draw_buffer_sz, 0);
assert(buf2);
// initialize LVGL draw buffers
lv_display_set_buffers(display, buf1, buf2, draw_buffer_sz,
LV_DISPLAY_RENDER_MODE_PARTIAL);
// associate the mipi panel handle to the display
lv_display_set_user_data(display, panel_handle);
// set color depth
lv_display_set_color_format(display, LV_COLOR_FORMAT_RGB565);
// set the callback which can copy the rendered image to an area of the
// display
lv_display_set_flush_cb(display, example_lvgl_flush_cb);
ESP_LOGI(TAG, "Install LVGL tick timer");
// Tick interface for LVGL (using esp_timer to generate 2ms periodic event)
const esp_timer_create_args_t lvgl_tick_timer_args = {
.callback = &example_increase_lvgl_tick, .name = "lvgl_tick"};
esp_timer_handle_t lvgl_tick_timer = NULL;
ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer));
ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer,
EXAMPLE_LVGL_TICK_PERIOD_MS * 1000));
ESP_LOGI(
TAG,
"Register io panel event callback for LVGL flush ready notification");
const esp_lcd_panel_io_callbacks_t cbs = {
.on_color_trans_done = example_notify_lvgl_flush_ready,
};
/* Register done callback */
ESP_ERROR_CHECK(
esp_lcd_panel_io_register_event_callbacks(io_handle, &cbs, display));
#if CONFIG_EXAMPLE_LCD_TOUCH_ENABLED
// 仅在触摸启用时初始化 I2C
ESP_LOGI(TAG, "Initialize I2C for touch");
i2c_config_t i2c_conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = EXAMPLE_PIN_NUM_TOUCH_SDA,
.scl_io_num = EXAMPLE_PIN_NUM_TOUCH_SCL,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = TOUCH_I2C_MASTER_FREQ_HZ,
};
ESP_ERROR_CHECK(i2c_param_config(TOUCH_I2C_MASTER_NUM, &i2c_conf));
ESP_ERROR_CHECK(
i2c_driver_install(TOUCH_I2C_MASTER_NUM, I2C_MODE_MASTER, 0, 0, 0));
ESP_LOGI(TAG, "Initialize touch controller CST816");
esp_lcd_touch_handle_t tp = NULL;
esp_lcd_touch_config_t tp_cfg = {
.x_max = EXAMPLE_LCD_H_RES,
.y_max = EXAMPLE_LCD_V_RES,
.rst_gpio_num = EXAMPLE_PIN_NUM_TOUCH_RST,
.int_gpio_num = EXAMPLE_PIN_NUM_TOUCH_INT,
.flags =
{
.swap_xy = 0,
.mirror_x = 0,
.mirror_y = 0,
},
};
// CST816 使用 I2C 接口
ESP_ERROR_CHECK(
esp_lcd_touch_new_i2c_cst816(TOUCH_I2C_MASTER_NUM, &tp_cfg, &tp));
static lv_indev_t *indev;
indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
lv_indev_set_display(indev, display);
lv_indev_set_user_data(indev, tp);
lv_indev_set_read_cb(indev, example_lvgl_touch_cb);
#endif
ESP_LOGI(TAG, "Create LVGL task");
xTaskCreate(example_lvgl_port_task, "LVGL", EXAMPLE_LVGL_TASK_STACK_SIZE,
NULL, EXAMPLE_LVGL_TASK_PRIORITY, NULL);
ESP_LOGI(TAG, "Display LVGL Meter Widget");
// Lock the mutex due to the LVGL APIs are not thread-safe
_lock_acquire(&lvgl_api_lock);
example_lvgl_demo_ui(display);
_lock_release(&lvgl_api_lock);
// Initialize NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
if (CONFIG_LOG_MAXIMUM_LEVEL > CONFIG_LOG_DEFAULT_LEVEL) {
/* If you only want to open more logs in the wifi module, you need to make
* the max level greater than the default level, and call
* esp_log_level_set() before esp_wifi_init() to improve the log level of
* the wifi module. */
esp_log_level_set("wifi", CONFIG_LOG_MAXIMUM_LEVEL);
}
ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
wifi_init_sta();
}