Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions examples/Modules/StamPLC_IO/HotPlugDetection/HotPlugDetection.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*
* M5StamPLC IO Hot-Plug Detection Example
*
* This example demonstrates hot-plug detection for multiple M5StamPLC IO modules:
* - Automatically scan I2C bus and detect connected modules (0x20-0x2F)
* - Display online modules list
* - Real-time detection of module insertion and removal
*/
#include <Arduino.h>
#include <M5StamPLC.h>

#define MAX_MODULES 16
#define SCAN_INTERVAL_MS 2000

struct ModuleInfo {
uint8_t address;
uint8_t firmware_version;
bool connected;
};

ModuleInfo modules[MAX_MODULES];
uint8_t module_count = 0;
unsigned long last_scan_time = 0;

void initModules()
{
for (int i = 0; i < MAX_MODULES; i++) {
modules[i].address = M5StamPLC_IO::I2C_ADDR_MIN + i;
modules[i].firmware_version = 0;
modules[i].connected = false;
}
module_count = 0;
}

void scanModules()
{
bool found_map[0x80] = {false};
m5::In_I2C.scanID(found_map);

for (int i = 0; i < MAX_MODULES; i++) {
uint8_t addr = M5StamPLC_IO::I2C_ADDR_MIN + i;
if (found_map[addr] && !modules[i].connected) {
M5StamPLC_IO temp_device;
if (temp_device.begin(addr, false)) {
modules[i].address = addr;
modules[i].firmware_version = temp_device.getFirmwareVersion();
modules[i].connected = true;
module_count++;
Serial.printf("[+] Module connected: 0x%02X (FW: 0x%02X)\n", addr, modules[i].firmware_version);
}
} else if (!found_map[addr] && modules[i].connected) {
Serial.printf("[-] Module disconnected: 0x%02X\n", modules[i].address);
modules[i].connected = false;
module_count--;
}
}
}

void displayModules()
{
M5StamPLC.Display.fillScreen(TFT_BLACK);
M5StamPLC.Display.setCursor(0, 0);

M5StamPLC.Display.setTextColor(TFT_GREENYELLOW);
M5StamPLC.Display.println("=== IO Hot-Plug ===");

M5StamPLC.Display.setTextColor(TFT_CYAN);
M5StamPLC.Display.printf("Online: %d\n\n", module_count);

if (module_count == 0) {
M5StamPLC.Display.setTextColor(TFT_ORANGE);
M5StamPLC.Display.println("No modules found");
} else {
int displayed = 0;
for (int i = 0; i < MAX_MODULES && displayed < 8; i++) {
if (modules[i].connected) {
M5StamPLC.Display.setTextColor(TFT_GREEN);
M5StamPLC.Display.printf("%d. Addr: 0x%02X\n", displayed + 1, modules[i].address);
M5StamPLC.Display.setTextColor(TFT_YELLOW);
M5StamPLC.Display.printf(" FW: 0x%02X\n", modules[i].firmware_version);
displayed++;
}
}
}
}

void setup()
{
M5StamPLC.begin();
M5StamPLC.Display.setTextScroll(false);
M5StamPLC.Display.setTextSize(1);
M5StamPLC.Display.setFont(&fonts::efontCN_16);

Serial.begin(115200);
Serial.println("\n=== M5StamPLC IO Hot-Plug Detection ===");

initModules();

M5StamPLC.Display.fillScreen(TFT_BLACK);
M5StamPLC.Display.setCursor(0, 0);
M5StamPLC.Display.setTextColor(TFT_GREENYELLOW);
M5StamPLC.Display.println("M5StamPLC IO");
M5StamPLC.Display.println("Hot-Plug Detection");
M5StamPLC.Display.setTextColor(TFT_CYAN);
M5StamPLC.Display.println("\nScanning...");

delay(1000);
scanModules();
displayModules();
last_scan_time = millis();
}

void loop()
{
M5StamPLC.update();

if (millis() - last_scan_time > SCAN_INTERVAL_MS) {
scanModules();
displayModules();
last_scan_time = millis();
}

delay(100);
}
151 changes: 151 additions & 0 deletions examples/Modules/StamPLC_IO/PWM_Control/PWM_Control.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*
* M5StamPLC IO PWM Control Example
*
* This example demonstrates how to use the PWM control function of the M5StamPLC IO module:
* - Switch between IO mode and PWM mode
* - Set PWM frequency (1-100 Hz)
* - Adjust CH1 and CH2 duty cycle (0-1000 thousandths)
*
* Button functions:
* - Button A: Toggle PWM mode on/off
* - Button B: Increase CH1 duty cycle (+10%)
* - Long press B: Decrease CH1 duty cycle (-10%)
* - Button C: Increase CH2 duty cycle (+10%)
* - Long press C: Decrease CH2 duty cycle (-10%)
*/
#include <Arduino.h>
#include <M5StamPLC.h>

M5StamPLC_IO stamplc_io;

bool pwm_mode = false;
uint8_t pwm_freq = 50;
uint16_t ch1_duty = 0;
uint16_t ch2_duty = 0;
bool btnB_longPressed = false;
bool btnC_longPressed = false;

unsigned long lastUpdateTime = 0;

void updateDisplay()
{
M5StamPLC.Display.fillScreen(TFT_BLACK);
M5StamPLC.Display.setCursor(0, 0);

M5StamPLC.Display.setTextColor(TFT_GREENYELLOW);
M5StamPLC.Display.println("=== PWM Control ===");

M5StamPLC.Display.setTextColor(TFT_CYAN);
M5StamPLC.Display.printf("Mode: %s\n", pwm_mode ? "PWM" : "IO");
M5StamPLC.Display.printf("Frequency: %d Hz\n", pwm_freq);

M5StamPLC.Display.setTextColor(TFT_YELLOW);
M5StamPLC.Display.printf("CH1 Duty: %d.%d%% (%d/1000)\n", ch1_duty / 10, ch1_duty % 10, ch1_duty);
M5StamPLC.Display.printf("CH2 Duty: %d.%d%% (%d/1000)\n", ch2_duty / 10, ch2_duty % 10, ch2_duty);

M5StamPLC.Display.setTextColor(TFT_DARKGREY);
M5StamPLC.Display.println("A: Toggle PWM mode");
M5StamPLC.Display.println("B: CH1+ Long press: CH1-");
M5StamPLC.Display.println("C: CH2+ Long press: CH2-");
}

void setup()
{
M5StamPLC.begin();
M5StamPLC.Display.setTextScroll(false);
M5StamPLC.Display.setTextSize(1);
M5StamPLC.Display.setFont(&fonts::efontCN_16);
M5StamPLC.Display.println("Try to find M5StamPLC IO module...");

/* Init M5StamPLC IO */
while (!stamplc_io.begin()) {
M5StamPLC.Display.println("Not found, retry in 1s...");
delay(1000);
}

M5StamPLC.Display.printf("Found IO module: 0x%02X\n", stamplc_io.getCurrentAddress());
M5StamPLC.Display.printf("Firmware Version: 0x%02X\n", stamplc_io.getFirmwareVersion());

delay(2000);

pwm_mode = stamplc_io.getPWMMode();
pwm_freq = stamplc_io.getPWMFrequency();
ch1_duty = stamplc_io.getChannelDuty(1);
ch2_duty = stamplc_io.getChannelDuty(2);

if (pwm_freq == 0) {
pwm_freq = 50;
stamplc_io.setPWMFrequency(pwm_freq);
}

updateDisplay();
lastUpdateTime = millis();
}

void loop()
{
M5StamPLC.update();

bool needUpdate = false;

// Button A: Toggle PWM mode
if (M5StamPLC.BtnA.wasClicked()) {
pwm_mode = !pwm_mode;
stamplc_io.setPWMMode(pwm_mode);
needUpdate = true;
}

// Button B: Adjust CH1 duty cycle
if (M5StamPLC.BtnB.wasClicked()) {
// Increase 10% (100/1000)
ch1_duty += 100;
if (ch1_duty > 1000) ch1_duty = 1000;
stamplc_io.setChannelDuty(1, ch1_duty);
needUpdate = true;
} else if (M5StamPLC.BtnB.pressedFor(500) && !btnB_longPressed) {
// Decrease 10%
btnB_longPressed = true;
if (ch1_duty >= 100) {
ch1_duty -= 100;
} else {
ch1_duty = 0;
}
stamplc_io.setChannelDuty(1, ch1_duty);
needUpdate = true;
} else if (!M5StamPLC.BtnB.isPressed()) {
btnB_longPressed = false;
}

// Button C: Adjust CH2 duty cycle
if (M5StamPLC.BtnC.wasClicked()) {
// Increase 10% (100/1000)
ch2_duty += 100;
if (ch2_duty > 1000) ch2_duty = 1000;
stamplc_io.setChannelDuty(2, ch2_duty);
needUpdate = true;
} else if (M5StamPLC.BtnC.pressedFor(500) && !btnC_longPressed) {
// Decrease 10%
btnC_longPressed = true;
if (ch2_duty >= 100) {
ch2_duty -= 100;
} else {
ch2_duty = 0;
}
stamplc_io.setChannelDuty(2, ch2_duty);
needUpdate = true;
} else if (!M5StamPLC.BtnC.isPressed()) {
btnC_longPressed = false;
}

// Periodically update display
if (needUpdate || (millis() - lastUpdateTime > 1000)) {
updateDisplay();
lastUpdateTime = millis();
}

delay(10);
}
Loading
Loading