跳到主要内容

Arduino 开发

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

Arduino 入门教程

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

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

配置开发环境

1. 安装和配置 Arduino IDE

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

2. 安装库

可从 此链接Arduino 目录中,下载 ESP32-Touch-LCD-3.5 开发板的示例程序包。包内的 Arduino\libraries 目录已包含本教程所需的全部库文件。

库或文件名称说明版本安装方式
ESP32-audioI2S-master音频处理库v3.4.0通过库管理器或手动安装
GFX_Library_for_ArduinoGFX图形库v1.6.0通过库管理器或手动安装
lvglLVGL图形库v8.4.0通过库管理器或手动安装
OneButton按键库v2.6.1通过库管理器或手动安装
SensorLib传感器驱动库v0.3.1通过库管理器或手动安装
TCA9554扩展IO库v0.1.2通过库管理器或手动安装
XPowersLib电源管理库v0.2.9通过库管理器或手动安装
ESP32-A2DP蓝牙音频处理——手动安装
版本兼容性说明

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

安装步骤:

1.下载 示例程序包。 2. 将其 Arduino\libraries 目录下的所有文件夹(GFX_Library_for_Arduino 、ESP32-audioI2S-master等)复制到 Arduino 的库文件夹中。

信息

Arduino 库文件夹的路径通常是:c:\Users\<用户名>\Documents\Arduino\libraries

也可以在 Arduino IDE 中通过 文件 > 首选项,查看“项目文件夹位置”来定位。库文件夹就是此路径下的 libraries 文件夹。

  1. 其他安装方式请参考:Arduino 库管理教程

3. 其他提示

ESP32-Touch-LCD-3.5 Arduino 工程参数设置,需要选择ESP32 Dev Module。

示例程序

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

示例程序基础例程说明依赖库
01_i2s_audio读取SD卡的音频文件,并播放ESP32-audioI2S-master
02_axp2101_example打印电源管理芯片的数据XPowersLib
03_button_example按键测试OneButton
04_es8311_example录音一段时间,并播放es8311
05_pcf85063_example打印RTC获取的数据SensorLib
06_tca9554_example扩展io测试TCA9554
07_sd_card_test测试SD卡的读写-
08_gfx_helloworld屏幕上显示HelloWorldGFX_Library_for_Arduino、TCA9554
09_lvgl_arduino_v8lvgl v8.4.0 示例程序GFX_Library_for_Arduino、TCA9554、lvgl、SensorLib
10_lvgl_arduino_v9lvgl v9.3.0 示例程序GFX_Library_for_Arduino、TCA9554、lvgl、SensorLib
11_bt_music_receiver_arduino_i2s蓝牙音乐播放示例ESP32-A2DP、GFX_Library_for_Arduino、TCA9554、OneButton

01_i2s_audio

本示例演示ESP32-Touch-LCD-3.5读取SD卡的音频文件并使用喇叭播放,支持MP3、AAC、WAV等格式。

准备工作

  • 将SD卡插入电脑
  • 在SD卡根目录新建文件夹 music
  • 把本工程下data文件夹里面的1.mp3拷贝到SD卡的music文件夹里
  • 将SD卡插入 ESP32-Touch-LCD-3.5

运行效果

播放音频文件,屏幕无现象

代码

01_i2s_audio.ino
#include "Arduino.h"
#include "Audio.h"
#include "SPI.h"
#include "SD.h"
#include "FS.h"

#include "es8311.h"
#include "esp_check.h"
#include "TCA9554.h"
#include "Wire.h"

// Digital I/O used
#define SD_CS 15
#define SPI_MOSI 23
#define SPI_MISO 19
#define SPI_SCK 18

#define I2S_DOUT 12
#define I2S_BCLK 2
#define I2S_LRC 4

#define I2C_SDA 21
#define I2C_SCL 22

#define EXAMPLE_SAMPLE_RATE (16000)
#define EXAMPLE_MCLK_MULTIPLE (256) // If not using 24-bit data width, 256 should be enough
#define EXAMPLE_MCLK_FREQ_HZ (EXAMPLE_SAMPLE_RATE * EXAMPLE_MCLK_MULTIPLE)
#define EXAMPLE_VOICE_VOLUME (75)

TCA9554 TCA(0x20);
Audio audio;


static esp_err_t es8311_codec_init(void) {

es8311_handle_t es_handle = es8311_create(I2C_NUM_0, ES8311_ADDRRES_0);
ESP_RETURN_ON_FALSE(es_handle, ESP_FAIL, TAG, "es8311 create failed");
const es8311_clock_config_t es_clk = {
.mclk_inverted = false,
.sclk_inverted = false,
.mclk_from_mclk_pin = false,
// .mclk_frequency = EXAMPLE_MCLK_FREQ_HZ,
.sample_frequency = EXAMPLE_SAMPLE_RATE
};

ESP_ERROR_CHECK(es8311_init(es_handle, &es_clk, ES8311_RESOLUTION_32, ES8311_RESOLUTION_32));
// ESP_RETURN_ON_ERROR(es8311_sample_frequency_config(es_handle, EXAMPLE_SAMPLE_RATE * EXAMPLE_MCLK_MULTIPLE, EXAMPLE_SAMPLE_RATE), TAG, "set es8311 sample frequency failed");
ESP_RETURN_ON_ERROR(es8311_voice_volume_set(es_handle, EXAMPLE_VOICE_VOLUME, NULL), TAG, "set es8311 volume failed");
ESP_RETURN_ON_ERROR(es8311_microphone_config(es_handle, false), TAG, "set es8311 microphone failed");

return ESP_OK;
}


void setup() {
Serial.begin(115200);
Wire.begin(I2C_SDA, I2C_SCL);
TCA.begin();
TCA.pinMode1(2,OUTPUT);
TCA.write1(2, 1);

es8311_codec_init();

SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI, SD_CS);
if (!SD.begin(SD_CS)) {
esp_rom_printf("Card Mount Failed\n");
while (1) {
};
}

audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
audio.setVolume(21); // 0...21

audio.connecttoFS(SD, "music/1.mp3");
}

void loop() {
vTaskDelay(1);
audio.loop();
if (Serial.available()) { // put streamURL in serial monitor
audio.stopSong();
String r = Serial.readString();
r.trim();
if (r.length() > 5) audio.connecttohost(r.c_str());
log_i("free heap=%i", ESP.getFreeHeap());
}
}

// optional
void audio_info(const char *info) {
Serial.print("info ");
Serial.println(info);
}
void audio_id3data(const char *info) { //id3 metadata
Serial.print("id3data ");
Serial.println(info);
}
void audio_eof_mp3(const char *info) { //end of file
Serial.print("eof_mp3 ");
Serial.println(info);
}
void audio_showstation(const char *info) {
Serial.print("station ");
Serial.println(info);
}
void audio_showstreamtitle(const char *info) {
Serial.print("streamtitle ");
Serial.println(info);
}
void audio_bitrate(const char *info) {
Serial.print("bitrate ");
Serial.println(info);
}
void audio_commercial(const char *info) { //duration in sec
Serial.print("commercial ");
Serial.println(info);
}
void audio_icyurl(const char *info) { //homepage
Serial.print("icyurl ");
Serial.println(info);
}
void audio_lasthost(const char *info) { //stream URL played
Serial.print("lasthost ");
Serial.println(info);
}

代码解释

  • 初始化I2C外设,配置es8311解码器,同时使能功放管脚PA_CTRL:

    Wire.begin(I2C_SDA, I2C_SCL);
    TCA.begin();
    TCA.pinMode1(2,OUTPUT);
    TCA.write1(2, 1);

    es8311_codec_init();
  • 初始化I2S外设,挂载TF卡,设置播放音量,播放路径为music/1.mp3的MP3文件:

    SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI, SD_CS);
    if (!SD.begin(SD_CS)) {
    esp_rom_printf("Card Mount Failed\n");
    while (1) {
    };
    }

    audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
    audio.setVolume(21); // 0...21

    audio.connecttoFS(SD, "music/1.mp3");

02_axp2101_example

本示例演示使用XPowers驱动AXP2101,并通过串口打印数据

运行效果

代码

02_axp2101_example.ino
/*
! WARN:
Please do not run the example without knowing the external load voltage of the PMU,
it may burn your external load, please check the voltage setting before running the example,
if there is any loss, please bear it by yourself
*/
// #ifndef XPOWERS_NO_ERROR
// #error "Running this example is known to not damage the device! Please go and uncomment this!"
// #endif
// Defined using AXP2102
#define XPOWERS_CHIP_AXP2101

#include <Wire.h>
#include <Arduino.h>
#include "XPowersLib.h"

#ifndef CONFIG_PMU_SDA
#define CONFIG_PMU_SDA 21
#endif

#ifndef CONFIG_PMU_SCL
#define CONFIG_PMU_SCL 22
#endif

#ifndef CONFIG_PMU_IRQ
#define CONFIG_PMU_IRQ 35
#endif

bool pmu_flag = 0;
XPowersPMU power;

const uint8_t i2c_sda = CONFIG_PMU_SDA;
const uint8_t i2c_scl = CONFIG_PMU_SCL;
const uint8_t pmu_irq_pin = CONFIG_PMU_IRQ;

void setFlag(void)
{
pmu_flag = true;
}


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

bool result = power.begin(Wire, AXP2101_SLAVE_ADDRESS, i2c_sda, i2c_scl);

if (result == false) {
Serial.println("power is not online..."); while (1)delay(50);
}

Serial.printf("getID:0x%x\n", power.getChipID());

// Set the minimum common working voltage of the PMU VBUS input,
// below this value will turn off the PMU
power.setVbusVoltageLimit(XPOWERS_AXP2101_VBUS_VOL_LIM_4V36);

// Set the maximum current of the PMU VBUS input,
// higher than this value will turn off the PMU
power.setVbusCurrentLimit(XPOWERS_AXP2101_VBUS_CUR_LIM_1500MA);


// Get the VSYS shutdown voltage
uint16_t vol = power.getSysPowerDownVoltage();
Serial.printf("-> getSysPowerDownVoltage:%u\n", vol);

// Set VSY off voltage as 2600mV , Adjustment range 2600mV ~ 3300mV
power.setSysPowerDownVoltage(2600);

vol = power.getSysPowerDownVoltage();
Serial.printf("-> getSysPowerDownVoltage:%u\n", vol);


// DC1 IMAX=2A
// 1500~3400mV,100mV/step,20steps
power.setDC1Voltage(3300);
Serial.printf("DC1 : %s Voltage:%u mV \n", power.isEnableDC1() ? "+" : "-", power.getDC1Voltage());

// DC2 IMAX=2A
// 500~1200mV 10mV/step,71steps
// 1220~1540mV 20mV/step,17steps
power.setDC2Voltage(1000);
Serial.printf("DC2 : %s Voltage:%u mV \n", power.isEnableDC2() ? "+" : "-", power.getDC2Voltage());

// DC3 IMAX = 2A
// 500~1200mV,10mV/step,71steps
// 1220~1540mV,20mV/step,17steps
// 1600~3400mV,100mV/step,19steps
power.setDC3Voltage(3300);
Serial.printf("DC3 : %s Voltage:%u mV \n", power.isEnableDC3() ? "+" : "-", power.getDC3Voltage());

// DCDC4 IMAX=1.5A
// 500~1200mV,10mV/step,71steps
// 1220~1840mV,20mV/step,32steps
power.setDC4Voltage(1000);
Serial.printf("DC4 : %s Voltage:%u mV \n", power.isEnableDC4() ? "+" : "-", power.getDC4Voltage());

// DC5 IMAX=2A
// 1200mV
// 1400~3700mV,100mV/step,24steps
power.setDC5Voltage(3300);
Serial.printf("DC5 : %s Voltage:%u mV \n", power.isEnableDC5() ? "+" : "-", power.getDC5Voltage());

//ALDO1 IMAX=300mA
//500~3500mV, 100mV/step,31steps
power.setALDO1Voltage(3300);

//ALDO2 IMAX=300mA
//500~3500mV, 100mV/step,31steps
power.setALDO2Voltage(3300);

//ALDO3 IMAX=300mA
//500~3500mV, 100mV/step,31steps
power.setALDO3Voltage(3300);

//ALDO4 IMAX=300mA
//500~3500mV, 100mV/step,31steps
power.setALDO4Voltage(3300);

//BLDO1 IMAX=300mA
//500~3500mV, 100mV/step,31steps
power.setBLDO1Voltage(3300);

//BLDO2 IMAX=300mA
//500~3500mV, 100mV/step,31steps
power.setBLDO2Voltage(3300);

//CPUSLDO IMAX=30mA
//500~1400mV,50mV/step,19steps
power.setCPUSLDOVoltage(1000);

//DLDO1 IMAX=300mA
//500~3400mV, 100mV/step,29steps
power.setDLDO1Voltage(3300);

//DLDO2 IMAX=300mA
//500~1400mV, 50mV/step,2steps
power.setDLDO2Voltage(3300);


// power.enableDC1();
power.enableDC2();
power.enableDC3();
power.enableDC4();
power.enableDC5();
power.enableALDO1();
power.enableALDO2();
power.enableALDO3();
power.enableALDO4();
power.enableBLDO1();
power.enableBLDO2();
power.enableCPUSLDO();
power.enableDLDO1();
power.enableDLDO2();


Serial.println("DCDC=======================================================================");
Serial.printf("DC1 : %s Voltage:%u mV \n", power.isEnableDC1() ? "+" : "-", power.getDC1Voltage());
Serial.printf("DC2 : %s Voltage:%u mV \n", power.isEnableDC2() ? "+" : "-", power.getDC2Voltage());
Serial.printf("DC3 : %s Voltage:%u mV \n", power.isEnableDC3() ? "+" : "-", power.getDC3Voltage());
Serial.printf("DC4 : %s Voltage:%u mV \n", power.isEnableDC4() ? "+" : "-", power.getDC4Voltage());
Serial.printf("DC5 : %s Voltage:%u mV \n", power.isEnableDC5() ? "+" : "-", power.getDC5Voltage());
Serial.println("ALDO=======================================================================");
Serial.printf("ALDO1: %s Voltage:%u mV\n", power.isEnableALDO1() ? "+" : "-", power.getALDO1Voltage());
Serial.printf("ALDO2: %s Voltage:%u mV\n", power.isEnableALDO2() ? "+" : "-", power.getALDO2Voltage());
Serial.printf("ALDO3: %s Voltage:%u mV\n", power.isEnableALDO3() ? "+" : "-", power.getALDO3Voltage());
Serial.printf("ALDO4: %s Voltage:%u mV\n", power.isEnableALDO4() ? "+" : "-", power.getALDO4Voltage());
Serial.println("BLDO=======================================================================");
Serial.printf("BLDO1: %s Voltage:%u mV\n", power.isEnableBLDO1() ? "+" : "-", power.getBLDO1Voltage());
Serial.printf("BLDO2: %s Voltage:%u mV\n", power.isEnableBLDO2() ? "+" : "-", power.getBLDO2Voltage());
Serial.println("CPUSLDO====================================================================");
Serial.printf("CPUSLDO: %s Voltage:%u mV\n", power.isEnableCPUSLDO() ? "+" : "-", power.getCPUSLDOVoltage());
Serial.println("DLDO=======================================================================");
Serial.printf("DLDO1: %s Voltage:%u mV\n", power.isEnableDLDO1() ? "+" : "-", power.getDLDO1Voltage());
Serial.printf("DLDO2: %s Voltage:%u mV\n", power.isEnableDLDO2() ? "+" : "-", power.getDLDO2Voltage());
Serial.println("===========================================================================");

// Set the time of pressing the button to turn off
power.setPowerKeyPressOffTime(XPOWERS_POWEROFF_4S);
uint8_t opt = power.getPowerKeyPressOffTime();
Serial.print("PowerKeyPressOffTime:");
switch (opt) {
case XPOWERS_POWEROFF_4S: Serial.println("4 Second");
break;
case XPOWERS_POWEROFF_6S: Serial.println("6 Second");
break;
case XPOWERS_POWEROFF_8S: Serial.println("8 Second");
break;
case XPOWERS_POWEROFF_10S: Serial.println("10 Second");
break;
default:
break;
}
// Set the button power-on press time
power.setPowerKeyPressOnTime(XPOWERS_POWERON_128MS);
opt = power.getPowerKeyPressOnTime();
Serial.print("PowerKeyPressOnTime:");
switch (opt) {
case XPOWERS_POWERON_128MS: Serial.println("128 Ms");
break;
case XPOWERS_POWERON_512MS: Serial.println("512 Ms");
break;
case XPOWERS_POWERON_1S: Serial.println("1 Second");
break;
case XPOWERS_POWERON_2S: Serial.println("2 Second");
break;
default:
break;
}

Serial.println("===========================================================================");

bool en;

// DCDC 120%(130%) high voltage turn off PMIC function
en = power.getDCHighVoltagePowerDownEn();
Serial.print("getDCHighVoltagePowerDownEn:");
Serial.println(en ? "ENABLE" : "DISABLE");
// DCDC1 85% low voltage turn off PMIC function
en = power.getDC1LowVoltagePowerDownEn();
Serial.print("getDC1LowVoltagePowerDownEn:");
Serial.println(en ? "ENABLE" : "DISABLE");
// DCDC2 85% low voltage turn off PMIC function
en = power.getDC2LowVoltagePowerDownEn();
Serial.print("getDC2LowVoltagePowerDownEn:");
Serial.println(en ? "ENABLE" : "DISABLE");
// DCDC3 85% low voltage turn off PMIC function
en = power.getDC3LowVoltagePowerDownEn();
Serial.print("getDC3LowVoltagePowerDownEn:");
Serial.println(en ? "ENABLE" : "DISABLE");
// DCDC4 85% low voltage turn off PMIC function
en = power.getDC4LowVoltagePowerDownEn();
Serial.print("getDC4LowVoltagePowerDownEn:");
Serial.println(en ? "ENABLE" : "DISABLE");
// DCDC5 85% low voltage turn off PMIC function
en = power.getDC5LowVoltagePowerDownEn();
Serial.print("getDC5LowVoltagePowerDownEn:");
Serial.println(en ? "ENABLE" : "DISABLE");

// power.setDCHighVoltagePowerDown(true);
// power.setDC1LowVoltagePowerDown(true);
// power.setDC2LowVoltagePowerDown(true);
// power.setDC3LowVoltagePowerDown(true);
// power.setDC4LowVoltagePowerDown(true);
// power.setDC5LowVoltagePowerDown(true);

// It is necessary to disable the detection function of the TS pin on the board
// without the battery temperature detection function, otherwise it will cause abnormal charging
power.disableTSPinMeasure();

// power.enableTemperatureMeasure();

// Enable internal ADC detection
power.enableBattDetection();
power.enableVbusVoltageMeasure();
power.enableBattVoltageMeasure();
power.enableSystemVoltageMeasure();


/*
The default setting is CHGLED is automatically controlled by the PMU.
- XPOWERS_CHG_LED_OFF,
- XPOWERS_CHG_LED_BLINK_1HZ,
- XPOWERS_CHG_LED_BLINK_4HZ,
- XPOWERS_CHG_LED_ON,
- XPOWERS_CHG_LED_CTRL_CHG,
* */
power.setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG);


// Force add pull-up
pinMode(pmu_irq_pin, INPUT_PULLUP);
attachInterrupt(pmu_irq_pin, setFlag, FALLING);


// Disable all interrupts
power.disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
// Clear all interrupt flags
power.clearIrqStatus();
// Enable the required interrupt function
power.enableIRQ(
XPOWERS_AXP2101_BAT_INSERT_IRQ | XPOWERS_AXP2101_BAT_REMOVE_IRQ | //BATTERY
XPOWERS_AXP2101_VBUS_INSERT_IRQ | XPOWERS_AXP2101_VBUS_REMOVE_IRQ | //VBUS
XPOWERS_AXP2101_PKEY_SHORT_IRQ | XPOWERS_AXP2101_PKEY_LONG_IRQ | //POWER KEY
XPOWERS_AXP2101_BAT_CHG_DONE_IRQ | XPOWERS_AXP2101_BAT_CHG_START_IRQ //CHARGE
// XPOWERS_AXP2101_PKEY_NEGATIVE_IRQ | XPOWERS_AXP2101_PKEY_POSITIVE_IRQ | //POWER KEY
);

// Set the precharge charging current
power.setPrechargeCurr(XPOWERS_AXP2101_PRECHARGE_50MA);
// Set constant current charge current limit
power.setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_200MA);
// Set stop charging termination current
power.setChargerTerminationCurr(XPOWERS_AXP2101_CHG_ITERM_25MA);

// Set charge cut-off voltage
power.setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V1);

// Set the watchdog trigger event type
power.setWatchdogConfig(XPOWERS_AXP2101_WDT_IRQ_TO_PIN);
// Set watchdog timeout
power.setWatchdogTimeout(XPOWERS_AXP2101_WDT_TIMEOUT_4S);
// Enable watchdog to trigger interrupt event
power.enableWatchdog();

// power.disableWatchdog();

// Enable Button Battery charge
power.enableButtonBatteryCharge();

// Set Button Battery charge voltage
power.setButtonBatteryChargeVoltage(3300);

}

void printPMU()
{
Serial.print("isCharging:"); Serial.println(power.isCharging() ? "YES" : "NO");
Serial.print("isDischarge:"); Serial.println(power.isDischarge() ? "YES" : "NO");
Serial.print("isStandby:"); Serial.println(power.isStandby() ? "YES" : "NO");
Serial.print("isVbusIn:"); Serial.println(power.isVbusIn() ? "YES" : "NO");
Serial.print("isVbusGood:"); Serial.println(power.isVbusGood() ? "YES" : "NO");
Serial.print("getChargerStatus:");
uint8_t charge_status = power.getChargerStatus();
if (charge_status == XPOWERS_AXP2101_CHG_TRI_STATE) {
Serial.println("tri_charge");
} else if (charge_status == XPOWERS_AXP2101_CHG_PRE_STATE) {
Serial.println("pre_charge");
} else if (charge_status == XPOWERS_AXP2101_CHG_CC_STATE) {
Serial.println("constant charge");
} else if (charge_status == XPOWERS_AXP2101_CHG_CV_STATE) {
Serial.println("constant voltage");
} else if (charge_status == XPOWERS_AXP2101_CHG_DONE_STATE) {
Serial.println("charge done");
} else if (charge_status == XPOWERS_AXP2101_CHG_STOP_STATE) {
Serial.println("not charge");
}

Serial.print("getBattVoltage:"); Serial.print(power.getBattVoltage()); Serial.println("mV");
Serial.print("getVbusVoltage:"); Serial.print(power.getVbusVoltage()); Serial.println("mV");
Serial.print("getSystemVoltage:"); Serial.print(power.getSystemVoltage()); Serial.println("mV");

// The battery percentage may be inaccurate at first use, the PMU will automatically
// learn the battery curve and will automatically calibrate the battery percentage
// after a charge and discharge cycle
if (power.isBatteryConnect()) {
Serial.print("getBatteryPercent:"); Serial.print(power.getBatteryPercent()); Serial.println("%");
}

Serial.println();
}



void enterPmuSleep(void)
{
// Set the wake-up source to PWRKEY
power.wakeupControl(XPOWERS_AXP2101_WAKEUP_IRQ_PIN_TO_LOW, true);

// Set sleep flag
power.enableSleep();

power.disableDC2();
power.disableDC3();
power.disableDC4();
power.disableDC5();

power.disableALDO1();
power.disableALDO2();
power.disableALDO3();
power.disableALDO4();

power.disableBLDO1();
power.disableBLDO2();

power.disableCPUSLDO();
power.disableDLDO1();
power.disableDLDO2();

// Finally, turn off the power of the control chip
power.disableDC1();
}

void loop()
{

if (pmu_flag) {

pmu_flag = false;

// Get PMU Interrupt Status Register
uint32_t status = power.getIrqStatus();
Serial.print("STATUS => HEX:");
Serial.print(status, HEX);
Serial.print(" BIN:");
Serial.println(status, BIN);

if (power.isDropWarningLevel2Irq()) {
Serial.println("isDropWarningLevel2");
}
if (power.isDropWarningLevel1Irq()) {
Serial.println("isDropWarningLevel1");
}
if (power.isGaugeWdtTimeoutIrq()) {
Serial.println("isWdtTimeout");
}
if (power.isBatChargerOverTemperatureIrq()) {
Serial.println("isBatChargeOverTemperature");
}
if (power.isBatWorkOverTemperatureIrq()) {
Serial.println("isBatWorkOverTemperature");
}
if (power.isBatWorkUnderTemperatureIrq()) {
Serial.println("isBatWorkUnderTemperature");
}
if (power.isVbusInsertIrq()) {
Serial.println("isVbusInsert");
}
if (power.isVbusRemoveIrq()) {
Serial.println("isVbusRemove");
}
if (power.isBatInsertIrq()) {
Serial.println("isBatInsert");
}
if (power.isBatRemoveIrq()) {
Serial.println("isBatRemove");
}

if (power.isPekeyShortPressIrq()) {
Serial.println("isPekeyShortPress");
// enterPmuSleep();

Serial.print("Read pmu data buffer .");
uint8_t data[4] = {0};
power.readDataBuffer(data, XPOWERS_AXP2101_DATA_BUFFER_SIZE);
for (int i = 0; i < 4; ++i) {
Serial.print(data[i]);
Serial.print(",");
}
Serial.println();
}

if (power.isPekeyLongPressIrq()) {
Serial.println("isPekeyLongPress");
Serial.println("write pmu data buffer .");
uint8_t data[4] = {1, 2, 3, 4};
power.writeDataBuffer(data, XPOWERS_AXP2101_DATA_BUFFER_SIZE);
}

if (power.isPekeyNegativeIrq()) {
Serial.println("isPekeyNegative");
}
if (power.isPekeyPositiveIrq()) {
Serial.println("isPekeyPositive");
}
if (power.isWdtExpireIrq()) {
Serial.println("isWdtExpire");
printPMU();
}
if (power.isLdoOverCurrentIrq()) {
Serial.println("isLdoOverCurrentIrq");
}
if (power.isBatfetOverCurrentIrq()) {
Serial.println("isBatfetOverCurrentIrq");
}
if (power.isBatChargeDoneIrq()) {
Serial.println("isBatChargeDone");
}
if (power.isBatChargeStartIrq()) {
Serial.println("isBatChargeStart");
}
if (power.isBatDieOverTemperatureIrq()) {
Serial.println("isBatDieOverTemperature");
}
if (power.isChargeOverTimeoutIrq()) {
Serial.println("isChargeOverTimeout");
}
if (power.isBatOverVoltageIrq()) {
Serial.println("isBatOverVoltage");
}

// Clear PMU Interrupt Status Register
power.clearIrqStatus();

}
delay(10);
}

代码解释

  • 初始化I2C外设,初始化AXP2101电池管理IC:

    bool result = power.begin(Wire, AXP2101_SLAVE_ADDRESS, i2c_sda, i2c_scl);

    if (result == false) {
    Serial.println("power is not online...");
    while (1) delay(50);
    }

03_button_example

本示例演示如何使用 OneButton 库读取 BOOT、PWR、PLUS按键的单击、双击和长按等状态,并通过串口打印。

运行效果

代码

03_button_example.ino
#include "OneButton.h"

#define PIN_INPUT1 0
#define PIN_INPUT2 36


// Setup a new OneButton on pin PIN_INPUT2.
OneButton button1(PIN_INPUT1, true);
// Setup a new OneButton on pin PIN_INPUT2.
OneButton button2(PIN_INPUT2, false);


// setup code here, to run once:
void setup() {
// Setup the Serial port. see http://arduino.cc/en/Serial/IfSerial
Serial.begin(115200);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
Serial.println("Starting TwoButtons...");

// link the button 1 functions.
button1.attachClick(click1);
button1.attachDoubleClick(doubleclick1);
button1.attachLongPressStart(longPressStart1);
button1.attachLongPressStop(longPressStop1);
button1.attachDuringLongPress(longPress1);

// link the button 2 functions.
button2.attachClick(click2);
button2.attachDoubleClick(doubleclick2);
button2.attachLongPressStart(longPressStart2);
button2.attachLongPressStop(longPressStop2);
button2.attachDuringLongPress(longPress2);

} // setup


// main code here, to run repeatedly:
void loop() {
// keep watching the push buttons:
button1.tick();
button2.tick();

// You can implement other code in here or just wait a while
delay(10);
} // loop


// ----- button 1 callback functions

// This function will be called when the button1 was pressed 1 time (and no 2. button press followed).
void click1() {
Serial.println("BOOT Button click.");
} // click1


// This function will be called when the button1 was pressed 2 times in a short timeframe.
void doubleclick1() {
Serial.println("BOOT Button doubleclick.");
} // doubleclick1


// This function will be called once, when the button1 is pressed for a long time.
void longPressStart1() {
Serial.println("BOOT Button longPress start");
} // longPressStart1


// This function will be called often, while the button1 is pressed for a long time.
void longPress1() {
Serial.println("BOOT Button longPress...");
} // longPress1


// This function will be called once, when the button1 is released after beeing pressed for a long time.
void longPressStop1() {
Serial.println("BOOT Button longPress stop");
} // longPressStop1


// ... and the same for button 2:

void click2() {
Serial.println("PWR Button click.");
} // click2


void doubleclick2() {
Serial.println("PWR Button doubleclick.");
} // doubleclick2


void longPressStart2() {
Serial.println("PWR Button longPress start");
} // longPressStart2


void longPress2() {
Serial.println("PWR Button longPress...");
} // longPress2

void longPressStop2() {
Serial.println("PWR Button longPress stop");
} // longPressStop2


// End

代码解释

  • 绑定按键事件回调函数 :

    button1.attachClick(click1);
    button1.attachDoubleClick(doubleclick1);
    button1.attachLongPressStart(longPressStart1);
    button1.attachLongPressStop(longPressStop1);
    button1.attachDuringLongPress(longPress1);

04_es8311_example

本示例演示使用ESP32-Touch-LCD-3.5驱动ES8311音频编解码器,实现音频录制及回放功能。。

运行效果

  • 屏幕无现象
  • 按下ESP32-Touch-LCD-3.5的RST按键进入音频录制状态,5s后播放录制的内容。

代码

04_es8311_example.ino
#include <Arduino.h>
#include "ESP_I2S.h"

#include "esp_check.h"

#include "Wire.h"
#include "es8311.h"
#include "TCA9554.h"

#define I2C_SDA 21
#define I2C_SCL 22

#define I2S_NUM I2S_NUM_0

#define I2S_MCK_PIN -1
#define I2S_BCK_PIN 2
#define I2S_LRCK_PIN 4
#define I2S_DOUT_PIN 12
#define I2S_DIN_PIN 34

#define EXAMPLE_SAMPLE_RATE (48000)
#define EXAMPLE_MCLK_MULTIPLE (256) // If not using 24-bit data width, 256 should be enough
#define EXAMPLE_MCLK_FREQ_HZ (EXAMPLE_SAMPLE_RATE * EXAMPLE_MCLK_MULTIPLE)
#define EXAMPLE_VOICE_VOLUME (70)

I2SClass i2s;
TCA9554 TCA(0x20);

void setupI2S() {
i2s.setPins(I2S_BCK_PIN, I2S_LRCK_PIN, I2S_DOUT_PIN, I2S_DIN_PIN, I2S_MCK_PIN);
// Initialize the I2S bus in standard mode
if (!i2s.begin(I2S_MODE_STD, EXAMPLE_SAMPLE_RATE, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO, I2S_STD_SLOT_BOTH)) {
Serial.println("Failed to initialize I2S bus!");
return;
}
}


static esp_err_t es8311_codec_init(void) {
es8311_handle_t es_handle = es8311_create(I2C_NUM_0, ES8311_ADDRRES_0);
ESP_RETURN_ON_FALSE(es_handle, ESP_FAIL, TAG, "es8311 create failed");
const es8311_clock_config_t es_clk = {
.mclk_inverted = false,
.sclk_inverted = false,
.mclk_from_mclk_pin = false,
// .mclk_frequency = EXAMPLE_MCLK_FREQ_HZ,
.sample_frequency = EXAMPLE_SAMPLE_RATE
};

ESP_ERROR_CHECK(es8311_init(es_handle, &es_clk, ES8311_RESOLUTION_32, ES8311_RESOLUTION_32));
ESP_RETURN_ON_ERROR(es8311_voice_volume_set(es_handle, EXAMPLE_VOICE_VOLUME, NULL), TAG, "set es8311 volume failed");
ESP_RETURN_ON_ERROR(es8311_microphone_config(es_handle, false), TAG, "set es8311 microphone failed");

return ESP_OK;
}

void setup() {
uint8_t *wav_buffer;
size_t wav_size;
Serial.begin(115200);
Wire.begin(I2C_SDA, I2C_SCL);
es8311_codec_init();
TCA.begin();
TCA.pinMode1(2,OUTPUT);
TCA.write1(2, 1);

setupI2S();
Serial.println("I2S Initialized");

wav_buffer = i2s.recordWAV(5, &wav_size);
delay(1000);
Serial.println("I2S playWAV");
i2s.playWAV(wav_buffer, wav_size);
}

void loop() {
delay(1000);
}

代码解释

  • 初始化I2C,ES8311,I2S :

    Wire.begin(I2C_SDA, I2C_SCL);
    es8311_codec_init();
    setupI2S();
  • 音频录制5s,并播放录制的内容 :

    wav_buffer = i2s.recordWAV(5, &wav_size);
    delay(1000);
    Serial.println("I2S playWAV");
    i2s.playWAV(wav_buffer, wav_size);

05_pcf85063_example

本实例演示ESP32-Touch-LCD-3.5驱动PCF85063,时间和日期的设置与获取。

运行效果

  • 屏幕无现象
  • 打开串口监视器

代码

05_pcf85063_example.ino

#include <Wire.h>
#include <SPI.h>
#include <Arduino.h>
#include <SensorPCF85063.hpp>

#ifndef SENSOR_SDA
#define SENSOR_SDA 21
#endif

#ifndef SENSOR_SCL
#define SENSOR_SCL 22
#endif

#ifndef SENSOR_IRQ
#define SENSOR_IRQ 39
#endif

SensorPCF85063 rtc;
uint32_t interval = 0;
uint32_t loopCount = 0;

void printInt(int val)
{
if (val < 10) {
Serial.print("0");
}
Serial.print(val);
}


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

// Try to initialize the RTC module using I2C with specified SDA and SCL pins
if (!rtc.begin(Wire, SENSOR_SDA, SENSOR_SCL)) {
Serial.println("Failed to find PCF85063 - check your wiring!");
// Enter an infinite loop to halt the program
while (1) {
delay(1000);
}
}

uint16_t year = 2025;
uint8_t month = 1;
uint8_t day = 1;
uint8_t hour = 12;
uint8_t minute = 00;
uint8_t second = 00;

// Set the defined date and time on the RTC
rtc.setDateTime(year, month, day, hour, minute, second);

if (!rtc.isClockIntegrityGuaranteed()) {
Serial.println("[ERROR]:Clock integrity is not guaranteed; oscillator has stopped or has been interrupted");
}
}

void loop()
{
// Check if one second has passed since the last update
if (millis() > interval) {

// Update the interval to the current time
interval = millis() + 1000;

// Retrieve the current date and time from the RTC
RTC_DateTime datetime = rtc.getDateTime();

Serial.print("[RTC ]:");
Serial.print(" Year :"); printInt(datetime.getYear());
Serial.print(" Month:"); printInt(datetime.getMonth());
Serial.print(" Day :"); printInt(datetime.getDay());
Serial.print(" Hour:"); printInt(datetime.getHour());
Serial.print(" Minute:"); printInt(datetime.getMinute());
Serial.print(" Sec :"); printInt(datetime.getSecond());
Serial.println();

// Convert the RTC date and time to Unix time
struct tm info = datetime.toUnixTime();
Serial.print("[UNIX]:");
Serial.print(" Year :"); printInt(info.tm_year + 1900); // tm_year starts counting from 1900
Serial.print(" Month:"); printInt(info.tm_mon + 1); // tm_mon range is 0 - 11, 0 means January
Serial.print(" Day :"); printInt(info.tm_mday);
Serial.print(" Hour:"); printInt(info.tm_hour);
Serial.print(" Minute:"); printInt(info.tm_min);
Serial.print(" Sec :"); printInt(info.tm_sec);
Serial.println();

// Set a new Unix time at the 10th loop iteration
if (loopCount == 10) {
Serial.print("Set Unix Time:");
Serial.println();
Serial.println();
struct tm utc_tm;
utc_tm.tm_year = 2025 - 1900; // tm_year starts counting from 1900
utc_tm.tm_mon = 0; // tm_mon range is 0 - 11, 0 means January
utc_tm.tm_mday = 23;
utc_tm.tm_hour = 7;
utc_tm.tm_min = 1;
utc_tm.tm_sec = 28;
rtc.setDateTime(utc_tm);
}

// Set a UTC time with a time zone offset of 8 hours at the 20th loop iteration
if (loopCount == 20) {
Serial.print("Set UTC time to time zone offset 8 hours:");
Serial.println();
Serial.println();
struct tm utc_tm;
utc_tm.tm_year = 2025 - 1900; // tm_year starts counting from 1900
utc_tm.tm_mon = 0; // tm_mon range is 0 - 11, 0 means January
utc_tm.tm_mday = 23;
utc_tm.tm_hour = 7;
utc_tm.tm_min = 1;
utc_tm.tm_sec = 28;
rtc.convertUtcToTimezone(utc_tm, 8 * 3600);
rtc.setDateTime(utc_tm);
}

if (loopCount > 30) {

char buf[64];

struct tm timeinfo;
// Get the time C library structure
rtc.getDateTime(&timeinfo);

// Format the output using the strftime function
// For more formats, please refer to :
// https://man7.org/linux/man-pages/man3/strftime.3.html

size_t written = strftime(buf, 64, "%A, %B %d %Y %H:%M:%S", &timeinfo);

if (written != 0) {
Serial.println(buf);
}

written = strftime(buf, 64, "%b %d %Y %H:%M:%S", &timeinfo);
if (written != 0) {
Serial.println(buf);
}

written = strftime(buf, 64, "%A, %d. %B %Y %I:%M%p", &timeinfo);
if (written != 0) {
Serial.println(buf);
}
}

++loopCount;
}
}

代码解释

  • 初始化 :

      // Try to initialize the RTC module using I2C with specified SDA and SCL pins
    if (!rtc.begin(Wire, SENSOR_SDA, SENSOR_SCL)) {
    Serial.println("Failed to find PCF85063 - check your wiring!");
    // Enter an infinite loop to halt the program
    while (1) {
    delay(1000);
    }
    }
  • 设置时间、日期 :

    rtc.setDateTime(year, month, day, hour, minute, second);
  • 获取时间、日期 :

    RTC_DateTime datetime = rtc.getDateTime();

06_tca9554_example

本实例演示ESP32-Touch-LCD-3.5驱动TCA9554,对扩展IO的引脚进行读写操作。。

运行效果

  • 屏幕无现象
  • 打开串口监视器

代码

06_tca9554_example.ino
#include "TCA9554.h"


TCA9554 TCA(0x20);


void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("TCA9554_LIB_VERSION: ");
Serial.println(TCA9554_LIB_VERSION);
Serial.println();

Wire.begin(21, 22);
TCA.begin();


Serial.println("Set pinMode8 OUTPUT");
for (int pin = 0; pin < 8; pin++)
{
TCA.pinMode1(pin, OUTPUT);
}

for (int pin = 0; pin < 8; pin++)
{
TCA.write1(pin, LOW);
}
delay(1000);
Serial.println("Set pinMode8 INPUT");
for (int pin = 0; pin < 8; pin++)
{
TCA.pinMode1(pin, INPUT);
}
}


void loop()
{
Serial.print("INPUT->");
for (int pin = 0; pin < 8; pin++)
{
int val = TCA.read1(pin);
Serial.printf("pin%d: %d\t", pin, val);
}
Serial.println();
Serial.println("\ndone...");
delay(1000);
}

代码解释

  • 设置引脚模式 :

    TCA.pinMode1(pin, OUTPUT);
  • 设置引脚电平 :

    TCA.write1(pin, LOW);
  • 读取引脚电平 :

    int val = TCA.read1(pin);

07_sd_card_test

本示例演示使用 ESP32-Touch-LCD-3.5 测试SD卡的读写功能

硬件连接

  • 将板子接入电脑
  • 将Micro SD卡插入卡槽(SD卡需要格式化为FAT32)

运行效果

  • 屏幕无现象
  • 打开串口监视器

代码

07_sd_card_test.ino

#include "FS.h"
#include "SD.h"
#include "SPI.h"


#define REASSIGN_PINS
int sck = 18;
int miso = 19;
int mosi = 23;
int cs = 15;

void listDir(fs::FS &fs, const char *dirname, uint8_t levels) {
Serial.printf("Listing directory: %s\n", dirname);

File root = fs.open(dirname);
if (!root) {
Serial.println("Failed to open directory");
return;
}
if (!root.isDirectory()) {
Serial.println("Not a directory");
return;
}

File file = root.openNextFile();
while (file) {
if (file.isDirectory()) {
Serial.print(" DIR : ");
Serial.println(file.name());
if (levels) {
listDir(fs, file.path(), levels - 1);
}
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print(" SIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}

void createDir(fs::FS &fs, const char *path) {
Serial.printf("Creating Dir: %s\n", path);
if (fs.mkdir(path)) {
Serial.println("Dir created");
} else {
Serial.println("mkdir failed");
}
}

void removeDir(fs::FS &fs, const char *path) {
Serial.printf("Removing Dir: %s\n", path);
if (fs.rmdir(path)) {
Serial.println("Dir removed");
} else {
Serial.println("rmdir failed");
}
}

void readFile(fs::FS &fs, const char *path) {
Serial.printf("Reading file: %s\n", path);

File file = fs.open(path);
if (!file) {
Serial.println("Failed to open file for reading");
return;
}

Serial.print("Read from file: ");
while (file.available()) {
Serial.write(file.read());
}
file.close();
}

void writeFile(fs::FS &fs, const char *path, const char *message) {
Serial.printf("Writing file: %s\n", path);

File file = fs.open(path, FILE_WRITE);
if (!file) {
Serial.println("Failed to open file for writing");
return;
}
if (file.print(message)) {
Serial.println("File written");
} else {
Serial.println("Write failed");
}
file.close();
}

void appendFile(fs::FS &fs, const char *path, const char *message) {
Serial.printf("Appending to file: %s\n", path);

File file = fs.open(path, FILE_APPEND);
if (!file) {
Serial.println("Failed to open file for appending");
return;
}
if (file.print(message)) {
Serial.println("Message appended");
} else {
Serial.println("Append failed");
}
file.close();
}

void renameFile(fs::FS &fs, const char *path1, const char *path2) {
Serial.printf("Renaming file %s to %s\n", path1, path2);
if (fs.rename(path1, path2)) {
Serial.println("File renamed");
} else {
Serial.println("Rename failed");
}
}

void deleteFile(fs::FS &fs, const char *path) {
Serial.printf("Deleting file: %s\n", path);
if (fs.remove(path)) {
Serial.println("File deleted");
} else {
Serial.println("Delete failed");
}
}

void testFileIO(fs::FS &fs, const char *path) {
File file = fs.open(path);
static uint8_t buf[512];
size_t len = 0;
uint32_t start = millis();
uint32_t end = start;
if (file) {
len = file.size();
size_t flen = len;
start = millis();
while (len) {
size_t toRead = len;
if (toRead > 512) {
toRead = 512;
}
file.read(buf, toRead);
len -= toRead;
}
end = millis() - start;
Serial.printf("%u bytes read for %lu ms\n", flen, end);
file.close();
} else {
Serial.println("Failed to open file for reading");
}

file = fs.open(path, FILE_WRITE);
if (!file) {
Serial.println("Failed to open file for writing");
return;
}

size_t i;
start = millis();
for (i = 0; i < 2048; i++) {
file.write(buf, 512);
}
end = millis() - start;
Serial.printf("%u bytes written for %lu ms\n", 2048 * 512, end);
file.close();
}

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

#ifdef REASSIGN_PINS
SPI.begin(sck, miso, mosi, cs);
if (!SD.begin(cs)) {
#else
if (!SD.begin()) {
#endif
Serial.println("Card Mount Failed");
return;
}
uint8_t cardType = SD.cardType();

if (cardType == CARD_NONE) {
Serial.println("No SD card attached");
return;
}

Serial.print("SD Card Type: ");
if (cardType == CARD_MMC) {
Serial.println("MMC");
} else if (cardType == CARD_SD) {
Serial.println("SDSC");
} else if (cardType == CARD_SDHC) {
Serial.println("SDHC");
} else {
Serial.println("UNKNOWN");
}

uint64_t cardSize = SD.cardSize() / (1024 * 1024);
Serial.printf("SD Card Size: %lluMB\n", cardSize);

listDir(SD, "/", 0);
createDir(SD, "/mydir");
listDir(SD, "/", 0);
removeDir(SD, "/mydir");
listDir(SD, "/", 2);
writeFile(SD, "/hello.txt", "Hello ");
appendFile(SD, "/hello.txt", "World!\n");
readFile(SD, "/hello.txt");
deleteFile(SD, "/foo.txt");
renameFile(SD, "/hello.txt", "/foo.txt");
readFile(SD, "/foo.txt");
testFileIO(SD, "/test.txt");
Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
}

void loop() {}

代码解释

  • 初始化 :

    if(!SD_MMC.setPins(clk, cmd, d0)){
    Serial.println("Pin change failed!");
    return;
    }

    if (!SD_MMC.begin( "/sdcard", true)) {
    Serial.println("Card Mount Failed");
    return;
    }

08_gfx_helloworld

本示例演示 ESP32-Touch-LCD-3.5 使用GFX_Library_for_Arduino库驱动屏幕并在屏幕上显示HelloWorld

运行效果

代码

08_gfx_helloworld.ino
#include <Arduino_GFX_Library.h>
#include "TCA9554.h"


#define GFX_BL 25 // default backlight pin, you may replace DF_GFX_BL to actual backlight pin

TCA9554 TCA(0x20);

Arduino_DataBus *bus = new Arduino_ESP32SPI(27 /* DC */, 5 /* CS */, 18 /* SCK */, 23 /* MOSI */, 19 /* MISO */);

Arduino_GFX *gfx = new Arduino_ST7796(bus, GFX_NOT_DEFINED /* RST */, 0 /* rotation */, true /* IPS */);



void setup(void)
{
#ifdef DEV_DEVICE_INIT
DEV_DEVICE_INIT();
#endif
Wire.begin(21, 22);
TCA.begin();
TCA.pinMode1(0,OUTPUT);
TCA.write1(0, 1);
delay(10);
TCA.write1(0, 0);
delay(10);
TCA.write1(0, 1);
delay(200);

Serial.begin(115200);
// Serial.setDebugOutput(true);
// while(!Serial);
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

gfx->setCursor(10, 10);
gfx->setTextColor(RGB565_RED);
gfx->println("Hello World!");

delay(5000); // 5 seconds
}

void loop()
{
gfx->setCursor(random(gfx->width()), random(gfx->height()));
gfx->setTextColor(random(0xffff), random(0xffff));
gfx->setTextSize(random(6) /* x scale */, random(6) /* y scale */, random(2) /* pixel_margin */);
gfx->println("Hello World!");

delay(1000); // 1 second
}

代码解释

  • 配置屏幕接口以及屏幕的分辨率等:
    Arduino_DataBus *bus = new Arduino_ESP32SPI(27 /* DC */, 5 /* CS */, 18 /* SCK */, 23 /* MOSI */, 19 /* MISO */);

    Arduino_GFX *gfx = new Arduino_ST7796(bus, GFX_NOT_DEFINED /* RST */, 0 /* rotation */, true /* IPS */);

09_lvgl_arduino_v8

本示例演示了使用 ESP32-Touch-LCD-3.5 运行lvgl( v8.4.0)示例程序。

需要安装 lvgl v8.4.0 版本,如已安装其他版本,请重新安装。

运行效果

代码

09_lvgl_example_v8.ino
#include <lvgl.h>

/*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 <Arduino_GFX_Library.h>

#include "TCA9554.h"

#include "TouchDrvFT6X36.hpp"
#include <Wire.h>


#define GFX_BL 25 // default backlight pin, you may replace DF_GFX_BL to actual backlight pin

TCA9554 TCA(0x20);

Arduino_DataBus *bus = new Arduino_ESP32SPI(27 /* DC */, 5 /* CS */, 18 /* SCK */, 23 /* MOSI */, 19 /* MISO */);

Arduino_GFX *gfx = new Arduino_ST7796(bus, GFX_NOT_DEFINED /* RST */, 0 /* rotation */, true /* IPS */);

TouchDrvFT6X36 touch;


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;

#if LV_USE_LOG != 0
/* Serial debugging */
void my_print(const char *buf) {
Serial.printf(buf);
Serial.flush();
}
#endif

/* 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);
}

/*Read the touchpad*/
void my_touchpad_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data) {
int16_t x[1], y[1];
uint8_t touched = touch.getPoint(x, y, 1);

if (touched) {
data->state = LV_INDEV_STATE_PR;

/*Set the coordinates*/
data->point.x = x[0];
data->point.y = y[0];
} else {
data->state = LV_INDEV_STATE_REL;
}
}

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

Wire.begin(21, 22);
TCA.begin();
TCA.pinMode1(0, OUTPUT);
TCA.pinMode1(1, OUTPUT);
TCA.write1(0, 1);
TCA.write1(1, 1);
delay(10);
TCA.write1(0, 0);
TCA.write1(1, 0);
delay(10);
TCA.write1(0, 1);
TCA.write1(1, 1);
delay(200);

Serial.begin(115200);
// Serial.setDebugOutput(true);
// while(!Serial);
Serial.println("Arduino_GFX LVGL_Arduino_v8 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

// Init touch device
if (!touch.begin(Wire, FT6X36_SLAVE_ADDRESS)) {
Serial.println("Failed to find FT6X36 - check your wiring!");
while (1) {
delay(1000);
}
}

lv_init();

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

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

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

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

if (!disp_draw_buf1 || !disp_draw_buf2) {
Serial.println("LVGL disp_draw_buf allocate failed!");
} else {
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;
#ifdef DIRECT_RENDER_MODE
disp_drv.direct_mode = true;
#endif
lv_disp_drv_register(&disp_drv);

/* Initialize the (dummy) input device driver */
static lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = my_touchpad_read;
lv_indev_drv_register(&indev_drv);

/* Option 1: Create simple label */
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);

lv_obj_t *sw = lv_switch_create(lv_scr_act());
lv_obj_align(sw, LV_ALIGN_TOP_MID, 0, 50);

sw = lv_switch_create(lv_scr_act());
lv_obj_align(sw, LV_ALIGN_BOTTOM_MID, 0, -50);

/* 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/e7f88efa5853128bf871dde335c0ca8da9eb7731/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_keypad_encoder();
// lv_Demo_music();
// lv_Demo_stress();
}

Serial.println("Setup done");
}

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

// #ifdef DIRECT_RENDER_MODE
// #if (LV_COLOR_16_SWAP != 0)
// gfx->draw16bitBeRGBBitmap(0, 0, (uint16_t *)disp_draw_buf, screenWidth, screenHeight);
// #else
// gfx->draw16bitRGBBitmap(0, 0, (uint16_t *)disp_draw_buf, screenWidth, screenHeight);
// #endif
// #endif // !DIRECT_RENDER_MODE

delay(5);
}

代码解释

  • setup()

    • 初始化屏幕以及LVGL;
  • loop()

    • 调用 lv_timer_handler 让 LVGL 处理图形界面的任务;

10_lvgl_arduino_v9

本示例演示了使用 ESP32-Touch-LCD-3.5 运行lvgl( v9.3.0)示例程序

需要安装 lvgl v9.3.0 版本,如已安装其他版本,请重新安装。

运行效果

代码

10_lvgl_example_v9.ino
/*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 */

#include <lvgl.h>

/*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 <Arduino_GFX_Library.h>

#include "TCA9554.h"

#include "TouchDrvFT6X36.hpp"
#include <Wire.h>


#define GFX_BL 25 // default backlight pin, you may replace DF_GFX_BL to actual backlight pin

TCA9554 TCA(0x20);

Arduino_DataBus *bus = new Arduino_ESP32SPI(27 /* DC */, 5 /* CS */, 18 /* SCK */, 23 /* MOSI */, 19 /* MISO */);

Arduino_GFX *gfx = new Arduino_ST7796(bus, GFX_NOT_DEFINED /* RST */, 0 /* rotation */, true /* IPS */);

TouchDrvFT6X36 touch;


uint32_t screenWidth;
uint32_t screenHeight;
uint32_t bufSize;
lv_display_t *disp;
lv_color_t *disp_draw_buf1;
lv_color_t *disp_draw_buf2;

#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)
{
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);

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

/*Read the touchpad*/
void my_touchpad_read(lv_indev_t *indev, lv_indev_data_t *data)
{
int16_t x[1], y[1];
uint8_t touched = touch.getPoint(x, y, 1);

if (touched) {
data->state = LV_INDEV_STATE_PR;

/*Set the coordinates*/
data->point.x = x[0];
data->point.y = y[0];
} else {
data->state = LV_INDEV_STATE_REL;
}
}

void setup()
{
#ifdef DEV_DEVICE_INIT
DEV_DEVICE_INIT();
#endif
Wire.begin(21, 22);
TCA.begin();
TCA.pinMode1(0, OUTPUT);
TCA.pinMode1(1, OUTPUT);
TCA.write1(0, 1);
TCA.write1(1, 1);
delay(10);
TCA.write1(0, 0);
TCA.write1(1, 0);
delay(10);
TCA.write1(0, 1);
TCA.write1(1, 1);
delay(200);

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

// Init touch device
if (!touch.begin(Wire, FT6X36_SLAVE_ADDRESS)) {
Serial.println("Failed to find FT6X36 - check your wiring!");
while (1) {
delay(1000);
}
}

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;
disp_draw_buf1 = (lv_color_t *)heap_caps_malloc(bufSize * 2, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
disp_draw_buf2 = (lv_color_t *)heap_caps_malloc(bufSize * 2, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
#else
bufSize = screenWidth * 40;
disp_draw_buf1 = (lv_color_t *)heap_caps_malloc(bufSize * 2, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
disp_draw_buf2 = (lv_color_t *)heap_caps_malloc(bufSize * 2, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
#endif
if (!disp_draw_buf1 || !disp_draw_buf2)
{
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_buf1, disp_draw_buf2, bufSize * 2, LV_DISPLAY_RENDER_MODE_DIRECT);
#else
lv_display_set_buffers(disp, disp_draw_buf1, disp_draw_buf2, 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);

lv_obj_t *sw = lv_switch_create(lv_scr_act());
lv_obj_align(sw, LV_ALIGN_TOP_MID, 0, 50);

sw = lv_switch_create(lv_scr_act());
lv_obj_align(sw, LV_ALIGN_BOTTOM_MID, 0, -50);

/* 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_keypad_encoder();
// lv_Demo_music();
// lv_Demo_stress();
}

Serial.println("Setup done");
}

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

代码解释

  • my_disp_flush()

    • 这个函数是 LVGL 显示驱动的刷新函数。它负责将 LVGL 的绘图缓冲区内容刷新到显示屏上;
    • 根据不同的颜色格式设置,调用 gfx 对象的相应函数来绘制位图到特定的区域;
    • 最后通知 LVGL 显示刷新已完成。
  • loop()

    • 调用 lv_timer_handler 让 LVGL 处理图形界面的任务;
    • 通过 delay(5) 增加数据轮询的频率,以确保及时获取传感器数据并更新显示。

11_bt_music_receiver_arduino_i2s

本示例演示了使用 ESP32-Touch-LCD-3.5 连接蓝牙播放音乐,屏幕显示歌曲信息。

设置 Partition Scheme 为 "Custom"

  • QQ音乐:设置->歌词->车载蓝牙歌词
  • 网易云音乐:设置->通用->外部设备->外接设备蓝牙歌词

运行效果

  • 手机或平板连接蓝牙。(名称:ESP32-Touch-LCD-3.5)
  • 屏幕上显示歌曲信息