Initial commit: mata avispas Arduino code and README

This commit is contained in:
Padrino
2026-06-04 18:00:54 +02:00
commit 14d4cfb943
2 changed files with 254 additions and 0 deletions
+25
View File
@@ -0,0 +1,25 @@
# mata avispas
Flyback high voltage generator (≈12kV output) controlled by an ESP32C3.
Features
- ESP32C3 runs as a WiFi Access Point (AP) so you can connect directly to it.
- A simple web server lets you adjust the PWM frequency/duty cycle that drives the XYMOS driver.
- PWM output is generated on a GPIO using the LEDC hardware (highresolution, glitchfree).
- Safety: the PWM can be disabled via the web page.
Hardware notes
- XYMOS driver expects a PWM signal (typically 5V logic) on its INPUT pin.
- Connect ESP32C3 GPIO to XYMOS INPUT through a levelshifter if needed (ESP32C3 is 3.3V tolerant, most XYMOS accept 3.3V).
- Flyback transformer secondary should be properly insulated and terminated with a highvoltage diode/CockcroftWalton multiplier if you need DC.
- Always use proper shielding, grounding, and never touch the output while powered.
How to build
1. Install the ESP32 Arduino core (Boards Manager → esp32 by Espressif Systems).
2. Select "ESP32C3 Dev Module" (or your specific board).
3. Copy this folder to your Arduino sketchbook or open with PlatformIO/VSCode.
4. Compile and upload.
5. After upload, the ESP32C3 will start an AP named `MataAvispas_AP` (password `avispas123`).
6. Connect your phone/laptop to that AP, open a browser to `http://192.168.4.1` and adjust PWM.
License: MIT feel free to adapt.
+229
View File
@@ -0,0 +1,229 @@
/*
* 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
}