Forum: Mikrocontroller und Digitale Elektronik [C] Merkwürdige Erscheinung


von Stefan (Gast)


Lesenswert?

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
char DC1=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

von Helge S. (helge_s)


Lesenswert?

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?

von Hmm (Gast)


Lesenswert?

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.

von Helge S. (helge_s)


Lesenswert?

Quatsch, umgekehrt:

ersetzen von:
"DC2=rcvd[2];"

durch
"DC1=rcvd[2];"


sorum isses richtich!

von Stefan (Gast)


Lesenswert?

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!

von Hmm (Gast)


Lesenswert?

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?

von Da D. (dieter)


Lesenswert?

Hmm schrieb:
> Bitte alle Optimierungen abschalten.

Ähm... Nein!?! Nicht tun! Was soll das bringen? Ein Programm muss mit 
Optimierungen funktionieren.

von Lutz (Gast)


Lesenswert?

Wie is'n rcvd[] definiert?

von Jürgen (Gast)


Lesenswert?

Stefan schrieb:
> ... das war nur ein "Tippfehler" beim Verfassen des Threads ...

Eine Frage: Bist du zu blöd den Quellcode auszuschneiden und zu posten?

von W.S. (Gast)


Lesenswert?

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.

von Stefan (Gast)


Lesenswert?

Lutz schrieb:
> Wie is'n rcvd[] definiert?
1
 char rcvd[5];

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ß

von Peter D. (peda)


Lesenswert?

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

von Stefan (Gast)


Lesenswert?

W.S. schrieb:
> Warum schreibst du bloß sowas?

Vermutlich, weil es so gelernt habe ;)

Aber danke für die Anregungen!

von Hmm (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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

von Lutz (Gast)


Lesenswert?

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.

von Oliver (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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)

von Rene H. (Gast)


Lesenswert?

Naja, Karl Heinz

Ich würde es mir nicht antun wollen hier den kompletten Code zu posten. 
Da wird man doch direkt verrissen.  :-)

Grüsse,
R.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Hmm (Gast)


Lesenswert?

Ähm. Karl Heinz! Der Rene ist nicht der TO.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Thomas E. (thomase)


Lesenswert?

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.

von Hmm (Gast)


Lesenswert?

Na schön. Vielleicht hilfts ja, wenn Du fragst, Karl Heinz:

Das hätten wir ja schon vor drei Stunden haben können.
Beitrag "Re: [C] Merkwürdige Erscheinung"

von Hmm (Gast)


Lesenswert?

>Bei dir kann man sich aber auch auf nichts verlassen.

Danke für das Kompliment.

von Ingo (Gast)


Lesenswert?

@peda
Ich würde mal tippen das einer der Ports nur 7 Bit hat? Oder warum steht 
dann da 0x7F?


Ingo

von Rene H. (Gast)


Lesenswert?

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.

von Rene H. (Gast)


Lesenswert?

Danke Hmm :-)

Grüsse,
R.

von Peter D. (peda)


Lesenswert?

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

von Dennis S. (whiterussian)


Lesenswert?

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

von 6shw46uu (Gast)


Lesenswert?

Ein Debugger wäre auch sehr hilfreich, um den Fehler schneller finden
zu können.

von Simon B. (nomis)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Simon B. (nomis)


Lesenswert?

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."

von Rechnung Tor (Gast)


Lesenswert?

Ah, meine Augen bluten ... das ist ja schrecklich!

W.S. schrieb:
> Schreib lieber
>
> void MyBlabla(blabla)
>
> { int DC1, DC2, DC3;
>
>   DC1 = DC2 = DC3 = 0;
>
>   ...

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

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
Noch kein Account? Hier anmelden.