CoreMatrix 内部集成 Stamp Timer Power2(M5PM1)+ M5IOE1,结合硬件电路实现了多级电源开关,不同级别对应不同的主控运行状态及外设与接口供电状态。用户可根据运行需求,切换主控运行状态及相关电源使能,关闭未使用的外设部分,实现整机低功耗。
使用 M5PM1 / M5IOE1 驱动库能够非常便捷地配置 M5PM1 / M5IOE1 的引脚功能,用于低功耗唤醒以及外设供电开关。
此级电源条件下,电池保持对 M5PM1 的供电。电池电量未耗尽的情况下,该层电源将一直保持,M5PM1 支持基础的按键开关机操作。
此外,L0 域还包含 M5PM1 的 EXT_5V boost 输出(5V_INOUT):它为 M5-Bus 提供 5V,并转换后产生 M5BUS_3V3_L0。该路输出由 M5PM1 的 EXT_5V_EN 单独控制,默认关闭,M5Unified 初始化时会自动打开,不随 L1 ~ L3B 的分级开关变化。
关闭输出后,5V_INOUT 可作为外部 5V 输入;开启输出时请勿从 M5-Bus 的 5V 引脚反向供电。
pm1.setBoostEnable(true); // M5-Bus 5V + M5-Bus 3V3 ON
pm1.setBoostEnable(false); // M5-Bus 5V + M5-Bus 3V3 OFF 此级电源条件下,将启用 IMU、KEY1~KEY3 按键上拉及相关逻辑供电。该层级的电源开关使用 M5PM1 的 3V3_L1,可通过以下 API 实现开关控制。
pm1.setLdoEnable(true); // L1 ON
pm1.setLdoEnable(false); // L1 OFF 同时,BMI270 INT1 连接至 M5PM1 G4,KEY1~KEY3 分别连接 M5PM1 G0~G2。需要由 IMU 或按键唤醒 M5PM1 时,应保持 L1 供电后 M5PM1 进入休眠:
pm1.setLdoEnable(true);
pm1.ldoSetPowerHold(true);
pm1.setLedEnLevel(true);
pm1.shutdown(); 此级电源条件下,将启用 ESP32-C61、M5IOE1、I2C 上拉及主控相关外设供电。该层级使用 M5PM1 的 DCDC 输出 3V3_L3A,可通过以下 API 实现开关控制。
pm1.setDcdcEnable(true); // L3A ON
pm1.setDcdcEnable(false); // L3A OFF L3B 层级控制 LED 点阵、microSD、蜂鸣器和 Grove 等外设的供电或相关配置。该层级基于 M5IOE1 IO 拓展芯片实现控制,允许独立控制该层级的部分外设。
| M5IOE1 | PYG1 | PYG2 | PYG3 | PYG4 | PYG5 | PYG8 | PYG10 | PYG11 |
|---|---|---|---|---|---|---|---|---|
| microSD | PYB_TF_EN | PYB_TFCARD_DET | ||||||
| Buzzer | PYB_BUZZER_EN | PYB_BUZZER_PWM | ||||||
| Charge | PYB_CHG_PROG | PYB_CHG_STAT | ||||||
| LED Matrix | PYB_LEDS_EN | |||||||
| Grove 5V | PYB_GROVE_EN |
TF_3V3_L3B 电源使能BUZZER_3V3_L3B 电源使能LEDS_3V3_L3B 电源使能M5IOE1_PWM_CH3(索引 2)具体的外设供电控制,通过下方 M5IOE1 的 API 进行独立控制:
ioe1.pinMode(M5IOE1_PIN_4, OUTPUT);
ioe1.digitalWrite(M5IOE1_PIN_4, HIGH); Grove 接口的 5V 输出由 PYB_GROVE_EN (PYG5) 控制。M5Unified 的 cfg.output_power 默认为 true,即 M5.begin() 后 Grove 5V 默认已打开,可通过以下 API 控制:
M5.Power.setExtOutput(true); // 打开 Grove 5V
M5.Power.setExtOutput(false); // 关闭 Grove 5V M5PM1 可通过程序手动控制进入休眠状态,降低整机功耗。默认状态下,直接设置休眠将回退至低功耗供电状态,此时 M5PM1 保持供电。
pm1.shutdown(); 需要保留 IMU、按键上拉等 L1 电路时,应使用 M5PM1 驱动库配置 L1 供电保持和对应唤醒源,再执行 pm1.shutdown()。
M5PM1 支持配置 I2C 空闲自动休眠。进入休眠后,ESP32 与 M5PM1 的首次通信用于唤醒 M5PM1,有效通信将在下一次通信中完成。
m5pm1_err_t setI2cSleepTime(uint8_t seconds); M5PM1 支持配置定时器功能,当计时结束后执行开机、关机、复位等操作。
m5pm1_err_t timerSet(uint32_t seconds, m5pm1_tim_action_t action); typedef enum {
M5PM1_TIM_ACTION_STOP = 0b000, // 停止,无动作
// Stop, no action
M5PM1_TIM_ACTION_FLAG = 0b001, // 仅设置标志
// Set flag only
M5PM1_TIM_ACTION_REBOOT = 0b010, // 系统复位
// System reboot
M5PM1_TIM_ACTION_POWERON = 0b011, // 开机
// Power on
M5PM1_TIM_ACTION_POWEROFF = 0b100 // 关机
// Power off
} m5pm1_tim_action_t; 案例说明:按下 KEY1 设置 3 秒后自动开机并立即关机,按下 KEY2 设置 5 秒后自动关机。关机后可通过单击 PWR_BTN 重新开机。
#include <M5Unified.h>
#include <M5PM1.h>
M5PM1 pm1;
static void drawState(uint8_t state)
{
M5.Display.startWrite();
M5.Display.fillScreen(TFT_BLACK);
M5.Display.drawRect(0, 0, 16, 16, TFT_WHITE);
if (state == 0) {
M5.Display.fillRect(7, 7, 2, 2, TFT_WHITE);
} else if (state == 1) {
M5.Display.fillRect(3, 3, 4, 4, TFT_WHITE);
} else {
M5.Display.fillRect(9, 9, 4, 4, TFT_WHITE);
}
M5.Display.endWrite();
M5.Display.display();
}
void setup()
{
auto cfg = M5.config();
cfg.serial_baudrate = 115200;
M5.begin(cfg);
M5.Display.setColorDepth(8);
M5.Display.setRotation(1);
M5.Display.setBrightness(128);
const m5pm1_err_t err = pm1.begin(&M5.In_I2C, M5PM1_DEFAULT_ADDR, M5PM1_I2C_FREQ_100K);
if (err != M5PM1_OK) {
Serial.printf("M5PM1 init failed: %d\n", err);
while (true) delay(1000);
}
Serial.println("KEY1: power on after 3s");
Serial.println("KEY2: power off after 5s");
drawState(0);
}
void loop()
{
M5.update();
if (M5.BtnA.wasClicked()) {
Serial.println("Set power-on timer: 3s");
drawState(1);
delay(200);
pm1.timerSet(3, M5PM1_TIM_ACTION_POWERON);
pm1.shutdown();
}
if (M5.BtnB.wasClicked()) {
Serial.println("Set power-off timer: 5s");
drawState(2);
pm1.timerSet(5, M5PM1_TIM_ACTION_POWEROFF);
}
delay(20);
}电源切换至 L1 Mode,CoreMatrix 的 IMU、KEY1~KEY3 按键上拉和 M5PM1 处于供电状态。在配置 IMU 唤醒功能后,M5PM1 进入休眠状态,同时保持 L1 的输出供电 (3V3_L1_EN),用于维持 BMI270 工作。
此时可通过翻转或移动设备,触发 BMI270 INT1 输出低电平,唤醒 M5PM1 重新启动。
M5PM1 唤醒后将重新运行 L0、L1 和 L3A 上电流程。ESP32-C61 重新执行初始化。
案例说明:设备开机后,单击按键 A(KEY1)配置 IMU 中断模式与 M5PM1 L1 电源保持,M5PM1 进入休眠。此时翻转或移动设备即可触发 M5PM1 唤醒,ESP32-C61 重新上电。
#include <M5Unified.h>
#include <M5PM1.h>
#include <Wire.h>
#include "SparkFun_BMI270_Arduino_Library.h"
BMI270 imu;
M5PM1 pm1;
void setup(void)
{
M5.begin();
Serial.begin(115200);
Wire.setPins(M5.getPin(m5::pin_name_t::in_i2c_sda), M5.getPin(m5::pin_name_t::in_i2c_scl));
// Initialize PM1
m5pm1_err_t err = pm1.begin(&M5.In_I2C, M5PM1_DEFAULT_ADDR, M5PM1_I2C_FREQ_100K);
if (err == M5PM1_OK) {
Serial.println("PM1 initialization successful");
pm1.gpioSetWakeEnable(M5PM1_GPIO_NUM_4, true);
pm1.gpioSetWakeEdge(M5PM1_GPIO_NUM_4, M5PM1_GPIO_WAKE_FALLING); // Falling edge
} else {
Serial.printf("PM1 initialization failed, error code: %d\n", err);
}
// Check if sensor is connected and initialize
// Address defaults to 0x68
while(imu.beginI2C(BMI2_I2C_PRIM_ADDR, Wire) != BMI2_OK)
{
Serial.println("Error: BMI270 not connected, check wiring and I2C address!");
delay(1000);
}
imu.disableFeature(BMI2_ANY_MOTION);
Serial.println("BMI270 initialization successful");
M5.Display.setColorDepth(8);
M5.Display.setRotation(1);
M5.Display.setBrightness(128);
M5.Display.fillScreen(TFT_BLACK);
M5.Display.drawRect(0, 0, 16, 16, TFT_WHITE);
M5.Display.fillRect(7, 7, 2, 2, TFT_WHITE);
M5.Display.display();
}
void loop(void)
{
M5.update();
if (M5.BtnA.wasPressed()) {
int8_t ret = imu.enableFeature(BMI2_ANY_MOTION);
// Optional
// bmi2_sens_config config;
// config.type = BMI2_ANY_MOTION;
// config.cfg.any_motion.threshold = 0xA0; // 1LSB equals to 0.48mg. Default is 83mg. Lower is more sensitive
// config.cfg.any_motion.duration = 0x0A; // 1LSB equals 20ms. Default is 100ms.
// ret |= imu.setConfig(config);
//
bmi2_int_pin_config intPinConfig;
intPinConfig.pin_type = BMI2_INT1;
intPinConfig.int_latch = BMI2_INT_NON_LATCH;
intPinConfig.pin_cfg[0].lvl = BMI2_INT_ACTIVE_LOW;
intPinConfig.pin_cfg[0].od = BMI2_INT_PUSH_PULL;
intPinConfig.pin_cfg[0].output_en = BMI2_INT_OUTPUT_ENABLE;
intPinConfig.pin_cfg[0].input_en = BMI2_INT_INPUT_DISABLE;
ret |= imu.setInterruptPinConfig(intPinConfig);
ret |= imu.mapInterruptToPin(BMI2_ANY_MOTION_INT, BMI2_INT1);
if (!ret) {
Serial.println("BMI270 AnyMotionInterrupt enabled successfully");
} else {
Serial.println("Failed to enable BMI270 AnyMotionInterrupt");
}
M5.Display.fillScreen(TFT_BLACK);
M5.Display.drawRect(0, 0, 16, 16, TFT_WHITE);
M5.Display.fillRect(5, 5, 6, 6, TFT_WHITE);
M5.Display.display();
delay(1000);
// Shutdown
pm1.setLdoEnable(true);
pm1.ldoSetPowerHold(true);
pm1.setLedEnLevel(true);
pm1.shutdown();
}
}例程效果演示:
M5PM1 的 G3 IRQ 引脚在电路上连接到了 ESP32-C61 的 G2 上,可以通过链式的唤醒信号实现 ESP32-C61 唤醒,实现步骤如下:
案例说明:设备开机后,单击按键 A(KEY1)配置 IMU 中断模式并注册 ESP32-C61 G2 下降沿中断。翻转或移动设备即可触发 GPIO 中断处理函数,点阵图案由待触发状态变为已触发状态。再次单击按键 A 可清除 M5PM1 IRQ 标志位并重新测试;若启用代码中注释的深度休眠部分,运动后会唤醒 ESP32-C61 并从 setup() 重新运行。
#include <M5Unified.h>
#include <M5PM1.h>
#include <Wire.h>
#include "SparkFun_BMI270_Arduino_Library.h"
#include "driver/rtc_io.h"
BMI270 imu;
M5PM1 pm1;
void setup(void)
{
M5.begin();
Serial.begin(115200);
Wire.setPins(M5.getPin(m5::pin_name_t::in_i2c_sda), M5.getPin(m5::pin_name_t::in_i2c_scl));
// Initialize PM1
m5pm1_err_t err = pm1.begin(&M5.In_I2C, M5PM1_DEFAULT_ADDR, M5PM1_I2C_FREQ_100K);
if (err == M5PM1_OK) {
Serial.println("PM1 initialization successful");
pm1.irqClearGpioAll();
pm1.irqClearSysAll();
pm1.irqClearBtnAll();
pm1.irqSetGpioMaskAll(M5PM1_IRQ_MASK_ENABLE);
pm1.irqSetSysMaskAll(M5PM1_IRQ_MASK_ENABLE);
pm1.irqSetBtnMaskAll(M5PM1_IRQ_MASK_ENABLE);
pm1.irqSetGpioMask(M5PM1_IRQ_GPIO4, M5PM1_IRQ_MASK_DISABLE);
pm1.gpioSetMode(M5PM1_GPIO_NUM_4, M5PM1_GPIO_MODE_INPUT);
pm1.gpioSetPull(M5PM1_GPIO_NUM_4, M5PM1_GPIO_PULL_UP);
pm1.gpioSetMode(M5PM1_GPIO_NUM_3, M5PM1_GPIO_MODE_OUTPUT);
pm1.gpioSetDrive(M5PM1_GPIO_NUM_3, M5PM1_GPIO_DRIVE_PUSHPULL);
pm1.gpioSetPull(M5PM1_GPIO_NUM_3, M5PM1_GPIO_PULL_UP);
pm1.gpioSetOutput(M5PM1_GPIO_NUM_3, true);
pm1.gpioSetFunc(M5PM1_GPIO_NUM_3, M5PM1_GPIO_FUNC_IRQ);
} else {
Serial.printf("PM1 initialization failed, error code: %d\n", err);
}
// Check if sensor is connected and initialize
// Address defaults to 0x68
while(imu.beginI2C(BMI2_I2C_PRIM_ADDR, Wire) != BMI2_OK)
{
Serial.println("Error: BMI270 not connected, check wiring and I2C address!");
delay(1000);
}
imu.disableFeature(BMI2_ANY_MOTION);
Serial.println("BMI270 initialization successful");
M5.Display.setColorDepth(8);
M5.Display.setRotation(1);
M5.Display.setBrightness(128);
M5.Display.fillScreen(TFT_BLACK);
M5.Display.drawRect(0, 0, 16, 16, TFT_WHITE);
M5.Display.fillRect(7, 7, 2, 2, TFT_WHITE);
M5.Display.display();
}
volatile bool pm1IrqTriggered = false;
void ARDUINO_ISR_ATTR pm1_irq_handler()
{
pm1IrqTriggered = true;
}
void loop(void)
{
M5.update();
if (pm1IrqTriggered) {
pm1IrqTriggered = false;
uint16_t status = 0;
imu.getInterruptStatus(&status);
Serial.printf("BMI270 interrupt status: 0x%04X\n", status);
M5.Display.fillScreen(TFT_BLACK);
M5.Display.drawRect(0, 0, 16, 16, TFT_WHITE);
M5.Display.fillRect(4, 4, 8, 8, TFT_WHITE);
M5.Display.display();
}
if (M5.BtnA.wasPressed()) {
pm1.irqClearGpioAll();
pm1.irqClearSysAll();
pm1.irqClearBtnAll();
int8_t ret = imu.enableFeature(BMI2_ANY_MOTION);
// Optional
// bmi2_sens_config config;
// config.type = BMI2_ANY_MOTION;
// ret |= imu.getConfig(&config);
// config.cfg.any_motion.threshold = 0xE0; // 1LSB equals to 0.48mg. Default is 83mg. Lower is more sensitive
// config.cfg.any_motion.duration = 0x0A; // 1LSB equals 20ms. Default is 100ms.
// ret |= imu.setConfig(config);
bmi2_int_pin_config intPinConfig;
intPinConfig.pin_type = BMI2_INT1;
intPinConfig.int_latch = BMI2_INT_NON_LATCH;
intPinConfig.pin_cfg[0].lvl = BMI2_INT_ACTIVE_LOW; // Active low
intPinConfig.pin_cfg[0].od = BMI2_INT_PUSH_PULL;
intPinConfig.pin_cfg[0].output_en = BMI2_INT_OUTPUT_ENABLE;
intPinConfig.pin_cfg[0].input_en = BMI2_INT_INPUT_DISABLE;
ret |= imu.setInterruptPinConfig(intPinConfig);
ret |= imu.mapInterruptToPin(BMI2_ANY_MOTION_INT, BMI2_INT1);
if (!ret) {
Serial.println("BMI270 AnyMotionInterrupt enabled successfully");
} else {
Serial.println("Failed to enable BMI270 AnyMotionInterrupt");
}
M5.Display.fillScreen(TFT_BLACK);
M5.Display.drawRect(0, 0, 16, 16, TFT_WHITE);
M5.Display.fillRect(5, 5, 6, 6, TFT_WHITE);
M5.Display.display();
// Choose either of the two pieces of code below.
pinMode(GPIO_NUM_2, INPUT_PULLUP);
attachInterrupt(GPIO_NUM_2, pm1_irq_handler, FALLING);
// esp_sleep_enable_ext1_wakeup(1ULL << GPIO_NUM_2, ESP_EXT1_WAKEUP_ANY_LOW);
// rtc_gpio_pullup_en(GPIO_NUM_2);
// Serial.println("Going to sleep now");
// esp_deep_sleep_start();
}
}例程效果演示:
电源切换至 L1 Mode,CoreMatrix 的 KEY1~KEY3 按键上拉和 M5PM1 处于供电状态。在配置 KEY3 唤醒功能后,M5PM1 进入休眠状态,同时保持 L1 的输出供电 (3V3_L1_EN),用于维持按键上拉和唤醒逻辑工作。
此时可通过按下 KEY3,触发 M5PM1 G2 下降沿唤醒信号,唤醒 M5PM1 重新启动。
M5PM1 唤醒后将重新运行 L0、L1 和 L3A 上电流程。ESP32-C61 重新执行初始化。
案例说明:设备开机后,单击按键 B(KEY2)配置 KEY3 唤醒与 M5PM1 L1 电源保持,M5PM1 进入休眠。此时按下 KEY3 即可触发 M5PM1 唤醒,ESP32-C61 重新上电。
#include <M5PM1.h>
#include <M5Unified.h>
M5PM1 pm1;
void setup(void)
{
M5.begin();
Serial.begin(115200);
if (pm1.begin(&M5.In_I2C, M5PM1_DEFAULT_ADDR, M5PM1_I2C_FREQ_100K) != M5PM1_OK) {
Serial.println("PM1 initialization failed");
while (true) {
delay(1000);
}
}
Serial.println("PM1 initialization successful");
M5.Display.setColorDepth(8);
M5.Display.setRotation(1);
M5.Display.setBrightness(128);
M5.Display.fillScreen(TFT_BLACK);
M5.Display.drawRect(0, 0, 16, 16, TFT_WHITE);
M5.Display.fillRect(7, 7, 2, 2, TFT_WHITE);
M5.Display.display();
pm1.gpioSetWakeEdge(M5PM1_GPIO_NUM_2, M5PM1_GPIO_WAKE_FALLING);
pm1.gpioSetWakeEnable(M5PM1_GPIO_NUM_2, true);
pm1.setLdoEnable(true);
pm1.ldoSetPowerHold(true);
}
void loop(void)
{
M5.update();
if (M5.BtnB.wasPressed()) {
M5.Display.fillScreen(TFT_BLACK);
M5.Display.drawRect(0, 0, 16, 16, TFT_WHITE);
M5.Display.fillRect(5, 5, 6, 6, TFT_WHITE);
M5.Display.display();
Serial.println("KEY3 wakeup enabled");
delay(1000);
// Shutdown
pm1.setLedEnLevel(true);
pm1.shutdown();
}
}例程效果演示:
M5PM1 的 G3 IRQ 引脚在电路上连接到了 ESP32-C61 的 G2 上,可以通过链式的唤醒信号实现 ESP32-C61 唤醒,实现步骤如下:
案例说明:设备开机后,单击按键 B(KEY2)配置 KEY3 对应的 M5PM1 G2 中断并注册 ESP32-C61 G2 下降沿中断。按下 KEY3 即可触发 GPIO 中断处理函数,点阵图案由待触发状态变为已触发状态。再次单击按键 B 可清除 M5PM1 IRQ 标志位并重新测试;若启用代码中注释的深度休眠部分,按下 KEY3 后会唤醒 ESP32-C61 并从 setup() 重新运行。
#include <M5Unified.h>
#include <M5PM1.h>
#include "driver/rtc_io.h"
M5PM1 pm1;
void setup(void)
{
M5.begin();
Serial.begin(115200);
// Initialize PM1
m5pm1_err_t err = pm1.begin(&M5.In_I2C, M5PM1_DEFAULT_ADDR, M5PM1_I2C_FREQ_100K);
if (err == M5PM1_OK) {
Serial.println("PM1 initialization successful");
pm1.irqClearGpioAll();
pm1.irqClearSysAll();
pm1.irqClearBtnAll();
pm1.irqSetGpioMaskAll(M5PM1_IRQ_MASK_ENABLE);
pm1.irqSetSysMaskAll(M5PM1_IRQ_MASK_ENABLE);
pm1.irqSetBtnMaskAll(M5PM1_IRQ_MASK_ENABLE);
pm1.irqSetGpioMask(M5PM1_IRQ_GPIO2, M5PM1_IRQ_MASK_DISABLE);
pm1.gpioSetMode(M5PM1_GPIO_NUM_2, M5PM1_GPIO_MODE_INPUT);
pm1.gpioSetPull(M5PM1_GPIO_NUM_2, M5PM1_GPIO_PULL_UP);
pm1.gpioSetMode(M5PM1_GPIO_NUM_3, M5PM1_GPIO_MODE_OUTPUT);
pm1.gpioSetDrive(M5PM1_GPIO_NUM_3, M5PM1_GPIO_DRIVE_PUSHPULL);
pm1.gpioSetPull(M5PM1_GPIO_NUM_3, M5PM1_GPIO_PULL_UP);
pm1.gpioSetOutput(M5PM1_GPIO_NUM_3, true);
pm1.gpioSetFunc(M5PM1_GPIO_NUM_3, M5PM1_GPIO_FUNC_IRQ);
} else {
Serial.printf("PM1 initialization failed, error code: %d\n", err);
}
M5.Display.setColorDepth(8);
M5.Display.setRotation(1);
M5.Display.setBrightness(128);
M5.Display.fillScreen(TFT_BLACK);
M5.Display.drawRect(0, 0, 16, 16, TFT_WHITE);
M5.Display.fillRect(7, 7, 2, 2, TFT_WHITE);
M5.Display.display();
}
volatile bool pm1IrqTriggered = false;
void ARDUINO_ISR_ATTR pm1_irq_handler()
{
pm1IrqTriggered = true;
}
void loop(void)
{
M5.update();
if (pm1IrqTriggered) {
pm1IrqTriggered = false;
Serial.println("PM1 IRQ triggered");
M5.Display.fillScreen(TFT_BLACK);
M5.Display.drawRect(0, 0, 16, 16, TFT_WHITE);
M5.Display.fillRect(4, 4, 8, 8, TFT_WHITE);
M5.Display.display();
}
if (M5.BtnB.wasPressed()) {
pm1.irqClearGpioAll();
pm1.irqClearSysAll();
pm1.irqClearBtnAll();
Serial.println("KEY3 IRQ enabled successfully");
M5.Display.fillScreen(TFT_BLACK);
M5.Display.drawRect(0, 0, 16, 16, TFT_WHITE);
M5.Display.fillRect(5, 5, 6, 6, TFT_WHITE);
M5.Display.display();
// Choose either of the two pieces of code below.
pinMode(GPIO_NUM_2, INPUT_PULLUP);
attachInterrupt(GPIO_NUM_2, pm1_irq_handler, FALLING);
// esp_sleep_enable_ext1_wakeup(1ULL << GPIO_NUM_2, ESP_EXT1_WAKEUP_ANY_LOW);
// rtc_gpio_pullup_en(GPIO_NUM_2);
// Serial.println("Going to sleep now");
// esp_deep_sleep_start();
}
}例程效果演示:
CoreMatrix 的 M5IOE1 负责 L3B 级外设的电源使能和状态读取。通过 M5IOE1 API 可以独立控制 LED 点阵、microSD、蜂鸣器和 Grove 5V,并读取充电与插卡状态。
| M5IOE1 引脚 | CoreMatrix 功能 |
|---|---|
PYG1 | microSD 电源使能 |
PYG2 | 蜂鸣器电源使能 |
PYG3 | 充电电流档位 |
PYG4 | LED 点阵电源使能 |
PYG5 | Grove 5V 输出使能 |
PYG8 | 充电状态输入 |
PYG10 | microSD 检测输入 |
PYG11 | 蜂鸣器 PWM 输出 |
下面示例直接初始化 M5IOE1,开启 LED 点阵、microSD 和 Grove 5V 电源,关闭蜂鸣器电源,并读取充电状态与 microSD 检测状态。
#include <M5Unified.h>
#include <M5IOE1.h>
M5IOE1 ioe1;
#define IOE_TF_EN M5IOE1_PIN_1
#define IOE_BUZZER_EN M5IOE1_PIN_2
#define IOE_LEDS_EN M5IOE1_PIN_4
#define IOE_GROVE_EN M5IOE1_PIN_5
#define IOE_CHG_STAT M5IOE1_PIN_8
#define IOE_TF_DET M5IOE1_PIN_10
void setup()
{
auto cfg = M5.config();
cfg.serial_baudrate = 115200;
M5.begin(cfg);
M5.Display.setColorDepth(8);
M5.Display.setRotation(1);
M5.Display.setBrightness(128);
const m5ioe1_err_t err = ioe1.begin(&M5.In_I2C, M5IOE1_DEFAULT_ADDR_2, M5IOE1_I2C_FREQ_100K);
if (err != M5IOE1_OK) {
Serial.printf("M5IOE1 init failed: %d\n", err);
while (true) delay(1000);
}
ioe1.pinMode(IOE_TF_EN, OUTPUT);
ioe1.pinMode(IOE_BUZZER_EN, OUTPUT);
ioe1.pinMode(IOE_LEDS_EN, OUTPUT);
ioe1.pinMode(IOE_GROVE_EN, OUTPUT);
ioe1.pinMode(IOE_CHG_STAT, INPUT);
ioe1.pinMode(IOE_TF_DET, INPUT_PULLUP);
ioe1.digitalWrite(IOE_TF_EN, HIGH);
ioe1.digitalWrite(IOE_LEDS_EN, HIGH);
ioe1.digitalWrite(IOE_GROVE_EN, HIGH);
ioe1.digitalWrite(IOE_BUZZER_EN, LOW);
Serial.println("CoreMatrix L3B rails enabled");
}
void loop()
{
M5.update();
const int chargeState = ioe1.digitalRead(IOE_CHG_STAT);
const int tfState = ioe1.digitalRead(IOE_TF_DET);
Serial.printf("CHG_STAT: %d, TF_DET: %d\n", chargeState, tfState);
delay(1000);
}成功烧录后,程序会每秒通过串口输出 CHG_STAT 和 TF_DET 状态。CHG_STAT 为低电平时表示正在充电,TF_DET 为低电平时表示已插入 microSD 卡。