Hallo!
Habe ein sehr komisches Problem, dass mich zur Verzweiflung bringt.
Folgenden Auszug aus dem Sourcecode für die Ansteuerung eines Pins:
if (variable_a == ON) PORTD |= (1 << PD4);
if (variable_a == OFF) PORTD &= ~(1 << PD4);
if (variable_b == ON) PORTD |= (1 << PD5);
if (variable_b == OFF) PORTD &= ~(1 << PD5);
Der Source-Code von variable_a funktioniert, der von b aber nicht.
Tausche ich nun die Zeilen untereinander aus ist es genau umgekehrt,
variable_b funktioniert und a nicht mehr... warum?
Hier mein Memory Usage:
AVR Memory Usage:
-----------------
Device: atmega8
Program: 5144 bytes (62.8% Full)
(.text + .data + .bootloader)
Data: 125 bytes (12.2% Full)
(.data + .bss + .noinit)
Die Optimierung ist auf s gestellt.
Was ist das Problem? Compiler?
:-) Das dachte ich am Anfang auch, aber habe alles durchgesehen, da die
Programmteile dieser Ausgänge genau gleich sind. Es ist aber alles
komplett gleich (bis auf variablenname, usw. ;-))
Der Source-Code hat um die 900 Zeilen, darum schreibe ich noch dazu, wo
das Problem auftritt:
Im Unterprogramm Ausgang_setzen() werden die Pins angesteuert, je
nachdem welchen Zustand die zugehörige Variable hat. Komplett einfach
gehalten. Der Zustand der zugehörigen Variablen in der if-Abfrage ist
korrekt (0 oder 1), d.h. das funktioniert alles. Es funktionieren alle
Ausgänge einwandfrei, bis auf den für den Motorraum (Zeile 478 und 479).
Tausche ich nun die beiden Zeilen für den Motorraum (Zeile 478 und 479)
mit z.b. den Frontsystem-Zeilen (Zeile 465 und 466) aus, funktioniert
der Motorraum-Ausgang, dafür aber ein anderer von diesen auf einmal
nicht mehr.
Darum bin ich mir sicher, dass kein Programmfehler vorhanden ist, da der
Ausgang, der vorher nicht funktioniert hat, auf einmal funktioniert,
wenn man seine Code-Zeilen wo anders hinverschiebt, wo es aber keinen
Einfluss darauf hat.
PLEASE HELP!...
dachte am anfang das programm wird nicht so gross, hab es dann aber
immer weiter ausgebaut und mir ist es egal, wenn alles in einer datei
ist, und nicht auf mehrere aufgeteilt.
wenn du es gekürzt haben willlst:
-) alles mit lcd funktioniert einwandfrei
-) schalter einlesen funktioniert
-) menüs funktionieren
eigentlich funktioniert ALLES einwandfrei, bis auf die Ausgabe durch die
Variable Motorraum.
Werden die Ausgaben in einer anderen Reihenfolge getätigt, funktioniert
eine andere nicht, aber Motorraum dafür...
Wolfgang K. wrote:
> dachte am anfang das programm wird nicht so gross, hab es dann aber> immer weiter ausgebaut und mir ist es egal, wenn alles in einer datei> ist, und nicht auf mehrere aufgeteilt.
Dir ja, aber nicht denen, die den Kram nun reviewen sollen, weil du
nicht mehr wirklich durchblickst... Compilieren lässt es sich auch
nicht, weil noch allerlei anderer Kram ringsrum fehlt.
Aber eigentlich ist die Sache recht eindeutig:
1
if(Fussraum==ON)PORTD|=(1<<PD0);
2
if(Fussraum==OFF)PORTD&=~(1<<PD0);
3
if(Fussraum==BLNK)
4
if(Fussraum==GLOW)
5
if(Fussraum==RPM1)
6
if(Fussraum==RPM2)
7
8
if(Motorraum==ON)PORTD|=(1<<PD1);
9
if(Motorraum==OFF)PORTD&=~(1<<PD1);
Guck dir mal die Zeilen vor deiner ,,Problemzeile'' an, dann sollte
dir der Seifensieder aufgehen.
Jörg Wunsch wrote:
> Guck dir mal die Zeilen vor deiner ,,Problemzeile'' an, dann sollte> dir der Seifensieder aufgehen.
Hehe, böser Fehler ;-)
MFG
Falk
@ Marian (Gast)
>Ich als Anfänger sehe das Problem immer noch nicht :). Kann mir das>einer genau erklären oder genauer drauf zeigen?
Ja.
1
if(Fussraum==ON)PORTD|=(1<<PD0);
2
if(Fussraum==OFF)PORTD&=~(1<<PD0);
3
if(Fussraum==BLNK)
4
if(Fussraum==GLOW)
5
if(Fussraum==RPM1)
6
if(Fussraum==RPM2)
7
8
if(Motorraum==ON)PORTD|=(1<<PD1);
9
if(Motorraum==OFF)PORTD&=~(1<<PD1);
Die vier if() ohne Anweiusung dahinter (welche später einfügt werden
sollten) sind ja nicht einfach weg, sondern werden schön brav
ausgeführt. Allerdings kommt dann eine GANZ anderes Struktur raus.
Nämlich die (umgeschriene mit Einrückung un Klammern, verkettete If()
Anweisungen)
1
if(Fussraum==ON)PORTD|=(1<<PD0);
2
if(Fussraum==OFF)PORTD&=~(1<<PD0);
3
if(Fussraum==BLNK){
4
if(Fussraum==GLOW){
5
if(Fussraum==RPM1){
6
if(Fussraum==RPM2){
7
8
if(Motorraum==ON)PORTD|=(1<<PD1);
9
}
10
}
11
}
12
}
13
if(Motorraum==OFF)PORTD&=~(1<<PD1);
Böse Falle. Mit Pascal wär das nicht passiert ;-)
MfG
Falk
Es schadet nicht, zumindest eine Kurzfassung der "MISRA roules" (MISRA
Guidelines for the Use of the C Language in Vehicle Based Software)
durchzulesen, z.B. MisraC.pdf von iar.com. Einige der Regeln sind
vielleicht etwas übertrieben aber viele simple Fehler kann man durch
Beachtung des Regelsatzes vermeiden. Oben wurde z.b. Rule 59 nicht
beachtet: "The statements forming the body of an if, else if, else,
while, do … while or for statement shall always be enclosed in braces."
Bei Anwendung der Regel hätte man das gesehen, was Falk Brunner gezeigt
hat und die Fehlerursache wäre deutlich offensichtlicher geworden.
(Nähkästchen: Ja - ich beachtet die Regeln auch nicht immer wenn nicht
grade explizit verlangt aber das hat sich auch schon gelegentlich
gerächt und längeres "Codeanstarren" oder Debug-Sitzungen eingebracht.)
@ Jörg
>> if (Fussraum == BLNK) ;
vieleicht doch besser so
if (Fussraum == BLNK) { }
Sonst kommt man leicht zu einem
if (Fussraum == BLNK) ;
{ MachMalWas(); }
Ist immer wieder nett sowas zu debuggen ;)
Naja, ich war schon davon ausgegangen, dass nach jedem dieser "if"s
ohnehin nur ein einfacher Ausdruck (im Sinne des ,,Bitwackelns'')
stehen soll. Dafür finde ich wiederum, dass die Übersichtlichkeit
insgesamt am Ende besser ist, als wenn man stur der MISRA-Regel
folgt.
Ich leg noch mal ein schönes Macro drauf ;)
#define SPI_WAIT() while(!(SPI_STATUS_REGISTER & ( 1<<SPIF )));
spi_back_byte=SPI_DATA_REGISTER;
if (Fussraum == BLNK) SPI_WAIT();
oder doch besser ?
if (Fussraum == BLNK) { SPI_WAIT(); }
Was kann ich denn dafür, dass du wie Funktionen aussehene Makros
so schreibst, dass sie sich doch nicht wie Funktionen benehmen?
Jedes Kind :) weiß doch, dass man den Makro so schreibt:
1
#define SPI_WAIT() do { while(!(SPI_STATUS_REGISTER & ( 1<<SPIF ))); } while (0)
(Kein Spaß. Verquerer Konstrukt, aber der Makro tut danach, was man
von ihm erwartet.)
>Was kann ich denn dafür, dass du wie Funktionen aussehene Makros>so schreibst, dass sie sich doch nicht wie Funktionen benehmen?
Natürlich gar nichts.
Das hier gehört eigentlich in EINE Zeile:
>#define SPI_WAIT() while(!(SPI_STATUS_REGISTER & ( 1<<SPIF ))); >spi_back_byte=SPI_DATA_REGISTER;
Das sollte nur mal verdeutlichen was einen erwarten kann
wenn man keine {} hinter if oder for setzt. Bei Macros kann
das tödlich sein.
>>Das hier gehört eigentlich in EINE Zeile:>>#define SPI_WAIT() while(!(SPI_STATUS_REGISTER & ( 1<<SPIF )));>>spi_back_byte=SPI_DATA_REGISTER;
Kleiner Nachtrag: Das tut auch was ich möchte OHNE
diesen merkwürdigen Konstrukt. Man muss halt nur Klammern setzen.
holger wrote:
> Kleiner Nachtrag: Das tut auch was ich möchte OHNE> diesen merkwürdigen Konstrukt. Man muss halt nur Klammern setzen.
Das widerspricht aber dem `principle of least astonishment'. Der
Implementierer des Makros (und nur der) weiß, dass sich sein Makro
nicht wirklich so verhält, wie er auf den ersten Blick aussieht
(nämlich wie eine Funktion). Folglich sehe ich denjenigen in der
Pflicht, sich um die Vermeidung entsprechender Seiteneffekte zu
kümmern, statt diese Verpflichtung auf den Benutzer des Makros zu
übertragen (was du mit deiner zwanghaften Verpflichtung, nach einem
if ein Paar Klammern zu setzen, letztlich machst).
Klar ist der Anweder in der Regel gut beraten, wenn er die Klammern
setzt, aber da es die Sprache nicht vorschreibt, dass sie gesetzt
werden müssen, gehört es halt genauso gut zur ,,Unfallverhütung'',
dass man die Makros selbst ,,idiotensicher'' macht. (In diese
Kategorie fällt auch mit, dass ein Makro all seine benutzten
Makro-Argumente selbst klammert.)
Alternativ kannst du deinen Makro ja auch mit einer inline-Funktion
realisieren, wenn dir der do...while(0)-Hack nicht gefällt.
@Falk Brunner: Danke, die 4 if Anweisungen habe ich natürlich völlig
ignoriert :). Finde den Fehler sehr interessant, da lohnt es sich doch
ein paar Klammern mehr zu setzen um solche Dinger ungeschehen zu machen.
Jörg Wunsch wrote:
> ...> Folglich sehe ich denjenigen in der> Pflicht, sich um die Vermeidung entsprechender Seiteneffekte zu> kümmern, statt diese Verpflichtung auf den Benutzer des Makros zu> übertragen (was du mit deiner zwanghaften Verpflichtung, nach einem> if ein Paar Klammern zu setzen, letztlich machst).> ...
Das sehe ich genau so wie du. (Immerhin bist du hier der erfahrene
Programmierer)
In meiner T6963c-Library habe ich auch ein paar Makros in die
Header-Datei gepackt um zwei Funktionsaufrufe quasi zu bündeln. Dort
habe ich ebenfalls das do{}while(0); Konstrukt benutzt.
Also: Auch wenn man weiß, dass man immer schön Klammern setzt, und genau
deswegen das Makro schlampig designt, dann kommen die bösen Fehler
spätestens dann, wenn nen Anfänger (oder Ahnungsloser ;)) sich den Mist
kopiert und bei sich einbaut. Absolut Gemeingefährlich.
PS: Zum Glück hatte ich zum Zeitpunkt der T6963c Library schon was von
dem do{}while(0);-Hack gehört. Sonst hätte ich es zu diesem Zeitpunkt
auch nicht besser gewusst *räusper... ;)