Created
May 21, 2025 02:33
-
-
Save GOROman/94563caf239a08310a5ecb5c643a7128 to your computer and use it in GitHub Desktop.
M5Core2_PWM.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Wiring Diagram: | |
M5Stack Core2 | |
------------- | |
GPIO 26 ---+ 1kΩ Resistor --- Gate/Base of MOSFET/Transistor | |
| | |
GND (Common Ground) | |
Motor Supply | |
------------- | |
+5V --- Anode of Fly-back Diode --- Emitter/Collector of MOSFET/Transistor | |
| --- Cathode of Fly-back Diode --- Motor Terminal 1 | |
GND (Common Ground) --- Motor Terminal 2 | |
Note: Ensure the M5Stack Core2's GND and the Motor Supply GND are connected. | |
The fly-back diode should be across the motor terminals, protecting against inductive spikes. | |
*/ | |
#include <M5Core2.h> | |
// --- Hardware Constants --- | |
constexpr uint8_t PWM_PIN = 26; // GPIO pin for PWM output | |
constexpr uint8_t PWM_CHANNEL = 0; // LEDC channel for PWM | |
constexpr uint32_t PWM_FREQUENCY = 1000; // PWM frequency in Hz (1 kHz) | |
constexpr uint8_t PWM_RESOLUTION_BITS = 8; // PWM resolution in bits (0-255) | |
constexpr uint32_t PWM_MAX_DUTY_CYCLE = (1 << PWM_RESOLUTION_BITS) - 1; // Max duty cycle value (255) | |
// --- UI Elements --- | |
M5::Slider *speed_slider = nullptr; | |
M5::Label *speed_label = nullptr; | |
M5::Button *start_button = nullptr; | |
M5::Button *stop_button = nullptr; | |
M5::Label *fps_label = nullptr; | |
// --- Global Variables --- | |
uint8_t current_duty_cycle = 0; // Current PWM duty cycle (0-255) | |
bool motor_running = false; // Flag to indicate if the motor is supposed to be running | |
uint32_t last_update_time_ms = 0; // Time of last FPS update | |
uint32_t frame_count = 0; // Frame counter for FPS calculation | |
/** | |
* @brief Updates the FPS (Frames Per Second) display on the screen. | |
*/ | |
void update_fps() { | |
frame_count++; | |
uint32_t current_time_ms = millis(); | |
if (current_time_ms - last_update_time_ms >= 1000) { // Update every 1 second | |
float fps = (float)frame_count * 1000.0 / (current_time_ms - last_update_time_ms); | |
char fps_text[20]; | |
snprintf(fps_text, sizeof(fps_text), "FPS: %.1f", fps); | |
fps_label->setText(fps_text); | |
frame_count = 0; | |
last_update_time_ms = current_time_ms; | |
} | |
} | |
/** | |
* @brief Initializes the M5Stack Core2 and the UI elements. | |
*/ | |
void setup_m5_ui() { | |
M5.begin(); | |
M5.Lcd.setRotation(1); // Set screen orientation | |
M5.Lcd.setTextFont(4); // Set default font size (adjust as needed) | |
M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK); | |
// Create UI elements | |
speed_slider = new M5::Slider(50, 80, 220, 30); | |
speed_slider->setRange(0, 100); | |
speed_slider->setValue(0); | |
speed_slider->setLabel("Speed ( 0–100 % )"); | |
speed_label = new M5::Label(180, 120, 80, 20, "0 %"); | |
start_button = new M5::Button(50, 160, 100, 40); | |
start_button->setLabel("START"); | |
stop_button = new M5::Button(170, 160, 100, 40); | |
stop_button->setLabel("STOP"); | |
fps_label = new M5::Label(10, 220, 100, 20, "FPS: 0.0"); | |
// Add elements to the display stack | |
M5.add(speed_slider); | |
M5.add(speed_label); | |
M5.add(start_button); | |
M5.add(stop_button); | |
M5.add(fps_label); | |
// Set initial state | |
current_duty_cycle = 0; | |
motor_running = false; | |
speed_label->setText("0 %"); | |
} | |
/** | |
* @brief Configures the PWM peripheral for the motor control. | |
*/ | |
void setup_pwm() { | |
// Configure PWM channel | |
ledcSetup(PWM_CHANNEL, PWM_FREQUENCY, PWM_RESOLUTION_BITS); | |
// Attach PWM channel to the specified GPIO pin | |
ledcAttachPin(PWM_PIN, PWM_CHANNEL); | |
// Set initial duty cycle to 0 (motor off) | |
ledcWrite(PWM_CHANNEL, 0); | |
} | |
/** | |
* @brief Updates the PWM duty cycle based on the slider value. | |
* @param percentage The desired speed percentage (0-100). | |
*/ | |
void update_motor_duty_cycle(int percentage) { | |
// Convert percentage (0-100) to duty cycle (0-255) | |
current_duty_cycle = (uint8_t)(((float)percentage / 100.0) * PWM_MAX_DUTY_CYCLE); | |
// Apply the new duty cycle if the motor is running | |
if (motor_running) { | |
ledcWrite(PWM_CHANNEL, current_duty_cycle); | |
} | |
// Update the display label | |
char label_text[10]; | |
snprintf(label_text, sizeof(label_text), "%d %%", percentage); | |
speed_label->setText(label_text); | |
} | |
/** | |
* @brief Starts the motor with the currently set duty cycle. | |
*/ | |
void start_motor() { | |
motor_running = true; | |
ledcWrite(PWM_CHANNEL, current_duty_cycle); | |
} | |
/** | |
* @brief Stops the motor by setting the duty cycle to 0. | |
*/ | |
void stop_motor() { | |
motor_running = false; | |
ledcWrite(PWM_CHANNEL, 0); | |
} | |
void setup() { | |
setup_m5_ui(); | |
setup_pwm(); | |
// Attach event handlers for UI elements | |
speed_slider->onChanged([](const Event_t &e) { | |
update_motor_duty_cycle(speed_slider->getValue()); | |
}); | |
start_button->onPressed([](const Event_t &e) { | |
start_motor(); | |
}); | |
stop_button->onPressed([](const Event_t &e) { | |
stop_motor(); | |
}); | |
last_update_time_ms = millis(); | |
frame_count = 0; | |
} | |
void loop() { | |
M5.update(); // Update M5Stack screen and button states | |
update_fps(); // Update the FPS display | |
// No other complex logic needed in the loop for this example, | |
// UI updates are handled by M5.update() and event handlers. | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment