Forum: Compiler & IDEs Alarme und Positionsvariablen durchlaufen lassen


von Stefanie (Gast)


Lesenswert?

Hi,
ich habe ein int-Variable, bei der jedes Bit für einen Alarm steht.

Nun habe ich für jeden Alarm eine Fehlermeldung abgespeichert (die ich 
durch defines aufrufen kann: Error0, Error1, ....)

Die Fehlermeldungen sollen der Reihe nach am Bildschirm angezeigt werden 
(zweispaltig), die einzelnen Positionen habe ich auch mit #defines 
festgelegt
#define x_ErrorResult0_8              20
#define x_ErrorResult9_16            420
#define y_ErrorResult0_9              70
#define y_ErrorResult1_10            110
#define y_ErrorResult2_11            150
#define y_ErrorResult3_12            190
...

Nun möchte ich Bitweise meine Alarmvariable durchlaufen und im 
Fehlerfall die Alarme der Reihe nach am Bildschirm ausgeben.

Wie mache ich das am geschicktesten?
(Ich dachte an eine for-Schleife, die die Alarmvariable durchläuft und 
im Fehlerfall die Alarmpositionen incrementiert, ist aber alles noch 
sehr vage)
Hat wer eine bessere Idee?

von Wolfgang Horn (Gast)


Lesenswert?

Nachteule an Stefanie:

> ich habe ein int-Variable, bei der jedes Bit für einen Alarm steht.
> Nun möchte ich Bitweise meine Alarmvariable durchlaufen und im
> Fehlerfall die Alarme der Reihe nach am Bildschirm ausgeben.

Denke doch mal wie ein Projektmanager: Was muss zuletzt passieren?
Da könnte eine printf(cAlarmmeldungen)-Anweisung stehen, die den String 
"cAlarmmeldungen" ausgibt.
Was muss im zweitletzten Schritt passieren? Dieser String muss 
zusammengepuzzelt worden sein. Das wird jetzt Arbeit, deshalb zieht sich 
der Berater hochnäsig aus der Affäre....

Huhuhuuu!
Nachteule

von Karl H. (kbuchegg)


Lesenswert?

Stefanie schrieb:
> Hi,
> ich habe ein int-Variable, bei der jedes Bit für einen Alarm steht.
>

Du meinst: Jedes Bit steht für einen andern Typ von Alarm


> (zweispaltig), die einzelnen Positionen habe ich auch mit #defines
> festgelegt
> #define x_ErrorResult0_8              20
> #define x_ErrorResult9_16            420
> #define y_ErrorResult0_9              70
> #define y_ErrorResult1_10            110
> #define y_ErrorResult2_11            150
> #define y_ErrorResult3_12            190
> ...

vorhin hast du noch von Bits gesprochen und jetzt tauchen da 
Dezimalzahlen auf. Das ist nicht besonders geschickt. Denn aus dem 
Dezimalzahlen sieht man nicht, wie sich die Zahl aus den Bits 
zusammensetzt (ausser du bist sehr gut und kennst die binären 
Darstellungen aller Zahlen von 0 bis 255 auswendig)

Mach dir doch nicht selbst das Leben schwer.

Als erstes definierst du deine Alarmtypen. Für die Bits könnte man 
binäre Zahlen oder auch Hex-Zahlen nehmen oder aber die 
Shift-Schreibweise
1
als Hexzahlen geschrieben
2
3
#define     OVERFLOW_ALARM      0x01
4
#define     WATER_STOP_ALARM    0x20
5
#define     LIGHT_OFF_ALARM     0x40
6
#define  ....
7
8
als Binärzahlen geschrieben
9
10
#define     OVERFLOW_ALARM      0b00000001
11
#define     WATER_STOP_ALARM    0b00000010
12
#define     LIGHT_OFF_ALARM     0b00000100
13
#define  ....
14
15
oder in der Shift-Schreibweise
16
17
#define     OVERFLOW_ALARM      (1 << 0)
18
#define     WATER_STOP_ALARM    (1 << 1)
19
#define     LIGHT_OFF_ALARM     (1 << 2)
20
#define  ....

jede einzelne der Schreibweisen ist schon mal besser als Dezimalzahlen, 
weil man mit ein wenig übung sofort erkennen kann, welches Bit für 
welchen Alarmtyp zuständig ist

Aus diesen Alarmtypen setzt du dir jetzt deine Kombinationen zusammen. 
Das machst du aber nicht, indem du selber die Zahlen zusammenzählst, 
sondern das lässt du den Compiler für dich machen
1
#define x_ErrorResult0_8     ( OVERFLOW_ALARM | LIGHT_OFF_ALARM )
2
#define x_ErrorResult9_16    ( WATER_STOP_ALARM | LIGHT_OFF_ALARM )
3
#define y_ErrorResult0_9  ...
4
...

Und dann schreibst du dir eine Funktion, die einen kombinierten 
Alarmwert wieder in die Bits aufdröselt und dir entsprechende Meldung 
ausgibt
1
void notifyUser( unsigned int Alarm )
2
{
3
  if( Alarm & OVERFLOW_ALARM )
4
    printf( "Es ist ein Overflow aufgetreten\n" );
5
6
  if( Alarm & WATER_STOP_ALARM )
7
    printf( "Das Rückschlagventil der Waschmaschine hat ausgelöst\n" );
8
9
  if( Alarm & LIGHT_OFF_ALARM )
10
    printf( "Im Vorhaus hat die ganze Nacht das Licht gebrannt\n" );
11
12
  ....
13
}


Organisation ist das halbe Leben eines Programmierers. Und das fängt 
ganz unten bei den Bits an. Man fängt immer bei den kleinsten Einheiten 
(in deinem Fall den Bits) an, diesen Namen zu geben und arbeitet dann in 
weiterr Folge mit diesen Namen und nicht mehr mit den konkreten 
Zahlenwerten


Bitmanipulation

von Stefanie (Gast)


Lesenswert?

Hallo Karl Heinz,

vielen herzlichen Dank für deine ausführliche Antwort!!!

Du hast dir soviel Arbeit gemacht, aber ich hab die Frage ganz anders 
gemeint.

Ich habe meine Alarme bereits so definiert:
#define LED_TEST_FAILED    0
#define BUZZER1_TEST_FAILED  1
...
und ich habe auch die dazugehörigen Alarmmeldungen definiert, diese kann 
ich mit Error0, Error1, ....aufrufen (die Zahl steht für das Alarmbit).

Nun sind diese dezimalen Zahlen die POSITIONEN, wo die Alarmmeldung 
stehen soll
z.B. der erste Alarm auf x_ErrorResult0_8, y_ErrorResult0_9
der zweite Alarm auf     x_ErrorResult0_8, y_ErrorResult1_10
der dritte Alarm auf     x_ErrorResult0_8, y_ErrorResult2_11
der 9.Alarm wäre in der 2. Spalte also auf
                         x_ErrorResult9_16,y_ErrorResult0_9
und der 10. wäre in der 2. Spalte an 2.Position
                         x_ErrorResult9_16,y_ErrorResult1_10

Nun kann ich aber nicht jeder Alarmmeldung einen festen Platz zuweisen, 
sondern diese Meldungen sollen je nachdem welche Alarme aktiv sind, der 
Reihe nach angezeigt werden.

Meine Arbeitsschritte lauten also
1.Durchlaufen meiner Fehlervariablen
2.Bei erkanntem Fehler (Bit ist gesetzt) den Fehlerstring an der 
obersten Alarmposition ausgeben
3.Nächstes gesetzte Bit suchen
4.an der nächsten Alarmposition am Bildschirm ausgeben...

Vielleicht wäre es einfacher, wenn ich die Koordinaten mit
x_ErrorResult0, y_ErrorResult0,
x_ErrorResult1, y_ErrorResult1,
x_ErrorResult2, y_ErrorResult2,
benennen würde?

von Matthias L. (Gast)


Lesenswert?

>Nun kann ich aber nicht jeder Alarmmeldung einen festen Platz zuweisen,
>sondern diese Meldungen sollen je nachdem welche Alarme aktiv sind, der
>Reihe nach angezeigt werden.

Sowas hab ich mal mit ner verketteten Liste gemacht.

Immer wenn ein Alarm aktiviert wird (Set), dann kommt er in die 
verkettete Liste. Wird der Alarm gelöscht/quittiert, fliegt er aus der 
Liste heraus.

Also kurz so:

Alarm  <=  => verk. Liste
-----------------------------
Set            an Anfang der Liste eintragen/verschieben
Reset          aus Liste löschen.


Unabhängig davon kannst du die verkettete Liste (nach logischer) 
Reihenfolge auslesen und die eingetragenen Alarme nach 
(Aktivierungs)Reihenfolge anzeigen.

von Stefanie (Gast)


Lesenswert?

Kann ich es auch so machen:

1.Gehe zu x_ErrorResult0, y_ErrorResult0 (1.Alarmposition)
2.for(...) //Alarmvariable durchlaufen, bis 1.Bit gesetzt >> 
Dazugehörige Alarmmeldung ausgeben
3.Aktuelle Stelle der Alarmvariablen z.B. in Alarmtemp abspeichern
3.Gehe zur 2. Alarmposition
4.for-Schleife ab i=Alarmtemp+1 beginnen, nächsten Alarm ausgeben usw.
5.Wenn Alarmvariable durchlaufen, mit return alles verlassen.

Würde das gehen?
Wie würde es aussehen, wenn ich die Alarmvariable bitweise durchlaufe?

von Karl H. (kbuchegg)


Lesenswert?

Stefanie schrieb:
> Kann ich es auch so machen:
>
> 1.Gehe zu x_ErrorResult0, y_ErrorResult0 (1.Alarmposition)
> 2.for(...) //Alarmvariable durchlaufen, bis 1.Bit gesetzt >>
> Dazugehörige Alarmmeldung ausgeben
> 3.Aktuelle Stelle der Alarmvariablen z.B. in Alarmtemp abspeichern
> 3.Gehe zur 2. Alarmposition
> 4.for-Schleife ab i=Alarmtemp+1 beginnen, nächsten Alarm ausgeben usw.
> 5.Wenn Alarmvariable durchlaufen, mit return alles verlassen.
>
> Würde das gehen?

Könnte hinkommen. Kommt mir aber kompliziert vor

> Wie würde es aussehen, wenn ich die Alarmvariable bitweise durchlaufe?

Bitmanipulation

Wenn du die 'Nummer' des auszugebenden Alarms hast, kannst du dir daraus 
ja ganz leicht ausrechnen in welcher Spalte bzw. Zeile der kommen muss, 
und dann entsprechend Positionieren

So ungefähr
1
  uint8_t alarmNr = 0;
2
  uint16_t alarmSpalten[] = { x_ErrorResult0_8, x_ErrorResult9_16 };
3
  uint16_t alarmZeilen[] = { y_ErrorResult0_9, y_ErrorResult1_10, y_ErrorResult2_11, ... };
4
  const char* Alarmmeldung[] = {
5
     "LCD test fehlgeschlagen",
6
     "Buzzer antwortet nicht",
7
     "V'ger will den Schöpfer sprechen",
8
     "Beem me up, Scotty",
9
     ...
10
  };
11
12
  for( i = 0; i < sizeof(int); ++i ) {  // alle Bits durchgehen
13
    if( alarm & ( 1 << i ) ) {          // ist das entsprechende Alarmbit gesetzt?
14
      utin8_t Spalte = alarmNr / 8;                   // 8 Meldungen pro Spalte
15
      uint8_t Zeile  = alarmNr % 8;
16
17
      setPos( alarmSpalten[Spalte], alarmZeilen[Zeile] );
18
      output( Alarmmeldung[i] );
19
20
      alarmNr++;
21
    }
22
  }


Ich hoffe ich habe dich diesmal nicht falsch verstanden.


> Vielleicht wäre es einfacher, wenn ich die Koordinaten mit
> x_ErrorResult0, y_ErrorResult0,
> x_ErrorResult1, y_ErrorResult1,
> x_ErrorResult2, y_ErrorResult2,
> benennen würde?

Das bringt dich überhaupt nicht weiter. Mir scheint du hast eine falsche 
Vorstellung davon, was ein #define eigentlich macht. Was du brauchst 
sind richtige Variablen. Eventuell sogar Arrays, in denen du die 
Positionen bzw. Texte speicherst, damit du dann mit dem entsprechenden 
Index zugreifen kannst. Mit #define kommst du da nicht weiter.

von Stefanie (Gast)


Lesenswert?

@Karl Heinz

Vielen lieben Dank, es funktioniert (fast)!!

Leider scheitert es bei Fehlern deren Bit-Nr > 8 ist
Meine "alarm" Variable ist vom Typ int

und ich habe z.B. folgendes definiert
#define TEMP_TEST_FAILED    10
#define BUZZER2_TEST_FAILED 11

und setzte diese Alarme auch:
1
{
2
//10.Bit der Variablen setzen
3
alarm" |= (1 << TEMP_TEST_FAILED);
4
}
5
6
oder
7
{
8
//11.Bit der Variablen setzen
9
alarm" |= (1 << BUZZER2_TEST_FAILED);
10
}

Doch in meiner int-Variablen sind ab dem 8.Bit nie Werte gesetzt.
Ich nutze den Codevision-Compiler.
Ist da was anders?

von Ralf G. (ralg)


Lesenswert?

Sehr mystisch. Eigentlich müsste es gehen. Diesen Effekt hat man 
normalerweise nur, wenn die Datenbreite der Konstanten nicht passt. Aber 
'int' mit 16Bit sollte eigentlich immer das Minimum sein.
Mal probieren:
1
1L << TEMP_TEST_FAILED

von Karl H. (kbuchegg)


Lesenswert?

Stefanie schrieb:

> Doch in meiner int-Variablen sind ab dem 8.Bit nie Werte gesetzt.
> Ich nutze den Codevision-Compiler.
> Ist da was anders?

Könnte sein.
Der Codevision Compiler verlässt ab und zu zu Gunsten von 8-Bit Komfort 
den C-Standard. Scheinbar hat er nicht realisiert, dass er bei

   1 << TEMP_TEST_FAILED

das ganze als 16 Bit Operation implementieren muss und ist bei 8 Bit 
stecken geblieben (und genau wegen solcher Sachen mag ich diese nicht 
Standard Erweiterungen nicht).

NUr: wie bringen wir ihn da jetzt dazu.

Probier mal alle Variablen auf unsigned zu machen. Das solltest du dir 
sowieso angewöhnen, wenn du mit Bits operierst.
Alarm ist eine unsigned Variable, weil alle Bits völlig gleich sind und 
du nur an den Bits selber interessiert bist. Dass da das MSB bei einem 
int eine Sonderfunktion (das Vorzeichenbit) hat, willst du hier 
überhaupt nicht haben.

Ev. reicht das dem Compiler schon, dass er da keine 8-Bit Mätzchen mehr 
spielt.

von Ralf G. (ralg)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Der Codevision Compiler verlässt ab und zu zu Gunsten von 8-Bit Komfort
> den C-Standard.
Die Variablen hat sie ja 16-Bit (außer 'int' ist beim Codevision 
Compiler nur 8 Bit (???) ).
Aber die mit #define angelegten Konstanten und die 'Schiebe-Eins' werden 
bestimmt auf 8 Bit zusammengestrichen.

Die Umwandlung von 'int' nach 'unsigned int' würde ich erstmal in die 
Abteilung 'notwendige Schönheitsoperationen' verlegen.

Erste Wahl wäre für mich:
Ralf G. schrieb:
> Mal probieren: 1L << TEMP_TEST_FAILED
oder: (unsigned int)1 << TEMP_TEST_FAILED

Da fällt mir auf: Doch alles auf 'unsigned' ändern! Nicht, dass die 
nächsten Schwierigkeiten beim Bit 15 auftreten, weil der Compiler kein 
logic-shift macht.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.