Source-Code an andere Stelle -> funktioniert nicht mehr.

Gast #682723
Lesenswert?

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?
Gast #683219
Lesenswert?

:-) 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!...
Angehängte Dateien:
Gast #683263
Lesenswert?

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...
Moderator Persönliche Seite #683266
Lesenswert?

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.
#683412
Lesenswert?

@  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
Moderator Persönliche Seite #683439
Lesenswert?

Wäre übrigens auch nicht passiert, wenn man das ,,Gerippe'' einfach
komplett durchgezogen hätte:
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);

Ich vermute, dass es Wolfang auch nicht nochmal passiert. ;-)
Moderator Persönliche Seite #683450
Lesenswert?

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.)
Gast #683530
Lesenswert?

@ 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 ;)
Gast #683568
Lesenswert?

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(); }
Moderator Persönliche Seite #683586
Lesenswert?

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.)
Gast #683595
Lesenswert?

>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.
Gast #683603
Lesenswert?

>>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.
Moderator Persönliche Seite #683697
Lesenswert?

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.
Gast #683753
Lesenswert?

@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.
Persönliche Seite #686289
Lesenswert?

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... ;)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren