Portable Arduino IDE einrichten

Eine Aktion einmalig ausführen

Eine Aktion nur bei jedem x-ten Aufruf einer Funktion ausführen

Led mit millis() blinken

Datum auf Gültigkeit prüfen

Schalten über den Tageswechsel

Zeichen in String ersetzen

Datentypen Speicherbedarf Wertebereich

2D Array an Funktion

Array Min Max Durchschnitt

Struktur im Dateisystem des Esp ablegen

Esp8266 Doku

ESP8266 Arduino Core Dokumentation

Portable Arduino IDE

	    

Mehrere portable Esp Versionen nutzen

Lade die Arduino IDE als "Windows ZIP file for non admin install" herunter. Entpackt hast du aktuell den Ordner "arduino-1.8.19". Am besten gleich umbenennen in "Arduino_1.8.19_Master". Gehe jetzt in den Ordner und füge einen Ordner Namens "portable" hinzu. Anschließend die arduino.exe starten und gleich im Menü zu Datei/Voreinstellungen gehen. Nun unter dem Punkt "Zusätzliche Boardverwalter-URLs:" die folgenden Zeilen eintragen. https://arduino.esp8266.com/stable/package_esp8266com_index.json https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json Bei der Gelegenheit gleich noch die "Compiler Warnungen" auf "Alle" stellen. IDE und Master Ordner schließen. Jetzt zwei Kopien vom Master Ordner anlegen und entsprechend umbenennen. Arduino_1.8.19_Master Arduino_1.8.19_core_2.6.3 Arduino_1.8.19_core_2.7.4 Arduino_1.8.19_core_3.1.0 Anschließend die IDE in den beiden neuen Ordnern öffnen und im Menü Werkzeuge/Board/Boardverwalter den Boardverwalter öffnen. Oben hinter "Typ" esp reinschreiben. Esp Core Version einstellen und Installieren. Den Master Ordner bewahren wir für die kommende Core Version 3.1.1 auf.

Eine Aktion im Loop einmalig ausführen

C++17 if-Anweisung mit Initialisierer (ab ESP Core 3.x.x)

void loop() {
  if (static auto once {0}; !once++) Serial.println("Einmalig auch in for/while Schleifen.");
}

kurz und prägnant (veraltet ab C++17)

void loop() {
  static bool once {0};
  if (!once++) Serial.println("Einmalig"); // (bool Operator ++) veraltet ab EspCoreVersion 3.0.0.
}

Eine Aktion nur bei jedem x-ten Aufruf der Funktion ausführen.

C++17 if-Anweisung mit Initialisierer (ab ESP Core 3.x.x)

void funktion() {
  Serial.println("Wird bei jedem Aufruf ausgeführt!");    // Ausgabe nur zur Kontrolle, ansonsten kann das weg.
  constexpr uint8_t x = {5};
  if (static uint8_t viewsCount; !(++viewsCount, viewsCount %= x)) Serial.printf("Wird aller %u Aufrufe ausgeführt!\n", x);
}

C++14 (vor ESP Core 3.x.x)

void funktion() {
  Serial.println("Wird bei jedem Aufruf ausgeführt!");    // Ausgabe nur zur Kontrolle, ansonsten kann das weg.
  constexpr uint8_t x = {5};
  static uint8_t viewsCount;
  if (!(++viewsCount, viewsCount %= x)) Serial.printf("Wird aller %u Aufrufe ausgeführt!\n", x);
}

Gleichmäßig 500 ms an/aus

const byte LED_PIN = LED_BUILTIN;

void setup() {
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_PIN, millis() % 1000 >= 500);
}

Mit unterschiedlichen an und aus Zeiten.

const byte LED_PIN = LED_BUILTIN;

void setup() {
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  const uint32_t TIME_OFF = 200; // 200 ms aus  // 6e4 für 60 Sekunden aus // 18e5 für 30 Minuten aus
  const uint32_t TIME_ON = 400;  // 400 ms an   // 3e4 für 30 Sekunden an  // 36e5 für 60 Minuten an
  digitalWrite(LED_PIN, millis() % (TIME_OFF + TIME_ON) >= TIME_ON);
}

Zwei mit verschiedenen Zeiten.

const byte LED_SHORT = 2;
const byte LED_LONG = 16;

void setup() {
  pinMode(LED_SHORT, OUTPUT);
  pinMode(LED_LONG, OUTPUT);
}

void loop() {
  digitalWrite(LED_SHORT, millis() % 1000 >= 500);  // 500ms an/aus
  digitalWrite(LED_LONG, millis() % 2000 >= 1000);  // 1 s an/aus
}

Wechselblinker

const byte LED_LEFT = 2;
const byte LED_RIGHT = 16;

void setup() {
  pinMode(LED_LEFT, OUTPUT);
  pinMode(LED_RIGHT, OUTPUT);
}

void loop() {
  digitalWrite(LED_LEFT, !(millis() % 1000 >= 500));
  digitalWrite(LED_RIGHT, millis() % 1000 >= 500);
}

Datum auf Gültigkeit prüfen

Tag, Monat, Jahr prüfen

Datum_pruefen.ino

bool checkDate(uint8_t d, uint8_t m, uint16_t y) {
  uint8_t daysPerMonth[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  if ((!(y % 4) && y % 100) || !(y % 400)) daysPerMonth[2]++;
  bool valid = d <= daysPerMonth[m] && d && m <= 12 && m && y;
  Serial.printf("Datum %02d.%02d.%d ist %sgültig.\n", d , m , y , valid ? "" : "un");
  return valid;
}

void setup() {
  Serial.begin(115200);
  Serial.println();
  checkDate(29, 2, 2020); //day, month, year
}

void loop() {}

Testausgabe:

Datum 29.02.2020 ist gültig.

Schalten über den Tageswechsel

Ein- und Ausschalten über den Tageswechsel

Tageswechsel.ino

void setup() {
  Serial.begin(115200);
  delay(300);
  Serial.printf("\nSketchname: %s\t Hochgeladen: %s\n\n", __FILE__, __TIMESTAMP__);

  uint16_t onTime = 23 * 60 + 11;           // 23:11 Uhr Einschaltzeitpunkt
  uint16_t offTime = 06 * 60 + 05;          // 06:05 Uhr Ausschaltzeitpunkt
  const uint16_t currentTime = 3 * 60 + 21; // 03:21 Uhr Aktuelle Uhrzeit
  
  bool switched = (onTime < offTime) ? (currentTime >= onTime && currentTime < offTime) : (currentTime >= onTime || currentTime < offTime);
  Serial.printf("Um %02d:%02d Uhr ist der Ausgang %sgeschaltet.\n", currentTime / 60 % 100, currentTime % 60, switched ? "ein" : "aus");
}

void loop() {}

Testausgabe:

Um 03:21 Uhr ist der Ausgang eingeschaltet.

Mehrere unerwünschte Zeichen in einem String austauschen.

String Zeichen ersetzen

String_replace.ino

void setup() {
  String incoming = "Nach:und/kommt\"er;hier\\";
  Serial.begin(115200);
  Serial.println();
  Serial.println(incoming);
  for (auto& c : {'"', '/', ':', ';', '\\'}) for (auto& e : incoming) if (e == c) e = '_';    // Ersetzt alle unerwünschten Zeichen
  Serial.println(incoming);
}

void loop() {}

Testausgabe:

Nach:und/kommt"er;hier\
Nach_und_kommt_er_hier_

Esp8266 Datentypen, Speicherbedarf, Wertebereich und Alternative Bezeichnungen

 

Datentypen Esp8266 Core für Arduino C++

bool, boolean bool: 1 Byte Min: 0 Max: 1 ------------- int8_t, char, signed char Size: 1 Byte Min: -128 Max: 127 ------------- uint8_t, unsigned char, byte Size: 1 Byte Min: 0 Max: 255 ------------- int16_t, short, signed short, short int, signed short int, char16_t Size: 2 Byte Min: -32768 Max: 32767 ------------- uint16_t, unsigned short, word Size: 2 Byte Min: 0 Max: 65535 ------------- int32_t, long, int, signed long, signed int, long int, signed long int, char32_t Size: 4 Byte Min: -2147483648 Max: 2147483647 ------------- uint32_t, uint, unsigned long, unsigned int, unsigned long int Size: 4 Byte Min: 0 Max: 4294967295 ------------- int64_t, long long, signed long long, long long int, signed long long int, intmax_t Size: 8 Byte Min: -9223372036854775808 Max: 9223372036854775807 ------------- uint64_t, unsigned long long, unsigned long long int, uintmax_t Size: 8 Byte Min: 0 Max: 18446744073709551615 ------------- float Size: 4 Byte Min: 1.17549e-38 Max: 3.40282e+38 ------------- double Size: 8 Byte Min: 2.22507e-308 Max: 1.79769e+308

Sketch Datentypen Esp8266

Datentypen.ino

#include <limits.h>
#include <float.h>
#include <iostream>     // alle Bibliotheken sind im Esp Core enthalten

using namespace std;

void setup() {
  Serial.begin(115200);
  delay(100);
  Serial.printf("\n\nSketchname: %s\nBuild: %s\t\tIDE: %d.%d.%d\n%s\n\n",
                (__FILE__), (__TIMESTAMP__), ARDUINO / 10000, ARDUINO % 10000 / 100, ARDUINO % 100 / 10 ? ARDUINO % 100 : ARDUINO % 10, ESP.getFullVersion().c_str());

  cout << "\n Datentypen Esp8266 C++\n" << endl;
  cout << " bool, boolean" << endl;
  cout << " bool: " << sizeof(bool) << " Byte \t" << "Min: " <<  false << "\t" << "Max: " << true << endl;
  cout << "\t-------------" << endl;
  cout << " int8_t, char, signed char" << endl;
  cout << " Size: " << sizeof(char) << " Byte \t" << "Min: " << SCHAR_MIN << "\t" << "Max: " << SCHAR_MAX << endl;
  cout << "\t-------------" << endl;
  cout << " uint8_t, unsigned char, byte" << endl;
  cout << " Size: " << sizeof(unsigned char) << " Byte \t" << "Min:  " << "0" << "\t\t" << "Max: " << UCHAR_MAX << endl;
  cout << "\t-------------" << endl;
  cout << " int16_t, short, signed short, short int, signed short int, char16_t" << endl;
  cout << " Size: " << sizeof(short) << " Byte \t" << "Min: " << INT16_MIN << "\t" << "Max: " << INT16_MAX << endl;
  cout << "\t-------------" << endl;
  cout << " uint16_t, unsigned short, word" << endl;
  cout << " Size: " << sizeof(unsigned short) << " Byte \t" << "Min:  " << "0" << "\t\t" << "Max: " << USHRT_MAX << endl;
  cout << "\t-------------" << endl;
  cout << " int32_t, long, int, signed long, signed int, long int, signed long int, char32_t" << endl;
  cout << " Size: " << sizeof(long) << " Byte \t" << "Min: " << INT32_MIN << "\t" << "Max: " << INT32_MAX << endl;
  cout << "\t-------------" << endl;
  cout << " uint32_t, uint, unsigned long, unsigned int, unsigned long int" << endl;
  cout << " Size: " << sizeof(unsigned long) << " Byte \t" << "Min:  " << numeric_limits<uint>::min() << "\t\t\t" << "Max: " << numeric_limits<uint>::max() << endl;
  cout << "\t-------------" << endl;
  cout << " int64_t, long long, signed long long, long long int, signed long long int, intmax_t" << endl;
  cout << " Size: " << sizeof(long long) << " Byte \t" << "Min: " << INT64_MIN << "\t" << "Max: " << INT64_MAX << endl;
  cout << "\t-------------" << endl;
  cout << " uint64_t, unsigned long long, unsigned long long int, uintmax_t" << endl;
  cout << " Size: " << sizeof(unsigned long long) << " Byte \t" << "Min:  " << "0" << "\t\t\t\t" << "Max: " << UINT64_MAX << endl;
  cout << "\t-------------" << endl;
  cout << " float" << endl;
  cout << " Size: " << sizeof(float) << " Byte \t" << "Min: " << FLT_MIN  << "\t" << "Max: " << FLT_MAX << endl;
  cout << "\t-------------" << endl;
  cout << " double" << endl;
  cout << " Size: " << sizeof(double) << " Byte \t" << "Min: " << DBL_MIN  << "\t" << "Max: " << DBL_MAX << endl;
}

void loop() {}

Zweidimensionales Array an Funktion übergeben

Ein Funktionstemplate ist eine Vorlage, die Funktionen erzeugt der Compiler für die jeweiligen Datentypen.

Die Serielle Ausgabe innerhalb der Funktion ist nur zur Demonstration.

2D_Array.ino

#include <iostream>     // Bibliothek ist im Esp Core enthalten.

int intToUse[][5] = {{1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}, {11, 12, 13, 14, 15}};

float floatToUse[][6] = {{1.56, 2.67, 3.78, 4.89, 5.90, 6.12}, { -6.1, -7.2, -8.3, -9.4, -10.5, -11.6}, {11, 12, 13, 14, 15, 16}};

char charToUse[][4] = {{'a', 'b', 'c', 'd'}, {'A', 'B', 'C', 'D'}, {'1', '2', '3', '4'}};

template <typename T, size_t column, size_t row> T toPrintOut(T (&arr)[column][row]) {
  for (auto &columns : arr) {
    for (auto &value : columns) {
      std::cout << value << ", ";
    }
    std::endl (std::cout);
  }
}

void setup() {
  Serial.begin(115200);
  std::cout << "\n\n";
  std::cout << "Funktions-Template mit int" << std::endl;
  toPrintOut(intToUse);
  std::cout << "\nFunktions-Template mit float" << std::endl;
  toPrintOut(floatToUse);
  std::cout << "\nFunktions-Template mit char" << std::endl;
  toPrintOut(charToUse);
}

void loop() {}

Testausgabe:

Funktions-Template mit int
1, 2, 3, 4, 5, 
6, 7, 8, 9, 10, 
11, 12, 13, 14, 15, 

Funktions-Template mit float
1.56, 2.67, 3.78, 4.89, 5.9, 6.12, 
-6.1, -7.2, -8.3, -9.4, -10.5, -11.6, 
11, 12, 13, 14, 15, 16, 

Funktions-Template mit char
a, b, c, d, 
A, B, C, D, 
1, 2, 3, 4, 

Funktions-Template für Min Max Durchschnitt

Universelle Funktionen für Array aller Datentypen des Esp.

Template.ino

// Template Funktion größten Wert aus Array ermitteln
template <typename T, size_t size> T maxRead(const T (&arr)[size]) {
  T maxValue {arr[0]};
  for (auto &value : arr) maxValue = max(maxValue, value);
  return maxValue;
}

// Template Funktion kleinsten Wert aus Array ermitteln
template <typename T, size_t size> T minRead(const T (&arr)[size]) {
  T minValue {arr[0]};
  for (auto &value : arr) minValue = min(minValue, value);
  return minValue;
}

// Template Funktion Durchschnitt aus Array ermitteln
template <typename T, size_t size> T averageRead(const T (&arr)[size]) {
  double average {0};
  for (auto &value : arr) average += static_cast<double>(value) / size;
  return std::numeric_limits<T>::is_integer ? round(average) : average;
}

const char charArray[] {'%', 42, '!', 40};
const int8_t int8Array[] {5, 3, 2, 4, 5, 1, 3, 2, 4, 5, -1, 2, 3, 4, 2, 1, 6, 3, 2, 4, 1, 5, 3, 2, 4, 2, 5, 3, 2, 4, 3, 5, 1, 1, 2};
const uint8_t uint8Array[] {67, 107, 115, 123, 103, 116, 112, 175, 93, 4, 91, 99, 253, 111, 119, 118, 108, 89, 121, 77, 79, 97, 87, 59, 127, 126, 125, 124, 123};
const int32_t int32Array[] { -2134567890, 1234567890, 987654321, -69567433, 981, 483609};
const uint64_t uint64Array[] {2113720368549745289, 6134567890, 1337203685477587};
const float floatArray[] { -1.55, 8.94, 14.27, -5.63, 10.42, 2.38, 87.91, 3.39, 4.73};

void setup() {
  Serial.begin(115200);
  delay(100);
  Serial.printf("\n\n%s\n\n", __TIMESTAMP__);

  Serial.printf("char max:\t%4d\n", maxRead(charArray));
  Serial.printf("char min:\t%4d\n", minRead(charArray));
  Serial.printf("char mittel:\t%4d\n", averageRead(charArray));

  Serial.printf("\nint8 max:\t%4d\n", maxRead(int8Array));
  Serial.printf("int8 min:\t%4d\n", minRead(int8Array));
  Serial.printf("int8 mittel:\t%4d\n", averageRead(int8Array));

  Serial.printf("\nuint8 max:\t%4d\n", maxRead(uint8Array));
  Serial.printf("uint8 min:\t%4d\n", minRead(uint8Array));
  Serial.printf("uint8 mittel:\t%4d\n", averageRead(uint8Array));

  Serial.printf("\nfloat max:\t%11f\n", maxRead(floatArray));
  Serial.printf("float min:\t%11f\n", minRead(floatArray));
  Serial.printf("float mittel:\t%11f\n", averageRead(floatArray));
  
  Serial.printf("\nint32 max:\t%+11d\n", maxRead(int32Array));
  Serial.printf("int32 min:\t%+11d\n", minRead(int32Array));
  Serial.printf("int32 mittel:\t%+11d\n", averageRead(int32Array));

  Serial.printf("\nuint64 max:\t\t%19lld\n", maxRead(uint64Array));
  Serial.printf("uint64 min:\t\t%19lld\n", minRead(uint64Array));
  Serial.printf("uint64 mittel:\t%19lld\n", averageRead(uint64Array));
}

void loop() {}

Testausgabe:

Wed Apr 29 11:46:08 2020

char max:      42
char min:      33
char mittel:   38

int8 max:       6
int8 min:      -1
int8 mittel:    3

uint8 max:    253
uint8 min:      4
uint8 mittel: 109

float max:    87.910004
float min:    -5.630000
float mittel: 13.873334

int32 max:  +1234567890
int32 min:  -2134567890
int32 mittel:  +3095246

uint64 max:     2113720368549745289
uint64 min:              6134567890
uint64 mittel:   705019192789930368

Struktur im Dateisystem des Esp ablegen

Speichern und einlesen einer Struktur

SaveStruct.ino

#include <LittleFS.h>

// Struktur deklarieren
struct Collection {
  bool button;
  float currentTemp;
  float minTemp;
  float maxTemp;
  char minTime[9];
  char maxTime[9];
};

// Funktion zum speichern der Struktur in einer Datei im Dateisystem des Esp8266
bool toSave(Collection &departure) {
  File file = LittleFS.open("/stream.dat", "w");
  if (file) {
    file.write(reinterpret_cast<byte*>(&departure), sizeof(departure));   // Serialisierung
    file.close();
    return true;
  }
  return false;
}

// Funktion zum einlesen der Daten aus der Datei
bool toRead(Collection &destination) {
  File file = LittleFS.open("/stream.dat", "r");
  if (file) {
    file.read(reinterpret_cast<byte*>(&destination), sizeof(destination));  // Deserialisierung
    file.close();
    return true;
  }
  return false;
}

void setup() {
  Serial.begin(115200);
  delay(100);
  Serial.printf("\nSketchname: %s\nBuild: %s\t\tIDE: %d.%d.%d\n%s\n\n",
                (__FILE__), (__TIMESTAMP__), ARDUINO / 10000, ARDUINO % 10000 / 100, ARDUINO % 10, ESP.getFullVersion().c_str());
  // Dateisystem initialisieren
  LittleFS.begin();
  
  // eine Variable von Typ der Struktur anlegen
  Collection departure;
  
  // Testdaten in die Struktur schreiben
  departure.button = true;
  departure.currentTemp = 8.4;
  departure.minTemp = -2.3;
  departure.maxTemp = 15.9;
  strcpy(departure.minTime, "10:29:04");
  strcpy(departure.maxTime, "06:55:32");
  
  // Funktion zum speichern aufrufen
  bool result = toSave(departure);
  Serial.printf("Datei schreiben %s!\n", result ? "erfolgreich" : "fehlgeschlagen");
}

void loop() {
  static auto once {0};
  if (!once++) {
    // eine Variable von Typ der Struktur anlegen
    struct Collection destination;
    
    // Funktion zum einlesen aufrufen
    bool result = toRead(destination);
    Serial.printf("Datei lesen %s!\n", result ? "erfolgreich" : "fehlgeschlagen");
    
    // Testdaten Seriell ausgeben
    Serial.println("\nAusgabe:");
    Serial.println(destination.button);
    Serial.println(destination.currentTemp);
    Serial.println(destination.minTemp);
    Serial.println(destination.maxTemp);
    Serial.println(destination.minTime);
    Serial.println(destination.maxTime);
  }
}

Testausgabe:

Datei schreiben erfolgreich!
Datei lesen erfolgreich!

Ausgabe:
1
8.40
-2.30
15.90
10:29:04
06:55:32


6 Kommentare - Kommentar eintragen
H2orst ✪ ✪ ✪ 09.04.2024
Hut ab für deine Codes, Ideen und all die Variationen!
Darin ist genug zu lernen, probieren und neu zusammen setzen um eigene Projekte zu kreieren für lange Zeit.
Einfach nur Spitze. Schade ist nur das maximum 3 Sterne vergeben werden können. Ausgegangen von der Standard Bewertung sollten 5 Sternen für dich möglich sein.
Etwas anderes. Ich bin auf deine Seite gekommen weil ich ein Alten Heizungs-Thermostat durch ein ESP XXX ersetzen möchte wobei mir viele kleine Feature eingefallen sind. Ein B.z wäre wenn ein Abend mal länger wird die Heizung durch druck auf eine Taste +1 die Zeit um eine Stunden verlängern.
Wenn möglich würde mich eine Kontakt Aufnahme, für ein Paar Ideen Auszutauschen, sehr freuen.



Antwort:
Für einen Austausch, nutze bitte das Kontaktformular.

Gruß Fips
db91595 ✪ ✪ ✪ 19.02.2023
Ähre wem Ähre gebührt! (kein Schreibfehler - Absicht. Weil Fips sich so viel Mühe gemacht hat. Das ist eine Fundgrube und es macht so viel Freude darin zu stöbern.)
Herzlichen Dank Ähre ))

Antwort:
Danke, für dein Feedback.

Gruß Fips
UweL ✪ ✪ ✪ 30.09.2021
Hallo Fips,
ich möchte Deine Template.ino[Durchschnitt] verwenden. Meine Daten sind aber nicht in einem const[array], sondern können unterschiedliche Größen haben. Also z.B. 150 Daten, 100 Daten, 120 Daten usw. Die Rohdaten stammen vom 'analogRead'. Kann man das Template für diese Flexibilität umschreiben ?
Vielen Dank.

Antwort:
Entweder du machst das Array groß genug und füllst es mit Null auf oder verwendest die C++ Containers library ( zB.: std::vector), was ich vorziehen würde.

Gruß Fips
Markus B. ✪ ✪ ✪ 31.08.2021
Auch von mir Hochachtung für deine Arbeit und Mühen,
hier kann ich noch viel lernen (und gebrauchen) !!

MB

Antwort:
Danke, für dein Feedback!

Gruß Fips
Alf Rempka ✪ ✪ ✪ 07.04.2021
Super Vorlagen, da kann ich einiges lernen
Hast du auch ein einen Ringpuffer um neuste Daten zu speichern und die ältesten zu löschen?

Antwort:
Im TX23 Tab sind 6 "first in first out" Puffer enthalten.

Gruß Fips
Helge ✪ ✪ ✪ 09.03.2021
Danke!
Diese Seite ist der Hammer.
Gruss

Antwort:
Danke, für dein Feedback!

Gruß Fips
Kommentar eintragen

*