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?
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
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
alsHexzahlengeschrieben
2
3
#define OVERFLOW_ALARM 0x01
4
#define WATER_STOP_ALARM 0x20
5
#define LIGHT_OFF_ALARM 0x40
6
#define ....
7
8
alsBinärzahlengeschrieben
9
10
#define OVERFLOW_ALARM 0b00000001
11
#define WATER_STOP_ALARM 0b00000010
12
#define LIGHT_OFF_ALARM 0b00000100
13
#define ....
14
15
oderinderShift-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
Und dann schreibst du dir eine Funktion, die einen kombinierten
Alarmwert wieder in die Bits aufdröselt und dir entsprechende Meldung
ausgibt
1
voidnotifyUser(unsignedintAlarm)
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
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?
>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.
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?
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
for(i=0;i<sizeof(int);++i){// alle Bits durchgehen
13
if(alarm&(1<<i)){// ist das entsprechende Alarmbit gesetzt?
14
utin8_tSpalte=alarmNr/8;// 8 Meldungen pro Spalte
15
uint8_tZeile=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.
@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?
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:
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.
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.