跳到主要内容

Arduino 开发

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

Arduino 入门教程

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

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

配置开发环境

安装 Arduino IDE

请参考 安装和配置 Arduino IDE 教程 安装 Arduino IDE,并添加 ESP32 开发板支持。

选择开发板和端口

连接 ESP32-C5-Touch-LCD-1.69 到电脑后,在"工具"菜单中选择对应的串口号。

安装示例库

Arduino 示例位于工程的 example/arduino/examples 目录。运行示例前,先解压 example/arduino/ESP32_C5_Touch_LCD_1in69.zip,再将解压后的库放入 Arduino 默认的 libraries 目录。

Arduino 库文件夹通常位于:

C:\Users\<用户名>\Documents\Arduino\libraries

也可以在 Arduino IDE 中通过"文件 > 首选项"查看"项目文件夹位置",并在该路径下找到 libraries 文件夹。

示例程序

示例程序基础例程说明
01_RGB_Test屏幕刷色测试
02_Mic_Speaker_Test麦克风与扬声器测试
03_IMU_TestIMU 测试
04_Bat_Test电池检测测试
05_RTC_TestRTC 测试
06_LVGL_Demo_TestLVGL 示例测试

01_RGB_Test

硬件连接

  • 使用 USB 线将开发板接入电脑。

代码分析

RGB 刷色测试代码
static const uint16_t Colors[] = {
0xF800, // Red
0x07E0, // Green
0x001F, // Blue
0xFFFF, // White
0x0000, // Black
};

static const char *ColorNames[] = {
"R", "G", "B", "W", "BL",
};

void setup(void)
{
Serial.begin(115200);
delay(200);

if (!bsp_display_init()) {
Serial.println("bsp_display_init failed");
while (true) {
delay(1000);
}
}

bsp_display_backlight_on();
bsp_display_brightness_set(100);
}

void loop(void)
{
bsp_display_fill(Colors[color_index]);
Serial.printf("Show color: %s (%u)\n", ColorNames[color_index], color_index);

color_index++;
if (color_index >= (sizeof(Colors) / sizeof(Colors[0]))) {
color_index = 0;
}

delay(2000);
}

代码解释

  • Colors[] / ColorNames[]:RGB565 颜色值和名称数组(红/绿/蓝/白/黑),用于循环刷屏。
  • bsp_display_init():初始化 SPI 总线和 ST7789 LCD 面板。
  • bsp_display_backlight_on():点亮 LCD 背光。
  • bsp_display_brightness_set(100):设置背光亮度为 100%。
  • bsp_display_fill(Colors[color_index]):用指定 RGB565 颜色填充整屏。
  • Serial.printf(...):通过串口输出当前颜色名称和索引,便于调试。

运行效果

  • 屏幕依次显示红、绿、蓝、白、黑五种纯色,每种停留 2 秒后切换。
  • 串口每 2 秒输出一次当前颜色名称和索引。

ESP32-C5-Touch-LCD-1.69 Arduino 01 RGB


02_Mic_Speaker_Test

硬件连接

  • 使用 USB 线将开发板接入电脑。

代码分析

麦克风回环播放代码
constexpr size_t audio_frame_bytes = 1024;
constexpr uint8_t speaker_volume = 70;
constexpr uint8_t mic_gain_db = 18;

uint8_t audio_buffer[audio_frame_bytes];

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

if (!bsp_audio_init()) {
Serial.println("bsp_audio_init failed");
return;
}

bsp_audio_set_speaker_volume(speaker_volume);
bsp_audio_set_mic_gain(mic_gain_db);

Serial.println("microphone loopback to speaker");
}

void loop()
{
size_t bytes_read = 0;
size_t bytes_written = 0;

if (!bsp_audio_read(audio_buffer, sizeof(audio_buffer), &bytes_read) || (bytes_read == 0)) {
Serial.println("bsp_audio_read failed");
delay(10);
return;
}

if (!bsp_audio_write(audio_buffer, bytes_read, &bytes_written) || (bytes_written != bytes_read)) {
Serial.println("bsp_audio_write failed");
delay(10);
}
}

代码解释

  • bsp_audio_init():初始化 I2S 总线和 ES8311 编解码器。
  • bsp_audio_set_speaker_volume(70):设置扬声器音量为 70。
  • bsp_audio_set_mic_gain(18):设置麦克风增益为 18dB。
  • bsp_audio_read(audio_buffer, ...):从麦克风读取 1024 字节音频数据。
  • bsp_audio_write(audio_buffer, ...):将读取的音频数据写入扬声器,实现实时回环。

运行效果

  • 串口输出 microphone loopback to speaker
  • 对着麦克风说话,可从扬声器实时听到回放声音。

03_IMU_Test

硬件连接

  • 使用 USB 线将开发板接入电脑。

代码分析

QMI8658 初始化与数据读取代码
#define QMI8658_I2C_ADDRESS 0x6B

static QMI8658 imu(Wire);
static AccelData accel_data = { 0 };
static GyroData gyro_data = { 0 };

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

bsp_display_brightness_init();
bsp_display_brightness_set(100);

if (!bsp_i2c_init()) {
Serial.println("I2C init failed");
while (true) {
delay(1000);
}
}

imu.init(imu_calibration, QMI8658_I2C_ADDRESS);
imu.setAccelRange(8);
imu.setGyroRange(512);
imu.setAccelODR(1000);
imu.setGyroODR(1000);

Serial.println("QMI8658 ready");
}

void loop(void)
{
imu.update();
imu.getAccel(&accel_data);
imu.getGyro(&gyro_data);

Serial.print("ACC[g] ");
Serial.print(accel_data.accelX, 3);
Serial.print(", ");
Serial.print(accel_data.accelY, 3);
Serial.print(", ");
Serial.print(accel_data.accelZ, 3);
Serial.print(" GYRO[dps] ");
Serial.print(gyro_data.gyroX, 3);
Serial.print(", ");
Serial.print(gyro_data.gyroY, 3);
Serial.print(", ");
Serial.print(gyro_data.gyroZ, 3);
Serial.print(" TEMP[C] ");
Serial.println(imu.getTemp(), 2);

delay(100);
}

代码解释

  • bsp_i2c_init():初始化 I2C 总线(SDA=GPIO8,SCL=GPIO9,400kHz)。
  • imu.init(imu_calibration, QMI8658_I2C_ADDRESS):初始化 QMI8658,I2C 地址 0x6B。
  • imu.setAccelRange(8) / imu.setGyroRange(512):设置加速度量程 ±8g、陀螺仪量程 ±512dps。
  • imu.setAccelODR(1000) / imu.setGyroODR(1000):设置加速度和陀螺仪输出数据率为 1000Hz。
  • imu.update():更新传感器数据。
  • imu.getAccel(&accel_data) / imu.getGyro(&gyro_data):读取加速度和陀螺仪数据。
  • imu.getTemp():读取温度数据。

运行效果

  • 串口输出 QMI8658 ready 后,每 100ms 输出一行加速度(g)、陀螺仪(dps)和温度(℃)数据。
  • 轻微倾斜或转动开发板时,加速度和陀螺仪数据会随姿态变化。

ESP32-C5-Touch-LCD-1.69 Arduino 03 IMU


04_Bat_Test

硬件连接

  • 使用 USB 线将开发板接入电脑。
  • 连接锂电池到开发板。

代码分析

电池信息读取与显示代码
static const uint16_t battery_capacity_mah = 1500;

static const bsp_display_lvgl_partial_cfg_t battery_display_cfg = {
.use_psram = false,
.double_buffer = false,
.buffer_height = 120,
};

static void bat_update_label(const bsp_bat_info_t *bat_info)
{
const char *battery_state = "Idle";
const char *battery_note = "";

battery_state = (bat_info->ma > 0) ? "Charging" : ((bat_info->ma < 0) ? "Discharging" : "Idle");
battery_note = (bat_info->ma == 0) ? "battery not connected or full" : "battery connected";

lv_label_set_text_fmt(battery_label,
"Battery Test\n"
"State: %s\n"
"Voltage: %u mV\n"
"Current: %d mA\n"
"SOC: %u %%\n"
"Temp: %d C\n"
"Capacity: %u mAh\n"
"%s",
battery_state,
bat_info->mv,
bat_info->ma,
bat_info->soc,
bat_info->tc,
battery_capacity_mah,
battery_note);
}

void setup(void)
{
bsp_display_start_partial(&battery_display_cfg);
bsp_display_brightness_set(100);
bsp_bat_init(battery_capacity_mah);

bsp_display_lock(0);
battery_label = lv_label_create(lv_scr_act());
lv_obj_align(battery_label, LV_ALIGN_TOP_LEFT, 10, 10);
lv_label_set_text(battery_label, "Battery Test\nBattery status updating");
bsp_display_unlock();
}

void loop(void)
{
bsp_bat_info_t bat_info = {};

if (!bsp_get_bat_info(&bat_info)) {
Serial.println("battery info update failed");
return;
}

if (bat_info_changed(&battery_last_info, &bat_info)) {
if (bsp_display_lock(0)) {
bat_update_label(&bat_info);
battery_last_info = bat_info;
bsp_display_unlock();
}
}

delay(1000);
}

代码解释

  • bsp_display_start_partial(&battery_display_cfg):以局部刷新模式启动 LVGL,减少显存占用。
  • bsp_bat_init(battery_capacity_mah):初始化 BQ27220 电量计,设置电池容量为 1500mAh。
  • bsp_get_bat_info(&bat_info):读取电池信息(电压/电流/SOC/温度等)。
  • bsp_display_lock(0) / bsp_display_unlock():获取/释放 LVGL 互斥锁,确保线程安全。
  • lv_label_set_text_fmt(battery_label, ...):格式化并更新电池信息标签。
  • bat_info_changed(...):判断电池数据是否变化,避免无意义刷新。

运行效果

  • 屏幕显示电池状态信息:状态(Charging/Discharging/Idle)、电压(mV)、电流(mA)、SOC(%)、温度(℃)、容量(mAh)。
  • 串口同步输出电池数据。
  • 接入电池后,电流不为 0 时状态为 Charging 或 Discharging;未接电池或充满时状态为 Idle。

ESP32-C5-Touch-LCD-1.69 Arduino 04 Battery


05_RTC_Test

硬件连接

  • 使用 USB 线将开发板接入电脑。

代码分析

RTC 初始化与时间读取代码
static PCF85063A rtc(Wire);

static void rtc_set_to_build_time(void)
{
struct tm now_tm = {};
const char *build_date = __DATE__;
const char *build_time = __TIME__;

now_tm.tm_year = ((build_date[7] - '0') * 1000 + (build_date[8] - '0') * 100 +
(build_date[9] - '0') * 10 + (build_date[10] - '0')) - 1900;
now_tm.tm_mon = month_from_build_date(build_date);
now_tm.tm_mday = (build_date[4] == ' ') ? (build_date[5] - '0')
: ((build_date[4] - '0') * 10 + (build_date[5] - '0'));
now_tm.tm_hour = (build_time[0] - '0') * 10 + (build_time[1] - '0');
now_tm.tm_min = (build_time[3] - '0') * 10 + (build_time[4] - '0');
now_tm.tm_sec = (build_time[6] - '0') * 10 + (build_time[7] - '0');

rtc.set(&now_tm);
}

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

bsp_display_brightness_init();
bsp_display_brightness_set(100);

bsp_i2c_init();
rtc.begin();

if (rtc.oscillator_stop()) {
Serial.println("RTC lost power, set to build time");
rtc_set_to_build_time();
} else {
Serial.println("RTC running");
}
}

void loop(void)
{
time_t current_time = rtc.time(NULL);
struct tm *now_tm = localtime(&current_time);

Serial.printf("%04d-%02d-%02d %02d:%02d:%02d\r\n",
now_tm->tm_year + 1900,
now_tm->tm_mon + 1,
now_tm->tm_mday,
now_tm->tm_hour,
now_tm->tm_min,
now_tm->tm_sec);

delay(1000);
}

代码解释

  • bsp_i2c_init():初始化 I2C 总线。
  • rtc.begin():初始化 PCF85063A RTC 芯片。
  • rtc.oscillator_stop():检测 RTC 是否停振(掉电),返回 true 表示时间丢失。
  • rtc_set_to_build_time():使用编译时间(__DATE__ / __TIME__)设置 RTC 时间。
  • rtc.time(NULL):读取 RTC 时间戳。
  • localtime(&current_time):将时间戳转换为本地时间结构体,便于格式化输出。

运行效果

  • 串口输出 RTC runningRTC lost power, set to build time
  • 随后每秒输出一次 YYYY-MM-DD HH:MM:SS 格式的时间。

ESP32-C5-Touch-LCD-1.69 Arduino 05 RTC


06_LVGL_Demo_Test

硬件连接

  • 使用 USB 线将开发板接入电脑。

代码分析

LVGL Benchmark 初始化代码
static const bsp_display_lvgl_full_frame_cfg_t lgvl_config = {
.use_psram = true,
.double_buffer = true,
.full_refresh = true,
};

void setup(void)
{
Serial.begin(115200);
bsp_display_start_full_frame(&lgvl_config);
bsp_display_brightness_set(100);

bsp_display_lock(0);
lv_demo_benchmark_set_max_speed(true);
lv_demo_benchmark();
bsp_display_unlock();
}

void loop(void)
{
delay(1000);
}

代码解释

  • bsp_display_start_full_frame(&lgvl_config):以全帧模式启动 LVGL,启用 PSRAM、双缓冲和全刷新,获得最佳显示效果。
  • bsp_display_brightness_set(100):设置背光亮度为 100%。
  • bsp_display_lock(0) / bsp_display_unlock():获取/释放 LVGL 互斥锁,确保 UI 操作线程安全。
  • lv_demo_benchmark_set_max_speed(true):设置 benchmark 为最大速度模式。
  • lv_demo_benchmark():启动 LVGL benchmark 跑分演示。

运行效果

  • 屏幕依次显示 LVGL benchmark 各项测试画面(矩形、阴影、文字、图片、动画等渲染性能测试)。
  • 测试完成后显示各项 FPS 评分汇总。