1. Optimize language and format

This commit is contained in:
onexs-xsi
2026-01-07 14:11:02 +08:00
parent ea07b03857
commit 9876821cd8
5 changed files with 597 additions and 276 deletions
@@ -5,51 +5,63 @@
*/
/*
* M5IOE1 硬件中断示例
* M5IOE1 Hardware Interrupt Example
*
* 本示例演示如何使用 M5IOE1 库的硬件中断模式
* This example demonstrates how to use the M5IOE1 library in HARDWARE
* interrupt mode with a physical INT pin connected to GPIO1 of the host MCU.
*
* 硬件连接
* Hardware Connections:
* - M5IOE1 SDA -> GPIO 38 (default, configurable)
* - M5IOE1 SCL -> GPIO 39 (default, configurable)
* - M5IOE1 INT -> GPIO 1 (host MCU interrupt pin)
* - IO1 (M5IOE1) -> Button or switch (connect to GND for active LOW)
* - M5IOE1 SDA -> GPIO 38 (默认,可配置) (default, configurable)
* - M5IOE1 SCL -> GPIO 39 (默认,可配置) (default, configurable)
* - M5IOE1 INT -> GPIO 1 (主机 MCU 中断引脚) (host MCU interrupt pin)
* - IO1 (M5IOE1) -> 按钮或开关 (连接到 GND 为低电平有效) (Button or switch, connect to GND for active LOW)
*
* 演示功能
* Features demonstrated:
* - Initializing M5IOE1 with hardware interrupt pin (INT_PIN)
* - Using HARDWARE interrupt mode for instant response
* - Attaching multiple interrupt callbacks to different pins
* - Using attachInterruptArg() for callback with custom data
* - Interrupt enable/disable control
* - Reading interrupt status registers
* - 使用硬件中断引脚初始化 M5IOE1 (INT_PIN) (Initializing M5IOE1 with hardware interrupt pin)
* - 使用硬件中断模式实现即时响应 (Using HARDWARE interrupt mode for instant response)
* - 为不同引脚附加多个中断回调 (Attaching multiple interrupt callbacks to different pins)
* - 使用 attachInterruptArg() 进行带自定义数据的回调 (Using attachInterruptArg() for callback with custom data)
* - 中断启用/禁用控制 (Interrupt enable/disable control)
* - 读取中断状态寄存器 (Reading interrupt status registers)
*/
#include <M5IOE1.h>
// M5IOE1 设备实例
// M5IOE1 device instance
M5IOE1 ioe1;
// I2C 配置
// I2C configuration
#define I2C_SDA_PIN 38
#define I2C_SCL_PIN 39
#define I2C_FREQ 400000
// 主机 MCU 上的物理中断引脚 (默认为 GPIO1)
// Physical interrupt pin on host MCU (GPIO1 as default)
// 将此引脚连接到 M5IOE1 的 INT 引脚
// Connect this pin to M5IOE1's INT pin
#define INT_PIN 1
// M5IOE1 I2C 地址 (默认 0x6F)
// M5IOE1 I2C address (default 0x6F)
#define I2C_ADDR M5IOE1_DEFAULT_ADDR
// M5IOE1 GPIO 引脚定义
// Pin definitions for M5IOE1 GPIOs
#define IOE1_PIN_1 M5IOE1_PIN_1 // IO1 on M5IOE1 (pin index 0)
#define IOE1_PIN_2 M5IOE1_PIN_2 // IO2 on M5IOE1 (pin index 1)
#define IOE1_PIN_1 M5IOE1_PIN_1 // M5IOE1 上的 IO1 (引脚索引 0) (IO1 on M5IOE1, pin index 0)
#define IOE1_PIN_2 M5IOE1_PIN_2 // M5IOE1 上的 IO2 (引脚索引 1) (IO2 on M5IOE1, pin index 1)
// 中断事件计数器
// Counter for interrupt events
volatile int pin1Counter = 0;
volatile int pin2Counter = 0;
// 用于带参数回调的自定义数据结构
// Custom data structure for callback with argument
struct ButtonData {
const char* name;
@@ -60,17 +72,21 @@ struct ButtonData {
ButtonData button1Data = {"Button 1", &pin1Counter, IOE1_PIN_1};
ButtonData button2Data = {"Button 2", &pin2Counter, IOE1_PIN_2};
// 引脚 1 的简单回调 (无参数)
// Simple callback for pin 1 (without argument)
void IRAM_ATTR pin1Callback() {
pin1Counter++;
}
// 引脚 2 的带自定义数据参数的回调
// Callback with custom data argument for pin 2
void IRAM_ATTR pin2CallbackWithArg(void* arg) {
ButtonData* data = static_cast<ButtonData*>(arg);
if (data) {
(*(data->counter))++;
// 注意:避免在 ISR 上下文中使用 Serial 打印
// Note: Avoid Serial prints in ISR context
// 这仅用于演示 - 在实际应用中,使用标志并在 loop 中处理
// This is just demonstration - in real apps, use flags and handle in loop
}
}
@@ -83,10 +99,13 @@ void setup() {
Serial.println("M5IOE1 Hardware Interrupt Example");
Serial.println("========================================\n");
// 设置日志级别为 INFO
// Set log level to INFO
M5IOE1::setLogLevel(M5IOE1_LOG_LEVEL_INFO);
// 使用硬件中断引脚初始化 M5IOE1
// Initialize M5IOE1 with hardware interrupt pin
// 当提供 intPin 时,硬件中断是默认且最高效的模式
// When intPin is provided, HARDWARE mode is the default and most efficient
Serial.println("Initializing M5IOE1 in HARDWARE interrupt mode...");
Serial.println(" I2C: SDA=" + String(I2C_SDA_PIN) + ", SCL=" + String(I2C_SCL_PIN));
@@ -105,6 +124,7 @@ void setup() {
Serial.println("M5IOE1 initialized successfully!\n");
// 读取并显示设备信息
// Read and display device information
uint16_t uid;
uint8_t version;
@@ -124,17 +144,20 @@ void setup() {
Serial.println();
// 将 IO1 和 IO2 配置为带上拉电阻的输入
// Configure IO1 and IO2 as inputs with pull-up
Serial.println("Configuring IO1 and IO2 as inputs with internal pull-up...");
ioe1.pinMode(IOE1_PIN_1, INPUT_PULLUP);
ioe1.pinMode(IOE1_PIN_2, INPUT_PULLUP);
Serial.println("Pins configured successfully!\n");
// 为引脚 1 附加下降沿触发的中断 (简单回调)
// Attach interrupt to pin 1 with FALLING edge trigger (simple callback)
Serial.println("Attaching FALLING edge interrupt to IO1...");
ioe1.attachInterrupt(IOE1_PIN_1, pin1Callback, FALLING);
Serial.println("IO1 interrupt attached (simple callback)!\n");
// 为引脚 2 附加上升沿触发的中断 (带参数的回调)
// Attach interrupt to pin 2 with RISING edge trigger (callback with argument)
Serial.println("Attaching RISING edge interrupt to IO2...");
ioe1.attachInterruptArg(IOE1_PIN_2, pin2CallbackWithArg, &button2Data, RISING);
@@ -157,24 +180,29 @@ void setup() {
}
void loop() {
// 存储当前计数器值以检测变化
// Store current counter values to detect changes
static int lastPin1Counter = 0;
static int lastPin2Counter = 0;
// 检查引脚 1 中断计数器是否发生变化
// Check if pin 1 interrupt counter changed
if (pin1Counter != lastPin1Counter) {
Serial.println(">>> IO1 INTERRUPT TRIGGERED! <<<");
Serial.println(" Count: " + String(pin1Counter));
Serial.println(" Edge: FALLING");
// 读取 IO1 的当前状态
// Read current state of IO1
int pinState = ioe1.digitalRead(IOE1_PIN_1);
Serial.println(" IO1 state: " + String(pinState == LOW ? "LOW" : "HIGH"));
// 读取并显示中断状态寄存器
// Read and display interrupt status register
uint16_t status = ioe1.getInterruptStatus();
Serial.println(" INT status: 0b" + String(status, BIN));
// 清除此引脚的中断
// Clear the interrupt for this pin
ioe1.clearInterrupt(IOE1_PIN_1);
Serial.println(" Interrupt cleared\n");
@@ -182,6 +210,7 @@ void loop() {
lastPin1Counter = pin1Counter;
}
// 检查引脚 2 中断计数器是否发生变化
// Check if pin 2 interrupt counter changed
if (pin2Counter != lastPin2Counter) {
Serial.println(">>> IO2 INTERRUPT TRIGGERED! <<<");
@@ -189,14 +218,17 @@ void loop() {
Serial.println(" Edge: RISING");
Serial.println(" Callback: with argument (ButtonData)");
// 读取 IO2 的当前状态
// Read current state of IO2
int pinState = ioe1.digitalRead(IOE1_PIN_2);
Serial.println(" IO2 state: " + String(pinState == HIGH ? "HIGH" : "LOW"));
// 读取并显示中断状态寄存器
// Read and display interrupt status register
uint16_t status = ioe1.getInterruptStatus();
Serial.println(" INT status: 0b" + String(status, BIN));
// 清除此引脚的中断
// Clear the interrupt for this pin
ioe1.clearInterrupt(IOE1_PIN_2);
Serial.println(" Interrupt cleared\n");
@@ -204,18 +236,23 @@ void loop() {
lastPin2Counter = pin2Counter;
}
// 处理串口命令
// Handle serial commands
if (Serial.available() > 0) {
char cmd = Serial.read();
switch (cmd) {
case 'e':
// 启用 IO1 上的中断
// Enable interrupts on IO1
Serial.println("Enabling interrupts on IO1...");
ioe1.enableInterrupt(IOE1_PIN_1);
Serial.println("IO1 interrupts enabled\n");
break;
case 'd':
// 禁用 IO1 上的中断
// Disable interrupts on IO1
Serial.println("Disabling interrupts on IO1...");
ioe1.disableInterrupt(IOE1_PIN_1);
Serial.println("IO1 interrupts disabled\n");
@@ -223,6 +260,8 @@ void loop() {
case 's':
{
// 显示中断状态
// Show interrupt status
uint16_t status = ioe1.getInterruptStatus();
Serial.println("Interrupt Status:");
Serial.println(" Register: 0b" + String(status, BIN));
@@ -234,6 +273,8 @@ void loop() {
break;
case 'c':
// 清除所有中断标志
// Clear all interrupt flags
Serial.println("Clearing all interrupt flags...");
for (uint8_t i = 0; i < 14; i++) {
ioe1.clearInterrupt(i);
@@ -243,6 +284,7 @@ void loop() {
case '\n':
case '\r':
// 忽略换行符
// Ignore newlines
break;
@@ -253,5 +295,5 @@ void loop() {
}
}
delay(10); // Small delay
delay(10); // 小延迟 / Small delay
}
@@ -5,44 +5,54 @@
*/
/*
* M5IOE1 轮询中断示例
* M5IOE1 Interrupt Polling Example
*
* 本示例演示如何在没有物理中断引脚的情况下,以轮询模式使用 M5IOE1 库
* This example demonstrates how to use the M5IOE1 library in POLLING mode
* without a physical interrupt pin. The library periodically polls the
* interrupt status registers to detect GPIO changes.
*
* 硬件连接
* Hardware Connections:
* - M5IOE1 SDA -> GPIO 38 (default, configurable)
* - M5IOE1 SCL -> GPIO 39 (default, configurable)
* - IO1 (M5IOE1) -> Button or switch (connect to GND for active LOW)
* - M5IOE1 SDA -> GPIO 38 (默认,可配置) (default, configurable)
* - M5IOE1 SCL -> GPIO 39 (默认,可配置) (default, configurable)
* - IO1 (M5IOE1) -> 按钮或开关 (连接到 GND 为低电平有效) (Button or switch, connect to GND for active LOW)
*
* 演示功能
* Features demonstrated:
* - Initializing M5IOE1 in polling mode (no INT pin)
* - Attaching interrupt callback to pin 1 (IO1) with FALLING edge trigger
* - Reading device information (UID, version)
* - Using attachInterrupt() callback for event handling
* - Polling interval configuration
* - 以轮询模式初始化 M5IOE1 (无 INT 引脚) (Initializing M5IOE1 in polling mode, no INT pin)
* - 为引脚 1 (IO1) 附加下降沿触发的中断回调 (Attaching interrupt callback to pin 1 with FALLING edge)
* - 读取设备信息 (UID、版本) (Reading device information: UID, version)
* - 使用 attachInterrupt() 回调进行事件处理 (Using attachInterrupt() callback for event handling)
* - 轮询间隔配置 (Polling interval configuration)
*/
#include <M5IOE1.h>
// M5IOE1 设备实例
// M5IOE1 device instance
M5IOE1 ioe1;
// I2C 配置
// I2C configuration
#define I2C_SDA_PIN 38
#define I2C_SCL_PIN 39
#define I2C_FREQ 400000
// M5IOE1 I2C 地址 (默认 0x6F)
// M5IOE1 I2C address (default 0x6F)
#define I2C_ADDR M5IOE1_DEFAULT_ADDR
// 引脚定义
// Pin definitions
#define IOE1_PIN_1 M5IOE1_PIN_1 // IO1 on M5IOE1 (pin index 0)
#define IOE1_PIN_1 M5IOE1_PIN_1 // M5IOE1 上的 IO1 (引脚索引 0) (IO1 on M5IOE1, pin index 0)
// 中断事件计数器
// Counter for interrupt events
volatile int interruptCounter = 0;
// 引脚 1 下降沿中断的回调函数
// Callback function for pin 1 falling edge interrupt
void IRAM_ATTR pin1FallingCallback() {
interruptCounter++;
@@ -56,10 +66,13 @@ void setup() {
Serial.println("M5IOE1 Interrupt Polling Example");
Serial.println("========================================\n");
// 设置日志级别为 INFO (默认)
// Set log level to INFO (default)
M5IOE1::setLogLevel(M5IOE1_LOG_LEVEL_INFO);
// 以轮询模式初始化 M5IOE1 (无物理 INT 引脚)
// Initialize M5IOE1 in POLLING mode (no physical INT pin)
// 当未提供 intPin (或设置为 -1) 时,仅支持轮询和禁用模式
// When intPin is not provided (or set to -1), only POLLING and DISABLED modes are supported
Serial.println("Initializing M5IOE1 in polling mode...");
@@ -74,6 +87,7 @@ void setup() {
Serial.println("M5IOE1 initialized successfully!\n");
// 读取并显示设备信息
// Read and display device information
uint16_t uid;
uint8_t version;
@@ -93,19 +107,24 @@ void setup() {
Serial.println();
// 将 IO1 配置为带上拉电阻的输入
// Configure IO1 as input with pull-up
Serial.println("Configuring IO1 as input with internal pull-up...");
ioe1.pinMode(IOE1_PIN_1, INPUT_PULLUP);
Serial.println("IO1 configured successfully!\n");
// 为引脚 1 附加下降沿触发的中断
// Attach interrupt to pin 1 with FALLING edge trigger
// 在轮询模式下,库会定期检查中断状态,并在 IO1 上检测到下降沿时调用此回调
// In polling mode, the library will periodically check the interrupt status
// and call this callback when a falling edge is detected on IO1
Serial.println("Attaching interrupt callback to IO1 (FALLING edge)...");
ioe1.attachInterrupt(IOE1_PIN_1, pin1FallingCallback, FALLING);
Serial.println("Interrupt attached successfully!\n");
// 设置轮询间隔为 1 秒 (1000ms)
// Set polling interval to 1 second (1000ms)
// 默认为 5000ms。更短的间隔 = 更快的响应,但 CPU 使用率更高。
// Default is 5000ms. Shorter intervals = faster response but more CPU usage.
Serial.println("Setting polling interval to 1.0 second...");
if (ioe1.setPollingInterval(1.0f)) {
@@ -126,32 +145,40 @@ void setup() {
}
void loop() {
// 存储当前计数器值以检测变化
// Store current counter value to detect changes
static int lastCounter = 0;
// 检查中断计数器是否发生变化
// Check if interrupt counter changed
if (interruptCounter != lastCounter) {
Serial.println(">>> INTERRUPT TRIGGERED! Count: " + String(interruptCounter) + " <<<");
lastCounter = interruptCounter;
// 读取 IO1 的当前状态
// Read current state of IO1
int pinState = ioe1.digitalRead(IOE1_PIN_1);
Serial.println(" IO1 state: " + String(pinState == LOW ? "LOW (pressed)" : "HIGH (released)"));
// 读取并显示中断状态寄存器
// Read and display interrupt status register
uint16_t status = ioe1.getInterruptStatus();
Serial.println(" Interrupt status register: 0b" + String(status, BIN) + "\n");
// 清除此引脚的中断
// Clear the interrupt for this pin
ioe1.clearInterrupt(IOE1_PIN_1);
}
// 可选:手动轮询检查 (库会在后台自动执行此操作)
// Optional: Manual polling check (the library does this automatically in background)
// 这仅用于演示 - 库会自动处理轮询
// This is just for demonstration - the library handles polling automatically
static unsigned long lastStatusCheck = 0;
if (millis() - lastStatusCheck > 5000) {
lastStatusCheck = millis();
// 显示当前轮询模式信息
// Display current polling mode info
Serial.println("--- Status Update ---");
Serial.println(" Total interrupts: " + String(interruptCounter));
@@ -159,5 +186,5 @@ void loop() {
Serial.println(" Polling mode: ACTIVE (background task)\n");
}
delay(100); // Small delay to prevent excessive CPU usage
delay(100); // 小延迟以防止过度的 CPU 使用 / Small delay to prevent excessive CPU usage
}
+259 -130
View File
File diff suppressed because it is too large Load Diff
+216 -108
View File
File diff suppressed because it is too large Load Diff
+30 -15
View File
@@ -16,7 +16,8 @@
#include "Wire.h"
// ============================
// Arduino I2C 功能 / Arduino I2C Functions
// Arduino I2C 功能
// Arduino I2C Functions
// ============================
#ifndef M5IOE1_I2C_READ_BYTE
@@ -57,7 +58,8 @@ static inline bool M5IOE1_I2C_READ_REG16(TwoWire *wire, uint8_t addr, uint8_t re
if (!M5IOE1_I2C_READ_BYTES(wire, addr, reg, 2, buf)) {
return false;
}
// 小端模式:低字节在前 / Little-endian: low byte first
// 小端模式:低字节在前
// Little-endian: low byte first
*data = (uint16_t)buf[0] | ((uint16_t)buf[1] << 8);
return true;
}
@@ -92,7 +94,8 @@ static inline bool M5IOE1_I2C_WRITE_BYTES(TwoWire *wire, uint8_t addr, uint8_t s
#ifndef M5IOE1_I2C_WRITE_REG16
static inline bool M5IOE1_I2C_WRITE_REG16(TwoWire *wire, uint8_t addr, uint8_t reg, uint16_t data) {
uint8_t buf[2];
// 小端模式:低字节在前 / Little-endian: low byte first
// 小端模式:低字节在前
// Little-endian: low byte first
buf[0] = (uint8_t)(data & 0xFF);
buf[1] = (uint8_t)((data >> 8) & 0xFF);
return M5IOE1_I2C_WRITE_BYTES(wire, addr, reg, 2, buf);
@@ -110,17 +113,23 @@ extern "C" {
#endif
// ============================
// I2C 驱动类型选择 / I2C Driver Type Selection
// I2C 驱动类型选择
// I2C Driver Type Selection
// ============================
typedef enum {
M5IOE1_I2C_DRIVER_NONE = 0, // 未初始化 / Not initialized
M5IOE1_I2C_DRIVER_SELF_CREATED, // 使用 i2c_port_t 自创建 / Self-created using i2c_port_t
M5IOE1_I2C_DRIVER_MASTER, // ESP-IDF 原生 i2c_master 驱动 / ESP-IDF native i2c_master driver
M5IOE1_I2C_DRIVER_BUS // esp-idf-lib i2c_bus 组件 / esp-idf-lib i2c_bus component
M5IOE1_I2C_DRIVER_NONE = 0, // 未初始化
// Not initialized
M5IOE1_I2C_DRIVER_SELF_CREATED, // 使用 i2c_port_t 自创建
// Self-created using i2c_port_t
M5IOE1_I2C_DRIVER_MASTER, // ESP-IDF 原生 i2c_master 驱动
// ESP-IDF native i2c_master driver
M5IOE1_I2C_DRIVER_BUS // esp-idf-lib i2c_bus 组件
// esp-idf-lib i2c_bus component
} m5ioe1_i2c_driver_t;
// ============================
// ESP-IDF I2C 函数 / ESP-IDF I2C Functions (i2c_bus)
// ESP-IDF I2C 函数 (i2c_bus)
// ESP-IDF I2C Functions (i2c_bus)
// ============================
#ifndef M5IOE1_I2C_READ_BYTE
@@ -140,7 +149,8 @@ static inline esp_err_t M5IOE1_I2C_READ_REG16(i2c_bus_device_handle_t dev, uint8
uint8_t buf[2];
esp_err_t ret = i2c_bus_read_bytes(dev, reg, 2, buf);
if (ret == ESP_OK) {
// 小端模式:低字节在前 / Little-endian: low byte first
// 小端模式:低字节在前
// Little-endian: low byte first
*data = (uint16_t)buf[0] | ((uint16_t)buf[1] << 8);
}
return ret;
@@ -162,7 +172,8 @@ static inline esp_err_t M5IOE1_I2C_WRITE_BYTES(i2c_bus_device_handle_t dev, uint
#ifndef M5IOE1_I2C_WRITE_REG16
static inline esp_err_t M5IOE1_I2C_WRITE_REG16(i2c_bus_device_handle_t dev, uint8_t reg, uint16_t data) {
uint8_t buf[2];
// 小端模式:低字节在前 / Little-endian: low byte first
// 小端模式:低字节在前
// Little-endian: low byte first
buf[0] = (uint8_t)(data & 0xFF);
buf[1] = (uint8_t)((data >> 8) & 0xFF);
return i2c_bus_write_bytes(dev, reg, 2, buf);
@@ -170,7 +181,8 @@ static inline esp_err_t M5IOE1_I2C_WRITE_REG16(i2c_bus_device_handle_t dev, uint
#endif
// ============================
// ESP-IDF I2C 函数 (i2c_master - 原生驱动) / ESP-IDF I2C Functions (i2c_master - native driver)
// ESP-IDF I2C 函数 (i2c_master - 原生驱动)
// ESP-IDF I2C Functions (i2c_master - native driver)
// ============================
#ifndef M5IOE1_I2C_MASTER_READ_BYTE
@@ -190,7 +202,8 @@ static inline esp_err_t M5IOE1_I2C_MASTER_READ_REG16(i2c_master_dev_handle_t dev
uint8_t buf[2];
esp_err_t ret = i2c_master_transmit_receive(dev, &reg, 1, buf, 2, -1);
if (ret == ESP_OK) {
// 小端模式:低字节在前 / Little-endian: low byte first
// 小端模式:低字节在前
// Little-endian: low byte first
*data = (uint16_t)buf[0] | ((uint16_t)buf[1] << 8);
}
return ret;
@@ -206,7 +219,8 @@ static inline esp_err_t M5IOE1_I2C_MASTER_WRITE_BYTE(i2c_master_dev_handle_t dev
#ifndef M5IOE1_I2C_MASTER_WRITE_BYTES
static inline esp_err_t M5IOE1_I2C_MASTER_WRITE_BYTES(i2c_master_dev_handle_t dev, uint8_t start_reg, size_t len, const uint8_t *data) {
// 需要在数据前添加寄存器地址 / Need to prepend register address
// 需要在数据前添加寄存器地址
// Need to prepend register address
uint8_t *buf = (uint8_t*)malloc(len + 1);
if (buf == NULL) return ESP_ERR_NO_MEM;
buf[0] = start_reg;
@@ -221,7 +235,8 @@ static inline esp_err_t M5IOE1_I2C_MASTER_WRITE_BYTES(i2c_master_dev_handle_t de
static inline esp_err_t M5IOE1_I2C_MASTER_WRITE_REG16(i2c_master_dev_handle_t dev, uint8_t reg, uint16_t data) {
uint8_t buf[3];
buf[0] = reg;
// 小端模式:低字节在前 / Little-endian: low byte first
// 小端模式:低字节在前
// Little-endian: low byte first
buf[1] = (uint8_t)(data & 0xFF);
buf[2] = (uint8_t)((data >> 8) & 0xFF);
return i2c_master_transmit(dev, buf, 3, -1);