Ein- Aussteuerung

Hallo,
bin Anfänger beim Arduino. Ich möchte einen analog eingelesen Wert in Ein-/Ausschaltzeit eines Relais realisieren.
Die Erfassung eines Wertes Über Analogeingang A1 (0-1023) und Umsetzung mittels MAP (0-100%) stellt kein Problem dar. Auch habe ich eine Berechnung in Ein-/Ausschaltzeit schon hinbekommen (Bild).

Ich habe jetzt zwei Variablen einzeit und auszeit. Was ich nicht hinbekomme, wie steuere ich jetzt den Relaisausgang (Pin9) möglichst mit millis? Kann mir da jemand auf die Sprünge helfen?

Es soll in etwa sowas bei raus kommen, eben mit millis:

digitalWrite(RelaisPin, HIGH);
delay (einzeit);
digitalWrite(RelaisPin, LOW);
delay (auszeit);

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Setze die LCD I2C Addresse

int RelaisPin = 9;    // Relaisanschluss
int analogPin1 = 1;   // Potentiometer an A1 (0 - 5V)

int val1 = 0;
int analogA1 = 0;
int einzeit = 0;      // Variable um die Einschaltzeit zu speichern
int auszeit = 0;      // Variable um die Ausschaltzeit zu speichern

void setup()
{
  lcd.begin(20, 4);             // initialisiere das LCD
  lcd.clear();                  // LCD löschen
  lcd.home ();                  // Zeile 1
  pinMode(RelaisPin, OUTPUT);   // den LED-Pin als Ausgang konfigurieren
}

void loop()
{
  val1 = analogRead(analogPin1);         // Pin A1 lesen 
  analogA1 = map(val1, 0, 1023, 0, 100); //Umwandeln des Sensorwertes mit Hilfe des "map" Befehls
  
  lcd.home();                           // Homeposition
  lcd.print("Analog-In: ");             // 0 - 1023
  lcd.print(val1);                      // Analogwert von A1 anzeigen
  lcd.print("  ");

einzeit = 60 * analogA1 / 200;          // Einschaltzeit berechnen
auszeit = 30 - einzeit;             // Auszeit berechnen

  lcd.setCursor ( 0, 1 );           // LCD 2. Zeile Position 0 weiter schreiben
  lcd.print("Umrechnung: ");        // umgerechneten Map-Wert in 0-100% anzeigen
  lcd.print(analogA1);
  lcd.print("% ");
  lcd.setCursor ( 0, 2 );           // LCD 3. Zeile Position 0 weiter schreiben
  lcd.print("Einzeit: ");           // Einschaltzeit anzeigen
  lcd.print(einzeit);
  lcd.print(" ");
  lcd.setCursor ( 0, 3 );           // LCD 4. Zeile Position 0 weiter schreiben
  lcd.print("Auszeit : ");          // Ausschaltzeit anzeigen
  lcd.print(auszeit);
  lcd.print(" ");

}

So sieht es schon auf dem LCD aus:

comp_20200510_162324.jpg

Du musst Dir erst mal merken, in welchem Status Dein Relais ist. (an/aus)
Ansonsten schau Dir das Beispiel BlinkWithoutDelay in der IDE an. Da siehst Du die Arbeit mit millis(). Evtl. hilft Dir auch die Lektüre der Nachtwächtererklärung.

Gruß Tommy

Die Beispiele "BlinkWithoutDelay" und die "Nachtwächtererklärung" habe ich schon durchgekaut. Komme aber nicht dahinter wie ich das in meinem Beispiel umsetzen muss. Deswegen frage ich ja hier.

der_klaus:
Die Beispiele "BlinkWithoutDelay" und die "Nachtwächtererklärung" habe ich schon durchgekaut. Komme aber nicht dahinter wie ich das in meinem Beispiel umsetzen muss. Deswegen frage ich ja hier.

Nachtrag: Eine Abfrage des Relaiszustandes ist irrelevant. Ich möchte x Sekunden den Ausgang einschalten und y Sekunden wieder aus.

Dann hast Du sie noch nicht verstanden.

Womit willst Du denn den Vorgang starten? Ich sehe keinen Taster oder ähnliches. Oder soll das gleich beim Einschalten des Arduino los gehen und sich immer wiederholen?

Gruß Tommy

Edit:

der_klaus:
Nachtrag: Eine Abfrage des Relaiszustandes ist irrelevant. Ich möchte x Sekunden den Ausgang einschalten und y Sekunden wieder aus.

Und wie willst Du dann unterscheiden, ob Du die Zeit für angezogen oder die für abgefallen beachten musst?

Verstehen, im Prinzip schon. Nur wie ich das mit meinen beiden berechneten Variablen umsetze nicht.

Der Vorgang soll, wie der Sketch zeigt, sofort starten und sich immer wiederholen, ja.

Stell dir eine völlig unbrauchbare Temperaturregelung eines Grills vor (Bild). Der hat eine solch hohe Hysterese, macht kein Spaß, braucht ewig um nach dem Abschalten wieder Einzuschalten. Der Grillprozess ist eher ein garen. Das Grillgut kühlt länger ab, als es beim anheizen gebraucht hatte.

Nun habe ich mir zur Aufgabe gestellt das Teil effizienter zu gestalten. Habe experimentiert und bin auf Ein-/Ausschaltdauer gekommen, wobei ich sehr gute Ergebnisse erziehlt habe. Per Hand habe ich etwa 40% Heizzeit für Hähnchen eroiert. Das wären pro Minute 24s an und 36s aus. Das möchte ich in zwei Ein-/Ausschaltphasen trennen, also 12s an, 18s aus, 12s an, 18s aus. Die Ein-/Ausschaltdauer möchte ich nicht per Temperaturregelung hinbekommen, sondern per Zeitsteuerung.

Die Berechnung habe ich schon hinbekommen. Nur mir der Umsetzung in millis habert es.

comp_20200510_171019.jpg

Ich denke schon, ja. Ich habe da eine Blockade beim Umsetzen drin. Komm nicht auf die Lösung.

Als Pseudocode:

bool zustand = true;
unsigned long startMillis;

// im Setup einschalten und startMillis auf millis() setzen


if (zustand && millis() - startMillis >= einzeit) {
  startMillis = millis();
  zustand = !zustand;
  // ausschalten
}
if (!zustand && millis() - startMillis >= auszeit) {
  startMillis = millis();
  zustand = !zustand;
  // einschalten
}

Gruß Tommy

Tommy56:
Als Pseudocode:

bool zustand = true;

unsigned long startMillis;

// im Setup einschalten und startMillis auf millis() setzen

if (zustand && millis() - startMillis >= einzeit) {
 startMillis = millis();
 zustand = !zustand;
 // ausschalten
}
if (!zustand && millis() - startMillis >= auszeit) {
 startMillis = millis();
 zustand = !zustand;
 // einschalten
}




Gruß Tommy

Muss ich erstmal sacken lassen. Mit 50 viel mir das noch um ein vielfaches einfacher, ab 70+ hapert es langsam :wink:

Danke mal. Melde mich wieder...
Vielen Dank bis hierher.

kompiliert, musst aber schaun, dass deine Poti was vernünftiges rausgibt…

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Setze die LCD I2C Addresse
//LiquidCrystal_I2C lcd(0x3F, 20, 4);  // für meins


const int relaisPin = 9;    // Relaisanschluss
const int analogPin1 = A1;   // Potentiometer an A1 (0 - 5V)

int val1 = 0;
int analogA1 = 0;
uint32_t einzeit = 0;      // Variable um die Einschaltzeit zu speichern
uint32_t auszeit = 0;      // Variable um die Ausschaltzeit zu speichen


void doRelay()
{
  static uint32_t previousMillis;
  if (millis() - previousMillis > auszeit && digitalRead(relaisPin) == LOW)
  {
    Serial.println(F("Einschalten"));
    digitalWrite(relaisPin, HIGH);
    previousMillis = millis();
  }
  if (millis() - previousMillis > einzeit && digitalRead(relaisPin) == HIGH)
  {
    Serial.println(F("Ausschalten"));
    digitalWrite(relaisPin, LOW);
    previousMillis = millis();
  }
}

void setup()
{
  Serial.begin(115200);
  Wire.begin();                 // für mein Display. Außerdem ist eh Schei..e wenn libraries Wire.begin heimlich aufrufen
  lcd.begin(20, 4);             // initialisiere das LCD
  lcd.clear();                  // LCD löschen
  lcd.home ();                  // Zeile 1
  pinMode(relaisPin, OUTPUT);   // den LED-Pin als Ausgang konfigurieren
}

void loop()
{
  val1 = analogRead(analogPin1);         // Pin A1 lesen
  analogA1 = map(val1, 0, 1023, 0, 100); //Umwandeln des Sensorwertes mit Hilfe des "map" Befehls

  lcd.home();                           // Homeposition
  lcd.print("Analog-In: ");             // 0 - 1023
  lcd.print(val1);                      // Analogwert von A1 anzeigen
  lcd.print("  ");

  einzeit = 60 * analogA1 / 200;          // Einschaltzeit berechnen
  auszeit = 30 - einzeit;             // Auszeit berechnen

  lcd.setCursor ( 0, 1 );           // LCD 2. Zeile Position 0 weiter schreiben
  lcd.print("Umrechnung: ");        // umgerechneten Map-Wert in 0-100% anzeigen
  lcd.print(analogA1);
  lcd.print("% ");
  lcd.setCursor ( 0, 2 );           // LCD 3. Zeile Position 0 weiter schreiben
  lcd.print("Einzeit: ");           // Einschaltzeit anzeigen
  lcd.print(einzeit);
  lcd.print(" ");
  lcd.setCursor ( 0, 3 );           // LCD 4. Zeile Position 0 weiter schreiben
  lcd.print("Auszeit : ");          // Ausschaltzeit anzeigen
  lcd.print(auszeit);
  lcd.print(" ");

  doRelay();
}

Poti gibt sinnvolles an den Arduino. Aber eine LED an Pin 9 flackert, vermutlich 50% an, 50% aus mehrmals pro Sekunde. Geschätzt 4-5 x pro Sekunde. Egal was am Poti eingestellt ist immer im gleichen Takt.

Interessanter Ansatz zur Steuerung.
Bin neugierig

Das Mapping mappt auf 100 (Millisekunden, nicht % wie der TO meint). Es muss also eine Zeit als Faktor festgelegt werden, die als 100% fungiert.

Gruß Tommy

Verstehe ich nicht. Das Mapping setzt nur die Werte des Analogeingangs (0-1023) auf 0-100 um. Warum sollen das Millisekunden an der Stelle sein?

der_klaus:
Muss ich erstmal sacken lassen.

Was Du benötigst, ist eine Kombination aus zeitlichem Ablauf und einer Schrittkette. Um das zu verdeutlichen, mal ein längeres Konstrukt:

void doRelay() {
  uint32_t jetzt;
  jetzt = millis();
  static uint32_t vorhin = jetzt, intervall = 0;
  enum {EIN, AUS};
  static byte schritt = AUS;
  switch (schritt) {
    case EIN:
      if (jetzt - vorhin >= intervall) {
        intervall = auszeit;
        vorhin = jetzt;
        digitalWrite(RelaisPin, LOW);
        schritt = AUS;
      }
      break;
    case AUS:
      if (jetzt - vorhin >= intervall) {
        intervall = einzeit;
        vorhin = jetzt;
        digitalWrite(RelaisPin, HIGH);
        schritt = EIN;
      }
      break;
  }
}

Das kann man dann noch eindampfen, beispielsweise so:

void doRelay() {
  uint32_t jetzt;
  jetzt = millis();
  static uint32_t vorhin = jetzt, intervall = 0;
  static bool ein = false;
  
  if (jetzt - vorhin >= intervall) {
    vorhin = jetzt;
    intervall = ein ? auszeit : einzeit;
    ein = !ein;
    digitalWrite(RelaisPin, ein);
  }
}

Nun lasse es sacken :slight_smile:

Tommy56:
Das Mapping mappt auf 100 (Millisekunden, nicht % wie der TO meint). Es muss also eine Zeit als Faktor festgelegt werden, die als 100% fungiert.

Das passiert hier:

einzeit = 60 * analogA1 / 200;        // Einschaltzeit berechnen

Da wird es ja noch kürzer. Da analogA1 auf max. 100 gemappt ist, ergibt sich als maximaler Wert 30 ms.
Da bleibt das Huhn roh.

Gruß Tommy

agmue:
Was Du benötigst, ist eine Kombination aus zeitlichem Ablauf und einer Schrittkette. Um das zu verdeutlichen, mal ein längeres Konstrukt:

An der Stelle resigniere ich, muss passen.

Tommy56:
Da bleibt das Huhn roh.

Der eine mag es so, ich eher knusprig.

Wenn ich mal zitieren darf:

der_klaus:
Die Erfassung eines Wertes Über Analogeingang A1 (0-1023) und Umsetzung mittels MAP (0-100%) stellt kein Problem dar. Auch habe ich eine Berechnung in Ein-/Ausschaltzeit schon hinbekommen (Bild).

Dann soll es so sein, da wollte ich mich nicht einmischen :slight_smile:

agmue:
Das passiert hier:

einzeit = 60 * analogA1 / 200;        // Einschaltzeit berechnen

Nein, an der Stelle wird nur eine Zahl generiert.
Ihr überlest das hier aus Post #1
digitalWrite(RelaisPin, HIGH);
delay (einzeit);
digitalWrite(RelaisPin, LOW);
delay (auszeit);

Ich möchte die errechnete Zahl, nicht wie ihr interpretiert in ms, sondern in Sekunden.
Viele Beiträge, immer neues, unterschiedliches. Ich kann nicht folgen.

Führe Dir das in Ruhe zu Gemüte. Für uns alle war das irgendwann mal neu und wir haben es gelernt.
Das ist auch unabhängig vom Alter, wenn man es lernen will.

Gruß Tommy

PS: Bei der Berechnumg sollte 60 auf 60000UL umgesetzt werden, bei der anderen Zeit entsprechend anpassen.