Forum: Mikrocontroller und Digitale Elektronik Immer noch Fehler!


von Dennis (Gast)


Angehängte Dateien:

Lesenswert?

Hallo alle zusammen,

ich hatte in den vergangenen Tagen schon mein Problem mit der SPI eines 
Atmega32 gepostet.
Ich stelle nun den kompletten Code dazu, damit mir (vielleicht) jemand 
helfen.

Kurz zur Konfiguration:

Mastercontroller (Steuerung)
================

PA0 bis PA2 --> Triggerausgänge Ultraschallsensoren
PC5 bis PC7 --> Echoeingänge Ultraschallsensoren

Slavecontroller (Fahrwerk)
===============

PB3 --> PWM-Ausgang Maschine 1
PD7 --> PWM-Ausgang Maschine 2

Beide Controller sind über SPI miteinander verbunden.

Das Problem:

Aus einem mir nicht verständlichen Grund kommen die gesendeten Bytes auf 
dem Slavecontroller teilweise in einer anderen Reihenfolge an. Ich 
vermute, dass Bytes "verschluckt" werden, also verloren gehen.
Den Grund dafür habe ich nicht gefunden. Und weiter weiss ich leider 
auch nicht mehr. Ich hoffe, dass mir von Euch jemand helfen kann!

Grüße und Danke!

Dennis

Die andere C-Datei poste ich hier nach!

von Dennis (Gast)


Angehängte Dateien:

Lesenswert?

So, hier die andere C-Datei!!

von Karl H. (kbuchegg)


Lesenswert?

Das hier

Steuerung.c
1
    while (!((PINC = a)))          // Auf Echo warten (dauert 200us)
2
    {
3
      asm volatile ("nop");        // und solange nix machen
4
    }

sieht nicht koscher aus.
Wozu soll es gut sein an PINC den Wert von a zuzuweisen?

von Karl H. (kbuchegg)


Lesenswert?

Das hier
1
    // gesendet wurde erst Low-Byte dann High-Byte
2
    gap[a] = ((unsigned int) letter[(i+1)]) | (unsigned int) letter[i];

stimmt auch nicht
du musst letter[i+1] schon um 8 Bits nach links schieben.

von Karl H. (kbuchegg)


Lesenswert?

Diese ganze Sequenz
1
    TCNT1 = startval;            // 36ms
2
    TCCR1B = 0x03;              // Timer starten 36ms
3
4
    while ((PINC = a))            // Auf Ende des Echos warten
5
    {
6
      asm volatile ("nop");        // und solange nix machen
7
    }
8
9
    // Echodauer verarbeiten
10
    if (interrupt == 1)            // Zwischenzeitlich Interrupt?
11
    {
12
      control[(i >> 1)] = 3270;      // Mehr als 3m Platz
13
      interrupt = 0;            // Meldevariable l?en
14
    }
15
    else
16
    {
17
      control[(i >> 1)] = TCNT1 - startval;
18
                        // Abstand auswerten...
19
      TCCR1B = 0x00;            // ...und Timer stoppen
20
      interrupt = 0;            // vorsichtshalber
21
    }

sieht nicht gut aus.
Du startest zwar den Timer. Du stoppst ihn aber irgendwann (wann 
eigentlich) und rechnest zwischendurch mit dem TCNT1 Wert rum, als ob es 
kein morgen gäbe. So wirst du nie ein vernünftiges Timing kriegen.

Darf ich einen Vorschlag machen?
Ehe du mit dem SPI rummachst, gib dir doch die gemessenen Werte erst mal 
irgendwo aus (UART, PORT, LCD oder was du zur Verfügung hast) und mach 
erst mal deine Hausaufgaben einer vernünftigen, zuverlässigen Messung. 
Es bringt nichts sich an 3 Fronten gleichzeitig aufzureiben. Ein 
Subsystem nach dem anderen debuggen, lauffähig machen und deren korrekte 
Funktion sicherstellen.

von Karl H. (kbuchegg)


Lesenswert?

> Aus einem mir nicht verständlichen Grund kommen die
> gesendeten Bytes auf dem Slavecontroller teilweise in einer
> anderen Reihenfolge an. Ich vermute, dass Bytes "verschluckt"
> werden, also verloren gehen.

Das Wort, welches mich in diesem Absatz erschreckt ist "vermute".
Mit Vermutungen kommt man nicht weiter. Fakten zählen! Wenn du den 
Verdacht hast, dass da irgendetwas in einer falschen Reihenfolge 
passiert, dann schaff dir eine Möglichkeit, wie du dir Werte ansehen 
kannst.

Alles andere ist stochern im Nebel.
Bei der Fehlersuche darf man nicht 'vermuten', man muss wissen! Wissen 
kann man aber nur Dinge, die man mit eigenen Augen gesehen hat, weil 
einem das Programm Zwischenwerte in irgendeiner Form anzeigt.

von Dennis (Gast)


Lesenswert?

> Das hier

> Steuerung.c

>    while (!((PINC = a)))          // Auf Echo warten (dauert 200us)
>    {
>      asm volatile ("nop");        // und solange nix machen
>    }

> sieht nicht koscher aus.
> Wozu soll es gut sein an PINC den Wert von a zuzuweisen?

Es funktioniert aber. Die Ultraschallmessung läuft einwandfrei.
Es geht sich nur um die SPI-Übertragung.
Wenn ich die Auswertung auf "Start" oder "Stopp" in der Steuerung mache 
und nur ein Byte sende, dann funktioniert es. Sende ich 6 Bytes, klappt 
es nicht mehr.

> Das hier

>    // gesendet wurde erst Low-Byte dann High-Byte
>    gap[a] = ((unsigned int) letter[(i+1)]) | (unsigned int) letter[i];

> stimmt auch nicht
> du musst letter[i+1] schon um 8 Bits nach links schieben.

Stimmt leider doch. Ich habe das mit AVR-Simulator überprüft. Im 
SPI-Senderegister kommen die richtigen Werte an. Ich habe das überprüft, 
in dem ich Werte vor gegeben habe.

> Darf ich einen Vorschlag machen?
Klar ;)

> Ehe du mit dem SPI rummachst, gib dir doch die gemessenen Werte erst mal
> irgendwo aus (UART, PORT, LCD oder was du zur Verfügung hast) und mach
> erst mal deine Hausaufgaben einer vernünftigen, zuverlässigen Messung.
> Es bringt nichts sich an 3 Fronten gleichzeitig aufzureiben. Ein
> Subsystem nach dem anderen debuggen, lauffähig machen und deren korrekte
> Funktion sicherstellen.

Guter Vorschlag. Eigentlich mache ich das ja auch so. Wie gesagt ... die 
Ultraschallmessung läuft ja. Und sende ich dem Fahrwerk nur die Info "1" 
oder "0", sprich ein Byte, macht die Kiste alles was ich will.
Sobald 6 Bytes gesendet werden, gehen Infos verloren.

> Das Wort, welches mich in diesem Absatz erschreckt ist "vermute".

Warum? Ich programmiere noch nicht so lange. Hast Du immer gleich alles 
gewusst?

von Dennis (Gast)


Lesenswert?

> Das hier

>    // gesendet wurde erst Low-Byte dann High-Byte
>    gap[a] = ((unsigned int) letter[(i+1)]) | (unsigned int) letter[i];

> stimmt auch nicht
> du musst letter[i+1] schon um 8 Bits nach links schieben.

Entschuldigung!! Hast Recht. Ich habe das Schieben vergessen!!!

von Thomas K. (muetze1)


Lesenswert?

Und was ist mit dem ersten? Du machst eine Zuweisung auf PINC und 
keinen Vergleich!

Das ist definitiv nicht gewollt, da du so nicht PINC abfragst sondern er 
verlässt die Schleife wenn a 0 ist. Wenn das gewollt ist, dann kannst du 
dir das ansprechen von PINC sparen.

Also denk nochmal drüber nach...

von Dennis (Gast)


Lesenswert?

Er soll abfragen, ob der Wert, der am Port ansteht dem Wert von a 
entspricht.
Dann muss da stehen a = PINC, oder?! Also genau anders herum.

von Karl H. (kbuchegg)


Lesenswert?

Dennis schrieb:
> Er soll abfragen, ob der Wert, der am Port ansteht dem Wert von a
> entspricht.
> Dann muss da stehen a = PINC, oder?! Also genau anders herum.

Vergleich schreibt sich in C immer noch als ==

Das Tolle daran ist, dass ihn der Compiler sogar gewarnt hat:
"Bist du dir sicher, dass das eine Zuweisung sein soll und kein 
Vergleich? Wenn du dir 100%, absolut sicher bist, dann schlage ich vor, 
du machst noch eine Klammer drumherum."

Und das hat er dann auch getan
    while ((PINC = a))            // Auf Ende des Echos warten

von Dennis (Gast)


Lesenswert?

Ja ... ich nehm jetzt mal das Brett vom Kopf und dann schauen wir mal 
weiter..

von Dennis (Gast)


Lesenswert?

> Das Tolle daran ist, dass ihn der Compiler sogar gewarnt hat:
> "Bist du dir sicher, dass das eine Zuweisung sein soll und kein
> Vergleich? Wenn du dir 100%, absolut sicher bist, dann schlage ich vor,
> du machst noch eine Klammer drumherum."

Das ist nicht passiert. WEnn ich in AVR Studio 4.0 kompiliere, steht da 
"Build succeeded with 0 Warnings"

Über mich lustig machen brauchst Du Dich nicht ;)

von Karl H. (kbuchegg)


Lesenswert?

Dennis schrieb:

>> sieht nicht koscher aus.
>> Wozu soll es gut sein an PINC den Wert von a zuzuweisen?
>
> Es funktioniert aber. Die Ultraschallmessung läuft einwandfrei.

Das glaube ich nicht.
Eine Zuweisung ist kein Vergleich!

>> Das hier
>
>>    // gesendet wurde erst Low-Byte dann High-Byte
>>    gap[a] = ((unsigned int) letter[(i+1)]) | (unsigned int) letter[i];
>
>> stimmt auch nicht
>> du musst letter[i+1] schon um 8 Bits nach links schieben.
>
> Stimmt leider doch. Ich habe das mit AVR-Simulator überprüft.

Auch das kann ich mir nicht vorstellen.
Wenn du 8 Bit mit anderen 8 Bit veroderst kommt alles mögliche raus. 
Aber sicher nicht eine vernünftige 16 Bit Zahl.

Das Ergebnis von 0x0020 | 0x0040  ist nun mal 0x0060 und nicht 0x2040, 
so wie es eigentlich sein sollte, wenn du 2 einzelne Bytes (nämlich 0x20 
und 0x40) zu einem int zusammensetzt.

(Man könnte es auch so sagen:
Wenn du beim Senden einen Teil der Zahl um 8 Stellen nach rechts 
schiebst, dann muss genau dieser empfangene Teil im Empfänger wieder um 
8 Stellen nach links geschoben werden, damit er wieder an seiner 
ursprünglichen Lage zu liegen kommt)

>> Das Wort, welches mich in diesem Absatz erschreckt ist "vermute".
>
> Warum? Ich programmiere noch nicht so lange. Hast Du immer gleich alles
> gewusst?

Nein. Aber genau deshalb erzähl ich es dir, wie man an die Dinge 
rangeht. Ich könnte dich auch noch ein paar Tage im Nebel stochern 
lassen!

von Dennis (Gast)


Lesenswert?

>> Das hier
>
>>    // gesendet wurde erst Low-Byte dann High-Byte
>>    gap[a] = ((unsigned int) letter[(i+1)]) | (unsigned int) letter[i];
>
>> stimmt auch nicht
>> du musst letter[i+1] schon um 8 Bits nach links schieben.
>
> Stimmt leider doch. Ich habe das mit AVR-Simulator überprüft.

> Auch das kann ich mir nicht vorstellen.
> Wenn du 8 Bit mit anderen 8 Bit veroderst kommt alles mögliche raus.
> Aber sicher nicht eine vernünftige 16 Bit Zahl.

> Das Ergebnis von 0x0020 | 0x0040  ist nun mal 0x0060 und nicht 0x2040,
> so wie es eigentlich sein sollte, wenn du 2 einzelne Bytes (nämlich 0x20
> und 0x40) zu einem int zusammensetzt.

> (Man könnte es auch so sagen:
> Wenn du beim Senden einen Teil der Zahl um 8 Stellen nach rechts
> schiebst, dann muss genau dieser empfangene Teil im Empfänger wieder um
> 8 Stellen nach links geschoben werden, damit er wieder an seiner
> ursprünglichen Lage zu liegen kommt)

Du hast ja Recht. Ich habe das nur auf der anderen Seite überprüft. 
Diesen Teil habe ich nicht gecheckt.
Genau diese Zeile bestätigt damit ja auch meine Vermutung, dass Bytes 
verloren gehen. Nämlich jeweils das Low-Byte, weil es vom High-Byte 
deswegen überschrieben wird, da ich es versäumt hatte, es um 8 Bits nach 
links zu schieben.

> Nein. Aber genau deshalb erzähl ich es dir, wie man an die Dinge
> rangeht. Ich könnte dich auch noch ein paar Tage im Nebel stochern
> lassen!

ISt schon OK! Ich danke Dir ja auch dafür.

von Karl H. (kbuchegg)


Lesenswert?

Dennis schrieb:
>> Das Tolle daran ist, dass ihn der Compiler sogar gewarnt hat:
>> "Bist du dir sicher, dass das eine Zuweisung sein soll und kein
>> Vergleich? Wenn du dir 100%, absolut sicher bist, dann schlage ich vor,
>> du machst noch eine Klammer drumherum."
>
> Das ist nicht passiert. WEnn ich in AVR Studio 4.0 kompiliere, steht da
> "Build succeeded with 0 Warnings"
>
> Über mich lustig machen brauchst Du Dich nicht ;)

Tu ich nicht.
Aber schreib mal testweise

    while (PINC = a)            // Auf Ende des Echos warten

also nur mit einer Klammer :-) und schau nach, was der gcc dazu sagt :-)

Und da ich nicht davon ausgehe, dass jemand freiwillig hier bei einem 
irrtümlichen Vergleich ein zusätzliches Klammernpaar schreibt, hattest 
du das ursprünglich so ...,
    while (PINC = a)            // Auf Ende des Echos warten
 ... der Compiler hat dich gewarnt und du hast das 2.te Klammerpaar 
dazugemacht:
    while ((PINC = a))            // Auf Ende des Echos warten
wenn eigentlich
    while (PINC == a)            // Auf Ende des Echos warten
richtig gewesen wäre

Nimms doch nicht persönlich! Genau dieser Fehler passiert tausende male 
am Tag. Und genau aus diesem Grund gibt es diese Warnung. Der COmpiler 
kann aber nicht wissen, welche der beiden Varianten richtig ist und gibt 
daher den Hinweis, wie man die Warnung los werden kann, wenn man sich 
absolut 100% sicher ist, dass die Zuweisung gewollt ist.

Was du daraus lernen sollst: Compilerwarnungen und vor allen Dingen 
Vorschläge, die darin enthalten sind, nicht für Gottes letztes Wort zu 
nehmen, sondern selbst noch einmal nachdenken: Hier stimmt was nicht, 
was könnte es sein?

von Dennis (Gast)


Lesenswert?

> Und da ich nicht davon ausgehe, dass jemand freiwillig hier bei einem
> irrtümlichen Vergleich ein einzelnes = schreibt, hattest du das
> ursprünglich so, der Compiler hat dich gewarnt und du hast das 2.te
> Klammerpaar dazugemacht.

Jep :-D

von Klaus W. (mfgkw)


Lesenswert?

Dennis schrieb:
> ...
> Warum? Ich programmiere noch nicht so lange. Hast Du immer gleich alles
> gewusst?

Karl heinz Buchegger ist auch Anfänger, und weiß es trotzdem:
Beitrag "Re: Kann man ne this global über ne operatorfunktion"

von Dennis (Gast)


Lesenswert?

> Karl heinz Buchegger ist auch Anfänger, und weiß es trotzdem:
> Beitrag "Kann man ne this global über ne operatorfunktion"

Thema ist doch schon gehalten. Bleiben wir beim Fachlichen, okay ;)

von Karl H. (kbuchegg)


Lesenswert?

Karl heinz Buchegger schrieb:

> wenn eigentlich
>     while (PINC == a)            // Auf Ende des Echos warten
> richtig gewesen wäre


Wobei selbst das noch fraglich ist, ob das tatsächlich so richtig ist, 
Oder ob das in Wirklichkeit nicht

  while( PINC & a )

heißen müsste.

von Dennis (Gast)


Lesenswert?

Ist das Ergebnis nicht dasselbe?
Einmal fragt man auf Gleichheit ab, das andere Mal maskiert man und 
setzt damit gleichfalls voraus, dass beide Ergebnisse gleich sind, um 
die Bedingung zu erfüllen.

Wo ist da nun genau der Unterschied?

von Klaus W. (mfgkw)


Lesenswert?

Bei a&b wird das Ergebnis bitweise gebildet, Ergebnis ist
eine Zahl, in der alle Bits gesetzt sind, die sowohl in a als
auch in b gesetzt sind.
Im if wird das auf ungleich 0 getestet.
Das if wird also genau dann ausgeführt, wenn a und b mindestens
ein gemeinsames gesetztes Bit haben.

Bei a==b kommt entweder 0 heraus oder 1.
1 ergibt sich genau dann, wenn a und b in allen Bits exakt
übereinstimmen.

0&0 ergibt 0
0==0 ergibt 1
1&3 ergibt 1
1==3 ergibt 0
7&3 ergibt 3
7==3 ergibt 0

von Karl H. (kbuchegg)


Lesenswert?

Dennis schrieb:

> Wo ist da nun genau der Unterschied?

Der Unterschied kommt dann zum tragen, wenn in PINC auch noch andere 
Bits gesetzt sind, als das an dem du deinen einen Empfänger 
angeschlossen hast.

Bei
  PINC & 0x80

betrachtest du wirklich nur genau dieses eine Bit (das 7-te Bit) und 
sonst nichts. Alle anderen Bits können stehen wie sie wollen, sie 
beeinflussen das Ergebnis nicht.

Bei
  PINC == 0x80

müssen die anderen Bits alle 0 sein. Ist auch nur eines davon nicht 0, 
wird die Abfrage schief gehen, selbst wenn Bit 7 auf 1 steht.

von Dennis (Gast)


Lesenswert?

Alles klar!!

Ich danke Euch sehr für Eure Hilfe!!

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.