Forum: Compiler & IDEs while beendet obwohl nicht "0"


von Michael D. (Gast)


Angehängte Dateien:

Lesenswert?

Nabend.

Ich bin dabei mit eine Motorsteuerung zu bauen, welche über 
Hallsensoren, welche über 6Magnete angesteuert werden zählen kann in 
welcher Position die Welle sich befindet.

Leider habe ich beim Zählen (450Schritte Linkslauf) das Problem, das er 
teilweise (jedes 5-7te mal) nach geschätzt der Hälfe stehen bleibt.

Darauf hin habe ich das Signal der Hallsensoren auf dem Oszilloskop 
angeschaut und gesehen das vereinzelnt Spikes vorhanden sind, weswegen 
ich also eine Schleife eingebaut habe, welche nicht sofort zählt.


Nachdem ich nun 1Woche dabei bin habe ich mal Spaßeshalber aus:
1
while(CountPulses) {
2
}

den Befehl:
1
while(CountPulses) {
2
}
3
while(CountPulses) {
4
}

gemacht. Also einfach die Abfrage doppelt genommen und siehe da: Es 
funktioniert (50Durchläufe).

Kann mir jemand sagen woran das liegt?
Count Pulses ist eine volatile 16Bit Variable.

Pollen mache ich über Timer0 mit einem Teiler von 8:
1
ISR(TIMER0_OVF_vect) {
2
     uint8_t temp=PHall1;
3
     if(!((temp&Hall1)==((temp&Hall2)>>1))) {
4
          if(((Status&LetzteHall1)==(temp&Hall1))) {
5
               switch (Status&0xC0) {
6
7
                    case 0x80:
8
                         break;
9
10
                    case 0x40:
11
                         Status^= LetzteHall1;
12
                         Status+= 0x40;
13
14
                    default:
15
                         Status&= 0xCF;
16
                         Status+= 0x40;
17
                         break;
18
19
               }
20
          } else {
21
               switch (Status&0x30) {
22
23
                    case 0x20:
24
                         break;
25
26
                    case 0x10:
27
                         if((Status&Drehrichtung)) {
28
                              CountPulses++;
29
                         } else {
30
                              CountPulses--;
31
                         }
32
                         Status+= 0x10;
33
                         break;
34
35
                    default:
36
                         Status&= 0x3F;
37
                         Status+= 0x10;
38
                         break;
39
40
               }
41
          }
42
     } else {
43
          Status&= 0x3F;
44
     }
45
}

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Meine neu gekaufte Glaskugel meint:

FAQ #1: "volatile" vergessen (bei "CountPulses").

von Stefan E. (sternst)


Lesenswert?

Michael D. schrieb:
> Leider habe ich beim Zählen (450Schritte Linkslauf) das Problem, das er
> teilweise (jedes 5-7te mal) nach geschätzt der Hälfe stehen bleibt.

Michael D. schrieb:
> Count Pulses ist eine volatile 16Bit Variable.

Das liegt daran, dass das Lesen in der Schleife nicht atomar ist. Daher 
kann beim Übergang von 256 nach 255 vorzeitig eine 0 erkannt werden.

von Michael D. (Gast)


Lesenswert?

Stefan Ernst schrieb:
> Das liegt daran, dass das Lesen in der Schleife nicht atomar ist. Daher
> kann beim Übergang von 256 nach 255 vorzeitig eine 0 erkannt werden.

Weiß zwar nicht wie das "atomar" gemeint ist, denke aber, das während 
des Lesevorganges die ISR aufgerufen wird und das Byte geändert.

Würde jetzt als Laie in der while() die Variable zwischen einem cli() 
und sei() kopieren sodass eine Kopie überprüft wird.

Oder gibt es da eine fertige Lösung?

von Stefan E. (sternst)


Lesenswert?

Michael D. schrieb:
> Weiß zwar nicht wie das "atomar" gemeint ist, denke aber, das während
> des Lesevorganges die ISR aufgerufen wird und das Byte geändert.

Es ist ja nicht nur ein Byte, sondern zwei. Und um festzustellen, ob die 
Variable 0 ist, müssen beide Bytes getestet werden. Und wenn nun genau 
zwischen diesen beiden Tests der Interrupt die Variable von 256 auf 255 
ändert, wird fälschlicherweise eine 0 erkannt.

Michael D. schrieb:
> Würde jetzt als Laie in der while() die Variable zwischen einem cli()
> und sei() kopieren sodass eine Kopie überprüft wird.

Ich würde es so machen:
1
#include <util/atomic.h>
2
...
3
4
    uint16_t tmp = 1;
5
    while (tmp) {
6
        ATOMIC_BLOCK(ATOMIC_FORCEON) {
7
            tmp = CountPulses;
8
        }    
9
    }

von Michael D. (Gast)


Lesenswert?

Vielen Dank für die Info.

Habe mir das mal im .lss angeschaut, werde beim cli()/sei() bleiben, da 
es genau gleich über setzt wird und für mich einfacher ist.

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.