Forum: Mikrocontroller und Digitale Elektronik Quellcode - Verständnis Schwierigkeiten


von picnoob (Gast)


Lesenswert?

Hi alle, habe mir ein PIC StarterKit zugelegt und schon ein bisschen was 
gemacht (LEDs ein aus), da gibts ja von PIC diese PDFs mit Beispielen, 
die sind ganz gut finde ich, allerdings bin ich nun bei einem Beispiel 
angelangt wo mir der Quellcode nicht ganz klar wird, das ist er:
1
void main (void)
2
{
3
    unsigned char Switch_Count = 0;
4
5
    LED_Display = 1;            // initialize
6
7
    TRISD = 0b00000000;       // PORTD bits 7:0 are all outputs (0)
8
    INTCON2bits.RBPU = 0;  // enable PORTB internal pullups
9
    WPUBbits.WPUB0 = 1;    // enable pull up on RB0
10
    ANSELH = 0x00;              // AN8-12 are digital inputs (AN12 on RB0)
11
    TRISBbits.TRISB0 = 1;       // PORTB bit 0 (con to switch) is input (1)
12
13
    while (1)
14
    {
15
        LATD = LED_Display;     // output LED_Display value to PORTD LEDs
16
17
        LED_Display <<= 1;      // rotate display by 1
18
        // Bit shifting oder Bitmanipulation
19
20
        if (LED_Display == 0)
21
            LED_Display = 1;    // rotated bit out, so set bit 0
22
23
24
xxxxxxx while (Switch_Pin != 1);// wait for switch to be released
25
        
26
        Switch_Count = 5;
27
        do
28
        { // monitor switch input for 5 lows in a row to debounce
29
            if (Switch_Pin == 0)
30
            { // pressed state detected
31
                Switch_Count++;
32
            }
33
            else
34
            {
35
                Switch_Count = 0;
36
            }   
37
            Delay10TCYx(25);    // delay 250 cycles or 1ms.
38
        } while (Switch_Count < DetectsInARow); 
39
    }
40
}

Das StarterKit hat eine LED Reihe mit 8 LEDs, wenn ich das Programm 
ausführe schaltet sich immer eine LED weiter sobald ich den Taster 
drücke.

Ab der Zeile die ich im Code mit xxxxxxx markiert habe, verstehe ich den 
ABlauf nicht mehr...

von Detlef K. (adenin)


Lesenswert?

Ok, den Source versteh ich auch nicht im Moment, aber da fehlt ja 
einiges.
zB DetectsInARow muss ja irgendwo definiert sein.
Wo gibt es denn die Source?
Die Pic's sind ja ein bisschen andersrum mit ihren Flags.
Aber das sollte sich doch nicht auf C auswirken.
Das sieht suspekt aus. Die Schleife wird doch bestimmt nicht mindestens 
5mal wiederholt.

ahja, das C ist andersrum :)

: Bearbeitet durch User
von Rene H. (Gast)


Lesenswert?

Ohne den restlichen Code zu kennen ist Dir nicht zu helfen. So wie die 
Schleife ist, liegt der Schlüssel in DetectsInRow.

Grüsse,
René

von picnoob (Gast)


Lesenswert?

DetectsInARow hat den Wert 5 (dient zum entprellen eines Tasters). 
"Switch_Pin" ist übrigens in einer Header definiert und soll einfach die 
Benennung des Ports an dem der Taster angeschlossen ist klarer machen.

Der Quellcode ist vollständig, dachte das ist zum Verständnis nicht 
wichtig.
Jetzt verständlicher?

von Karl H. (kbuchegg)


Lesenswert?

Das ganze ist eine Tastenentprellung nach der 'Warte-Methode'.

Was ist das Problem?
Das Problem ist, dass du zwar deinem Gefühl nach einen Taster 
niederdrückst und damit einen Eingang von 1 auf 0 umschaltest.
Das ist schön. Aber dein Gefühl trügt.
Der Taster schaltet nicht mit einem Schlag von 1 auf 0 und alles ist 
gut. Sondern das sind 2 Blechstreifen, die aufeinander gedrückt werden. 
Und so ein Blechstreifen federt ein wenig nach. Du drückst den einen auf 
den anderen. Der macht auch tatsächlich einen Kontakt. Aber nur ganz 
kurz, danach federt der Streifen soweit wieder weg, dass kein Kontakt 
mehr besteht -> der Eingang ist wieder auf 1. Dann federt er zurück und 
der Eingang kommt wieder auf 0.

D.h. dein µC sieht den Eingang beim Niederdrücken des Tasters so:
1
Zeit ->
2
3
   11111111110011001000000000
4
             ^
5
             |
6
           hier drückst du den Taster


Da sind ein paar 1-er eingestreut, die von dir nicht beabsichtigt sind, 
die  durch die Meachnik des Tasters bzw. durch ABnützung der Kontakte 
entstehen.

Und diese 1-er will man ausfiltern. Denn sonst passiert es dir, dass du 
1 mal niederdrückst, das Lauflicht aber um 2 oder 3 Stufen 
weiterspringt, weil der µC jeden einzelnen 1-0 Übergang als eigenen 
Tastendruck wertet (der µC ist um ein vielfaches schneller, als dieses 
Tastenprellen. Der arbeitet die Schleife viele hunderte male ab, ehe der 
Taster ein einziges mal prellen kann)

Der code macht
1
    while (Switch_Pin != 1)
2
      ;
hier wird erst mal drauf gewartet, dass der Pin auf 1 ist. WEnn der 
Taster also gedrückt ist, wenn das Programm zu dieser Stelle kommt, dann 
wird solange der Eingang abgefragt, bis er wieder auf 1 steht (du den 
taster also nicht mehr drückst)
1
        Switch_Count = 5;
das ist ein bischen missverständlich, denn die 5 sind durch nichts 
motiviert. Eine 0 wäre hier besser gewesen
1
        do
2
        { // monitor switch input for 5 lows in a row to debounce
3
            if (Switch_Pin == 0)
4
            { // pressed state detected
5
                Switch_Count++;
6
            }
7
            else
8
            {
9
                Switch_Count = 0;
10
            }   
11
            Delay10TCYx(25);    // delay 250 cycles or 1ms.
12
        } while (Switch_Count < DetectsInARow);

die schleife läuft also so lange, bis der Switch_Count größer oder 
gleich einer Vorgabe ist. Was ist dieser Switch_Count. Das ist nicht 
andeser als ein Zähler, der mitzählt wie oft hintereinander der Eingang 
auf 0 vorgefunden wurde. Jedesmal wenn das der Fall ist, dann wird 
dieser Zähler um 1 erhöht. Ist das nicht der Fall, dann beginnt die 
Zählerei wieder bei 0.
Es ist im Grunde, wie wenn du an der Strasse stehst und darauf wartest, 
dass 20 Sekunden lang kein Auto vorbeikommt. Jedesmal wenn ein Auto 
vorbei fährt startest du die Uhr wieder von vorne neu und nur dann, wenn 
die Uhr tatsächlich irgendwann bis 20 kommt, dann sind seit dem letzten 
Auto auch wirklich 20 Sekunden vergangen.

Hier ist es dann eben so, dass der Mechanismus solange wieder auf 0 
zurückgesetzt wird, solange immer wieder eine 1 am Eingang vorgefunden 
wird.
1
Zeit ->
2
             hier beginnt der Switch_count mit Zählen.
3
             |
4
             v             
5
   11111111110011001000000000
6
             ^
7
             |
8
           hier drückst du den Taster
1
Zeit ->
2
3
             0
4
              1
5
               Mist, da ist eine 1, also zurück auf Anfang. Wieder neu bei 0 anfangen zu zählen
6
               |
7
               v
8
   11111111110011001000000000
9
             ^
10
             |
11
           hier drückst du den Taster
1
Zeit ->
2
               Das gibts doch nicht, noch ein 1-er. Also switch_count wieder bei 0
3
                |
4
                v
5
   11111111110011001000000000
6
             ^
7
             |
8
           hier drückst du den Taster
1
Zeit ->
2
                 0
3
                  1
4
                   noch ein 1-er: marsch, marsch, wieder bei 0 anfangen
5
                   |
6
                   v
7
   11111111110011001000000000
8
             ^
9
             |
10
           hier drückst du den Taster
1
Zeit ->
2
                    0
3
                     1
4
                      2
5
                       3
6
                        4
7
                         5
8
                           das wars. nach menschlichem Ermessen hat sich jetzt
9
                           der Taster beruhigt. Da kommt kein 1-er mehr.
10
                           Ab jetzt gilt der Tastendruck als erkannt
11
                           
12
   11111111110011001000000000
13
             ^
14
             |
15
           hier drückst du den Taster

: Bearbeitet durch User
von adenin (Gast)


Lesenswert?

Und das passiert wirklich im ersten Scgleifendurchlauf:     :-b
-die Taste wird gedrückt.
-Switch_Count wird mit 5 initalisert
-wir beginnen die do_wihle_Schleife
-Pin0 ist noch 0 (es sind ja erst ein paar Prozzessortakte seit dem 
ersten hinschauen vergangen) also wird Switch_Count++ ausgeführt. 
Switch_Count hat nun einen Wert von 6
-Delayzeit abwarten
-do_wihle_Bedingung prüfen, da Switch_Count (aktuell 6) jetzt größer 
DetectsInARow (5) ist, wird die Enprellroutine verlassen.
Super ;)

von picnoob (Gast)


Lesenswert?

Danke für die Erklärungen.
1
while (Switch_Pin != 1);// wait for switch to be released

diese Schleife läuft also endlos, es sei denn der Taster hat einen Wert 
ungleich 1, also 0. Mich irritiert schon die Tatsache, dass der Taster 
einen Wert von 0 liefern muss um als betätigt erkennt zu werden, eine 1 
wäre irgendwie logischer.

Das nächste was ich nicht ganz verstanden habe, ich habe gedacht, dass 
der µc alle paar Takte die Signale auf die Pins schickt, wie aber kann 
er das  tun wenn er in dieser Endlosschleife festhängt? (ich drücke den 
Taster einfach nicht).

Ich habe mal mit einer SPS zu tun gehabt, die alle 1ms Signale 
rausgeschickt hat / Signale eingelesen hat, wenn ich dort eine 
Endlosschleife programmiert habe, kam sofort ne Fehlermeldung (konnte zB 
die Schleife nicht 500 mal ausführen weil die 1ms zu kurz dafür war).

von Karl H. (kbuchegg)


Lesenswert?

picnoob schrieb:
> Danke für die Erklärungen.
>
>
1
> while (Switch_Pin != 1);// wait for switch to be released
2
>
>
> diese Schleife läuft also endlos, es sei denn der Taster hat einen Wert
> ungleich 1, also 0.

Nein. genau anders rum.
while bedeutet 'so lange wie'

Da steht also
  mache, solange wie sitch_pin ungleich 1 ist.

ungleich 1 ist dasselbe wie 0. Etwas vereinfacht steht da also
  mache, solange wie switch_pin gleich 0 ist

> Mich irritiert schon die Tatsache, dass der Taster
> einen Wert von 0 liefern muss um als betätigt erkennt zu werden, eine 1
> wäre irgendwie logischer.

ist eine reine Konvention. Du gewöhnst dich daran.

von Karl H. (kbuchegg)


Lesenswert?

adenin schrieb:
> Und das passiert wirklich im ersten Scgleifendurchlauf:     :-b
> -die Taste wird gedrückt.
> -Switch_Count wird mit 5 initalisert
> -wir beginnen die do_wihle_Schleife
> -Pin0 ist noch 0

Nope. Der kommt da nicht her.
Das schaffst du nur, wenn du es schaffst, die Taste exakt während der 
ersten while Schleife und der zweiten do-while Schleife zu drücken. 
Möglich ist es theoretisch, genau den Zeitpunkt zu erwischen. Aber eher 
unwahrscheinlich.

von Karl H. (kbuchegg)


Lesenswert?

picnoob schrieb:

> Das nächste was ich nicht ganz verstanden habe, ich habe gedacht, dass
> der µc alle paar Takte die Signale auf die Pins schickt, wie aber kann
> er das  tun wenn er in dieser Endlosschleife festhängt? (ich drücke den
> Taster einfach nicht).

wenn du den Taster nicht drückst, gibt es in diesem Programm auch keinen 
Grund die Anzeige zu verändern. Die letzte Ausgabe, die du auf den Port 
gemacht hast, bleibt dann dort einfach erhalten, während der µC darauf 
wartet, dass eine Taste gedrückt wird.

In diesem Moment
>         LATD = LED_Display;     // output LED_Display value to PORTD LEDs
hast du eine Ausgabe an die Leds. Und die verändert sich erst, wenn eine 
erneute Ausgabe an LATD gemacht wird. In der Zwischenzeit halten die 
Ausgabepins einfach den letzten Zustand.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz Buchegger schrieb:

> ist eine reine Konvention. Du gewöhnst dich daran.

d.h es ist nicht nur eine Konvention.
Es hat damit zu tun, dass der µC sog. Pullup Widerstände eingebaut hat 
und keine Pulldown. Der Pullup Widerstand sorgt dafür, dass der Eingang 
auch dann einen definierten Pegel hat, wenn der Taster nicht gedrückt 
ist. Und da es ein Pull-Up ist, ist dann der Pegel nun mal 1. Gäbe es 
einen Pull-Down, dann würde man das umdrehen: der Pull-Down sorgt für 
einen definierten 0-Pegel bei nicht gedrücktem Taster und der Taster 
selbst sorgt beim Drücken dann für einen 1-Pegel.

Aber wie gesagt: Das hast du schnell intus, dass ein gedrückter Taster 
einer 0 entspricht. Das ist nichts gravierendes.

von picnoob (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Es hat damit zu tun, dass der µC sog. Pullup Widerstände eingebaut hat
> und keine Pulldown. Der Pullup Widerstand sorgt dafür, dass der Eingang
> auch dann einen definierten Pegel hat, wenn der Taster nicht gedrückt
> ist. Und da es ein Pull-Up ist, ist dann der Pegel nun mal 1. Gäbe es
> einen Pull-Down, dann würde man das umdrehen: der Pull-Down sorgt für
> einen definierten 0-Pegel bei nicht gedrücktem Taster und der Taster
> selbst sorgt beim Drücken dann für einen 1-Pegel.

Super Erklärung Danke :-) Bei solchen Dingen ist mir eine technische 
Erklärung immer am liebsten, dann kann man es logisch nachvollziehen.

von Karl H. (kbuchegg)


Lesenswert?

picnoob schrieb:

> Super Erklärung Danke :-) Bei solchen Dingen ist mir eine technische
> Erklärung immer am liebsten, dann kann man es logisch nachvollziehen.


Die technische Erklärung ist, dass ein nicht gedrückter Taster
1
     +-------------> um µC
2
     |
3
   \
4
    \
5
     |
6
     |
7
   --+------ GND

auf der Leitung keinen besonderen Pegel hinterlässt. Wie denn auch, die 
Leitung ist ja mit nichts verbunden. Was du da hast ist im Grunde 
einfach nur eine Antenne, die sich jedes dahergelaufene 
elektromagnetische Feld aus der Umgebung einfängt.

Erst jetzt ...
1
          ---+------ +5V
2
             |
3
            +-+
4
            | |
5
            +-+
6
             |
7
     +-------+-----> um µC
8
     |
9
   \
10
    \
11
     |
12
     |
13
   --+------ GND
... mit einem Pullup Widerstand, hat die Leitung auch dann einen 
definierten Pegel, wenn der Taster nicht gedrückt ist. Ist der Taster 
nicht gedrückt, dann gibt es eine Verbindung über den Widerstand nach 
+5V. Der Eingang sieht also definiert +5V (oder eben 1 im Programm). 
Wird der Taster gedrückt, dann gibt es keinen Kurzschluss, sondern über 
dem Widerstand fallen die 5V ab und die Leitung ist auf GND Potential. 
Im Programm ist das dann eine 0.

: Bearbeitet durch User
von picnoob (Gast)


Lesenswert?

1
while (Switch_Pin != 1);// wait for switch to be released
2
        
3
        Switch_Count = 5;
4
        do
5
        { // monitor switch input for 5 lows in a row to debounce
6
            if (Switch_Pin == 0)
7
            { // pressed state detected
8
                Switch_Count++;
9
            }
10
            else
11
            {
12
                Switch_Count = 0;
13
            }   
14
            Delay10TCYx(25);    // delay 250 cycles or 1ms.
15
        } while (Switch_Count < DetectsInARow);

Hmm ich könnte das jetzt auch selber kurz testen, aber ich frage mal, 
würde das Programm nicht auch ohne die oberste While Schleife korrekt 
funktionieren?

von Karl H. (kbuchegg)


Lesenswert?

picnoob schrieb:

> Hmm ich könnte das jetzt auch selber kurz testen, aber ich frage mal,
> würde das Programm nicht auch ohne die oberste While Schleife korrekt
> funktionieren?

Nein.
Denn wenn die Taste einmal gedrückt war, dann muss sie erst mal 
losgelassen werden, ehe dann der nächste Tastendruck tatsächlich zählt.

Die oberste while Schleife realisiert genau das: Warte darauf, dass die 
Taste auch wieder mal losgelassen wird.

Die untere Schleife realisiert ja nur den Teil: Ist die Taste sauber 
niedergedrückt, wobei eventuelle kleine Preller ausgefiltert werden. 
Nidergedrückt ist aber nicht dasselbe wie 'jetzt gerade niedergedrückt'. 
Du kannst eine halbe Stunde auf der Taste drauf bleiben. Deswegen wurde 
sie aber nur ein einziges mal niedergedrückt. Und dieser eine Vorgang, 
der Vorgang des Umschaltens von nicht gedrückt zu gedrückt, das ist 
genau der Vorgang, der hier interessiert. Dazu muss aber erst mal die 
Ausgangssituation eingetreten sein. Und die lautet: die Taste ist nicht 
gedrückt. Das Programm kommt nur dann aus dieser ersten while Schleife 
raus, wenn diese Ausgangssituation auch tatsächlich eingetreten ist. 
Selbst dann, wenn du 1 Stunde lang mit dem Finger den Taster 
niedergepresst hast.

: Bearbeitet durch User
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.