Files
mata-avispas/mata_avispas.ino
T

229 lines
7.0 KiB
Arduino
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* mata avispas Flyback high voltage generator controller
* ESP32C3 as Access Point + Web server to configure PWM driving an XYMOS driver
*
* PWM output: GPIO2 (adjustable via LEDC)
* Web page: http://192.168.4.1
* AP SSID: MataAvispas_AP
* AP Password: avispas123
*
* The page lets you set:
* - Frequency (Hz) : 100 20000
* - Duty cycle (%) : 0 100
* - Enable/Disable output
*
* Uses the ESP32 Arduino core (https://github.com/espressif/arduino-esp32)
*/
#include <WiFi.h>
#include <WebServer.h>
// ==== USER SETTINGS ====
const char* AP_SSID = "MataAvispas_AP";
const char* AP_PASSWORD = "avispas123";
const uint8_t PWM_GPIO = 2; // XYMOS INPUT pin
const uint8_t PWM_CHANNEL = 0; // LEDC channel 0
const uint8_t PWM_RESOLUTION = 10; // 10bit resolution => 01023
// =======================
WebServer server(80);
// Current PWM state
uint32_t pwmFrequency = 1000; // default 1kHz
uint32_t pwmDuty = 512; // 50% of 1023
bool pwmEnabled = false;
// HTML page (stored in PROGMEM to save RAM)
const char INDEX_HTML[] PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, charset=utf-8">
<title>Mata Avispas PWM Config</title>
<style>
body { font-family: Arial, Helvetica, sans-serif; margin: 20px; background:#f4f4f4; }
.container { max-width: 480px; margin: auto; background:#fff; padding:20px; box-shadow:0 0 10px rgba(0,0,0,.1); border-radius:8px; }
h1 { color:#2c3e50; text-align:center; }
label { display:block; margin-top:15px; font-weight:bold; }
input[type="number"], input[type="range"] { width:100%; padding:8px; margin-top:5px; }
.btn { display:inline-block; margin-top:20px; padding:10px 20px; background:#27ae60; color:#fff; border:none; border-radius:4px; cursor:pointer; }
.btn.disabled { background:#95a5a6; cursor:not-allowed; }
.status { margin-top:15px; padding:10px; background:#ecf0f1; border-radius:4px; }
</style>
</head>
<body>
<div class="container">
<h1>Mata Avispas</h1>
<div class="status" id="status">PWM: <span id="pwmState">OFF</span></div>
<label for="freq">Frequency (Hz)</label>
<input type="number" id="freq" min="100" max="20000" value="1000">
<small>Range: 100 20000 Hz</small>
<label for="duty">Duty cycle (%)</label>
<input type="range" id="duty" min="0" max="100" value="50">
<span id="dutyVal">50</span>%
<label for="enable">Output</label>
<select id="enable">
<option value="0">Disabled</option>
<option value="1">Enabled</option>
</select>
<button class="btn" id="sendBtn">Apply Settings</button>
</div>
<script>
const freqIn = document.getElementById('freq');
const dutyIn = document.getElementById('duty');
const dutyVal = document.getElementById('dutyVal');
const enableIn = document.getElementById('enable');
const btn = document.getElementById('sendBtn');
const status = document.getElementById('status');
const pwmState = document.getElementById('pwmState');
dutyIn.addEventListener('input', () => {
dutyVal.textContent = dutyIn.value;
});
btn.addEventListener('click', () => {
const data = {
freq: parseInt(freqIn.value),
duty: parseInt(dutyIn.value),
en: parseInt(enableIn.value)
};
fetch('/set', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
})
.then(r => r.json())
.then(resp => {
if (resp.ok) {
pwmState.textContent = resp.enabled ? 'ON' : 'OFF';
status.innerHTML = `PWM: <strong>${resp.enabled ? 'ON' : 'OFF'}</strong> (freq: ${resp.freq} Hz, duty: ${resp.duty}%)`;
status.style.background = resp.enabled ? '#dff0d8' : '#f2dede';
} else {
alert('Error: ' + resp.msg);
}
})
.catch(err => {
alert('Network error: ' + err);
});
});
// Load current settings on page load
window.addEventListener('load', () => {
fetch('/get')
.then(r => r.json())
.then(data => {
freqIn.value = data.freq;
dutyIn.value = data.duty;
dutyVal.textContent = data.duty;
enableIn.value = data.enabled ? '1' : '0';
pwmState.textContent = data.enabled ? 'ON' : 'OFF';
status.innerHTML = `PWM: <strong>${data.enabled ? 'ON' : 'OFF'}</strong> (freq: ${data.freq} Hz, duty: ${data.duty}%)`;
status.style.background = data.enabled ? '#dff0d8' : '#f2dede';
});
});
</script>
</body>
</html>
)rawliteral";
void handleRoot() {
server.send_P(200, "text/html", INDEX_HTML, strlen_P(INDEX_HTML));
}
void handleGet() {
String json = "{";
json += "\"freq\":" + String(pwmFrequency) + ",";
json += "\"duty\":" + String(map(pwmDuty, 0, (1<<PWM_RESOLUTION)-1, 0, 100)) + ",";
json += "\"enabled\":" + String(pwmEnabled ? "true" : "false");
json += "}";
server.send(200, "application/json", json);
}
void handleSet() {
if (server.method() != HTTP_POST) {
server.send(405, "text/plain", "Method Not Allowed");
return;
}
if (!server.hasArg("plain")) {
server.send(400, "text/plain", "Missing JSON body");
return;
}
String body = server.arg("plain");
// Very simple JSON parsing (expects {"freq":N,"duty":M,"en":0|1})
int freq = 1000;
int duty = 50;
int en = 0;
int idx = body.indexOf("\"freq\":");
if (idx >= 0) {
String sub = body.substring(idx + 7);
freq = sub.substring(0, sub.indexOf(",")).toInt();
}
idx = body.indexOf("\"duty\":");
if (idx >= 0) {
String sub = body.substring(idx + 7);
duty = sub.substring(0, sub.indexOf(",")).toInt();
}
idx = body.indexOf("\"en\":");
if (idx >= 0) {
String sub = body.substring(idx + 5);
en = sub.substring(0, sub.indexOf("}")).toInt();
}
// Clamp values
if (freq < 100) freq = 100;
if (freq > 20000) freq = 20000;
if (duty < 0) duty = 0;
if (duty > 100) duty = 100;
// Update PWM
pwmFrequency = freq;
pwmDuty = map(duty, 0, 100, 0, (1<<PWM_RESOLUTION)-1);
pwmEnabled = (en == 1);
if (pwmEnabled) {
ledcSetup(PWM_CHANNEL, pwmFrequency, PWM_RESOLUTION);
ledcAttachPin(PWM_GPIO, PWM_CHANNEL);
ledcWrite(PWM_CHANNEL, pwmDuty);
} else {
ledcDetachPin(PWM_GPIO);
}
String json = "{";
json += "\"ok\":true,\"freq\":" + String(pwmFrequency) + ",";
json += "\"duty\":" + String(duty) + ",";
json += "\"enabled\":" + String(pwmEnabled ? "true" : "false");
json += "}";
server.send(200, "application/json", json);
}
void setup() {
Serial.begin(115200);
// Set PWM GPIO as output (safe default)
pinMode(PWM_GPIO, OUTPUT);
digitalWrite(PWM_GPIO, LOW);
// Start AP
WiFi.mode(WIFI_AP);
WiFi.softAP(AP_SSID, AP_PASSWORD);
IPAddress apIP = WiFi.softAPIP();
Serial.print("AP IP address: ");
Serial.println(apIP);
// Web server routes
server.on("/", HTTP_GET, handleRoot);
server.on("/get", HTTP_GET, handleGet);
server.on("/set", HTTP_POST, handleSet);
server.begin();
Serial.println("HTTP server started");
}
void loop() {
server.handleClient();
// Nothing else needed; PWM runs in hardware
}