Migrate to Arduino: NeoPixel 7-phase relaxation (10/8/5/2/1/4/7 Hz)
This commit is contained in:
@@ -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);
|
||||
}
|
||||
+5
-2
@@ -1,7 +1,10 @@
|
||||
[env:xiao-esp32c6]
|
||||
platform = espressif32
|
||||
board = seeed_xiao_esp32c6
|
||||
framework = espidf
|
||||
framework = arduino
|
||||
monitor_speed = 115200
|
||||
board_build.flash_size = 2MB
|
||||
board_build.flash_size = 4MB
|
||||
build_type = release
|
||||
|
||||
lib_deps =
|
||||
adafruit/Adafruit NeoPixel@^1.15.0
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
# This file was automatically generated for projects
|
||||
# without default 'CMakeLists.txt' file.
|
||||
|
||||
FILE(GLOB_RECURSE app_sources ${CMAKE_SOURCE_DIR}/src/*.*)
|
||||
|
||||
idf_component_register(SRCS ${app_sources})
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "esp_check.h"
|
||||
#include "led_strip_encoder.h"
|
||||
|
||||
static const char *TAG = "led_encoder";
|
||||
|
||||
typedef struct {
|
||||
rmt_encoder_t base;
|
||||
rmt_encoder_t *bytes_encoder;
|
||||
rmt_encoder_t *copy_encoder;
|
||||
int state;
|
||||
rmt_symbol_word_t reset_code;
|
||||
} rmt_led_strip_encoder_t;
|
||||
|
||||
RMT_ENCODER_FUNC_ATTR
|
||||
static size_t rmt_encode_led_strip(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
|
||||
{
|
||||
rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
|
||||
rmt_encoder_handle_t bytes_encoder = led_encoder->bytes_encoder;
|
||||
rmt_encoder_handle_t copy_encoder = led_encoder->copy_encoder;
|
||||
rmt_encode_state_t session_state = RMT_ENCODING_RESET;
|
||||
rmt_encode_state_t state = RMT_ENCODING_RESET;
|
||||
size_t encoded_symbols = 0;
|
||||
switch (led_encoder->state) {
|
||||
case 0: // send RGB data
|
||||
encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, primary_data, data_size, &session_state);
|
||||
if (session_state & RMT_ENCODING_COMPLETE) {
|
||||
led_encoder->state = 1; // switch to next state when current encoding session finished
|
||||
}
|
||||
if (session_state & RMT_ENCODING_MEM_FULL) {
|
||||
state |= RMT_ENCODING_MEM_FULL;
|
||||
goto out; // yield if there's no free space for encoding artifacts
|
||||
}
|
||||
// fall-through
|
||||
case 1: // send reset code
|
||||
encoded_symbols += copy_encoder->encode(copy_encoder, channel, &led_encoder->reset_code,
|
||||
sizeof(led_encoder->reset_code), &session_state);
|
||||
if (session_state & RMT_ENCODING_COMPLETE) {
|
||||
led_encoder->state = RMT_ENCODING_RESET; // back to the initial encoding session
|
||||
state |= RMT_ENCODING_COMPLETE;
|
||||
}
|
||||
if (session_state & RMT_ENCODING_MEM_FULL) {
|
||||
state |= RMT_ENCODING_MEM_FULL;
|
||||
goto out; // yield if there's no free space for encoding artifacts
|
||||
}
|
||||
}
|
||||
out:
|
||||
*ret_state = state;
|
||||
return encoded_symbols;
|
||||
}
|
||||
|
||||
static esp_err_t rmt_del_led_strip_encoder(rmt_encoder_t *encoder)
|
||||
{
|
||||
rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
|
||||
rmt_del_encoder(led_encoder->bytes_encoder);
|
||||
rmt_del_encoder(led_encoder->copy_encoder);
|
||||
free(led_encoder);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
RMT_ENCODER_FUNC_ATTR
|
||||
static esp_err_t rmt_led_strip_encoder_reset(rmt_encoder_t *encoder)
|
||||
{
|
||||
rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
|
||||
rmt_encoder_reset(led_encoder->bytes_encoder);
|
||||
rmt_encoder_reset(led_encoder->copy_encoder);
|
||||
led_encoder->state = RMT_ENCODING_RESET;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
rmt_led_strip_encoder_t *led_encoder = NULL;
|
||||
ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
||||
led_encoder = rmt_alloc_encoder_mem(sizeof(rmt_led_strip_encoder_t));
|
||||
ESP_GOTO_ON_FALSE(led_encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for led strip encoder");
|
||||
led_encoder->base.encode = rmt_encode_led_strip;
|
||||
led_encoder->base.del = rmt_del_led_strip_encoder;
|
||||
led_encoder->base.reset = rmt_led_strip_encoder_reset;
|
||||
// different led strip might have its own timing requirements, following parameter is for WS2812
|
||||
rmt_bytes_encoder_config_t bytes_encoder_config = {
|
||||
.bit0 = {
|
||||
.level0 = 1,
|
||||
.duration0 = 0.3 * config->resolution / 1000000, // T0H=0.3us
|
||||
.level1 = 0,
|
||||
.duration1 = 0.9 * config->resolution / 1000000, // T0L=0.9us
|
||||
},
|
||||
.bit1 = {
|
||||
.level0 = 1,
|
||||
.duration0 = 0.9 * config->resolution / 1000000, // T1H=0.9us
|
||||
.level1 = 0,
|
||||
.duration1 = 0.3 * config->resolution / 1000000, // T1L=0.3us
|
||||
},
|
||||
.flags.msb_first = 1 // WS2812 transfer bit order: G7...G0R7...R0B7...B0
|
||||
};
|
||||
ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder(&bytes_encoder_config, &led_encoder->bytes_encoder), err, TAG, "create bytes encoder failed");
|
||||
rmt_copy_encoder_config_t copy_encoder_config = {};
|
||||
ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(©_encoder_config, &led_encoder->copy_encoder), err, TAG, "create copy encoder failed");
|
||||
|
||||
uint32_t reset_ticks = config->resolution / 1000000 * 50 / 2; // reset code duration defaults to 50us
|
||||
led_encoder->reset_code = (rmt_symbol_word_t) {
|
||||
.level0 = 0,
|
||||
.duration0 = reset_ticks,
|
||||
.level1 = 0,
|
||||
.duration1 = reset_ticks,
|
||||
};
|
||||
*ret_encoder = &led_encoder->base;
|
||||
return ESP_OK;
|
||||
err:
|
||||
if (led_encoder) {
|
||||
if (led_encoder->bytes_encoder) {
|
||||
rmt_del_encoder(led_encoder->bytes_encoder);
|
||||
}
|
||||
if (led_encoder->copy_encoder) {
|
||||
rmt_del_encoder(led_encoder->copy_encoder);
|
||||
}
|
||||
free(led_encoder);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "driver/rmt_encoder.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Type of led strip encoder configuration
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t resolution; /*!< Encoder resolution, in Hz */
|
||||
} led_strip_encoder_config_t;
|
||||
|
||||
/**
|
||||
* @brief Create RMT encoder for encoding LED strip pixels into RMT symbols
|
||||
*
|
||||
* @param[in] config Encoder configuration
|
||||
* @param[out] ret_encoder Returned encoder handle
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG for any invalid arguments
|
||||
* - ESP_ERR_NO_MEM out of memory when creating led strip encoder
|
||||
* - ESP_OK if creating encoder successfully
|
||||
*/
|
||||
esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
-123
@@ -1,123 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_timer.h"
|
||||
#include "driver/rmt_tx.h"
|
||||
#include "led_strip_encoder.h"
|
||||
|
||||
#define RMT_LED_STRIP_RESOLUTION_HZ 10000000
|
||||
#define LED_GPIO_NUM 18
|
||||
#define LED_NUMBERS 30
|
||||
|
||||
static const char *TAG = "led-laser";
|
||||
|
||||
static uint8_t led_pixels[LED_NUMBERS * 3];
|
||||
static rmt_channel_handle_t led_chan = NULL;
|
||||
static rmt_encoder_handle_t led_encoder = NULL;
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
int freq_hz;
|
||||
int duration_sec;
|
||||
uint8_t r, g, b;
|
||||
} preset_t;
|
||||
|
||||
static const preset_t presets[] = {
|
||||
{"Ankommen / Beta→Alpha", 10, 60, 255, 80, 0},
|
||||
{"Alpha-Entspannung", 8, 90, 255, 40, 0},
|
||||
{"Theta-Eintauchen", 5, 90, 200, 0, 0},
|
||||
{"Delta-Regeneration", 2,120, 180, 0, 0},
|
||||
{"Delta-Tiefschlaf", 1,120, 150, 0, 0},
|
||||
{"Theta-Aufstieg", 4, 90, 220, 30, 0},
|
||||
{"Alpha-Weckphase", 7, 90, 255, 60, 0}
|
||||
};
|
||||
#define PRESET_COUNT (sizeof(presets)/sizeof(presets[0]))
|
||||
|
||||
static int current_preset = -1;
|
||||
static bool led_on = false;
|
||||
static int64_t last_toggle_us = 0;
|
||||
static int64_t phase_start_us = 0;
|
||||
|
||||
static void set_all_pixels(uint8_t r, uint8_t g, uint8_t b){
|
||||
for(int i=0;i<LED_NUMBERS;i++){
|
||||
led_pixels[i*3+0]=g;
|
||||
led_pixels[i*3+1]=r;
|
||||
led_pixels[i*3+2]=b;
|
||||
}
|
||||
}
|
||||
|
||||
static void flush_leds(void){
|
||||
rmt_transmit_config_t tx_cfg = { .loop_count = 0 };
|
||||
ESP_ERROR_CHECK(rmt_transmit(led_chan, led_encoder, led_pixels, sizeof(led_pixels), &tx_cfg));
|
||||
ESP_ERROR_CHECK(rmt_tx_wait_all_done(led_chan, portMAX_DELAY));
|
||||
}
|
||||
|
||||
static void apply_preset(int idx){
|
||||
if(idx<0 || idx>=PRESET_COUNT) return;
|
||||
current_preset = idx;
|
||||
const preset_t *p = &presets[idx];
|
||||
set_all_pixels(p->r,p->g,p->b);
|
||||
led_on = true;
|
||||
last_toggle_us = esp_timer_get_time();
|
||||
phase_start_us = esp_timer_get_time();
|
||||
ESP_LOGI(TAG,"Preset %d %s %dHz %ds", idx, p->name, p->freq_hz, p->duration_sec);
|
||||
}
|
||||
|
||||
static void stop_leds(void){
|
||||
memset(led_pixels,0,sizeof(led_pixels));
|
||||
flush_leds();
|
||||
current_preset = -1;
|
||||
}
|
||||
|
||||
void app_main(void){
|
||||
ESP_LOGI(TAG,"LED Laser Frequenz start");
|
||||
|
||||
rmt_tx_channel_config_t tx_cfg = {
|
||||
.clk_src=RMT_CLK_SRC_DEFAULT,
|
||||
.gpio_num=LED_GPIO_NUM,
|
||||
.mem_block_symbols=64,
|
||||
.resolution_hz=RMT_LED_STRIP_RESOLUTION_HZ,
|
||||
.trans_queue_depth=4
|
||||
};
|
||||
ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_cfg,&led_chan));
|
||||
led_strip_encoder_config_t enc_cfg={.resolution=RMT_LED_STRIP_RESOLUTION_HZ};
|
||||
ESP_ERROR_CHECK(rmt_new_led_strip_encoder(&enc_cfg,&led_encoder));
|
||||
ESP_ERROR_CHECK(rmt_enable(led_chan));
|
||||
|
||||
memset(led_pixels,0,sizeof(led_pixels));
|
||||
flush_leds();
|
||||
|
||||
apply_preset(0);
|
||||
ESP_LOGI(TAG,"Auto-Start Pin D10/GPIO18");
|
||||
|
||||
while(1){
|
||||
if(current_preset>=0){
|
||||
const preset_t *p=&presets[current_preset];
|
||||
int64_t now = esp_timer_get_time();
|
||||
int64_t period_us = p->freq_hz>0 ? 1000000LL / p->freq_hz : 1000000LL;
|
||||
int64_t half_us = period_us/2;
|
||||
if(half_us<1000) half_us=1000;
|
||||
if(now - last_toggle_us >= half_us){
|
||||
led_on = !led_on;
|
||||
last_toggle_us = now;
|
||||
if(led_on){
|
||||
set_all_pixels(p->r,p->g,p->b);
|
||||
}else{
|
||||
memset(led_pixels,0,sizeof(led_pixels));
|
||||
}
|
||||
flush_leds();
|
||||
}
|
||||
if(now - phase_start_us >= (int64_t)p->duration_sec * 1000000LL){
|
||||
if(current_preset+1 < PRESET_COUNT){
|
||||
apply_preset(current_preset+1);
|
||||
}else{
|
||||
stop_leds();
|
||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||
apply_preset(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(2));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user