Wie bekomme ich meine Vorgaben in eine Struktur gepackt

Hallo zusammen,

ich will einen Entfeuchter zu bestimmten Zeitfenstern jeweils mit Grenzwerten versorgen.
Beispiel:
Unter der Woche:

  • Nacht= 22:00 Uhr; Obergrenze 70; Untergrenze 60
  • Morgen = 9.00 Uhr; Obergrenze 65; Untergrenze 55
  • Mittag = 12.00 Uhr ; Obergrenze 60; Untergrenze 50
  • Abend = 18.00 Uhr ; Obergrenze 55; Untergrenze 50
    Und das gleiche fürs Wochenende.
  • Nacht= 22:00 Uhr; Obergrenze 70; Untergrenze 60
  • Morgen = 11.00 Uhr; Obergrenze 65; Untergrenze 55
  • Mittag = 15.00 Uhr; Obergrenze 60; Untergrenze 50
  • Abend = 19.00 Uhr; Obergrenze 55; Untergrenze 50

Wie bekomme ich das in eine Struktur?

Enum Zust {Nacht, Morgen, Mittag, Abend};
Enum Zust Zustand=Nacht;

Der Zustand hat eine Zeit=Stunde*60+Minute und eine Ober- und Untergrenze und eine Unterscheidung WE, oder Woche.

Ich könnte:

boolean WE; // Wochenende Ja/nein
boolean Obergrenze;

Wenn WE=false und Obergrenze=false und Zustand=Nacht, dann ist
Vorgabe[WE,Obergrenze,Nacht]= Vorgabe[0,0,0] ist die Untergrenze unter der Woche in der Nacht

Wenn WE=true und Zustand =Abend, dann ist Zeit[WE,Zustand]=Zeit[1,3] = Startzeit Abend am Wochenende.

Ich werde 2 Felder machen. Eins mit der Zeit (int Zeit[Zustand,WE]) und eins mit den Grenzwerten (byte GW[Zustand,Obergrenze])

Vorsicht, pascalige Syntax!

Ich würde eine

struct MyStruct { int Obergrenze, Untergrenze; };

deklarieren, und davon ein Array

const struct MyStruct Grenzen[enum Zust] = ...

Die Ermittlung des Zustands hast Du ja schon skizziert.

Hallo,

Vorschlag.

/*
  16.01.2019
  https://forum.arduino.cc/index.php?topic=591139.0
*/

// konkrete Wertzuweisung wegen Indexzugriff
enum {nacht = 0, morgen = 1, mittag = 2, abend = 3};

struct t_setup
{
  const byte uhrzeit;
  const byte obergrenze;
  const byte untergrenze;

  // Konstruktor
  t_setup (byte _t, byte _o, byte _u) :
    uhrzeit(_t),
    obergrenze(_o),
    untergrenze(_u)
  {}
};

t_setup woche[] = {
  {22, 70, 60},   // nacht
  { 9, 65, 55},   // morgen
  {12, 60, 50},   // mittag
  {18, 55, 50},   // abend
};

t_setup wochenende[] = {
  {22, 70, 60},  
  {11, 65, 55},
  {15, 60, 50},
  {19, 45, 40},
};


// falls für Index und for Schleife benötigt
const byte ANZAHL_woche = sizeof(woche) / sizeof(t_setup);
const byte ANZAHL_wochenende = sizeof(wochenende) / sizeof(t_setup);


void setup()
{
  Serial.begin(9600);

  // Zugriffsbeispiele
  // um mit dem Index drüber zugehen könnte man das so machen
  byte a = woche[0].uhrzeit;
  byte b = woche[3].untergrenze;

  // oder per enum
  byte c = wochenende[mittag].uhrzeit;
  byte d = wochenende[abend].untergrenze;

  Serial.print(a); Serial.print('\t'); Serial.println(b);
  Serial.print(c); Serial.print('\t'); Serial.println(d);
}


void loop()
{
  
}

Ich würde noch den Wochentag als Bitfield mit ins struct aufnehmen.

Als Code sieht das dann so aus:

#define montag     0b00000001
#define dienstag   0b00000010
#define mittwoch   0b00000100
#define donnerstag 0b00001000
#define freitag    0b00010000
#define samstag    0b00100000
#define sonntag    0b01000000

#define werktag (montag | dienstag | mittwoch | donnerstag | freitag)
#define wochenende (samstag | sonntag)
#define taeglich (werktag | wochenende)

struct ausloeser{
  byte wochentag; // bitfield des wochentages
  uint16_t startzeit; // minuten seit mitternacht
  int obergrenze;
  int untergrenze;
};

#define anzahl_ausloeser 8

ausloeser werte[anzahl_ausloeser] = { // muss nach startzeit aufsteigend sortiert sein
  {taeglich, 0, 70, 60},
  {werktag, 540, 65, 55},
  {wochenende, 660, 65, 55},
  {werktag, 720, 60, 50},
  {wochenende, 900, 60, 50},
  {werktag, 1080, 55, 50},
  {wochenende, 1140, 55, 50},
  {taeglich, 1320, 70, 60}
};


int findeAusloeser(uint16_t uhrzeit, byte wochentag){
  // uhrzeit -> minuten seit mitternacht
  // wochentag -> 0..6, 0=montag, 1=dienstag, ... 6=sonntag
  int idx = -1;

  byte wochentagBit = 1<<wochentag;

  for(int x=0; x<anzahl_ausloeser; x++){
    if((werte[x].wochentag & wochentagBit) == 0){
      // ausloeser nicht fuer diesen wochentag aktiv
      continue;
    }
    if(werte[x].startzeit <= uhrzeit){
      idx = x;
    }
  }
  return idx;
}

//********************************************

uint16_t jetzt = 0;
byte wochentag = 0;

String wochentage[] = { "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"};

void setup() {
  Serial.begin(9600);
}

void loop() {
  jetzt += 30;
  if(jetzt >= (24*60)){
    wochentag += 1;
    wochentag = wochentag % 7;
  }
  jetzt = jetzt % (24*60);

  int idx = findeAusloeser(jetzt, wochentag);
  
  int stunde = jetzt / 60;
  int minute = jetzt % 60;
  
  Serial.print(stunde);
  Serial.print(":");
  Serial.print(minute);
  Serial.print("\t");
  Serial.print(wochentage[wochentag]);
  Serial.print(":\t");

  if (idx >= 0){
    Serial.print(werte[idx].obergrenze);
    Serial.print("\t");
    Serial.println(werte[idx].untergrenze);
  }

  delay(500);
}

Vielen Dank DrDiettrich, Doc_Arduino und Rintin,

sehr nett für die tolle Antwort.

Gehe ich richtig in der Annahme, dass der Compiler die Wertzuweisung für die Zustände automatisch macht. Dem erster Zustand wird die 0 zugewiesen, dem 2. die 1 usw.

Ich muss also nicht explizit

enum {nacht = 0, morgen = 1, mittag = 2, abend = 3};

zuweisen.

boolean a = true, b = true;
byte Feld[2][2];
byte x, y;
int i, j;
void setup() {
  Serial.begin(9600);
  Serial.println(F("Start"));

  for ( i = 0; i < 2; i++) {
    for ( j = 0; j < 2; j++) {
      Feld[i][j] = i * 2 + j;
      Serial.print("i="); Serial.print(i);
      Serial.print(" j="); Serial.print(j);
      Serial.print("Feld["); Serial.print(i); Serial.print("]["); Serial.print(j);
      Serial.print("]="); Serial.println(Feld[i][j]);
    }
  }
}

void loop() {

  for (i = 0; i < 2; i++) {
    a = !a;
    for (j = 0; j < 2; j++) {
      b = !b;
      Serial.print(F("Feld[i,j]="));
      Serial.print(Feld[i][j]);
      Serial.print(F("Feld["));
      if (a) Serial.print(F("true")); else Serial.print(F("false"));
      Serial.print(F(","));
      if (b) Serial.print(F("true]=")); else Serial.print(F("false]="));
      Serial.println(Feld[a][b]);
    }
  }
  while (1);
}

liefert

Start
22:36:20.499 -> i=0 j=0Feld[0][0]=0
22:36:20.499 -> i=0 j=1Feld[0][1]=1
22:36:20.546 -> i=1 j=0Feld[1][0]=2
22:36:20.593 -> i=1 j=1Feld[1][1]=3
22:36:20.593 -> Feld[i,j]=0Feld[false,false]=0
22:36:20.593 -> Feld[i,j]=1Feld[false,true]=1
22:36:20.640 -> Feld[i,j]=2Feld[true,false]=2
22:36:20.687 -> Feld[i,j]=3Feld[true,true]=3

Null und eins kann man also beliebig durch true und false ersetzen.

Ja, macht er. Nur wenn Du abweichende Werte willst, musst Du sie explizit angeben.

Gruß Tommy

Hi

Du musst nicht, Du KANNST aber.
Normal wird auch mit 0 begonnen und hoch gezählt.
Wenn Du für die Bezeichnungen keinen expliziten Wert benötigst, lass den Kompiler sich dafür die Zahlen 'ausdenken'.
Du willst ja eh über die Bezeichner arbeiten, da ist der eigentliche Wert dahinter völlig egal.
(so wie A0 auf dem Nano/Uno für den Wert 14 steht und damit den Digital-Pin D14=A0 benennt, Der in anderen Tiefen des Framework auf einen µC-Pin gemapt ist, Der rein gar Nichts mit 0 oder 14 zu tun haben muß).

In dem Beispiel oben von DocArduino in #2 sind die 0...3 allerdings genau so wichtig, da diese Zahlen sich auf den Index von woche[] beziehen - und bei 4 Elementen muß der Index 0...3 sein.

MfG

postmaster-ino:
In dem Beispiel oben von DocArduino in #2 sind die 0...3 allerdings genau so wichtig, da diese Zahlen sich auf den Index von woche[] beziehen - und bei 4 Elementen muß der Index 0...3 sein.

Das ist er bei der automatischen Zuordnung auch.

Gruß Tommy

Hallo,

enums wird der Wert erstmal automatisch zugewiesen. Richtig.
In der Regel fängt es bei 0 an und ist fortlaufend.
Nur darauf verlassen kann/sollte man sich nicht.
Erst recht nicht wenn es für den Indexzugriff wichtig ist.
postmaster hat das Problem schon richtig erkannt. Ich habe es auch nicht umsonst kommentiert. :wink:
Der Compiler kann den enums irgendwelche Werte zuweisen, weil es dem Anwender im Normalfall nicht interessiert welche Werte dahinter stehen. Spätestens wenn Hausknecht noch ein zweites enum davor deklariert wird es essig, wenn er alles dem Compiler überlässt.

Welche anderen Werte sollte ein Compiler den Elementen zuweisen, als jeweils 1 mehr als für das vorige Element? Andere Enums haben auf die Wertevergabe keinen Einfluß.

Hallo,

ich meinte mit welchen Wert er anfängt bei der Zuweisung.

Ist aber alles Schnee von gestern. Da muss ich mich korrigieren. Ich dachte ich hätte das einmal gelesen, dass man sich auf die Wertzuweisung nicht verlassen kann, also das er nicht immer mit 0 anfängt. Er könnte auch alle enums zusammenfassen und durchnummerieren, solange es in sein Standard int passt. Das hatte ich im Kopf gehabt. :o

Habe das getestet, er fängt tatsächlich immer bei 0 an. Egal ob verschiedene enums oder verschiedene Initialisierungen mit dem gleichem enum.

Habe auch im Working Draft N4791 Seite 194 nachgelesen. Ohne ersten Initialisierer beginnt es mit Null. Demnach kann man sich darauf verlassen. https://github.com/cplusplus/draft/blob/master/papers/n4791.pdf

Entschuldigung, wollte niemanden durcheinander bringen oder Mist erzählen.

Vielen Dank für deine Mühe.
Wir sind doch alle nur Menschen und es geht ja auch nicht ums Recht haben.
Ich finde es toll, dass hier so geholfen wird.

Nochmal vielen Dank.