Hallo,
ich möchte im Programm ein Signal für die Modellbahn schalten.
Controller ist der ATMEGA16.
Momentan sieht mein Programm folgendermaßen aus:
1
#define vorsignal_rot_0 (PORTD &= ~(1 << 4))
2
#define vorsignal_rot_1 (PORTD |= (1 << 4))
3
#define hauptsignal_rot_0 (PORTD &= ~(1 << 3))
4
#define hauptsignal_rot_1 (PORTD |= (1 << 3))
5
#define vorsignal_gruen_0 (PORTD &= ~(1 << 5))
6
#define vorsignal_gruen_1 (PORTD |= (1 << 5))
7
#define hauptsignal_gruen_0 (PORTD &= ~(1 << 2))
8
#define hauptsignal_gruen_1 (PORTD |= (1 << 2))
Im Programm werden die Signale dann folgendermaßen auf z.B. rot
geschaltet:
1
vorsignal_rot_1;
2
hauptsignal_rot_1;
3
vorsignal_gruen_0;
4
hauptsignal_gruen_0;
Gibt es eine Möglichkeit, das ganze noch etwas zu vereinfachen. So dass
z.B. mit einer Deklaration die Rote Lampe ein und die grüne gleichzeitig
ausgeschaltet wird? Momentan benötige ich hierfür 2 Deklarationen, die
ich ständig beide aufrufen muss.
MitLeser schrieb:> einfach für EIN Makro alle Bitmanipulationen durchführen> die gewünscht sind
zunächst mal Danke für den Hinweis.
Ich kenne mich mit C noch nicht so gut aus. Wenn ich es richtig
verstanden habe einfach 2 Bitmanipulationen hinter einem #define
geschrieben und durch ein & verknüpft. Ist das so richtig?
Das AVR Studio bringt mal keinen Fehler und funktionieren tut es auch.
Also ich habe ja Zweifel an der Grundidee, aber sowas muss jeder mal am
Anfang durchmachen und ich will das jetzt nicht kritisieren.
Aber in:
>Wenn ich es richtig verstanden habe einfach 2 Bitmanipulationen hinter einem
#define geschrieben und durch ein & verknüpft.
liegt jedenfalls ein Denkfehler. Warum sollten denn hier zwei
Zusweisungen Und-verknüfpft werden? Da das Resultat nicht verwendet
werden soll macht das keinen Sinn.
Ich vermute mal, das Und war die Lösung für das Problem: Wie führe ich
zwei Zuweisungen in einem Define aus.
Das geht auch anders und in einer Form die der Sprache gerecht wird.
Ein Vorschlag ist:
ist zwar zu spät aber so wie Kali schreibt hatte ich es auch gemeint.
ich würde coding style-mässig jedoch Makros gross schreiben, gibt es
hier im Forum auch Beiträge zu, Suchwörter "coding style",
"programmierregeln" etc.
Bsp:
#define LED_AUS() (PORTD |= (1 << 4))
Funktioniert bestens. Das mit der Großschreibung werde ich noch ändern.
Hier werde ich noch nach den empfolenen Beiträgen suchen und mal in
aller Ruhe durchlesen. Vielleicht kann ich noch mehr Punkte verbessern.
R. F. schrieb:> Gibt es eine Möglichkeit, das ganze noch etwas zu vereinfachen. So dass> z.B. mit einer Deklaration die Rote Lampe ein und die grüne gleichzeitig> ausgeschaltet wird? Momentan benötige ich hierfür 2 Deklarationen, die
Was spricht eigentlich dagegen, dafür das in C vorgesehene Sprachmittel
zu benutzen: Funktionen?
1
voidvor_stopp(void)
2
{
3
vorsignal_rot_1;
4
vorsignal_gruen_0;
5
}
6
7
voidvor_start(void)
8
{
9
vorsignal_rot_0;
10
vorsignal_gruen_1;
11
}
12
13
14
intmain()
15
{
16
....
17
18
19
vor_stopp();
20
...
Ich kann auf lange Sicht nur davor warnen, zuviel 'Funktions-Kram' in
Makros zu quetschen. Zumnal hier zwischen den Zeilen lesbar ist, dass
der Fragesteller wieder mal eine falsche Vorstellung davon hat, was
Makros eigentlich machen.
>#define vor_stopp vorsignal_rot_1; vorsignal_gruen_0;>#define vor_start vorsignal_rot_0; vorsignal_gruen_1;>>So ist das wenigstens in sich stimmig.
Mit sowas fällt man ganz schnell auf die Fresse.
if(blabla) vor_stopp;
Was macht der Präprozessor daraus:
if(blabla) vorsignal_rot_1; vorsignal_gruen_0;;
Mal sortieren:
if(blabla) vorsignal_rot_1;
vorsignal_gruen_0;;
Tut nicht unbedingt was es soll;)
Karl Heinz Buchegger schrieb:> Was spricht eigentlich dagegen, dafür das in C vorgesehene Sprachmittel> zu benutzen: Funktionen?
Genau. Und dann auch gleich die Regeln mit eingebaut.
Es gibt drei mögliche Signalkombinationen:
Hp0 + Vr0, Hp1 + Vr1, Hp1 + Vr0
Die Kombination Hp0 + Vr1 (Halt + Fahrt erwarten) ist ausgeschlossen.
void Signal (char Hp, char Vr)
{
PORTD &= 0xC3; //Alle aus
if (!Hp) //Hp0 Halt
{
//Halt, Halt erwarten
PORTD |= (1<<3)|(1<<4); //Hp0 + Vr0 = rot + gelb-gelb
}
else
{ //Hp1 Fahrt
//Fahrt, Fahrt erwarten
if (Vr) PORTD |= (1<<5)|(1<<2); //Hp1 + Vr1 = grün + grün-grün
//Fahrt, Halt erwarten (Nachdem der Zug das Vorsignal passiert hat)
else PORTD |= (1<<4)|(1<<2); //Hp1 + Vr0 = grün + gelb-gelb
}
}
Die Aufrufe sind dann
#define Hp0 0
#define Hp1 1
#define Vr0 0
#define Vr1 1
Signal(Hp0, Vr0); //rot, gelb-gelb
Signal(Hp0, Vr1); //unzulässig, angezeigt wird Hp0, Vr0
Signal(Hp1, Vr1); //grün, grün-grün
Signal(Hp1, Vr0); //grün, gelb-gelb
Damit muß man sich nur einmal Gedanken über die richtigen
Signalstellungen machen. Dazu ist ein Computer schließlich da.
Und C ist das auch.
mfg.
@Thomas: Man darf Funktionsnamen, Variablennamen und defines auch ruhig
länger als 3 Zeichen machen ;-)
Schild hochhalt Für aussagekräftigere Bezeichnungen!
Thomas Eckmann schrieb:> Die Aufrufe sind dann>> #define Hp0 0> #define Hp1 1> #define Vr0 0> #define Vr1 1>> Signal(Hp0, Vr0); //rot, gelb-gelb> Signal(Hp0, Vr1); //unzulässig, angezeigt wird Hp0, Vr0> Signal(Hp1, Vr1); //grün, grün-grün> Signal(Hp1, Vr0); //grün, gelb-gelb
Das würde ich dann aber nicht so machen.
Wenn es da Zustände gibt, dann sollte man die auch benennen, zb mit
#defines.
Der Signal-Funktion übergebe ich dann nur noch die Siganlbezeichnung und
den Zustandsnamen. Wie sich dass dann auf die Lichtführung auswirkt,
dass soll sich die Funktion selber ausklamüsern.
> Hp0 + Vr0, Hp1 + Vr1, Hp1 + Vr0
Ich versteh zu wenig von Eisenbahn um zu wissen, was das für Zusände
sind.
Ich denke mal das wird irgendwie sowas sein wie
1
#define TRAIN_STOP 0
2
#define TRAIN_GO 1
3
#define TRAIN_ATTENTION 2
und die Aufrufe sind dann
1
Signal(ENTER_SIGNAL_RIGHT,TRAIN_STOP);
und das hat ja dann schon eine ganz andere dokumentarische Qualität.
Simon K. schrieb:> @Thomas: Man darf Funktionsnamen, Variablennamen und defines auch ruhig> länger als 3 Zeichen machen ;-)>> Schild hochhalt Für aussagekräftigere Bezeichnungen!
Ich nehm dich auf meine Schultern, dann sieht man es noch besser.
Simon K. schrieb:> @Thomas: Man darf Funktionsnamen, Variablennamen und defines auch ruhig> länger als 3 Zeichen machen ;-)> Schild hochhalt Für aussagekräftigere Bezeichnungen!
Vergiss' es. Aussagekräftigere Bezeichnungen dafür gibt es nicht.
Das sind die offiziellen Abkürzungen aus dem Signalbuch der Bahn.
Deutsche Bundesbahn, um genau zu sein. Ganz so neu ist das Buch auch
nicht mehr.
mfg.
Ich verstehe nie so recht, warum sich die Leute so gegen Benutzung des
_BV()-Makros sperren; m. M. n. macht das den Code lesbarer und beugt
Flüchtigkeitsfehlern a la (1<3) vor...
Leider hat der TE nicht erwähnt, wie oft und in welchem Kontext er die
Signal-Makros/-Funktionen aufruft; je nachdem ist natürlich die eine
oder andere Variante besser. Für Anfänger denke ich jedoch auch, dass
Thomas' Funktion die beste Lösung darstellt. Beim Einsatz von Makros
muss man sich immer wieder bewusst machen, dass das lediglich eine
Textersetzung darstellt und Probleme wie von holger beschrieben geradezu
heraufbeschwört. Um sicher zu gehen, empfiehlt es sich, alle Parameter
von Makros (sofern sie über Parameter verfügen) im Makro-Körper in
Klammern zu setzen, und, sofern der Makro-Körper mehrere Befehle
enthält, ihn in geschweifte Klammern zu setzen. Beispiel:
Karl Heinz Buchegger schrieb:> Ich versteh zu wenig von Eisenbahn um zu wissen, was das für Zusände> sind.
Das Vorsignal ist dazu da, dem Lokführer anzuzeigen, was ihn am
Hauptsignal erwartet, da sein Bremsweg etwas länger ist, als der eines
Autofahrers.
Deshalb ist auch Hp0 + Vr1, das heisst nun mal so, unmöglich. Das
bedeutet nämlich am Vorsignal: "Du kannst voll Stoff geben". Und am
Hauptsignal:
"Ätschibätsch, reingelegt".
Signal(Hp0, Vr0);
Signal(Hp0, Vr1);
Signal(Hp1, Vr1);
Signal(Hp1, Vr0);
Ich finde es sehr logisch, daß so zu machen. Bei diesem Signal handelt
es sich um ein Blocksignal auf freier Strecke.
Das kennt eigentlich bei Lichtsignalen nur diese beiden Zustände:
Signal(Hp0, Vr0); = Halt, Block belegt
Signal(Hp1, Vr1); = Fahrt, Block frei
Ein Eisenbahner versteht das.
Selbst wenn er Programmierung für schwarze Magie hält.
Karl Heinz Buchegger schrieb:> Signal( ENTER_SIGNAL_RIGHT, TRAIN_STOP );
das ist mir in diesem Zusammenhang vielzu abstrakt.
mfg.
>> Signal( ENTER_SIGNAL_RIGHT, TRAIN_STOP );>das ist mir in diesem Zusammenhang vielzu abstrakt.
Das versteht aber ein Programmierer, auch wenn er Eisenbahnabkürzungen
für schwarze Magie hält ;)
Arno Nyhm schrieb:> Das versteht aber ein Programmierer, auch wenn er Eisenbahnabkürzungen> für schwarze Magie hält ;)
Und deswegen kriegen die auch ihre Stellwerke nicht zum Laufen.
Hamburg-Altona hat mal ein halbes Jahr stillgelegen, weil die Software
nicht lief.
mfg.
Arno Nyhm schrieb:> Das versteht aber ein Programmierer, auch wenn er Eisenbahnabkürzungen> für schwarze Magie hält ;)
Ich habe mich auch lange gefragt, was denn "Klimae Whzküös" bedeutet...
Noah schrieb:> Ich habe mich auch lange gefragt, was denn "Klimae Whzküös" bedeutet...
Das mit der elektrischen Klimaanlage geht ja noch. Aber stell' dir vor,
das würde da drauf stehen:
"Warmwasserheizung über Kühlwasserumlauf oder Ölbefeuerung,
selbstregelnd"
Da würde doch keiner mehr einsteigen.
mfg.
Thomas Eckmann schrieb:>> Signal(Hp0, Vr0);> Signal(Hp0, Vr1);> Signal(Hp1, Vr1);> Signal(Hp1, Vr0);>> Ich finde es sehr logisch, daß so zu machen.
Find ich nicht.
Ich finde das ist eine Fehlerquelle, die nicht sein muss. Zwischen
erstem und zweitem Argument besteht ein dubioser Zusammenhang, den mir
zwar die Funktion garantieren kann, aber wenn ich beim Aufruf schon
sicherstellen kann, dass die Funktionslogik da gar nicht eingreifen
muss, dann ist das allemal besser.
> Bei diesem Signal handelt> es sich um ein Blocksignal auf freier Strecke.>> Das kennt eigentlich bei Lichtsignalen nur diese beiden Zustände:> Signal(Hp0, Vr0); = Halt, Block belegt> Signal(Hp1, Vr1); = Fahrt, Block frei
Meine Sicht der Dinge ist es, die Sachen mögichst schnell auf tiefer
Ebene zu abstrahieren. Was interessiert mich wieviele Lichter es wann
und wo gibt.
Ich gebe den Block frei, und genau so will ich das auch programmieren
Signal( Blocksignal1, BLOCK_FREI );
Da brauch ich nur noch ein paar Füllwörter einfügen und das Verb in die
Mitte stellen und lese da ganz zwanglos "An dieser Stelle im Code wird
die Blocksignal-Anlage 1 so gestellt, dass der Block freigegeben ist".
Was das jetzt für die Signale selbst bedeutet (und wieviele Lampen da im
Spiel sind), interessiert mich doch nicht. Mein Ziel hab ich erreicht:
Der Block ist zumindest signaltechnisch freigeschaltet. Auf einer nächst
höheren Ebene gebe ich dann vielleicht noch den Block selber frei, der
neben den Signalen dann auch noch Weichen schalten muss um die
Fahrstrasse geschaltet zu kriegen.
Aber das ist meine Sicht der Dinge. Andere mögen das anders sehen.
Karl Heinz Buchegger schrieb:
>Aber das ist meine Sicht der Dinge. Andere mögen das anders sehen.
Durchaus. Aber, ich finde, das macht Sinn. Das ganze war von Anfang an,
ein wenig "dubios".
Karl Heinz Buchegger schrieb:> Meine Sicht der Dinge ist es, die Sachen mögichst schnell auf tiefer> Ebene zu abstrahieren. Was interessiert mich wieviele Lichter es wann> und wo gibt.> Ich gebe den Block frei, und genau so will ich das auch programmieren
Damit bist du aber schon eine Stufe höher.
Denn dahinter stecken immer noch die Signale mit ihren 6 Lämpchen. Und
irgendwo müssen dann ja auch die Ports geschaltet werden. Wobei ich für
mich die Funktion dann noch um Hp2 und Vr2 erweitern würde. Damit kann
ich dann den ganzen Bereich abdecken. Ob es sich dann um ein
Blocksignal, ein Ein- oder Ausfahrsignal oder sonstwas handelt ist auf
dieser Ebene vollkommen egal. Mag sein, daß man sich an den
Variablennamen stören kann. Aber mir sind diese Kürzel geläufig und
machen somit für mich auch Sinn.
Mit der Funktion oben kann man natürlich nur ein bestimmtes Signal
schalten. Was ja noch ein bisschen wenig ist. Aber bei der Frage oben
ging es nur darum, den Aufruf für das Bitgefriggel zu vereinfachen. Was
ein Blocksignal ist, muß doch diese Funktion gar nicht wissen.
Aber Dutzende Signale schalten kann man damit natürlich nicht.
Da kommt dann wieder deine Funktion ins Spiel.
Karl Heinz Buchegger schrieb:> Signal( Blocksignal1, BLOCK_FREI );
Jetzt interessiert es mich auch nicht, welche Lämpchen geschaltet werden
oder ob da einer mit 'ner Fahne winkt. Das will ich in der Funktion gar
nicht drin haben.
Aber dahinter muß das Bitgefriggel ja wieder gelöst werden. Ob nun so,
wie in meinem Beispiel oder aus einer Tabelle in der alle sinnvollen
Bitmuster drin stehen, die man dann per SPI auf 595er schiebt. Oder wie
auch immer, das ist dann wieder völlig egal.
mfg.
Thomas Eckmann schrieb:> Damit bist du aber schon eine Stufe höher.> Denn dahinter stecken immer noch die Signale mit ihren 6 Lämpchen. Und> irgendwo müssen dann ja auch die Ports geschaltet werden.
Dieses Wissen würde ich dann sowieso in Tabellen ablegen. Was alles muss
geschaltet werden, wenn ich einen Block freigebe. Damit ist dann aber
die Information über Vp und Hp sowieso schon aus dem Programmtext in
eine veränderbare Konfiguration gewandert, die ich unter einem Namen
verfügbar habe und bei der mir die Konfiguration mitteilt, welche
Hardware jetzt ganz genau bei welcher 'Zustandsänderung' zu betätigen
ist.
Aber wir 'streiten' um des Kaisers Bart. Letztendes muss der TO das für
sich entscheiden, was er alles tun will und wie er es machen will.
Was mir wichtig ist: Diese Attitüde, alles in ein Makro zu quetschen -
sie führt auf lange Sicht gesehen meistens zu schlechtem Code. Solange
man nur 1 oder 2 Statements ersetzen will, mag es noch angehen. Aber
spätestens wenn die Chance besteht, dass der Code auch mal ein wenig
komplizierter ist, fährt man mit Funktionen immer besser.
Ich hab das eigentlich im Desktop Bereich so nie erlebt, dass gerade
Anfänger alles sofort in Makros quetschen um sich dann hinterher mit
untauglichen Debugmitteln einen Wolf zu suchen, wie da jetzt durch die
Makroexpansion Unsinn rauskommt. Dazu kommt dann meistens auch noch eine
verquerte Vorstellung davon, was Makros eigentlich darstellen. Erkennbar
daran, dass dann plötzlich von 'Variablen' bzw. 'Funktionen' die Rede
ist, im Code aber nur ein unschuldiges #define steht.
Karl Heinz Buchegger schrieb:> Dieses Wissen würde ich dann sowieso in Tabellen ablegen.
Das Bitgefriggel ist dann reine Fleißarbeit, die man hat, bevor man auch
nur eine einzige Zeile Code geschrieben hat.
Karl Heinz Buchegger schrieb:> Aber wir 'streiten' um des Kaisers Bart.
Stimmt. Irgendwo ist immer ein wenig Interpretationsspielraum.
Karl Heinz Buchegger schrieb:> Was mir wichtig ist: Diese Attitüde, alles in ein Makro zu quetschen -> sie führt auf lange Sicht gesehen meistens zu schlechtem Code.
Und vor allen Dingen aufgebläht.
Der Codefetzen "Makro" wird schließlich jedes Mal wieder eingebaut. Ob
nun in C oder Assembler. Eine entsprechende Funktion oder ein
Unterprogramm existiert nur einmal. Darüber muß man sich auch im Klaren
sein.
Zwei Seiten Quelltext und der Speicher läuft über...
mfg.
Thomas Eckmann schrieb:> Karl Heinz Buchegger schrieb:>> Aber wir 'streiten' um des Kaisers Bart.>> Stimmt. Irgendwo ist immer ein wenig Interpretationsspielraum.
Und deswegen ist 'richtiges' Programmieren eine Art von Kunst.