跳到主要内容

Arduino 开发

本章节包含以下部分,请按需阅读:

Arduino 入门教程

初次接触 Arduino ESP32 开发,想要快速上手?我们为您准备了一套通用的 入门教程

请注意:该教程使用 ESP32-S3-Zero 作为教学示例,所有硬件代码均基于其引脚布局。在动手实践前,建议您对照手中的开发板引脚图,确认引脚配置无误。

配置开发环境

1. 安装和配置 Arduino IDE

请参考 安装和配置 Arduino IDE 教程 下载安装 Arduino IDE 并添加 ESP32 支持。

2. 安装库

要运行示例,需要安装对应的库。

库或文件名称说明版本安装方式
lvgllvgl 图形库v8.4.0 或 v9.2.2“在线”安装
GFX Library for ArduinoGFX 图形化库v1.6.0在线”安装
SensorLib传感器库v0.3.1在线”安装
版本兼容性说明

LVGL 及其驱动库的版本之间存在较强的依赖关系。例如,为 LVGL v8 编写的驱动可能不兼容 LVGL v9。为确保示例能够稳定复现,推荐使用上表列出的特定版本。混合使用不同版本的库可能导致编译失败或运行时异常。

安装步骤: 安装方式请参考:Arduino 库管理教程

示例程序

Arduino 示例程序位于 示例程序包Arduino 目录中。

示例程序基础例程说明
01_GPIO实现控制指定的左右共 20 个 GPIO 引脚依次循环进行高低电平切换,并串口打印每个引脚的电平变化状态
02_BlinkRGB实现控制 RGB 呈流水灯动态效果
03_GetchipID实现每隔三秒获取并打印 ESP32-c5 芯片的硬件信息,包括芯片型号、版本、核心数量以及芯片 ID
04_WIFI_AP实现通过 ESP32-C5-N16R4 开发板设置为 AP 热点 (2.4G),允许其他 WiFi 设备接入联网
05_WIFI_STA实现连接指定 WiFi 并打印连接信息,每 5 分钟调用 心知天气 API 获取数据后格式化打印响应,且支持 WiFi 断线自动重连。
06_WIFI_DHCP实现通过 ESP32-C5-N16R4 开发板使用 WIFI 连接,DHCP 分配 IP 地址
07_WIFI_StaticIP实现通过 ESP32-C5-N16R4 开发板使用 WIFI 连接,静态分配 IP 地址
08_lvgl8.4.0_demo 实现通过 2.4inch LCD Module 实现文本效果
09_lvgl9.2.2_demo实现通过 2.4inch LCD Module 实现文本效果

01_GPIO

该程序实现对左右共 20 个指定 GPIO 引脚的电平控制:左侧 11 个引脚依次循环执行 “高电平→低电平” 切换,右侧 9 个引脚依次循环执行 “低电平→高电平” 切换;每个电平状态持续 300 毫秒,且通过串口实时打印各引脚的电平变化状态。

01_GPIO 示例输出

代码

01_GPIO.ino
/*
author: liangjingheng
date: 2025-10-14
company: waveshare
*/
#define NUM_LEFT 11 // Number of left GPIO pins
#define NUM_RIGHT 9 // Number of right GPIO pins

// Left GPIO pins
const int left_gpios[NUM_LEFT] = {0, 1, 2, 3, 6, 7, 8, 9, 10, 25, 26};
// Right GPIO pins
const int right_gpios[NUM_RIGHT] = {24, 23, 15, 27, 5, 4, 28, 14, 13};

void setup() {
Serial.begin(115200); // Initialize serial port (for printing information)

// Initialize left GPIOs: output mode, default low level
for (int i = 0; i < NUM_LEFT; i++) {
pinMode(left_gpios[i], OUTPUT);
digitalWrite(left_gpios[i], LOW);
Serial.printf("Left GPIO %d initialized to LOW.\n", left_gpios[i]);
}

// Initialize right GPIOs: output mode, default high level
for (int i = 0; i < NUM_RIGHT; i++) {
pinMode(right_gpios[i], OUTPUT);
digitalWrite(right_gpios[i], HIGH);
Serial.printf("Right GPIO %d initialized to HIGH.\n", right_gpios[i]);
}
}

void loop() {
// Left GPIOs: HIGH → LOW (execute one by one)
for (int i = 0; i < NUM_LEFT; i++) {
digitalWrite(left_gpios[i], HIGH);
Serial.printf("Left GPIO %d set to HIGH.\n", left_gpios[i]);
delay(300); // Delay for 300ms to ensure visibility of the effect

digitalWrite(left_gpios[i], LOW);
Serial.printf("Left GPIO %d set to LOW.\n", left_gpios[i]);
delay(300);
}

// Right GPIOs: LOW → HIGH (execute one by one)
for (int i = 0; i < NUM_RIGHT; i++) {
digitalWrite(right_gpios[i], LOW);
Serial.printf("Right GPIO %d set to LOW.\n", right_gpios[i]);
delay(300);

digitalWrite(right_gpios[i], HIGH);
Serial.printf("Right GPIO %d set to HIGH.\n", right_gpios[i]);
delay(300);
}
}

代码解释

  • setup() 函数:

    • 初始化串口:通过 Serial.begin(115200) 配置串口波特率为 115200,用于打印 GPIO 状态信息。
    • 配置左侧 GPIO:遍历包含 11 个引脚(0、1、2、3、6、7、8、9、10、25、26)的数组,将每个引脚设为输出模式,默认输出低电平,并打印初始化状态。
    • 配置右侧 GPIO:遍历包含 9 个引脚(24、23、15、27、5、4、28、14、13)的数组,将每个引脚设为输出模式,默认输出高电平,并打印初始化状态。
  • loop () 函数 :

    • 左侧 GPIO控制:逐个将引脚从低电平切换为高电平,打印状态后延迟 300ms;再切换回低电平,打印状态后延迟 300ms。
    • 右侧 GPIO 控制:逐个将引脚从高电平切换为低电平,打印状态后延迟 300ms;再切换回高电平,打印状态后延迟 300ms。

02_BlinkRGB

本示例实现控制 RGB 灯呈流水灯动态效果

代码

02_BlinkRGB.ino
/*
BlinkRGB

Demonstrates usage of onboard RGB LED on some ESP dev boards.

Calling digitalWrite(RGB_BUILTIN, HIGH) will use hidden RGB driver.

RGBLedWrite demonstrates control of each channel:
void rgbLedWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val)

WARNING: After using digitalWrite to drive RGB LED it will be impossible to drive the same pin
with normal HIGH/LOW level
*/
//#define RGB_BRIGHTNESS 64 // Change white brightness (max 255)

// the setup function runs once when you press reset or power the board

void setup() {
// No need to initialize the RGB LED
}

// the loop function runs over and over again forever
void loop() {
#ifdef RGB_BUILTIN
digitalWrite(RGB_BUILTIN, HIGH); // Turn the RGB LED white
delay(1000);
digitalWrite(RGB_BUILTIN, LOW); // Turn the RGB LED off
delay(1000);

rgbLedWrite(RGB_BUILTIN, RGB_BRIGHTNESS, 0, 0); // Red
delay(1000);
rgbLedWrite(RGB_BUILTIN, 0, RGB_BRIGHTNESS, 0); // Green
delay(1000);
rgbLedWrite(RGB_BUILTIN, 0, 0, RGB_BRIGHTNESS); // Blue
delay(1000);
rgbLedWrite(RGB_BUILTIN, 0, 0, 0); // Off / black
delay(1000);
#endif
}

代码解释

  • setup () 函数:
    • 无需对 RGB LED 做额外初始化操作,因为 RGB 灯的控制可通过后续digitalWritergbLedWrite直接驱动。
  • loop () 函数 :
    • 循环实现 RGB 灯的多色切换与亮灭控制通过 digitalWrite(RGB_BUILTIN, HIGH) 点亮 RGB 灯为白色,延迟 1 秒后,用 digitalWrite(RGB_BUILTIN, LOW) 熄灭 RGB 灯,再延迟 1 秒;
    • 调用 rgbLedWrite 函数依次单独点亮红色、绿色、蓝色,每种颜色保持 1 秒;
    • 最后用 rgbLedWrite(RGB_BUILTIN, 0, 0, 0) 熄灭 RGB 灯,延迟 1 秒后重复整个循环。

03_GetchipID

本示例实现每隔三秒获取并打印 ESP32 芯片的硬件信息,包括芯片型号、版本、核心数量以及芯片 ID

示例 3 图示

代码

03_GetchipID.ino
/* The true ESP32 chip ID is essentially its MAC address.
This sketch provides an alternate chip ID that matches
the output of the ESP.getChipId() function on ESP8266
(i.e. a 32-bit integer matching the last 3 bytes of
the MAC address. This is less unique than the
MAC address chip ID, but is helpful when you need
an identifier that can be no more than a 32-bit integer
(like for switch...case).

created 2020-06-07 by cweinhofer
with help from Cicicok */

uint32_t chipId = 0;

void setup() {
Serial.begin(115200);
}

void loop() {
for (int i = 0; i < 17; i = i + 8) {
chipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
}

Serial.printf("ESP32 Chip model = %s Rev %d\n", ESP.getChipModel(), ESP.getChipRevision());
Serial.printf("This chip has %d cores\n", ESP.getChipCores());
Serial.print("Chip ID: ");
Serial.println(chipId);

delay(3000);
}

代码解释

  • setup () 函数:
    • 初始化串口通信通过 Serial.begin(115200) 配置串口波特率为 115200,为后续打印芯片信息提供输出通道。
  • loop () 函数 :
    • 打印芯片信息:调用 ESP.getChipModel()ESP.getChipRevision()ESP.getChipCores() 分别获取并打印芯片型号、版本、核心数;再打印计算得到的 chipId
    • 周期性执行:通过 delay(3000) 延迟 3 秒,重复上述芯片 ID 计算与信息打印流程。

04_WIFI_AP

本示例实现 ESP32-C5-N16R4 开发板创建名为 “ESP32-C5-N16R4”、密码为 “waveshare” 的 WiFi 热点,监控设备的连接 / 断开状态,并通过串口打印设备的 MAC 地址及分配的 IP 地址。

示例 4 图示

代码

04_WIFI_AP.ino
/**
******************************************************************************
* @file WiFi_AP.ino
* @brief ESP32-C5-N16R4 act as WiFi Access Point and monitor client connections
* @version V1.1
* @date 2025-10-14
* @author liangjingheng
* @company Waveshare
* @license MIT
******************************************************************************
* Enhanced Features:
* 1. Create WiFi Access Point with specified SSID ("ESP32-C5-N16R4") and password
* 2. Monitor client connection/disconnection events via WiFi event handler
* 3. Print connected device's MAC address, assigned IP address via serial port
* 4. Provide real-time status feedback for network events
******************************************************************************
*/

#include <WiFi.h>
#include <esp_wifi.h> // ESP-IDF library to access connected client info

// WiFi Access Point credentials
const char* ssid = "ESP32-C5-N16R4"; //your ap name
const char* password = "waveshare"; // your AP password

// Convert MAC address from byte array to readable string (XX:XX:XX:XX:XX:XX)
String formatMacAddress(const uint8_t* mac) {
char macStr[18];
snprintf(macStr, sizeof(macStr), "%02X:%02X:%02X:%02X:%02X:%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return String(macStr);
}

// Handle WiFi events (connection, disconnection, IP assignment)
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
switch (event) {
case ARDUINO_EVENT_WIFI_AP_STACONNECTED:
// Print MAC address when a new device connects to AP
Serial.println("New device connected:");
Serial.print("MAC Address: ");
Serial.println(formatMacAddress(info.wifi_ap_staconnected.mac));
break;

case ARDUINO_EVENT_WIFI_AP_STADISCONNECTED:
// Print message when a device disconnects from AP
Serial.println("Device disconnected from AP");
break;

case ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED:
// Print IP address assigned to connected device
Serial.print("Assigned IP to device: ");
Serial.println(IPAddress(info.got_ip.ip_info.ip.addr));
break;

default:
break;
}
}

void setup() {
// Initialize serial communication (115200 baud rate) for debugging
Serial.begin(115200);

// Start WiFi Access Point with specified SSID and password
WiFi.softAP(ssid, password);

// Register event handler to monitor client connection status
WiFi.onEvent(WiFiEvent);

// Short delay to stabilize WiFi AP setup
delay(1000);

// Print AP initialization status to serial console
Serial.println("WiFi Access Point initialized successfully");
Serial.print("AP SSID: ");
Serial.println(ssid);
Serial.print("AP Password: ");
Serial.println(password);
}

void loop() {
// No active operation in loop; CPU remains idle
delay(1000); // Small delay to reduce unnecessary CPU usage
}

代码解释

  • setup()

    • 初始化串口:通过 Serial.begin(115200) 开启串口通信,用于打印调试信息。
    • 启动 WiFi 接入点:调用 WiFi.softAP(ssid, password),将设备设置为 AP 模式(SSID 为"ESP32-C5-N16R4",密码为"waveshare")。
    • 注册事件处理器:通过 WiFi.onEvent(WiFiEvent) 注册自定义事件处理函数,监控客户端连接 / 断开、IP 分配等 WiFi 事件。
    • 打印初始化状态:延迟 1 秒后,向串口打印 AP 的 SSID、密码及 “初始化成功” 提示。
  • loop()

    • 仅通过 delay(1000) 执行 1 秒延迟,减少 CPU 不必要的资源消耗。

05_WIFI_STA

本示例实现 ESP32-C5-N16R4 开发板可连接指定 WiFi(SSID:waveshare,密码:12345678)并打印连接信息,调用心知天气 API 获取数据后格式化输出响应,同时支持 WiFi 断线自动重连,每 5 分钟自动请求一次 API。

05_WIFI_STA

代码

05_WIFI_STA .ino
/**
******************************************************************************
* @file WiFi_Weather_Enhanced.ino
* @brief ESP32-c5-n16r4 connect to WiFi and get weather data from Seniverse API
* @version V1.1
* @date 2025-10-14
* @author liangjingheng
* @company Waveshare
* @license MIT
******************************************************************************
* Enhanced Features:
* 1. Print connected WiFi SSID and password
* 2. Better formatted API response with clear line breaks
* 3. Connect to WiFi and get weather data from Seniverse API
******************************************************************************
*/

#include <WiFi.h>
#include <WiFiClientSecure.h>

// WiFi credentials
const char* ssid = "waveshare";
const char* password = "12345678";

// Seniverse API configuration
const char* request = "GET /v3/weather/now.json?key=SbslwZ6X47ih3u-bX&location=beijing&language=zh-Hans&unit=c HTTP/1.1\r\nhost:api.seniverse.com\r\n\r\n";
const char* host = "api.seniverse.com";
const uint16_t httpsPort = 443;

WiFiClientSecure client;

void setup() {
// Initialize serial communication
Serial.begin(115200);
while (!Serial); // Wait for serial port to connect

// Connect to WiFi
Serial.println("Connecting to WiFi...");
WiFi.begin(ssid, password);

// Wait for WiFi connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}

// Print connection success message with WiFi details
Serial.println("\n");
Serial.println("=====================================");
Serial.println("WiFi connection successful!");
Serial.print("Connected to SSID: ");
Serial.println(ssid);
Serial.print("With password: ");
Serial.println(password);
Serial.print("Assigned IP address: ");
Serial.println(WiFi.localIP());
Serial.println("=====================================\n");
}

void loop() {
// Check WiFi connection status
if (WiFi.status() != WL_CONNECTED) {
Serial.println("WiFi disconnected, reconnecting...");
WiFi.reconnect();
delay(1000);
return;
}

// Connect to Seniverse API server
Serial.print("Connecting to API server: ");
Serial.println(host);

client.setInsecure(); // Skip certificate verification for testing
if (!client.connect(host, httpsPort)) {
Serial.println("Connection to server failed!");
delay(5000); // Retry after 5 seconds
return;
}

// Send API request
Serial.println("Sending request to weather API...");
client.print(request);

// Wait for response with timeout
unsigned long timeout = millis();
while (client.available() == 0) {
if (millis() - timeout > 5000) { // 5 seconds timeout
Serial.println("Timeout waiting for API response!");
client.stop();
delay(5000);
return;
}
}

// Read and print API response with proper line breaks
Serial.println("\n--- API Response Start ---");
while (client.available()) {
String line = client.readStringUntil('\n');
Serial.println(line); // Using println to ensure each line is properly separated
}
Serial.println("--- API Response End ---\n");

// Close connection and wait for next request
client.stop();
Serial.println("Waiting 5 minutes for next update...");
Serial.println("=====================================\n");
delay(300000); // 5 minutes in milliseconds
}

}

代码解释

  • setup()

    • 初始化串口:通过 Serial.begin(115200) 开启串口通信,等待串口连接就绪。
    • 连接 WiFi:调用 WiFi.begin(ssid, password) 连接指定 WiFi(SSID:"waveshare",密码:"12345678"),通过循环等待- 连接成功(期间打印。提示)。
    • 打印连接信息:连接成功后,向串口输出 WiFi 连接详情,包括连接的 SSID、密码及设备分配的 IP 地址,用分隔线格式化显示。
  • loop()

    • WiFi 状态维护:检查 WiFi 连接状态,若断开则调用 WiFi.reconnect() 重新连接,避免因网络中断导致功能失效。
    • 连接 API 服务器:通过 client.connect(host, httpsPort) 连接 Seniverse API 服务器(api.seniverse.com,端口 443),跳过证书验证(client.setInsecure())用于测试。
    • 发送与接收请求:通过 client.print(request) 发送天气数据请求,等待响应(设置 5 秒超时),读取并按行打印响应内容。
    • 定时循环:关闭连接后,通过 delay(300000) 等待 5 分钟,再重复执行上述流程,实现定时获取天气数据的效果。

06_WIFI_DHCP

本示例演示了通过 ESP32-C5-N16R4 开发板使用 WIFI 连接,DHCP 分配 IP 地址。

示例 6 图示

代码

06_WIFI_DHCP.ino
/**
******************************************************************************
* @file WiFi_Connection.ino
* @brief ESP32 connect to specified Wi-Fi network and print assigned IP address
* @version V1.1
* @date 2025-10-14
* @author liangjingheng
* @company Waveshare
* @license MIT
******************************************************************************
* Features:
* 1. Connect ESP32 to target Wi-Fi network using provided SSID and password
* 2. Print connection progress and status via serial monitor
* 3. Display assigned IP address after successful connection
* 4. Maintain Wi-Fi connection in loop function
******************************************************************************
*/
#include <WiFi.h> // Include Wi-Fi library

// Replace with your Wi-Fi network credentials
const char *ssid = "waveshare"; // Your WiFi SSID
const char *password = "12345678"; // Your WiFi password

void setup() {
// Start serial communication
Serial.begin(115200);
while (!Serial) {
; // Wait for the serial port to be ready
}

Serial.println();
Serial.println("Connecting to WiFi...");

// Begin Wi-Fi connection
WiFi.begin(ssid, password);

// Wait until connected
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}

// Connection successful
Serial.println();
Serial.println("Connected to WiFi");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP()); // Print assigned IP address
}

void loop() {
// Keep connection alive (optional: can be used to add functionality)
delay(1000);
}

代码解释

  • WIFI 网络配置 :
    • 需把代码中的 WIFI 和密码对应改成自己环境中的 WIFI 路由器中的名称和密码。如果没有的话,可以手机创建一个同名的热点,供开发板连接测试。

07_WIFI_StaticIP

本示例展示如何通过 ESP32-C5-N16R4 开发板使用 WIFI 连接,静态分配 IP 地址。

示例 7 图示

代码

07_WIFI_StaticIP.ino
/**
******************************************************************************
* @file WiFi_StaticIP.ino
* @brief ESP32 connect to Wi-Fi with static IP configuration
* @version V1.2
* @date 2025-10-14
* @author liangjingheng
* @company Waveshare
* @license MIT
******************************************************************************
* Features:
* 1. Connect ESP32 to "JSBZY-5G" Wi-Fi network with static IP
* 2. Configure static IP, gateway, subnet mask, and DNS matching network settings
* 3. Print connection status and network info via serial monitor
* 4. Auto-reconnect if Wi-Fi connection drops
******************************************************************************
*/

#include <WiFi.h>

// Wi-Fi credentials (match network in screenshot)
const char *ssid = "waveshare"; // your Wi-Fi SSID
const char *password = "12345678"; // your Wi-Fi password

// Static IP configuration (matched to screenshot's network parameters)
IPAddress local_ip(192, 168, 9, 100); // Static IP for ESP32
IPAddress gateway(192, 168, 11, 1); // Gateway IP
IPAddress subnet(255, 255, 252, 0); // Subnet mask
IPAddress dns(192, 168, 11, 1); // DNS server

void setup() {
// Initialize serial communication (115200 baud rate)
Serial.begin(115200);
while (!Serial) {
; // Wait for serial port to initialize (for boards like Leonardo)
}

// Set Wi-Fi mode to Station (client mode)
WiFi.mode(WIFI_STA);

// Apply static IP configuration
WiFi.config(local_ip, gateway, subnet, dns);

// Start Wi-Fi connection
WiFi.begin(ssid, password);
Serial.println("Connecting to Wi-Fi (JSBZY-5G) with static IP...");

// Wait for connection with retry logic
int retryCount = 0;
const int maxRetries = 15; // Retry for 15 seconds (15 * 1000ms)
while (WiFi.status() != WL_CONNECTED && retryCount < maxRetries) {
delay(1000);
Serial.print(".");
retryCount++;
}

// Print connection result
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nSuccessfully connected to Wi-Fi!");
Serial.print("Static IP Address: ");
Serial.println(WiFi.localIP());
Serial.print("Gateway: ");
Serial.println(gateway);
Serial.print("Subnet Mask: ");
Serial.println(subnet);
} else {
Serial.println("\nFailed to connect to Wi-Fi!");
Serial.print("WiFi Status Code: ");
Serial.println(WiFi.status()); // Print code for debugging (e.g., 6 = AUTH_FAIL)
}
}

void loop() {
// Periodically check Wi-Fi connection and auto-reconnect
if (WiFi.status() != WL_CONNECTED) {
Serial.println("Wi-Fi disconnected, attempting reconnection...");
WiFi.begin(ssid, password); // Re-initiate connection
int retry = 0;
while (WiFi.status() != WL_CONNECTED && retry < 5) {
delay(1000);
Serial.print(".");
retry++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nReconnected to Wi-Fi!");
Serial.print("Current IP: ");
Serial.println(WiFi.localIP());
}
}
delay(5000); // Check connection every 5 seconds
}

代码解释

  • WIFI 网络配置 :
    • 需把代码中的 WIFI 和密码对应改成自己环境中的 WIFI 路由器中的名称和密码。如果没有的话,可以手机创建一个同名的热点,供开发板连接测试。
    • 需配置好网络 IP 相关配置

08_lvgl8.4.0_demo

本示例演示了通过 lvgl_v8.4.0 以及 GFX_Library_for_Arduino(GFX 图形化库)和 SensorLib(传感器库)实现文本显示效果

示例 8 图示
示例 8 图示

硬件连接

2.4inch LCD ModuleESP32-C5-N16R4
VCC3V3
GNDGND
DINGPIO2
CLKGPIO1
CSGPIO5
D/CGPIO3
RSTGPIO4
BLGPIO6

代码

08_lvgl8.4.0_demo.ino
/*
* @file LVGL8.4.0_demo.ino
* @brief ESP32-C5 drives 2.4-inch ILI9341 display and shows text labels via LVGL
* @version V1.0
* @date 2025-10-14
* @author liangjingheng
* @company Waveshare
* @license MIT
********************************************************************************/

/*Using LVGL with Arduino requires some extra steps:
*Be sure to read the docs here: https://docs.lvgl.io/master/get-started/platforms/arduino.html */

/*To use the built-in examples and demos of LVGL uncomment the includes below respectively.
*You also need to copy `lvgl/examples` to `lvgl/src/examples`. Similarly for the demos `lvgl/demos` to `lvgl/src/demos`.
Note that the `lv_examples` library is for LVGL v7 and you shouldn't install it for this version (since LVGL v8)
as the examples and demos are now part of the main LVGL library. */

// #include <examples/lv_examples.h>
// #include <demos/lv_demos.h>

// #define DIRECT_MODE // Uncomment to enable full frame buffer

#include <lvgl.h>
#include <Arduino_GFX_Library.h>

#define LCD_SCK 1
#define LCD_DIN 2
#define LCD_CS 5
#define LCD_DC 3
#define LCD_RST 4
#define LCD_BL 6

#define GFX_BL LCD_BL

Arduino_DataBus *bus = new Arduino_HWSPI(LCD_DC, LCD_CS, LCD_SCK, LCD_DIN);
Arduino_GFX *gfx = new Arduino_ILI9341(
bus, LCD_RST, 0 /* rotation */, false /* IPS */
);

uint32_t screenWidth;
uint32_t screenHeight;
uint32_t bufSize;
lv_disp_draw_buf_t draw_buf;
lv_color_t *disp_draw_buf1;
lv_color_t *disp_draw_buf2;
lv_disp_drv_t disp_drv;

/* Display flushing */
void my_disp_flush(lv_disp_drv_t *disp_drv, 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);

#if (LV_COLOR_16_SWAP != 0)
gfx->draw16bitBeRGBBitmap(area->x1, area->y1, (uint16_t *)&color_p->full, w, h);
#else
gfx->draw16bitRGBBitmap(area->x1, area->y1, (uint16_t *)&color_p->full, w, h);
#endif

lv_disp_flush_ready(disp_drv);
}

void setup() {

Serial.begin(115200);
Serial.println("Arduino_GFX Hello World example");

// Init Display
if (!gfx->begin()) {
Serial.println("gfx->begin() failed!");
}

gfx->fillScreen(RGB565_BLACK);

#ifdef GFX_BL
pinMode(GFX_BL, OUTPUT);
digitalWrite(GFX_BL, HIGH);
#endif

lv_init();

screenWidth = gfx->width();
screenHeight = gfx->height();

bufSize = screenWidth * 120;

disp_draw_buf1 = (lv_color_t *)heap_caps_malloc(bufSize * 2, MALLOC_CAP_DEFAULT | MALLOC_CAP_8BIT);

disp_draw_buf2 = (lv_color_t *)heap_caps_malloc(bufSize * 2, MALLOC_CAP_DEFAULT | MALLOC_CAP_8BIT);

lv_disp_draw_buf_init(&draw_buf, disp_draw_buf1, disp_draw_buf2, bufSize);

/* Initialize the display */
lv_disp_drv_init(&disp_drv);
/* Change the following line to your display resolution */
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 */
lv_obj_t *label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "Hello Arduino! (V" GFX_STR(LVGL_VERSION_MAJOR) "." GFX_STR(LVGL_VERSION_MINOR) "." GFX_STR(LVGL_VERSION_PATCH) ")");
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
/*hello waveshare label*/
lv_obj_t *label_waveshare = lv_label_create(lv_scr_act());
lv_label_set_text(label_waveshare, "Hello waveshare!");
lv_obj_align(label_waveshare, LV_ALIGN_CENTER, 0, 20);

/* Option 3: Or try out a demo. Don't forget to enable the demos in lv_conf.h. E.g. LV_USE_DEMOS_WIDGETS*/
// lv_demo_widgets();
// lv_demo_benchmark();
// lv_demo_music();

Serial.println("Setup done");
}

void loop() {
lv_timer_handler(); /* let the GUI do its work */
delay(1);
}

09_lvgl9.2.2_demo

本示例展示通过 lvgl_v9.2.2 以及 GFX_Library_for_Arduino(GFX 图形化库)和 SensorLib(传感器库)实现文本显示效果

示例 9 图示
示例 9 图示

硬件连接

2.4inch LCD ModuleESP32-C5-N16R4
VCC3V3
GNDGND
DINGPIO2
CLKGPIO1
CSGPIO5
D/CGPIO3
RSTGPIO4
BLGPIO6

代码

09_lvgl9.2.2_demo.ino
/*
* @file LVGL9.2.2_demo.ino
* @brief ESP32-C5 drives 2.4-inch ILI9341 display and shows text labels via LVGL
* @version V1.0
* @date 2025-10-14
* @author liangjingheng
* @company Waveshare
* @license MIT
********************************************************************************/
/*Using LVGL with Arduino requires some extra steps:
*Be sure to read the docs here: https://docs.lvgl.io/master/get-started/platforms/arduino.html */

/*To use the built-in examples and demos of LVGL uncomment the includes below respectively.
*You also need to copy `lvgl/examples` to `lvgl/src/examples`. Similarly for the demos `lvgl/demos` to `lvgl/src/demos`.
*Note that the `lv_examples` library is for LVGL v7 and you shouldn't install it for this version (since LVGL v8)
*as the examples and demos are now part of the main LVGL library. */

// #include <examples/lv_examples.h>
// #include <demos/lv_demos.h>

// #define DIRECT_RENDER_MODE // Uncomment to enable full frame buffer
#include <lvgl.h>
#include <Arduino_GFX_Library.h>

#define LCD_SCK 1
#define LCD_DIN 2
#define LCD_CS 5
#define LCD_DC 3
#define LCD_RST 4
#define LCD_BL 6

#define GFX_BL LCD_BL

Arduino_DataBus *bus = new Arduino_HWSPI(LCD_DC, LCD_CS, LCD_SCK, LCD_DIN);
Arduino_GFX *gfx = new Arduino_ILI9341(
bus, LCD_RST, 0 /* rotation */, false /* IPS */
);

uint32_t screenWidth;
uint32_t screenHeight;
uint32_t bufSize;
lv_display_t *disp;
lv_color_t *disp_draw_buf;

#if LV_USE_LOG != 0
void my_print(lv_log_level_t level, const char *buf)
{
LV_UNUSED(level);
Serial.println(buf);
Serial.flush();
}
#endif

uint32_t millis_cb(void)
{
return millis();
}

/* LVGL calls it when a rendered image needs to copied to the display*/
void my_disp_flush(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map)
{
#ifndef DIRECT_RENDER_MODE
uint32_t w = lv_area_get_width(area);
uint32_t h = lv_area_get_height(area);

gfx->draw16bitRGBBitmap(area->x1, area->y1, (uint16_t *)px_map, w, h);
#endif // #ifndef DIRECT_RENDER_MODE

/*Call it to tell LVGL you are ready*/
lv_disp_flush_ready(disp);
}

void setup()
{
#ifdef DEV_DEVICE_INIT
DEV_DEVICE_INIT();
#endif

Serial.begin(115200);
// Serial.setDebugOutput(true);
// while(!Serial);
Serial.println("Arduino_GFX LVGL_Arduino_v9 example ");
String LVGL_Arduino = String('V') + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();
Serial.println(LVGL_Arduino);

// Init Display
if (!gfx->begin())
{
Serial.println("gfx->begin() failed!");
}
gfx->fillScreen(RGB565_BLACK);

#ifdef GFX_BL
pinMode(GFX_BL, OUTPUT);
digitalWrite(GFX_BL, HIGH);
#endif

lv_init();

/*Set a tick source so that LVGL will know how much time elapsed. */
lv_tick_set_cb(millis_cb);

/* register print function for debugging */
#if LV_USE_LOG != 0
lv_log_register_print_cb(my_print);
#endif

screenWidth = gfx->width();
screenHeight = gfx->height();

#ifdef DIRECT_RENDER_MODE
bufSize = screenWidth * screenHeight;
#else
bufSize = screenWidth * 120;
#endif

disp_draw_buf = (lv_color_t *)heap_caps_malloc(bufSize * 2, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
if (!disp_draw_buf)
{
// remove MALLOC_CAP_INTERNAL flag try again
disp_draw_buf = (lv_color_t *)heap_caps_malloc(bufSize * 2, MALLOC_CAP_8BIT);
}

if (!disp_draw_buf)
{
Serial.println("LVGL disp_draw_buf allocate failed!");
}
else
{
disp = lv_display_create(screenWidth, screenHeight);
lv_display_set_flush_cb(disp, my_disp_flush);
#ifdef DIRECT_RENDER_MODE
lv_display_set_buffers(disp, disp_draw_buf, NULL, bufSize * 2, LV_DISPLAY_RENDER_MODE_DIRECT);
#else
lv_display_set_buffers(disp, disp_draw_buf, NULL, bufSize * 2, LV_DISPLAY_RENDER_MODE_PARTIAL);
#endif

/*Initialize the (dummy) input device driver*/
// lv_indev_t *indev = lv_indev_create();
// lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER); /*Touchpad should have POINTER type*/
// lv_indev_set_read_cb(indev, my_touchpad_read);

/* Option 1: Create a simple label
* ---------------------
*/
lv_obj_t *label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "Hello Arduino, I'm LVGL!(V" GFX_STR(LVGL_VERSION_MAJOR) "." GFX_STR(LVGL_VERSION_MINOR) "." GFX_STR(LVGL_VERSION_PATCH) ")");
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);

/*hello waveshare label*/
lv_obj_t *label_waveshare = lv_label_create(lv_scr_act());
lv_label_set_text(label_waveshare, "Hello waveshare!");
lv_obj_align(label_waveshare, LV_ALIGN_CENTER, 0, 20);

/* Option 2: Try an example. See all the examples
* - Online: https://docs.lvgl.io/master/examples.html
* - Source codes: https://github.com/lvgl/lvgl/tree/master/examples
* ----------------------------------------------------------------
*/
// lv_example_btn_1();

/* Option 3: Or try out a demo. Don't forget to enable the demos in lv_conf.h. E.g. LV_USE_DEMOS_WIDGETS
* -------------------------------------------------------------------------------------------
*/
// lv_demo_widgets();
// lv_demo_benchmark();
// lv_demo_music();
}

Serial.println("Setup done");
}

void loop()
{
lv_task_handler(); /* let the GUI do its work */
delay(5);
}

代码解释

  • setup () 函数
    • 基础设备与串口初始化
    • 显示屏初始化与控制
    • LVGL 核心与缓冲区配置
    • UI 元素与扩展功能