Hallo,
ich habe den ganzen Tag nach einem Bug in meiner Software gesucht und am
Ende durch Zufall festgestellt, dass sich das Problem durch Tausch einer
Variablen gegen eine andere gleichen Typs und gleicher Verwendung
beheben lässt.
Hier der Programmausschnitt um den es sich handelt.
1
switch(rcvd[1])// Option wählen
2
{
3
case'1':// Duty cycle PWM1 einstellen
4
DC2=rcvd[2];
5
PDC1=DC1*(PTPER/128);
6
break;
7
case'2':// Duty cycle PWM2 einstellen
8
DC2=rcvd[2];
9
PDC2=DC2*(PTPER/128);
10
break;
11
case'3':// Duty cycle PWM3 einstellen
12
DC3=rcvd[2];
13
PDC3=DC3*(PTPER/128);
14
break;
15
default:;// Nichts tun
16
}
Die Variablen werden wie folgt deklariert
1
charDC1=0x00,DC2=0x00,DC3=0x00;//Duty cycles
Der obige Programmausschnitt funktioniert nur bis
1
case'2'
Ab hier wird PDC3 bei Änderung von DC3 immer der Maximalwert zugewiesen,
ganz egal, was in DC3 steht.
So, nun zur "Lösung". Wenn ich DC3 gegen DC2 austausche funktioniert das
Programm fehlerfrei.
Ich verstehe es einfach nicht. Die Variablen sollten - abgesehen vom
Namen - doch identisch sein!?
Vielleicht weiß einer von Euch, woran das liegen könnte.
Das Programm läuft auf einem PIC und ich benutze den CCS Compiler.
Viele Grüße
Stefan
muss da nich:
case '1': // Duty cycle PWM1 einstellen
DC1=rcvd[2];
PDC1 =DC1*(PTPER/128);
break;
rein?
ersetzen von:
"DC1=rcvd[2];"
durch
"DC2=rcvd[2];"
oder irre ich mich da?
Zunächst habe ich Zweifel, das dieser Code ohne Warnung compiliert wird.
Falls es tatsächlich Warnungen gibt, poste die bitte hier.
Wenn PTPER tatsächlich um 7 Bit nach rechts verschoben werden kann und
das sinnvoll ist, dann ist es grösser als 8 Bit. Das Ergebnis ist aber
nur 8 Bit (char). Was hast Du Dir als Ergebnis vorgestellt und wie soll
es erreicht werden? Eigentlich sollten genau hier Warnungen ausgegeben
werden.
Ja, natürlich.
Das ist aber nicht das Problem, das war nur ein "Tippfehler" beim
Verfassen des Threads... Ich sollte mich anmelden, um sowas editieren zu
können.
Trotzdem danke!
Bitte nichst abtippen oder bei CopyNPaste noch redigieren.
Das gibt erfahrungsgemäß sehr frustrierende Erfahrungen im Forum.
Bitte alle Optimierungen abschalten.
Bitte den Code soweit wie mögliche reduzieren,
so das der Fehler aber noch auftritt.
Hast Du die Antwort hier:
Beitrag "Re: [C] Merkwürdige Erscheinung" gelesen?
Stefan schrieb:> ... das war nur ein "Tippfehler" beim Verfassen des Threads ...
Eine Frage: Bist du zu blöd den Quellcode auszuschneiden und zu posten?
Stefan schrieb:> default: ; // Nichts tun
und
Stefan schrieb:> char DC1=0x00, DC2=0x00, DC3=0x00; //Duty cycles
Warum schreibst du bloß sowas?
Also erstmal, die leere default-Anweisung kannst du getrost weglassen.
Wozu außer der Selbstverwirrung sollte die gut sein?
Und dann: Ich kann es nicht leiden, wenn jemand solche Deklarationen
schreibt wie du bei DC1..3. Sowas ist eigentlich IMMER Mist. Grund: es
hängt gar sehr von der Toolchain, dem Startupcode und dem konkreten
Programm ab, ob das hinhaut oder nicht. Bei manchen Konstellationen
funktioniert es nur dann, wenn Variablen im RAM auch korrekt im
Startupcode initialisiert worden sind. Schreib lieber
void MyBlabla(blabla)
{ int DC1, DC2, DC3;
DC1 = DC2 = DC3 = 0;
...
Wenn der Compiler optimieren kann, wird er's bei Vorlage solcher Quelle
schon richtig tun und du sparst mit deiner impliziten Vorbesetzung der
Variablen kein einziges Codebyte. Dafür ist die Quelle sauberer und
klarer.
Und wenn du deine lokalen Variablen als int deklarierst, dann kriegst du
auch keinen Datencrash infolge unzureichender Bitbreite wie bei deinem
Beispiel.
Meine Devise ist _immer_: Keinen "geniale" Quelle schreiben, sondern
bieder und einfach bleiben. System KISS! (Keep It Small and Simple).
Dazu gehörten eben auch explizite Initialisierungen, sofern sie nötig
sind.
W.S.
Hmm schrieb:> Das Ergebnis ist aber> nur 8 Bit (char). Was hast Du Dir als Ergebnis vorgestellt und wie soll> es erreicht werden?
Die linke Seite ist ein 16bit Wort, muss ich dann trotzdem für die
Rechnung D1 bzw. D2/D3 casten?
Danke schonmal!
Gruß
Stefan schrieb:> das war nur ein "Tippfehler" beim> Verfassen des Threads...
Geh an die Tafel und schreibe 1000 mal:
"Ich werde nie wieder Quellcode abschreiben. Ich benutze nur Copy&Paste
oder den Dateianhang (die beste Wahl)."
Peter
>Die linke Seite ist ein 16bit Wort, muss ich dann trotzdem für die>Rechnung D1 bzw. D2/D3 casten?
Und woher sollten wir das wissen? Bitte bei der nächsten Frage von
Anfang an vollständigen Code posten resp. den Code soweit reduzieren,
dass, obwohl noch compilierbar, der Fehler noch auftritt.
Also ich bin dann mal 'raus.
W.S. schrieb:> Stefan schrieb:>> char DC1=0x00, DC2=0x00, DC3=0x00; //Duty cycles>> Warum schreibst du bloß sowas?
Weil das korrekter und gut lesbarer Code ist.
W.S. schrieb:> Schreib lieber> void MyBlabla(blabla)> { int DC1, DC2, DC3;> DC1 = DC2 = DC3 = 0;
Solche Kettenzuweisungen sind schlechter Programmierstil, die können
böse Seiteneffekte haben.
Schreib mal beim ATmega48:
1
PORTD=PORTC=0xFF;
Und dann staune, warum PORTD = 0x7F ist.
Also vergiß diese fehlerträchtigen Kettenzuweisungen ganz schnell
wieder!
Peter
Anregungen, wie du es Anderen einfacher machen kannst, hast du ja
reichlich bekommen ...
Stefan schrieb:> Lutz schrieb:>> Wie is'n rcvd[] definiert?> char rcvd[5];
Popel, zieh, ...: Und was wird wie in rcvd[1] reingeschrieben?
Ich habe mir angewöhnt, statt char, int usw. (fast) nur noch uint8_t,
int32_t usw. zu benutzen. Da sieht man (ich) eher, wann was krachen
kann. Wobei man (ich) char eigentlich ziemlich selten wirklich brauche.
Ich vermute hier eine Menüeingabe, die ein uint8_t besser erfüllt. Denn
einen char shiften/teilen macht keinen Sinn.
Da immer noch nur der Geier weiß, wie der Rest definiert ist (z.B.
PTPER): Ich tippe mal auf irgendeinen Überlauf. Und den Begriff casten
kennst du auch.
Also wie schon alle anderen schreiben: Aussagekräftigen Originalcode
her, sonst wird das nichts.
W.S. schrieb:> Stefan schrieb:>> default: ; // Nichts tun>> und>> Stefan schrieb:>> char DC1=0x00, DC2=0x00, DC3=0x00; //Duty cycle> ...> Und dann: Ich kann es nicht leiden, wenn jemand solche Deklarationen> schreibt wie du bei DC1..3. Sowas ist eigentlich IMMER Mist. Grund: es> hängt gar sehr von der Toolchain, dem Startupcode und dem konkreten> Programm ab, ob das hinhaut oder nicht.
Nun ja, deine Befindlichkeiten sind dein persönliches Problem. Wer
toolchains nutzt, die korrekten C-Code nicht korrekt übersetzen, dem ist
nicht zu helfen. Mit so etwas wird die Erstellung eines funktionierendem
Programm zu einem Glücksspiel. Manchmal mag es ja Gründe geben, so etwas
nutzen zu müssen, aber daraus dann angeblich allgemeingültige
Programmierregeln abzuleiten, ist übertrieben.
Oliver
Ich tippe auf einen Array Overflow irgendwo im Programm
(Stringbehandlung?) und DC3 hat tatsächlich an dieser Stelle nicht mehr
den Wert 0, sondern einen anderen.
Daher: Poste Code!
(Aber bitte richtigen Code und nicht etwas speziell fürs Forum zurecht
gemachtes)
Rene H. schrieb:> Naja, Karl Heinz>> Ich würde es mir nicht antun wollen hier den kompletten Code zu posten.> Da wird man doch direkt verrissen. :-)>
Dann mach ein abgespecktes Beispiel zurecht, welches den gleichen Fehler
zeigt.
Aber ohne vollständigen Code, kann so ein Symptom schnell in Stochern im
Nebel ausarten.
Es hat immer einen Grund, warum eine Berechnung nicht das gewünschte
Ergebnis liefert. Und öfter als man denkt, haben dann die
Eingangsvariablen nicht die Werte, die der Programmierer seit Stunden
stillschweigend annimmt.
Kontrollier halt mal DC3 vor der Berechnung.
Die Annahme "müsste eigentlich 0 sein" kann richtig sein, kann aber auch
falsch sein.
Danke für die Korrektur.
Dann eben an den TO. Wenn dir der Code zuviel ist, dann zeige ein
abgespecktes Beispiel. Aber stell erst sicher, dass das Beispiel den
Fehler immer noch zeigt.
Aber so, mit ein paar Zeilen Code, hat das keinen Zweck.
Hmm schrieb:> Also ich bin dann mal 'raus.Hmm schrieb:> Ähm. Karl Heinz! Der Rene ist nicht der TO.
Bei dir kann man sich aber auch auf nichts verlassen.
mfg.
Hallo Stefan
Ich habe nicht alles gelesen, aber ich setze ein Wette und biete ein mir
und meiner Partnerin wichtiges Körperteil. Du hast ein ernsthaftes
Speicherproblem.
Du überschreibst da Speicher!
Zeichne mal den Speicher auf den Du alloziert hast und wie Du ihn
verwendest.
Grüsse,
R.
Ingo schrieb:> @peda> Ich würde mal tippen das einer der Ports nur 7 Bit hat?
Stimmt, PORTC ist 7 Bit breit. Und da die Kettenzuweisung ja wieder
zurücklesen muß, kriegt PORTD auch nur 7 Bit gesetzt.
Noch lustiger wird es beim PIC, wo das Ausgangslatch gesetzt wird, aber
die Eingangspins gelesen. Da legt man sich definitiv die Karten damit.
Die Kettenzuweisung vereint also alle Nachteile in sich (schlechte
Lesbarkeit, fehlerhaft, mehr Code). Somit gibt es keinen Grund, sie zu
benutzen.
Ich hab sowas allerdings auch schon in älterem Code gesehen.
Peter
...bei den Pic 16 gab es doch garkeine getrennten latches für Ein- und
Ausgang, wie das bei den 18nern ist habe ich ja nie ersichtet da auf
Atmel umgestiegen...
Gut war jedenfalls bei den 16nern auch die I/O Falle, siehe Sprut.
Klasse Sache. Da hat man sich schön Dinge eingefangen von Außen
kommend....
DS
Peter Dannegger schrieb:> Stimmt, PORTC ist 7 Bit breit. Und da die Kettenzuweisung ja wieder> zurücklesen muß, kriegt PORTD auch nur 7 Bit gesetzt.Muss sie?
Ich finde das gerade eine ziemlich spannende Fragestellung. Leider finde
ich nirgends den aktuellen C-Standard um das wirklich definitiv zu
finden.
http://c.comsci.us/etymology/operator/assignment.html behauptet:
1
=
2
name: assignment.
3
operand types: any.
4
result type: the type of the left operand.
5
result value: the value of the right operand.
6
side effect: The left operand is set to the value of the result.
7
associativity: Right to left.
Demnach wäre das Ergebnis 0x7f eigentlich nur zu rechtfertigen, wenn
PORTC als ein 7-Bit-Typ deklariert wäre (was ich glaube ich noch nie
gesehen habe).
Genauso ein problematisches Verhalten würde man dann ja bei
volatile-Variablen haben.
Mein Bauchgefühl sagt mir, dass da der Compiler Mist baut...
Viele Grüße,
Simon
Simon Budig schrieb:> Peter Dannegger schrieb:>> Stimmt, PORTC ist 7 Bit breit. Und da die Kettenzuweisung ja wieder>> zurücklesen muß, kriegt PORTD auch nur 7 Bit gesetzt.>> Muss sie?
Ja, muss sie.
double i, j;
int k;
i = k = j = 5.8;
j hat den Wert 5.8
k hat den Wert 5
i hat den Wert 5.0
> result value: the value of the right operand.
ist falsch.
Karl Heinz Buchegger schrieb:>> result value: the value of the right operand.> ist falsch.
Ok. Habe gerade auch in einem Standard-Draft die vermutlich relevante
Stelle gefunden:
1
An assignment operator stores a value in the object designated by
2
the left operand. An assignment expression has the value of
3
the left operand after the assignment, but is not an lvalue.
...wobei ein Freund von mir, der solche Standards in seiner Freizeit
liest gerade nicht mit meiner Interpretation übereinstimmt...
Viele Grüße,
Simon
PS: Oops, da ist ja noch eine Fußnote: "The implementation is permitted
to read the object to determine the value but is not required to, even
when the object has volatile-qualified type."
Stefan schrieb:> Vielleicht weiß einer von Euch, woran das liegen könnte.
Das beschriebene Verhalten deckt sich mit dem Verhalten eines
amoklaufenden Pointers. Zeig mal die Reihenfolge deiner
Variablendeklarationen. Oder wenn du sie nicht zeigen
willst/darfst/kannst: dreht mal die Reihenfolge der Deklarationen um.
Hast du dann andere Effekte?
> Das Programm läuft auf einem PIC
Ich denke, es läuft nicht... ;-)
Simon Budig schrieb:> PS: Oops, da ist ja noch eine Fußnote: "The implementation is permitted> to read the object to determine the value but is not required to, even> when the object has volatile-qualified type."
Aaah. Die Fussnote kannte ich noch nicht.
Ich kannte nur den Haupttext, dass der Wert einer Zuweisung, der Wert
des linken Ausdrucks nach der Zuweisung ist. D.h. das alle
Konvertierungen bzw. sonstige Dinge, die durch die Zuweisung notwendig
waren, sich im 'Wert der Zuweisung' wiederfinden. Von daher ist die
Frage tatsächlich interessant, ob hier auch hardware-Restriktionen mit
reinfallen, was ja durch die Fussnote als 'kann sein - kann auch nicht
sein' beantwortet wird.
Von daher: Lieber nicht.