Forum: Mikrocontroller und Digitale Elektronik MSP430 Schalterentprellung Not vs. Elend


von PistolPete (Gast)


Lesenswert?

Meine Digitaluhr nimmt langsam Form an. Doch eine Uhr die man nicht 
stellen kann ist nichts wert. Schnell stellte ich fest dass das ohne 
eine Entprellung nichts wird.

Nun habe ich es einmal mit dem einfachsten der Codebeispiele veruscht 
(im Tutorial der erste Code im Absatz Softwareentprellung). Dieser Code 
entprellt die Schalter tatsächlich sehr gut, doch seltsamerweise geht 
die Uhr damit nur manchmal überhaupt zu stellen. Ca. in 2 von 3 Fällen 
läuft sie zwar, reagiert aber gar nicht auf die Inputs die ich fürs 
Stellen verwende.
In den restlichen Fällen läuft sie und lässt sich auch stellen wie ich 
es mir vorstelle. Es entscheidet sich immer beim Einschalten, was von 
beiden nun Sache ist, und bis man sie wieder ausmacht bleibt es auch so.

Alternativ habe ich Flankenerkennung über Flags versucht (P2IFG). Die 
geht zu 100%, aber nicht so gut wie die erste Entprellung: teilweise 
wird doppelt geschaltet oder auch auf der "falschen" Flanke.

Hier mal der Code zu den beiden Lösungen.

1. Version aus Tutorial, für meine Zwecke leicht abgewandelt:
1
void staster(void)
2
{
3
    static unsigned char zustand;
4
 
5
    if(zustand == 0 && !(P2IN & BIT0) )   //Taster wird gedrueckt (steigende Flanke)
6
    {
7
        zustand = 1;
8
        s = 0;
9
        ts = 0;
10
    }
11
    else if (zustand == 1 && !(P2IN & BIT0) )   //Taster wird gehalten
12
    {
13
         zustand = 2;
14
    }
15
    else if (zustand == 2 && (P2IN & BIT0) )   //Taster wird losgelassen (fallende Flanke)
16
    {
17
        zustand = 3;
18
    }
19
    else if (zustand == 3 && (P2IN & BIT0) )   //Taster losgelassen
20
    {
21
        zustand = 0;
22
    }
23
}
24
25
void mintaster(void)
26
{
27
    static unsigned char zustand;
28
 
29
    if(zustand == 0 && !(P2IN & BIT1) )   //Taster wird gedrueckt (steigende Flanke)
30
    {
31
        zustand = 1;
32
        if(min==9)
33
        {
34
          min = 0;
35
          tmin++;
36
        }
37
        else
38
          min++;
39
    }
40
    else if (zustand == 1 && !(P2IN & BIT1) )   //Taster wird gehalten
41
    {
42
         zustand = 2;
43
    }
44
    else if (zustand == 2 && (P2IN & BIT1) )   //Taster wird losgelassen (fallende Flanke)
45
    {
46
        zustand = 3;
47
    }
48
    else if (zustand == 3 && (P2IN & BIT1) )   //Taster losgelassen
49
    {
50
        zustand = 0;
51
    }
52
}
53
54
void htaster(void)
55
{
56
    static unsigned char zustand;
57
 
58
    if(zustand == 0 && !(P2IN & BIT2) )   //Taster wird gedrueckt (steigende Flanke)
59
    {
60
        zustand = 1;
61
        if(h==9)
62
        {
63
          h = 0;
64
          th++;
65
        }
66
        else
67
          h++;
68
    }
69
    else if (zustand == 1 && !(P2IN & BIT2) )   //Taster wird gehalten
70
    {
71
         zustand = 2;
72
    }
73
    else if (zustand == 2 && (P2IN & BIT2) )   //Taster wird losgelassen (fallende Flanke)
74
    {
75
        zustand = 3;
76
    }
77
    else if (zustand == 3 && (P2IN & BIT2) )   //Taster losgelassen
78
    {
79
        zustand = 0;
80
    }
81
}
82
83
...
84
85
void main (void)
86
{  
87
  WDTCTL   = WDTPW + WDTHOLD;       //Watchdog stoppen
88
89
  P1DIR   = 255;           //127d = 1111111b -> 7 aktive Outputs an P1
90
  P1OUT   = 0;            //Voreinstellung: Null, alle Segmente außer g (0tes Bit)
91
92
  P2SEL   &= ~63;          //Funktionsauswahl P2: Input/Output
93
  P2DIR   = 248;          //P2 komplett als Input
94
  P2REN  = 7;
95
    
96
  BCSCTL1 &= ~XTS;        // Low Frequency Mode für den externen Quarzeingang setzen
97
  BCSCTL3 &= ~(LFXT1S0 | LFXT1S1);// 32768 Hz Modus einstellen
98
  BCSCTL3 |= XCAP1;          // 12.5 pF einstellen
99
100
  TACCTL0 = 0;            // zunächst ggf. aktiven Capture/Compare Interrupt für
101
102
  TACCR0   = 32767;               //Obere Zählgrenze für Timer
103
  TACTL  = MC_1|TASSEL_1|TACLR;   //Timer einstellen und starten
104
                            //Bedeutung: MC=Modus, hier 1=Aufwärtszählen
105
                            //TASSEL=Clock source select, hier: 1 = ACLK
106
                            //TACLR=Timer A clear= Zähler zurücksetzen
107
    
108
                            
109
 while(1)              //Immerwährender Zählprozess
110
{
111
  while((TACTL & 1)==0)      //TAIFG (Timer A Interrupt Flag) checken
112
  {
113
    staster();
114
    mintaster();
115
    htaster();
116
    
117
    shows();
118
    showts();
119
    showmin();
120
    showtmin();
121
    showh();
122
    showth();
123
  }                //nach 1s Schleife verlassen
124
    TACTL &= ~1;        //TAIFG nullen
125
    s++;
126
    clockwork();
127
    
128
}
129
130
}

2. Version mit P2IFG:
1
void main (void)
2
{  
3
  WDTCTL   = WDTPW + WDTHOLD;       //Watchdog stoppen
4
5
  P1DIR   = 255;           //127d = 1111111b -> 7 aktive Outputs an P1
6
  P1OUT   = 0;            //Voreinstellung: Null, alle Segmente außer g (0tes Bit)
7
8
  P2SEL   &= ~63;          //Funktionsauswahl P2: Input/Output
9
  P2DIR   = 248;          //P2 komplett als Input
10
  P2REN  = 7;
11
  
12
  P2IE  = 7;
13
  P2IES  = 0;
14
    
15
  BCSCTL1 &= ~XTS;        // Low Frequency Mode für den externen Quarzeingang setzen
16
  BCSCTL3 &= ~(LFXT1S0 | LFXT1S1);// 32768 Hz Modus einstellen
17
  BCSCTL3 |= XCAP1;          // 12.5 pF einstellen
18
19
  TACCTL0 = 0;            // zunächst ggf. aktiven Capture/Compare Interrupt für
20
21
  TACCR0   = 32767;               //Obere Zählgrenze für Timer
22
  TACTL  = MC_1|TASSEL_1|TACLR;   //Timer einstellen und starten
23
                            //Bedeutung: MC=Modus, hier 1=Aufwärtszählen
24
                            //TASSEL=Clock source select, hier: 1 = ACLK
25
                            //TACLR=Timer A clear= Zähler zurücksetzen
26
    
27
                            
28
 while(1)              //Immerwährender Zählprozess
29
{
30
  while((TACTL & 1)==0)      //TAIFG (Timer A Interrupt Flag) checken
31
  {  
32
    if(P2IFG & BIT0)
33
    {
34
      P2IFG &= ~BIT0;
35
      s = 0;
36
      ts = 0;
37
    }
38
    
39
    if(P2IFG & BIT1)
40
    {
41
      P2IFG &= ~BIT1;
42
      min++;
43
    }
44
    
45
    if(P2IFG & BIT2)
46
    {
47
      P2IFG &= ~BIT2;
48
      h++;
49
    }
50
    
51
    shows();
52
    showts();
53
    showmin();
54
    showtmin();
55
    showh();
56
    showth();
57
  }                //nach 1s Schleife verlassen
58
    TACTL &= ~1;        //TAIFG nullen
59
    s++;
60
    clockwork();
61
    
62
}
63
64
}

Die Variablen für die Zeit sind global deklariert.

von Klaus (Gast)


Lesenswert?

PistolPete schrieb:
> static unsigned char zustand;

Du musst deine Variablen zu Beginn auf einen definierten
Wert setzen

z.B.

static unsigned char zustand = {0};

Gruss Klaus

von Jean P. (fubu1000)


Lesenswert?

Klaus schrieb:
> PistolPete schrieb:
>> static unsigned char zustand;
Damit wird die Variable ins Ram gelegt mit "0" initialisierung.

> Du musst deine Variablen zu Beginn auf einen definierten
> Wert setzen
Schwachsinn, bei static.

> z.B.
> static unsigned char zustand = {0};
Doppelt Schwachsinn.

> Gruss Klaus
Hust

von Johann (Gast)


Lesenswert?

Jean Player schrieb:
> Klaus schrieb:
...
> Schwachsinn
...
> Doppelt Schwachsinn.
...
> Hust

Jungejungejunge, Du hast eine Ausdrucksweise! Was Klaus geschrieben hat 
ist zwar falsch, deshalb aber lange noch kein Schwachsinn! Hast Du 
eigentlich Freunde?

von PistolPete (Gast)


Lesenswert?

Es scheint als hätte ich das Problem gelöst.
Mit einem Tiefpass (3,24 k und 470n) und folgendem Code schaltet es nach 
einigen Test zuverlässig und fehlerfrei:
1
if( (P2IFG & BIT0)&&(P2IN & BIT0) )
2
    {
3
      P2IFG &= ~BIT0;
4
      s = 0;
5
      ts = 0;
6
    }
7
    
8
    if( (P2IFG & BIT1)&&(P2IN & BIT1) )
9
    {
10
      P2IFG &= ~BIT1;
11
      min++;
12
    }
13
    
14
    if( (P2IFG & BIT2)&&(P2IN & BIT2) )
15
    {
16
      P2IFG &= ~BIT2;
17
      h++;
18
    }

Meine Theorie: Im Tutorial steht zwar dass eine Hardwareentprellung 
überflüssig ist bei µC, jedoch sind meine Schalter und 
Spannungsversorgung nicht gerade in Premiumqualität ausgeführt, so dass 
es vielleicht doch die beste Lösung ist.

von Karl H. (kbuchegg)


Lesenswert?

PistolPete schrieb:

> Meine Theorie: Im Tutorial steht zwar dass eine Hardwareentprellung
> überflüssig ist bei µC, jedoch sind meine Schalter und
> Spannungsversorgung nicht gerade in Premiumqualität ausgeführt, so dass
> es vielleicht doch die beste Lösung ist.

Die auf der Seite Entprellung aufgeführte "Komfortlösung nach Peter 
Danegger" entprellt auch in solchen Fällen zuverlässig.
Man darf halt nicht immer die scheinbar einfachste Lösung benutzen.
Deine Zustandsmaschinenlösung funktioniert nur dann, wenn die 
Zustandsmaschine nicht zu oft (zu schnell hintereinander) aufgerufen 
wird.
Das Prinzip jeder Software-Entprellung besteht im Grunde darin, in 
gewissen Zeitabständen nachzusehen, ob sich der Zustand stabilisiert 
hat. Mach ich das zu schnell, dann prellt der Taster noch, während ich 
hinsehe. So gesehen ist deine Zustandsmaschine, wenn man sie zu schnell 
auswertet, eigentlich gar keine definierte Entprellung, sondern ein 
Mechanismus, in dem du das Drücken/Loslassen in Flanken verwandelst. Das 
das auch noch (manchmal) entprellt liegt einzig und alleine daran, dass 
zwischen den Aufrufen der Funktion genügend Zeit vergehen muss, damit 
sich das Prellen legt.
So gesehen, ist dieser Code eher in die Kategorie "wenn der Rest des 
Programmes nur langsam genug ist, dann entprellt er auch 
zufälligerweise" einzuordnen. Eine dezidierte und absichtlich gewollte 
Entprellung findet da nicht statt.

von Christian R. (supachris)


Lesenswert?

Ich hab am MSP430 die Taster immer mit einem 20ms Timer abgetastet, 
meist ist der WDT noch übrig.

von Klaus (Gast)


Lesenswert?

Jean Player schrieb:
>> PistolPete schrieb:
>>> static unsigned char zustand;
> Damit wird die Variable ins Ram gelegt mit "0" initialisierung.
...
> Schwachsinn
...
> Doppelt Schwachsinn.
...
> Hust

Abgesehen von Deiner Ausdrucksweise würde  ich mich mal mit den
Segmenten .text .data .bss .stack auseinandersetzen

Variablen stehen immer RAM, ob sie aber in .data .bss oder .stack stehen 
entscheidet der Progammierer

und dass .bss immer mit Nullen vorbelegt wird ist nicht sicher !!!

Wenn Du das
http://www.ureader.de/msg/12242485.aspx
liest
sollte Dir auch die Vorbelegung von "static" Variablen ein Begriff sein 
!!!

Gruss Klaus

von tom (Gast)


Lesenswert?

moins,

khb hat treffend erklärt warum die entprellung des tn nicht gefunzt hat.

klaus, du hast in der sache leider nicht recht und jean ist bezüglich 
höflichkeit etwas daneben... bessert euch jungs, sonst gibt es zu 
weihnachten die rute ;o) !

von Erik (Gast)


Lesenswert?

Hi,
manchmal sind auch die Schalter / Taster total ungeeignet .
die einfachen Taster die auf den Experimentierboards drauf sind
bekomme ich auch nicht 100% entprellt .
gute erfahrung habe ich mit so einer art Microtaster die beim
Betätigen so richtig klick machen .hab ich mal irgenwo ausgelötet .

mfg Erik

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.