# esp32s3_cpp_wathes **Repository Path**: jack_yang98/esp32s3_cpp_wathes ## Basic Information - **Project Name**: esp32s3_cpp_wathes - **Description**: 使用esp32s3,做一款智能手表 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-05 - **Last Updated**: 2026-07-13 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ESP32 C++ BSP + LVGL 工程 这个工程是一个基于 `ESP-IDF v5.5.2` 的 `ESP32-S3` C++ 板级工程,目标是把原先偏 C 风格的 BSP 拆分成可维护的 C++ 类,并在此基础上接入 `LVGL v9.5.0-dev`。 当前工程既可以作为: - 开发板底层 BSP 的统一入口 - LVGL 图形界面的移植基座 - 摄像头、触摸、音频、传感器、SD 卡等外设的实验工程 ## 1. 当前已接入的功能 - I2C 总线访问封装 - SPI 总线访问封装 - 板载 LED 与 BOOT 键 - XL9555 IO 扩展 - 24C02 EEPROM - AP3216C 光照 / 接近传感器 - QMA6100P 三轴加速度计 - RTC 时间工具 - 片内温度传感器 - ESP Timer 周期定时器封装 - ES8388 音频编解码器 - I2S 音频读写 - SPI LCD 显示 - CST816 触摸输入 - 摄像头采集与 LCD 直显 - SPI SD 卡挂载与容量统计 - FatFs 常用辅助工具 - 基于 RMT 的 NEC 红外收发 - LVGL v9 显示/触摸移植层 ## 2. 中间件与依赖 工程里实际用到的中间件/第三方组件如下: - `ESP-IDF v5.5.2` 说明:工程基础平台,提供 FreeRTOS、驱动、VFS、esp_timer、RMT、I2C、SPI、I2S 等 - `FreeRTOS` 说明:随 ESP-IDF 提供,当前 GUI 运行在独立任务中 - `LVGL v9.5.0-dev` 路径:`components/lvgl` 说明:图形库,当前已经完成 SPI LCD + CST816 触摸移植 - `esp32-camera` 路径:`components/esp32-camera` 说明:摄像头驱动组件,工程通过板级封装调用 - `FatFs` 说明:由 ESP-IDF 提供,用于 SD 卡文件系统 - `newlib` 说明:C/C++ 运行时依赖 ## 3. 硬件接口与总线分配 下面这部分描述的是当前代码里实际采用的板级接口分配,来源于: - `components/alientek_bsp_cpp/include/alientek_bsp_cpp/board_config.hpp` ### 3.1 板载基础 GPIO | 功能 | GPIO | 说明 | | --- | --- | --- | | LED | `GPIO1` | 板载状态灯 | | BOOT Key | `GPIO0` | 板载 BOOT 按键 | ### 3.2 总线与外设接口 | 接口 | GPIO / 端口 | 说明 | | --- | --- | --- | | I2C0 | `SDA=GPIO41`, `SCL=GPIO42` | 默认板载控制总线,代码中用于 EEPROM、AP3216C、QMA6100P、CST816、ES8388、XL9555 | | I2C1 | `SDA=GPIO5`, `SCL=GPIO4` | 代码中有预留,但当前默认未启用 | | SPI2 | `MOSI=GPIO11`, `MISO=GPIO13`, `SCLK=GPIO12` | LCD 与 SD 卡共用的 SPI 总线 | | LCD 控制 | `CS=GPIO21`, `WR=GPIO40` | SPI LCD 的片选与写控制脚 | | SD 卡 | `CS=GPIO2` | 通过 SPI2 挂载 | | 红外 RMT | `RX=GPIO2`, `TX=GPIO8` | NEC 红外收发 | | I2S0 | `BCK=GPIO46`, `WS=GPIO9`, `DOUT=GPIO10`, `DIN=GPIO14`, `MCLK=GPIO3` | 音频输入输出,配合 ES8388 | | Camera SCCB | `SDA=GPIO39`, `SCL=GPIO38` | 摄像头寄存器配置接口 | | Camera DVP | `D7=18`, `D6=17`, `D5=16`, `D4=15`, `D3=7`, `D2=6`, `D1=5`, `D0=4`, `VSYNC=47`, `HREF=48`, `PCLK=45` | 摄像头并口数据接口 | ### 3.3 当前需要注意的接口复用 - `GPIO2` 同时被定义为 `SD CS` 和 `RMT RX`,所以当前软件配置下不适合同时使用 SD 卡和红外接收 - `GPIO4 / GPIO5` 被定义为 `I2C1`,同时也被摄像头用作 `D0 / D1`,因此默认配置下 `I2C1` 与摄像头不能同时启用 - `GPIO40` 在当前代码里同时出现在 `LCD WR` 和 `XL9555 INT` 定义中;如果后面要启用 XL9555 中断驱动,建议先对照原理图再确认这一路映射 ## 4. 目录结构 - `components/alientek_bsp_cpp` 说明:板级 BSP C++ 封装主体 - `components/lvgl` 说明:LVGL 源码,版本参考 `E:\code\LVGL_study\lv_port_pc_vscode-master` - `components/lv_conf.h` 说明:当前工程使用的 LVGL 配置文件 - `components/esp32-camera` 说明:摄像头组件 - `main/app_main.cpp` 说明:当前应用入口,默认启动 LVGL 示例界面 - `examples/bringup_example.cpp` 说明:更偏底层的 BSP 拉起示例 - `docs/用法说明.md` 说明:模块用法说明 - `docs/移植计划.md` 说明:原 BSP 迁移梳理与设计记录 ## 5. 快速开始 建议在 `ESP-IDF Shell` 中操作。 ### 5.1 编译 ```powershell idf.py build ``` ### 5.2 烧录并查看日志 ```powershell idf.py -p COMx flash monitor ``` ### 5.3 当前默认行为 当前 `main/app_main.cpp` 会: - 初始化板级基础外设 - 创建独立的 LVGL GUI 任务 - 初始化 LCD、触摸与 LVGL - 显示一个可点击的简单界面 如果你只想验证 BSP,不想跑 LVGL,可以参考: - `examples/bringup_example.cpp` ## 6. 板级统一入口 工程推荐从 `Board` 类入手: 文件: - `components/alientek_bsp_cpp/include/alientek_bsp_cpp/board.hpp` 核心入口: ```cpp Board board; ESP_ERROR_CHECK(board.initializeCore()); ``` `Board::initializeCore()` 当前会完成以下基础初始化: - I2C0 - SPI2 - LED - BOOT 键 - XL9555 - EEPROM - AP3216C - QMA6100P - ES8388 - LCD - CST816 触摸 - FatFs 工作区 注意:下面这些模块不是 `initializeCore()` 自动拉起的,需要按需初始化: - `SD 卡` - `Camera` - `I2S` - `片内温度传感器` - `红外` - `ADC` ## 7. 主要接口总览 ### 7.1 `Board` 提供的访问入口 | 访问器 | 类型 | 作用 | | --- | --- | --- | | `board.i2c()` | `I2cMaster` | I2C 总线访问 | | `board.spi()` | `SpiBus` | SPI 总线访问 | | `board.led()` | `Led` | LED 控制 | | `board.bootKey()` | `BootKey` | BOOT 键扫描 | | `board.ioExpander()` | `Xl9555` | IO 扩展访问 | | `board.eeprom()` | `At24cxxEeprom` | EEPROM 读写 | | `board.ambientSensor()` | `Ap3216cSensor` | 光照/接近传感器 | | `board.motionSensor()` | `Qma6100pSensor` | 三轴加速度计 | | `board.codec()` | `Es8388Codec` | 音频编解码器 | | `board.display()` | `LcdDisplay` | LCD 绘图与刷屏 | | `board.touch()` | `Cst816Touch` | 触摸读取 | | `board.sdCard()` | `SdCard` | SD 卡挂载与容量查询 | | `board.adc()` | `Adc1Sampler` | ADC 采样 | | `board.temperatureSensor()` | `OnChipTemperatureSensor` | 片内温度 | | `board.i2s()` | `I2sAudio` | I2S 音频收发 | | `board.camera()` | `Camera` | 摄像头采集 | | `board.infrared()` | `InfraredTransceiver` | NEC 红外收发 | | `board.rtc()` | `RtcClock` | RTC 时间工具 | | `board.timer()` | `EspTimerTicker` | 周期定时器 | ### 7.2 总线接口 文件: - `components/alientek_bsp_cpp/include/alientek_bsp_cpp/buses.hpp` 常用方法: - `I2cMaster::initialize()` - `I2cMaster::readRegister()` - `I2cMaster::writeRegister()` - `SpiBus::initialize()` - `SpiBus::addDevice()` - `SpiBus::writeCommand()` - `SpiBus::writeData()` ### 7.3 GPIO / 扩展 IO 文件: - `components/alientek_bsp_cpp/include/alientek_bsp_cpp/gpio_devices.hpp` 常用方法: - `Led::initialize()` - `Led::set()` - `Led::toggle()` - `BootKey::scan()` - `Xl9555::initialize()` - `Xl9555::writePin()` - `Xl9555::readPin()` - `Xl9555::scanKeys()` ### 7.4 存储接口 文件: - `components/alientek_bsp_cpp/include/alientek_bsp_cpp/storage.hpp` 常用方法: - `At24cxxEeprom::read()` - `At24cxxEeprom::write()` - `At24cxxEeprom::check()` - `SdCard::mount()` - `SdCard::unmount()` - `SdCard::usage()` - `FatFsUtils::initializeWorkAreas()` - `FatFsUtils::copyFile()` - `FatFsUtils::copyFolder()` ### 7.5 传感器与系统工具 文件: - `components/alientek_bsp_cpp/include/alientek_bsp_cpp/sensors.hpp` 常用方法: - `Adc1Sampler::initialize()` - `Adc1Sampler::readAverage()` - `Ap3216cSensor::read()` - `Qma6100pSensor::read()` - `RtcClock::setTime()` - `RtcClock::now()` - `OnChipTemperatureSensor::initialize()` - `OnChipTemperatureSensor::readCelsius()` - `EspTimerTicker::startPeriodic()` - `EspTimerTicker::consumeFrameFlag()` ### 7.6 音频接口 文件: - `components/alientek_bsp_cpp/include/alientek_bsp_cpp/audio.hpp` 常用方法: - `Es8388Codec::initialize()` - `Es8388Codec::configureSai()` - `Es8388Codec::configureAdda()` - `Es8388Codec::configureOutput()` - `Es8388Codec::setHeadphoneVolume()` - `Es8388Codec::setSpeakerVolume()` - `I2sAudio::initialize()` - `I2sAudio::setClock()` - `I2sAudio::write()` - `I2sAudio::read()` ### 7.7 显示接口 文件: - `components/alientek_bsp_cpp/include/alientek_bsp_cpp/display.hpp` 常用方法: - `LcdDisplay::initialize()` - `LcdDisplay::clear()` - `LcdDisplay::fillRect()` - `LcdDisplay::drawPixel()` - `LcdDisplay::drawLine()` - `LcdDisplay::drawRectangle()` - `LcdDisplay::drawCircle()` - `LcdDisplay::drawString()` - `LcdDisplay::blitRgb565()` - `LcdDisplay::setPanelOffset()` - `LcdDisplay::setOrientation()` 说明: - 当前 LCD 逻辑分辨率为 `240 x 280` - `setPanelOffset(x, y)` 用于适配不同屏幕批次的显示整体偏移 ### 7.8 触摸接口 文件: - `components/alientek_bsp_cpp/include/alientek_bsp_cpp/touch.hpp` 常用方法: - `Cst816Touch::initialize()` - `Cst816Touch::read()` - `Cst816Touch::scan()` - `Cst816Touch::setCoordinateOffset()` - `Cst816Touch::setAxisTransform()` - `Cst816Touch::setBounds()` 返回结构: - `TouchPoint` 字段:`x`、`y`、`fingers`、`pressed` ### 7.9 摄像头接口 文件: - `components/alientek_bsp_cpp/include/alientek_bsp_cpp/camera.hpp` 常用方法: - `Camera::initialize()` - `Camera::capture()` - `Camera::release()` - `Camera::show()` 说明: - 当前封装基于 `esp32-camera` - `show()` 会直接将一帧 `RGB565` 图像刷到 LCD ### 7.10 红外接口 文件: - `components/alientek_bsp_cpp/include/alientek_bsp_cpp/infrared.hpp` 常用方法: - `InfraredTransceiver::initialize()` - `InfraredTransceiver::transmit()` - `InfraredTransceiver::receiveOnce()` - `InfraredTransceiver::runSelfTest()` 数据结构: - `NecScanCode` 字段:`address`、`command` ## 8. LVGL 移植说明 ### 8.1 版本 - 当前参考版本:`LVGL v9.5.0-dev` - 源码路径:`components/lvgl` - 配置路径:`components/lv_conf.h` ### 8.2 移植层 文件: - `components/alientek_bsp_cpp/include/alientek_bsp_cpp/lvgl_port.hpp` - `components/alientek_bsp_cpp/src/lvgl_port.cpp` 作用: - 初始化 LVGL - 创建 LVGL `display` - 把 LVGL flush 回调接到 `LcdDisplay::blitRgb565()` - 把 LVGL pointer 输入接到 `Cst816Touch::read()` - 使用 `esp_timer_get_time()` 作为 LVGL tick 来源 核心接口: - `LvglPort::initialize(Board& board, size_t buffer_lines = 20)` - `LvglPort::display()` - `LvglPort::pointer()` ### 8.3 当前运行方式 当前 GUI 运行在独立任务中,而不是直接跑在 `app_main()` 里。 这样做的原因是: - `main task` 默认栈较小 - LVGL 初始化和建界面在主任务中容易触发栈溢出 - 独立 GUI 任务更适合后续扩展 UI、动画和页面逻辑 ## 9. 使用示例 ### 9.1 最小 BSP 初始化 ```cpp #include "alientek_bsp_cpp/board.hpp" using namespace alientek::esp32s3; extern "C" void app_main(void) { Board board; ESP_ERROR_CHECK(board.initializeCore()); board.display().setPanelOffset(0, 20); board.display().clear(LcdDisplay::kWhite); board.display().drawString(10, 10, 220, 32, 16, "CPP BSP Ready", LcdDisplay::kRed); } ``` ### 9.2 读取传感器 ```cpp const auto als = board.ambientSensor().read(); const auto motion = board.motionSensor().read(); printf("ALS=%u IR=%u PS=%u\n", als.als, als.ir, als.ps); printf("ax=%.2f ay=%.2f az=%.2f\n", motion.acc_x, motion.acc_y, motion.acc_z); ``` ### 9.3 挂载 SD 卡 ```cpp ESP_ERROR_CHECK(board.sdCard().mount(board.spi())); const auto usage = board.sdCard().usage(); printf("total=%uKB free=%uKB\n", static_cast(usage.total_kb), static_cast(usage.free_kb)); ``` ### 9.4 摄像头直显 ```cpp ESP_ERROR_CHECK(board.camera().initialize(board.ioExpander())); ESP_ERROR_CHECK(board.camera().show(board.display(), 0, 0)); ``` ## 10. 当前已知事项 - 当前工程仍保留部分 `ESP-IDF` 旧版 `I2S / I2C / ADC` 接口,因此编译时会看到 deprecated warning - 这些 warning 不影响当前功能运行 - 当前代码里的部分接口定义存在复用关系,详见上面的“硬件接口与总线分配” - 后续如果继续演进 BSP,建议逐步迁移到 `driver/i2c_master.h`、`driver/i2s_std.h` 和 `esp_adc/adc_oneshot.h` ## 11. 相关文档 - `docs/用法说明.md` - `docs/移植计划.md` - `examples/bringup_example.cpp`