Compare commits
10
Commits
b64766ce9f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31f672be2c | ||
|
|
3d7417e837 | ||
|
|
907de6fd25 | ||
|
|
a27b91851f | ||
|
|
d385cb8a35 | ||
|
|
eea6fb7130 | ||
|
|
e1a0846312 | ||
|
|
c4a640105c | ||
|
|
bc37531bbf | ||
|
|
6cf7455986 |
@@ -0,0 +1,8 @@
|
|||||||
|
.pio/
|
||||||
|
build/
|
||||||
|
*.bin
|
||||||
|
*.elf
|
||||||
|
*.map
|
||||||
|
firmware/*.bin
|
||||||
|
.DS_Store
|
||||||
|
.vscode/
|
||||||
@@ -1,3 +1,40 @@
|
|||||||
# led-laser-frequenzen
|
# LED-Entspannungsablauf
|
||||||
|
|
||||||
ESP32-C6 LED-Laser-Frequenzsteuerung für Rotlichttherapie mit WS2812B (30 LEDs)
|
30× WS2812B / NeoPixel an Seeed XIAO ESP32-C6 für geführte Licht-Frequenz-Entrainment.
|
||||||
|
**Arduino-IDE**, **Adafruit NeoPixel**, Auto-Start beim Einschalten.
|
||||||
|
|
||||||
|
## Hardware
|
||||||
|
|
||||||
|
- **Controller:** Seeed XIAO ESP32-C6
|
||||||
|
- **LEDs:** 30× WS2812B / NeoPixel
|
||||||
|
- **Datenpin:** **D10 (GPIO18)** (330–470 Ω Vorwiderstand empfohlen)
|
||||||
|
- **Versorgung:** USB-C 5 V
|
||||||
|
|
||||||
|
## Ablauf – 7 Phasen, Auto-Start
|
||||||
|
|
||||||
|
Startet automatisch beim Einschalten. Nach Phase 7: 3 s Pause, dann von vorn.
|
||||||
|
|
||||||
|
| # | Name | Frequenz | Dauer | Farbe RGB | Wirkung |
|
||||||
|
|---|--------------------|----------|---------|-------------|-----------------------|
|
||||||
|
| 1 | Ankommen/Beta→Alpha| 10 Hz | 1 min | 255,80,0 | Einpendeln, Loslassen |
|
||||||
|
| 2 | Alpha-Entspannung | 8 Hz | 1.5 min | 255,40,0 | Gelassenheit |
|
||||||
|
| 3 | Theta-Eintauchen | 5 Hz | 1.5 min | 200,0,0 | Übergang zur Tiefe |
|
||||||
|
| 4 | Delta-Regeneration | 2 Hz | 2 min | 180,0,0 | Tiefschlaf/Heilung |
|
||||||
|
| 5 | Delta-Tiefschlaf | 1 Hz | 2 min | 150,0,0 | Maximale Tiefe |
|
||||||
|
| 6 | Theta-Aufstieg | 4 Hz | 1.5 min | 220,30,0 | Rückkehr beginnt |
|
||||||
|
| 7 | Alpha-Weckphase | 7 Hz | 1.5 min | 255,60,0 | Langsam wach werden |
|
||||||
|
|
||||||
|
**Blink:** 50 % ein / 50 % aus bei der jeweiligen Frequenz.
|
||||||
|
|
||||||
|
## Build & Upload (Arduino-IDE)
|
||||||
|
|
||||||
|
1. Board: **Seeed XIAO ESP32C6**
|
||||||
|
2. Port: `/dev/ttyACM0` (oder COMx)
|
||||||
|
3. Bibliothek: **Adafruit NeoPixel** (Library Manager → installieren)
|
||||||
|
4. `led_entspannung.ino` öffnen → **Upload**
|
||||||
|
|
||||||
|
Das war's. Startet automatisch.
|
||||||
|
|
||||||
|
## Dateien
|
||||||
|
|
||||||
|
- `led_entspannung.ino` — der Sketch
|
||||||
|
|||||||
@@ -1,224 +0,0 @@
|
|||||||
/*
|
|
||||||
* LED-Laser-Frequenzsteuerung für Rotlichttherapie
|
|
||||||
* Ziel-Hardware: ESP32-C6 mit WS2812B LED-Streifen (30 LEDs)
|
|
||||||
*
|
|
||||||
* Funktion: Steuert 30 WS2812B-LEDs über verschiedene Frequenz-Presets
|
|
||||||
* die Rotlichttherapie nachbilden. Jedes Preset definiert Farbe, Helligkeit
|
|
||||||
* und Pulsfrequenz für photobiostimulation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <Adafruit_NeoPixel.h>
|
|
||||||
|
|
||||||
// ===== KONFIGURATION =====
|
|
||||||
#define LED_PIN GPIO6 // Datenleitung zum WS2812B-Streifen
|
|
||||||
#define NUM_LEDS 30 // Anzahl LEDs im Streifen
|
|
||||||
#define DATA_RESISTOR 330 // Vorwiderstand in Ohm an der Datenleitung
|
|
||||||
|
|
||||||
// ===== FREQUENZ-PRESETS =====
|
|
||||||
// Jeder Preset definiert: Name, Grundfrequenz (Hz), Farbe (R,G,B), Helligkeit (0-255)
|
|
||||||
struct LaserPreset {
|
|
||||||
const char* name;
|
|
||||||
float frequencyHz; // Puls-Frequenz in Hz
|
|
||||||
uint8_t colorR;
|
|
||||||
uint8_t colorG;
|
|
||||||
uint8_t colorB;
|
|
||||||
uint8_t brightness; // 0-255, 255 = maximal
|
|
||||||
uint32_t durationMs; // Wie lange das Preset läuft (0 = unbegrenzt)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Therapeutische Frequenzen für Rotlichttherapie (Peptide / Laser Therapy)
|
|
||||||
// Diese Frequenzen sind typisch für die Behandlung von Gewebe/Regeneration
|
|
||||||
const LaserPreset presets[] = {
|
|
||||||
// [0] Niedrigfrequenz - Entspannung & Regeneration
|
|
||||||
{"Regeneration", 40.0, 255, 15, 0, 200, 60000},
|
|
||||||
|
|
||||||
// [1] Mittelfrequenz - Durchblutung
|
|
||||||
{"Durchblutung", 60.0, 255, 30, 0, 255, 60000},
|
|
||||||
|
|
||||||
// [2] Hochfrequenz - Tiefenwirksam
|
|
||||||
{"Tiefenwirkung", 80.0, 255, 60, 0, 230, 45000},
|
|
||||||
|
|
||||||
// [3] Gepulst Rot - Geweberegeneration
|
|
||||||
{"Gepulst Rot", 50.0, 255, 0, 0, 180, 60000},
|
|
||||||
|
|
||||||
// [4] Warmes Rot-Orange - Oberflächliche Heilung
|
|
||||||
{"Oberflächenlicht", 30.0, 255, 80, 10, 210, 45000},
|
|
||||||
|
|
||||||
// [5] Infrarot-Nachbildung (tiefes Rot) - Muskeln & Gelenke
|
|
||||||
{"Muskeln/Gelenke", 65.0, 200, 10, 0, 240, 60000},
|
|
||||||
|
|
||||||
// [6] Wechselnd - Ganzkörperbehandlung
|
|
||||||
{"Ganzkörper", 45.0, 255, 0, 0, 190, 90000},
|
|
||||||
};
|
|
||||||
|
|
||||||
#define NUM_PRESETS (sizeof(presets) / sizeof(presets[0]))
|
|
||||||
|
|
||||||
// ===== GLOBAL STATE =====
|
|
||||||
Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);
|
|
||||||
|
|
||||||
uint8_t currentR = 0, currentG = 0, currentB = 0;
|
|
||||||
float currentBrightness = 0.0;
|
|
||||||
uint32_t pulsePhase = 0;
|
|
||||||
unsigned long lastPulseUpdate = 0;
|
|
||||||
unsigned long presetStartTime = 0;
|
|
||||||
int currentPresetIndex = -1;
|
|
||||||
bool running = false;
|
|
||||||
|
|
||||||
// ===== SETUP =====
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(115200);
|
|
||||||
while (!Serial && millis() < 3000) {}
|
|
||||||
|
|
||||||
strip.begin();
|
|
||||||
strip.clear();
|
|
||||||
strip.show();
|
|
||||||
|
|
||||||
// Starte mit erstem Preset
|
|
||||||
selectPreset(0);
|
|
||||||
|
|
||||||
Serial.println("========================================");
|
|
||||||
Serial.println(" LED-Laser-Frequenzsteuerung (ESP32-C6)");
|
|
||||||
Serial.println(" WS2812B x 30 LEDs");
|
|
||||||
Serial.println("========================================");
|
|
||||||
printPresets();
|
|
||||||
running = true;
|
|
||||||
|
|
||||||
presetStartTime = millis();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== LOOP =====
|
|
||||||
void loop() {
|
|
||||||
if (!running) {
|
|
||||||
// Warte auf seriellen Befehl zum Neustart
|
|
||||||
if (Serial.available()) {
|
|
||||||
String cmd = Serial.readStringUntil('\n');
|
|
||||||
handleCommand(cmd);
|
|
||||||
}
|
|
||||||
yield();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const LaserPreset& preset = presets[currentPresetIndex];
|
|
||||||
unsigned long now = millis();
|
|
||||||
|
|
||||||
// Prüfe ob Preset-Zeit abgelaufen (wenn durationMs > 0)
|
|
||||||
if (preset.durationMs > 0 && (now - presetStartTime) >= preset.durationMs) {
|
|
||||||
nextPreset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Berechne pulsende Helligkeit basierend auf Frequenz
|
|
||||||
calculatePulse(preset, now);
|
|
||||||
|
|
||||||
// Update alle LEDs
|
|
||||||
uint32_t color = strip.Color(
|
|
||||||
(uint8_t)(currentR * currentBrightness / 255.0),
|
|
||||||
(uint8_t)(currentG * currentBrightness / 255.0),
|
|
||||||
(uint8_t)(currentB * currentBrightness / 255.0)
|
|
||||||
);
|
|
||||||
|
|
||||||
for (int i = 0; i < NUM_LEDS; i++) {
|
|
||||||
strip.setPixelColor(i, color);
|
|
||||||
}
|
|
||||||
strip.show();
|
|
||||||
|
|
||||||
// Seriellen Input prüfen für Befehle
|
|
||||||
if (Serial.available()) {
|
|
||||||
String cmd = Serial.readStringUntil('\n');
|
|
||||||
handleCommand(cmd.trim());
|
|
||||||
}
|
|
||||||
|
|
||||||
yield();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== PULSBERECHNUNG =====
|
|
||||||
void calculatePulse(const LaserPreset& preset, unsigned long now) {
|
|
||||||
float dutyCycle = 0.5; // Standard: 50% Tastgrad
|
|
||||||
|
|
||||||
// Sinusbasiertes Pulsieren für sanfte Übergänge
|
|
||||||
float periodMs = 1000.0 / preset.frequencyHz;
|
|
||||||
float phase = fmodf((float)(now % (uint32_t)periodMs), periodMs) / periodMs;
|
|
||||||
|
|
||||||
// Sanfter An- und Abstieg
|
|
||||||
currentBrightness = (uint8_t)(preset.brightness * sinf(phase * 3.14159f));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== PRESET SELEKTION =====
|
|
||||||
void selectPreset(int index) {
|
|
||||||
if (index < 0 || index >= NUM_PRESETS) return;
|
|
||||||
|
|
||||||
currentPresetIndex = index;
|
|
||||||
presetStartTime = millis();
|
|
||||||
currentBrightness = 0.0;
|
|
||||||
|
|
||||||
Serial.printf("\n>>> Preset: %s\n", presets[index].name);
|
|
||||||
Serial.printf(" Frequenz: %.1f Hz\n", presets[index].frequencyHz);
|
|
||||||
Serial.printf(" Farbe: R=%d, G=%d, B=%d\n",
|
|
||||||
presets[index].colorR,
|
|
||||||
presets[index].colorG,
|
|
||||||
presets[index].colorB);
|
|
||||||
Serial.printf(" Helligkeit: %d/255\n", presets[index].brightness);
|
|
||||||
if (presets[index].durationMs > 0) {
|
|
||||||
Serial.printf(" Dauer: %lu ms (%.1f min)\n",
|
|
||||||
presets[index].durationMs,
|
|
||||||
presets[index].durationMs / 60000.0);
|
|
||||||
} else {
|
|
||||||
Serial.println(" Dauer: unbegrenzt (⏹ zum Stoppen)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void nextPreset() {
|
|
||||||
int next = (currentPresetIndex + 1) % NUM_PRESETS;
|
|
||||||
selectPreset(next);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== PRESETS DRUCKEN =====
|
|
||||||
void printPresets() {
|
|
||||||
Serial.println("\nVerfügbare Presets:");
|
|
||||||
for (int i = 0; i < NUM_PRESETS; i++) {
|
|
||||||
const char* durStr;
|
|
||||||
if (presets[i].durationMs > 0) {
|
|
||||||
durStr = "";
|
|
||||||
} else {
|
|
||||||
durStr = " (⏹ stopp)";
|
|
||||||
}
|
|
||||||
Serial.printf(" [%d] %s %.1fHz R:%d G:%d B:%d hell:%d - Zeit: %s\n",
|
|
||||||
i,
|
|
||||||
presets[i].name,
|
|
||||||
presets[i].frequencyHz,
|
|
||||||
presets[i].colorR,
|
|
||||||
presets[i].colorG,
|
|
||||||
presets[i].colorB,
|
|
||||||
presets[i].brightness,
|
|
||||||
durStr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== SERIELLE BEFEHLE =====
|
|
||||||
void handleCommand(String cmd) {
|
|
||||||
if (cmd.equalsIgnoreCase("stop")) {
|
|
||||||
running = false;
|
|
||||||
strip.clear();
|
|
||||||
strip.show();
|
|
||||||
Serial.println("LEDs ausgeschaltet. Serieller Befehl zum Neustart.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cmd.equalsIgnoreCase("next")) {
|
|
||||||
nextPreset();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cmd.equalsIgnoreCase("list") || cmd.equalsIgnoreCase("presets")) {
|
|
||||||
printPresets();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Number parsing: "0", "1", etc. → Preset-Index
|
|
||||||
int idx = cmd.toInt();
|
|
||||||
if (idx >= 0 && idx < NUM_PRESETS) {
|
|
||||||
selectPreset(idx);
|
|
||||||
} else if (cmd.length() > 0 && !cmd[0].isdigit()) {
|
|
||||||
Serial.printf("Unbekannter Befehl: '%s'\n", cmd.c_str());
|
|
||||||
Serial.println("Verfügbare Befehle: 0-6, stop, next, list");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* led_entspannung.ino
|
||||||
|
* LED-Entspannungsablauf für XIAO ESP32-C6 + 30x WS2812B
|
||||||
|
*
|
||||||
|
* Pin: D10 (GPIO18) – wie im "Standard-Code" getestet und bestätigt
|
||||||
|
* Ablauf (auto-Start beim Einschalten):
|
||||||
|
* 1) Ankommen / Beta→Alpha 10 Hz 60 s (255, 80, 0)
|
||||||
|
* 2) Alpha-Entspannung 8 Hz 90 s (255, 40, 0)
|
||||||
|
* 3) Theta-Eintauchen 5 Hz 90 s (200, 0, 0)
|
||||||
|
* 4) Delta-Regeneration 2 Hz 120 s (180, 0, 0)
|
||||||
|
* 5) Delta-Tiefschlaf 1 Hz 120 s (150, 0, 0)
|
||||||
|
* 6) Theta-Aufstieg 4 Hz 90 s (220, 30, 0)
|
||||||
|
* 7) Alpha-Weckphase 7 Hz 90 s (255, 60, 0)
|
||||||
|
* Danach: alle LEDs aus, 3 s Pause, dann von vorn.
|
||||||
|
*
|
||||||
|
* Arduino-IDE:
|
||||||
|
* - Board: "Seeed XIAO ESP32C6"
|
||||||
|
* - Port: COMx (bzw. /dev/ttyACM0)
|
||||||
|
* - Bibliothek "Adafruit NeoPixel" muss installiert sein
|
||||||
|
* - Upload → fertig, es startet automatisch
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Adafruit_NeoPixel.h>
|
||||||
|
|
||||||
|
#define LED_PIN 18 // D10
|
||||||
|
#define NUM_LEDS 30
|
||||||
|
|
||||||
|
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);
|
||||||
|
|
||||||
|
struct Phase {
|
||||||
|
uint8_t r, g, b;
|
||||||
|
uint32_t freq_hz;
|
||||||
|
uint32_t duration_s;
|
||||||
|
const char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const Phase phases[] = {
|
||||||
|
{ 255, 80, 0, 10, 60, "Ankommen / Beta-Alpha" },
|
||||||
|
{ 255, 40, 0, 8, 90, "Alpha-Entspannung" },
|
||||||
|
{ 200, 0, 0, 5, 90, "Theta-Eintauchen" },
|
||||||
|
{ 180, 0, 0, 2, 120, "Delta-Regeneration" },
|
||||||
|
{ 150, 0, 0, 1, 120, "Delta-Tiefschlaf" },
|
||||||
|
{ 220, 30, 0, 4, 90, "Theta-Aufstieg" },
|
||||||
|
{ 255, 60, 0, 7, 90, "Alpha-Weckphase" },
|
||||||
|
};
|
||||||
|
#define NUM_PHASES (sizeof(phases) / sizeof(phases[0]))
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
delay(500);
|
||||||
|
Serial.println("==== LED-Entspannungsablauf (7 Phasen) ====");
|
||||||
|
Serial.printf("XIAO ESP32-C6 | D10 (GPIO%d) | %d LEDs\n", LED_PIN, NUM_LEDS);
|
||||||
|
|
||||||
|
strip.begin();
|
||||||
|
strip.setBrightness(255);
|
||||||
|
strip.show(); // alles aus
|
||||||
|
Serial.println("Strip initialisiert, Start in 1 s ...");
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
for (int p = 0; p < NUM_PHASES; p++) {
|
||||||
|
const Phase &ph = phases[p];
|
||||||
|
Serial.printf("Phase %d/%d: %s %d Hz %d s (%d,%d,%d)\n",
|
||||||
|
p + 1, NUM_PHASES, ph.name, ph.freq_hz, ph.duration_s, ph.r, ph.g, ph.b);
|
||||||
|
|
||||||
|
uint32_t start = millis();
|
||||||
|
while (millis() - start < ph.duration_s * 1000UL) {
|
||||||
|
uint32_t half_ms = (1000UL / ph.freq_hz) / 2; // 50 % ein / 50 % aus
|
||||||
|
|
||||||
|
for (int i = 0; i < NUM_LEDS; i++) strip.setPixelColor(i, ph.r, ph.g, ph.b);
|
||||||
|
strip.show();
|
||||||
|
delay(half_ms);
|
||||||
|
|
||||||
|
strip.clear();
|
||||||
|
strip.show();
|
||||||
|
delay(half_ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kurze Pause zwischen Durchläufen
|
||||||
|
Serial.println("Durchlauf beendet - 3 s Pause, dann neu");
|
||||||
|
strip.clear();
|
||||||
|
strip.show();
|
||||||
|
delay(3000);
|
||||||
|
}
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
; PlatformIO Project Configuration File
|
|
||||||
; ESP32-C6 mit WS2812B LED-Streifen (30 LEDs)
|
|
||||||
|
|
||||||
[env:esp32-c6-devkitc-1]
|
|
||||||
platform = espressif32
|
|
||||||
board = esp32-c6-devkitc-1
|
|
||||||
framework = arduino
|
|
||||||
monitor_speed = 115200
|
|
||||||
lib_deps =
|
|
||||||
adafruit/Adafruit NeoPixel@^1.12.3
|
|
||||||
build_flags =
|
|
||||||
-D LED_PIN=GPIO6
|
|
||||||
-D NUM_LEDS=30
|
|
||||||
-D WS2812B_SERIAL_SPEED=800000
|
|
||||||
Reference in New Issue
Block a user