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?
Wolfgang K. wrote:
> Was ist das Problem? Compiler?
Mit 99.9% Wahrscheinlichkeit sitzt das Problem vor dem
Bildschirm :-)
Zeig mal den ganzen Code.
:-) 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!...
Troll: 900 Zeilen Code in einer C-Datei... Was ist da schief gelaufen? ;) ;)
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
Alles klar!!! ;-)) Hab einfach alle Zustände hingeschrieben und wollte sie nacheinander hinzufügen... :-)))) Danke Jörg!!!
Tja, mit einem Editor, der automatisch das Einrückungsniveau selbst ermittelt, wär dir das nicht passiert...
Ich als Anfänger sehe das Problem immer noch nicht :). Kann mir das einer genau erklären oder genauer drauf zeigen?
@ 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
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. ;-)
Ah da drüben winkt gerade "Hr. Switch-Case" mit seinem Zaunpfahl..
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.
Dann hat mein problem schon mal jemand anderem auch geholfen... :-) Aus fehlern lernt man und macht sie nicht mehr. mfg
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... ;)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.