Forum: Mikrocontroller und Digitale Elektronik Programmierung - Doppelbelegung einer Taste


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Andy H. (schustermann)


Bewertung
-3 lesenswert
nicht lesenswert
Hi Allerseits,

ich habe mich mal etwas durchgeklickt und nichts passendes zu meiner 
Problemstellung gefunden, daher dieser Thread.

Es ist eine "banale" Aufgabe, allerdings bin ich ein absoluter Anfänger, 
muss jedoch morgen im laufe des Tages folgende Projektarbeit abgeben.
Ich habe mich nun 'ne woche damit beschäftigt und kam einfach nicht aufs 
Ergbnis, ja ich weiß kaum zu glauben, aber wie gesagt Anfänger =/

Der Mikrokontroller (STM32F...) (MK) hat eine Taste und diese soll eine 
Fernbedienung simulieren. Mit dieser Taste soll Start/ Stopp und Pause 
umgesetzt werden.
Um die Funktionalität zu überprüfen will ich zunächst die Funktionen mit 
LEDs zu Testzwecken verbinden.

Ein Funktion habe ich hinbekommen, aber die zweite kriege ich nicht 
korrekt drauf.

Ich bin mir sicher ich habe mindestens 2 Denkfehler, komme aber nicht 
auf die Lösung.

1.) Die Zeitmessung hat so keinen Sinn meiner Ansicht nach (wurde aber 
von meinem Betruer so empfohlen)
Weil sobald i = 1 dann wird ja die blaue LED direkt auf leuchten gesetzt

2.) die Zeitmessung ist ja nocht nicht einmal fertig und es wird schon 
in die set_blaueTaste funktion gegangen, deshalb wird immer die blaue 
LED zum leuchten gebracht.

3.) Es fehlt mindestens ein Befehl, mit diesem ich auch wirklich das 
Drücken des Knofes ermitteln kann

Folgendes habe ich mir gedacht: Fallunterscheidung durch Zeitmessung.

Wenn Knopf maximal 1sekunde lang gedrückt dann Start/ Stopp
wenn Knopf mehr als eine Sekunde gedrückt dann Pause bzw. Fortsetzen

Dazu habe ich folgendes gecoded:

while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 0)

    {
      //Zustand: schalter aus, knopf nicht gedrückt
     // wartet bis Knopf gedürckt
    }

//Knopf wird gedrückt i wird 1

    i++;
    //hier aktuelle uhrzeit Systickcount ausgeben
    tic = HAL_GetTick();
    if (i >= 2)
      {
        i = 0;
      }

 //Hier ist die void Funktion in einer separaten Datei (siehe unten)
    set_blaueTaste(i);


    while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 1)
    {
      // Hier ist der Knopf im gedrückten Zustand
      // bis i seinen wert ändert
    }

      // hier die zweite uhrzeit notieren
      toc = HAL_GetTick();

    // Hier DifferenzMessung der Zeit: Wie viel Zeit ist vergangen bis 
der Knopf gedrückt und los gelassen wurde

     uint32_t a = toc - tic;


Hier gehts weiter mit der obigen Funktion set_blaueTaste

void set_blaueTaste(uint8_t push)
{
// Wenn i == 1 - > Taste gedrückt

if (push == 1){

// Fallunterscheidung wenn Taste länger als 20ms gedrückt, dann LED rot

if((toc-tic) > 20){

HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_6,GPIO_PIN_SET);
//Wenn Taste kürzer als 20 ms gedrückt dann LED blau
}

else if((toc-tic) < 20){
    HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7,GPIO_PIN_SET);
    }
}

// Wenn Taste erneut gedrückt dann schalte LED aus

else if(push == 0){
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_6,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7,GPIO_PIN_RESET);
}

// Zur Sicherheit default, falls was passiert einfach alles ausschalten

else{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_6,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7,GPIO_PIN_RESET);
}


Wäre echt super wenn mir jemand Helfen würde, bin mega verzweifelt und 
komme einfach nicht auf die Lösung.

Schon 'mal im Voraus vielen Dank für eure Hilfe.

LG
Schustermann

von Peter D. (peda)


Bewertung
1 lesenswert
nicht lesenswert
Hier gibt es ne Lösung:

Beitrag "Universelle Tastenabfrage"

von Sascha W. (sascha-w)


Bewertung
0 lesenswert
nicht lesenswert
Hallo Andy,

also Zeit messen ist schon mal richtig, du musst aber die Zeit zwischen 
gedrückt und losgelassen messen.
Also beim Drücken Tick's speichern und beim Loslassen die Differenz 
berechnen.
Dann entscheiden:
<100ms hat wohl nur geprellt -> tu nix
<1s -> kurz gedrückt
sonst >1s -> lang gedrückt

Wenn du die Tastenabfrage jetzt noch nicht blockierend hin bekommst dann 
kannst du auch während die Taste noch gedrückt ist erkennen das sie Lang 
gedrückt wird und schon reagieren bevor der Nutzer die Taste wieder los 
lässt.

Sascha

von Andy H. (schustermann)


Bewertung
-1 lesenswert
nicht lesenswert
Erst einmal danke für eure Antworten.

Danke Sascha!
Ja so stell ich mir das vor aber ich stelle mich - auf gut deutsch 
gesagt - einfach zu blöd an.

Mein Verständnis ist, dass die Zeitmessung direkt mit i=1 anfängt und 
zwar sobald auf den Knopf gedrückt wird, wird i=0 zu i=1

und die Abfrage ist doch mit while(readPin(...)==1){}

dann endet die messsequenz mit toc und trotzdem passt es nicht

Hab ich das falsch interpreitert, Knopfdruckzeit ist mit "readPIN(...)"?
Offensichtlich checke ich nicht wie ich drücken und loslassen coden 
kann, wenn die while(readPin(...)==1) nicht korrekt sein soll

irgedwie passt es auch nicht, denn so lange es (while) =1 ist kann doch 
toc auch nicht gemssen werden? Daher bin ich mir sicher, dass ich ein 
Denkfehler habe -.-

das ist doch zum Mäusemelken


Ich habe mir mal einen anderen Plan ausgedacht der aber auch nicht 
funktioniert hat, stattdessen leuchtet die rote LED

die Funktion set_blaueTaste() habe ich aufgeteilt, damit in der 
if-abfrage die richtige Handlung abgearbeitet werden kann


while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 0)

    {
      //Zustand: schalter aus, knopf nicht gedrückt
      // warten auf Knopfdruck
    }

    i++;

//Zurücksetzen wenn zweimal gedrückt

    if (i >= 2)
      {
        i = 0;
      }

    //hier aktuelle StartUhrzeit Systickcount ausgeben und in tic 
speichern

    tic = HAL_GetTick();

    while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 1)

    {
      //hier Knopf gedrückt
      //bspw. Start und Pause

    } // hier die zweite uhrzeit (EndUhrzeit) ausgeben und in toc 
speichern

 toc = HAL_GetTick();

ZeitDifferenz der End-Startzeit in Variabl a gespeichert

uint32_t a = toc - tic;

// Wenn   Zeitdifferenz kleiner als 1200ms

if(a < 1200)
{
set_blaueTaste(i);
     }

// Wenn Zeitdifferenz größergleich 1200ms

else if (a >= 1200)
{
set_blaueTaste1(i);
     }

else
{
// Für den Fall der Fälle alle LEDs aus

        HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);
        HAL_GPIO_WritePin(GPIOC,GPIO_PIN_6,GPIO_PIN_RESET);
        HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7,GPIO_PIN_RESET);
        HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_RESET);
        HAL_GPIO_WritePin(GPIOC,GPIO_PIN_9,GPIO_PIN_RESET);
     }

void set_blaueTaste(uint8_t push)
{
// Wenn gedrückt i==1

if (push == 1){

HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_6,GPIO_PIN_SET);
}

//Wenn taste wieder gedrückt dann alle LEDs aus

else if(push == 0)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_6,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7,GPIO_PIN_RESET);
}

// Default Notfalls alle LEDs aus

else{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_6,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7,GPIO_PIN_RESET);
}
}

--------


void set_blaueTaste1(uint8_t push)
{
// Wenn gedrückt i==1

if (push == 1){

HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7,GPIO_PIN_SET);
}

//Wenn taste wieder gedrückt dann alle LEDs aus

else if(push == 0)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_6,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7,GPIO_PIN_RESET);
}

// Default Notfalls alle LEDs aus

else{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_6,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7,GPIO_PIN_RESET);
}
}

: Bearbeitet durch User
von Peter D. (peda)


Bewertung
1 lesenswert
nicht lesenswert
Blockierende Programmierung ist generell schwer zu durchschauen und 
fehlerträchtig.
Es hat schon seinen Sinn, warum ich alles im Timerinterrupt mache und 
das Main nur die Ereignisbits abzufragen braucht.

von Andy H. (schustermann)


Bewertung
0 lesenswert
nicht lesenswert
naja, tatsächlich ist es im interrupt-request-handler drin, nicht in der 
main.
Oder habe ich dich missverstanden?

von Peter D. (peda)


Bewertung
1 lesenswert
nicht lesenswert
Andy H. schrieb:
> naja, tatsächlich ist es im interrupt-request-handler drin, nicht in der
> main.

Wie soll jemand in den Schnipselchen durchsehen?
Hängt ein compilierbares C-File an.

von Andy H. (schustermann)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ach, so meinst du das.

Hab dann mal alle relevanten Dateien angefügt.
Wesentlicher code ist in den ersten 4 Dateien drin.
Im Wesentlich ist es schon der gesamte code, mehr ist wirklich nicht 
drin.
Hätte lieber den Ordner hochgeladen, aber ich konnte nur einzelne 
dateien hochladen.

ich denke, dass das hauptproblem an dieser Stelle liegt

//hier aktuelle StartUhrzeit Systickcount ausgeben und in tic
speichern

    tic = HAL_GetTick();

    while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 1)

    {
      //hier Knopf gedrückt
      //bspw. Start und Pause

    } // hier die zweite uhrzeit (EndUhrzeit) ausgeben und in toc
speichern

 toc = HAL_GetTick();

: Bearbeitet durch User
von Peter D. (peda)


Bewertung
1 lesenswert
nicht lesenswert
Andy H. schrieb:
> Hätte lieber den Ordner hochgeladen, aber ich konnte nur einzelne
> dateien hochladen.

Man darf auch ein Zip hochladen.

von nochEinHinweis (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Eine Bitte habe ich: Wenn du Code in deinen Posts hast, setz ihn doch in 
die passenden Tags wie über dem Postingformular beschrieben. Macht das 
Ganze viel lesbarer!
1
//hier aktuelle StartUhrzeit Systickcount ausgeben und in tic speichern
2
3
    tic = HAL_GetTick();
4
5
    while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 1)
6
7
    {
8
      //hier Knopf gedrückt
9
      //bspw. Start und Pause
10
11
    } // hier die zweite uhrzeit (EndUhrzeit) ausgeben und in toc speichern
12
13
 toc = HAL_GetTick();

Beitrag #6596962 wurde von einem Moderator gelöscht.
von Andy H. (schustermann)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
@Peter danke für den Hinweis, den nehme ich doch gerne an.
Anbei die Zip Datei =)

von Peter D. (peda)


Bewertung
1 lesenswert
nicht lesenswert
Puh, das ist ja ein riesen Brocken. Und haufenweise Code, der mit dem 
Problem nicht das geringste tun hat.
Um da durchzusteigen, müßte man erstmal den ganzen überflüssigen Ballast 
rauslöschen. Ansonsten ist das die Stecknadel im Heuhaufen suchen.

Andy H. schrieb:
> //hier aktuelle StartUhrzeit Systickcount ausgeben und in tic
> speichern
>
>     tic = HAL_GetTick();

Wozu soll das gut sein?
Man weiß doch selber ganz genau, wie man den Timerinterrupt 
konfiguruiert hat, d.h. in welchem Zeitintervall er aufgerufen wird.

von Schlaumaier (Gast)


Bewertung
-5 lesenswert
nicht lesenswert
Man was macht ihr ein Aufwand.

Das geht mit 5 Zeilen ;)

in den Falle

public Zeit as integer
public i as integer = 0

sub Taste_gedrückt

  if i = 1 and aktuelle_zeit - Zeit > 200 then ' 200 = Zeitwert der 
gewartet werden soll
   ' Zeitfenster abgelaufen :)
     i = 0
  else
     ' was machen wenn 2 Druck erfolgt
     i = 3
  end if

  if i = 0 then
    i = 1
    zeit = aktuelle_zeit
    ' ausführen was bei Druck 1 passieren soll
  end if

  if i = 3 then i= 0

End sub

Und fertig ist das ganze ;)

Und da ihr kein Basic mögt, muss der TO das nur noch in seine Sprache 
umrechnen ;)

von Andy H. (schustermann)


Bewertung
0 lesenswert
nicht lesenswert
Ne das sieht nur so aus, das sind voreinstellungen vom System.
Alles was ich gemacht habe ist quasi das was ich bereits zu beginn 
geschrieben habe, alles andere kannst du ignorieren.

Mein Code besteht gerade mal aus 20 - 40 Zeilen....
es geht nicht um den interrupt wann er es ausführen soll

sondern viel mehr dass während eines Arbeitsvorganges die zeit gemessen 
werden soll, und das konkret über den Button

wie lange wird auf den button gedrückt, start mit tic (es wird gedrückt)
ende bei toc (es wird los gelassen)
toc - tic = wie lange der Knopf gedrückt wurde

und dann die Fallunterscheidung wenn toc -tic > 100ms dann mache dass
wenn toc - toc <= 100ms dann mach jenes

das Prinzip ist wirklich sehr banal
die umsetzung anscheinend nicht so sehr

von Peter D. (peda)


Bewertung
1 lesenswert
nicht lesenswert
Andy H. schrieb:
> void TIM3_IRQHandler(void)
> ...
>  while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 1)

Ganz böses Foul.
Blockieren im Interrupt macht die Sache nur umso schlimmer.
So wird das nix.

Schau Dir mein Beispiel an. Der Port wir einmal im Interrupt 
eingelesen und dann ein Zähler hochgezählt oder rückgesetzt.

: Bearbeitet durch User
von Andy H. (schustermann)


Bewertung
-1 lesenswert
nicht lesenswert
@Schlaumaier

ja das denke ich auch.
Hab ich das denn nicht so in etwa wie du gemacht?
nur dass ich das separiert habe die if-Abfragen

Naja "Foul" hin oder her,

vielleicht kann mir jemand kommunizieren, wie man es konkret besser 
macht, denn ich bin im moment am Ende mit meinem Latein.

Wäre jedenfalls Super

Danke euch soweit schon mal

von Schlaumaier (Gast)


Bewertung
-3 lesenswert
nicht lesenswert
Andy H. schrieb:
> Hab ich das denn nicht so in etwa wie du gemacht?

Die Frage ist die Aufgabenstellung selbst.

Wie lautet die genau. ???

In meinen Code bedeutet das folgendes.

DRÜCKT der User innerhalb Zeit x (200 bei mir) die selbe Taste noch 1 x 
gilt das als "2. Funktion".

Anders muss der Code aussehen  (und etwas schweren) wenn du feststellen 
willst WIE LANGE der User die Taste drückt.

Beide Formen der Mehrfachbelegung sind Standard. Mein Code z.b. wird für 
die Aufnahme-Funktion meines LG-DVD-Recorder benutzt. 1 x Drücken = 
Aufnahme, innerhalb von 5 Sek nochmal drücken 10 min, nochmal 20 min 
u.s.w.

Bei meinen uralten Pager musste ich die Taste gedrückt halten, nach 
einigen Sekunden schaltete dann sich ein Menü ein, Taste weiter 
festgehalten und das Menü sprang immer weiter .

Ist halt wie gesagt eine Frage was du wirklich willst.

Die Grundlage : Die Zeitabfrage, brauchst du aber immer.

von Andy H. (schustermann)


Bewertung
0 lesenswert
nicht lesenswert
@schlaumaier

ok, das klingt doch schon mal ganz gut, ich würde mal behaupten, dass es 
bei mit sogar einfacher ist oder nicht wesentlich mehr als das was du 
gemacht hast.

ich will einfach mit dem SELBEN Knopf:
Start/Stopp und
Paus
bedienen

also quasi zweimal das Gleiche.

Als Ersatz habe ich zunächst LEDs angebunden, um zu testen dass es geht

Ungefähr so:
i=0;
alles ist aus mit while i == 0

aber wenn gedrückt wird dann i=1
zeitgleich wird die erste Zeit aufgenommen (tic)
Pin wird während des drückens und erst nach drücken des Knopfes auf 1 
gesetzt - also wenn losgelassen wird - danach wird die zweite zeit 
augenommen(toc)

und zum schluss Zeitdifferen = toc-tic
und mit dieser Zeitdifferenz soll die if-Abfrage gebildet werden

wenn 5sekunden gedrückt dann start,

wenn 5-10 sekunden gedrückt dann pause

wirklich sehr simpel

Im Grunde ist es zweimal das Gleiche nur auf jeweils einen anderen 
Zeitbereich unterteilt

aber ich kapier noch nicht was fehlt oder was ich anders machen muss

also konkret:
1
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 0)
2
3
    {
4
      //Zustand: schalter aus, knopf nicht gedrückt
5
      // warten auf Knopfdruck
6
    }
7
8
    i++;
9
10
//Zurücksetzen wenn zweimal gedrückt
11
12
    if (i >= 2)
13
      {
14
        i = 0;
15
      }
16
17
    //hier aktuelle StartUhrzeit Systickcount ausgeben und in tic 
18
speichern
19
20
    tic = HAL_GetTick();
21
22
    while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 1)
23
24
    {
25
      //hier Knopf gedrückt
26
      //bspw. Start und Pause
27
28
    } // hier die zweite uhrzeit (EndUhrzeit) ausgeben und in toc 
29
speichern
30
31
 toc = HAL_GetTick();
32
33
ZeitDifferenz der End-Startzeit in Variabl a gespeichert
34
35
uint32_t a = toc - tic;
36
37
// Wenn   Zeitdifferenz kleiner als 1200ms
38
39
if(a < 1200)
40
{
41
set_blaueTaste(i);
42
     }
43
44
// Wenn Zeitdifferenz größergleich 1200ms
45
46
else if (a >= 1200)
47
{
48
set_blaueTaste1(i);
49
     }
50
51
else
52
{
53
// Für den Fall der Fälle alle LEDs aus
54
55
        HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);
56
        HAL_GPIO_WritePin(GPIOC,GPIO_PIN_6,GPIO_PIN_RESET);
57
        HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7,GPIO_PIN_RESET);
58
        HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_RESET);
59
        HAL_GPIO_WritePin(GPIOC,GPIO_PIN_9,GPIO_PIN_RESET);
60
     }
61
62
void set_blaueTaste(uint8_t push)
63
{
64
// Wenn gedrückt i==1
65
66
if (push == 1){
67
68
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_SET);
69
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_6,GPIO_PIN_SET);
70
}
71
72
//Wenn taste wieder gedrückt dann alle LEDs aus
73
74
else if(push == 0)
75
{
76
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);
77
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_6,GPIO_PIN_RESET);
78
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7,GPIO_PIN_RESET);
79
}
80
81
// Default Notfalls alle LEDs aus
82
83
else{
84
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);
85
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_6,GPIO_PIN_RESET);
86
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7,GPIO_PIN_RESET);
87
}
88
}
89
90
--------
91
92
93
void set_blaueTaste1(uint8_t push)
94
{
95
// Wenn gedrückt i==1
96
97
if (push == 1){
98
99
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_SET);
100
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7,GPIO_PIN_SET);
101
}
102
103
//Wenn taste wieder gedrückt dann alle LEDs aus
104
105
else if(push == 0)
106
{
107
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);
108
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_6,GPIO_PIN_RESET);
109
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7,GPIO_PIN_RESET);
110
}
111
112
// Default Notfalls alle LEDs aus
113
114
else{
115
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);
116
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_6,GPIO_PIN_RESET);
117
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7,GPIO_PIN_RESET);
118
}
119
}

von Schlaumaier (Gast)


Bewertung
-3 lesenswert
nicht lesenswert
Andy H. schrieb:
> ich will einfach mit dem SELBEN Knopf:
> Start/Stopp und
> Paus
> bedienen

Dazu brauchst du meine Routine UND EIN STATUS.

Status hat folgende Zustände.  "Läuft" o. "Läuft nicht".

privat status as string = "läuft nicht"

Sub taste_gedrückt
if Status "läuft nicht" dann
  Status = "läuft"
  ' mach was du willst
else
  if i = 1 and aktuelle_zeit - Zeit > 200 then ' 200 = Zeitwert der
  gewartet werden soll '
    i = 0
    Status = "läuft"  ' gerät läuft weiter
  else
     ' was machen wenn 2 Druck erfolgt
     ' Stop befehl senden
      status = "läuft nicht"
     i = 3
  end if

  if i = 0 then
    i = 1
    zeit = aktuelle_zeit
    ' ausführen was bei Druck 1 passieren soll
    ' laufen lassen
    ' status = "läuft"
  end if

  if i = 3 then i= 0

end sub

So in etwas.

Ist der Status = "läuft nicht" wird beim 1 Druck auf die Taste, der 
Status geändert auf "läuft" und das Gerät gestartet.

Beim nächsten Druck auf die Taste nach einiger Zeit wird das Gerät in 
den Pause Modus versetzt.

Beim 2. Druck auf die Taste innerhalb Zeit X wird das Gerät  vom Pause 
Modus in den Modus gestoppt versetzt und Status ist "läuft nicht"

musst du halt ausknobbeln ;) Aber ohne einen Status als Gobale Variable 
wird das nix.

von Schlaumaier (Gast)


Bewertung
-3 lesenswert
nicht lesenswert
Nachtrag:

Das ist absolut kein Optimierter Code.

In echten Basic würde ich mit Case Arbeiten, aber ich weiß nicht ob das 
System von dir Case kann. If Then Zeug kann jedes Programmiersystem.

von Peter D. (peda)


Bewertung
1 lesenswert
nicht lesenswert
Schlaumaier schrieb:
> Die Grundlage : Die Zeitabfrage, brauchst du aber immer.

Die genaue Zeit muß man nicht wissen.
Einfacher ist es im Timerinterrupt eine Variable zählen zu lassen und 
ist ein bestimmter Wert erreicht, das Bit für Langdruck zu setzen.
Das Main kann dann bequem die beiden Bits für kurz oder lang auswerten.

von Schlaumaier (Gast)


Bewertung
-4 lesenswert
nicht lesenswert
Peter D. schrieb:
> Die genaue Zeit muß man nicht wissen.
> Einfacher ist es im Timerinterrupt eine Variable zählen zu lassen und
> ist ein bestimmter Wert erreicht, das Bit für Langdruck zu setzen.
> Das Main kann dann bequem die beiden Bits für kurz oder lang auswerten.

Dann brauch ich aber ein Timer ;)

Bei mein Arduino würde ich mit Millis arbeiten. Was die Sache einfacher 
macht. Alte_millis merken, und mit neuen Millis vergleichen. Nur ne 
lausige Variable, nix Timer ;)

Bloss ich muss zugeben das ich sein MC nicht kenne, und nicht weiß ob 
der Compiler Millis + Case kann. Wenn der so Spielereien nicht kann gebe 
ich dir Recht. Dann muss man sich mit Timerinterrupt herum schlagen.

von Peter D. (peda)


Bewertung
1 lesenswert
nicht lesenswert
Schlaumaier schrieb:
> Dann brauch ich aber ein Timer ;)

Nö, sondern einen Timerinterrupt, der das Abtastintervall festlegt. Der 
Trick ist, ich zähle nur, wenn die Taste gedrückt ist. Damit vermeide 
ich die tödliche Blockierung.

von Teo (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Andy H. schrieb:
> wenn 5sekunden gedrückt dann start,
>
> wenn 5-10 sekunden gedrückt dann pause
>
> wirklich sehr simpel

Was soll diese zeitliche Staffelung?!
Du hast doch nur zwei Zustände, Start und Stop. Eine "Auswahl" brauchts 
da ja nich...
Bei Zustand "Start", hat die Taste die Funktion nach xSekunden "Stop". 
Bei Zustand "Stop/Pause", hat die Taste die Funktion nach xSekunden 
"Start".

von Andy H. (schustermann)


Bewertung
0 lesenswert
nicht lesenswert
@Peter: also ich habe mir mal dein bsp angesehen, aber ich finde es 
schon sehr unübersichtlich zumindest für einen ungeübten.

Allerdings hapert es eher bei der umsetzung, aber vielleicht fällt mir 
noch was dazu ein.

@Schlaumaier: Es ist ein von STM32
Ich bin mir gar nicht so sicher ob, diese Art von Bibliotheken in diesem 
MK bekannt sind, auch wenn es absoluter c standard ist.
Aber wie gesagt, bin auch absoluter rookie

@Teo: Funktion1: Start/Stopp ist eine Funktion
      Funktion2: Pause
Deshalb ist eine Fallunterscheidung mittels Zeitmessung sinnvoll oder
Durch Zählen nötig, wie Peter es geschrieben hat.

Aber ich verstehe immer noch nicht warum mein code nicht funktioniert, 
also warum das nicht so funktionnieren kann, denn es sieht für mich 
plausibel aus

Ich denke ich werde eine Funktion einfach auslagern auf einen anderen 
Knopf, ist zwar am Ziel vorbei, aber ich werde das nicht mehr so schnell 
hinkriegen.

Mir raucht der Kopf...Danke für eure unterstützung.

Falls jemand doch noch innerhalb meines Codes eine Lösung parat hat, 
würde ich mich freuen, ich bin mir sicher, dass es trivialer ist, als 
gedacht.

VG
Andy

von Manfred (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> Blockierende Programmierung ist generell schwer zu durchschauen und
> fehlerträchtig.

Es kommt auf die Anwendung an, ich würde sie nicht grundsätlich 
verteufeln.

Meine Steuerung eines Heizelementes lässt jede Sekunde die LED blitzen 
(ohne delay) um ihr Leben zu signalisieren und pollt eine Taste. Wenn 
ich den Knopf drücke, blockiere ich und ermittele, ob dieser kurz, eine 
Sekunde oder drei Sekunden gedrückt wurde - da der µC nichts anderes zu 
tun hat, arbeite ich blockierend. Dass während der Taste die LED nicht 
blitzt, wird kein Benutzer beanstanden.

Wenn die Steuerung dann aktiv ist, wird in der Hauptschleife über 
gesetzte Timer die Heizung gepulst und die zwei Tasten werden gepollt. 
Die Starttaste weise ich direkt ab, wenn mein Flag "aktiv" gesetzt ist. 
Die Stop-Taste ist blockierend, wird nach 30ms erneut abgefragt - hat 
gepfurzt oder war wirklich gedrückt, der theoretisch mögliche Zeitverzug 
von 30ms ist für die Gesamtfunktion unkritisch.

Aufpassen muß man erst, wenn es zeitkritisch wird: In meiner Lötstation 
kann ich mir nicht erlauben, mal eben für 3 Sekunden die 
Temperaturreglung zu blockieren, dann ist die Lötspitze tot. Da kann ich 
entweder aufwendig Zeiten zählen oder ganz simpel bei Erkennen einer 
Taste den Heizstrom abschalten.

Ich finde blockierende Abfragen und Pollen von Tasten nicht pauschal 
böse, man muß wissen, was man tut.

von Nick M. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Andy H. schrieb:
> @Schlaumaier: Es ist ein von STM32
> Ich bin mir gar nicht so sicher ob, diese Art von Bibliotheken in diesem
> MK bekannt sind, auch wenn es absoluter c standard ist.

Der Schlaumeier hat sich schon zu Recht so genannt. Der postet Basic um 
schlau auszuschauen, ist in Wirklichkeit aber unschlau.

Das ganze ist wieder mal eine Zustandsmaschine.
Es gibt folgende Zustände:
keineTasteGedrueckt
TasteGedruecktBis1Sekunde
TasteGedrücktUeber1Sekunde

Das ganze wird in eine Schleife gepackt.

Ich schreib das in Pseudocode
1
bool TasteGedrueck() {
2
  // Taste abfragen und true wenn gedrueck zurückgeben.
3
}
4
5
zustand = keineTasteGedrueck
6
zeit = SysTick()
7
8
while true {
9
  if TasteGedrueck()
10
    if (zustand == keineTasteGedrueck)  // Taste wurde soeben gedrückt
11
      zeit = SysTick()
12
13
    if (sysTick() - zeit < 1)
14
      zustand = TasteGedruecktBis1Sekunde
15
    if (sysTick() - zeit > 1)
16
      zustand = TasteGedruecktUeber1Sekunde
17
  else
18
    zustand = keineTasteGedrueck
19
20
  // LED leuchten lassen nach Zustand, kann man aber auch 
21
  // überall da machen, wo sich der Zustand aendert.
22
  if zustand == keineTasteGedrueckt)
23
    LEDAus()
24
  if (zustand == Taste....
25
}

Achtung!
sysTick() liefert wohl keine Sekunden zurück, daher ist die Abfrage ob 
eine Sekunde rum ist, eher sowas:
if (sysTick() - zeit > 10000 ...

von LostInMusic (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wann wird void TIM3_IRQHandler(void) aufgerufen?

von Peter D. (peda)


Bewertung
1 lesenswert
nicht lesenswert
Manfred schrieb:
> Es kommt auf die Anwendung an, ich würde sie nicht grundsätlich
> verteufeln.

Man kann sich natürlich für jede Anwendung immer wieder neu die Mühe 
machen, eine Tastenabfrage mit all ihren Seiteneffekten irgendwie da 
hinein zu verbasteln.
Enorm zeit- und fehlersparender ist es allerdings, einmal eine 
universelle Tastenabfrage zu implementieren, die nicht in die Anwendung 
hinein verwebt werden muß, sondern völlig getrennt ihre Aufgabe 
erledigt.
Die Trennung, die Abfrageroutine liefert Ereignisbits, die Anwendung 
fragt die Ereignisbits ab, macht dann wieder alles sehr übersichtlich. 
Man muß sich nur erstmal auf die Trennung von Aufgaben einlassen und 
nicht alles als großen monolithischen Block ansehen. Teile und herrsche.

: Bearbeitet durch User
von Peter D. (peda)


Bewertung
1 lesenswert
nicht lesenswert
Andy H. schrieb:
> @Peter: also ich habe mir mal dein bsp angesehen, aber ich finde es
> schon sehr unübersichtlich zumindest für einen ungeübten.

Die Routinen sind doch sehr klein und übersichtlich. Jede Teilaufgabe 
hat ihre eigene Routine.
Hier noch eine Erklärung dazu:
https://www.compuphase.com/electronics/debouncing.htm

Andy H. schrieb:
> Allerdings hapert es eher bei der umsetzung, aber vielleicht fällt mir
> noch was dazu ein.

Der Hauptunterschied ist eigentlich nur die Syntax und die 
Initialisierung des Timerinterrupts. Der Rest ist plain C.

von Schlaumaier (Gast)


Bewertung
-3 lesenswert
nicht lesenswert
Nick M. schrieb:
> Das ganze ist wieder mal eine Zustandsmaschine.

> Das ganze wird in eine Schleife gepackt.
>
> Ich schreib das in Pseudocode

Genau das selbe habe ich auch gesagt und getan.

Ergo sind wir beide Schlaumeier. ;)

Ich habe nur kein Bock einen Schüler die Hausaufgaben zu machen. Ich 
gebe Hilfestellung und ein Schubs in die richtige Richtung. Genau das 
selbe was ich bei Lösungen zu einen Problem brauche. Ein Codeschnipsel 
der mir die Richtung anzeigt.

Den Rest sollte er selbst machen.

von Nick M. (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
Schlaumaier schrieb:
> Genau das selbe habe ich auch gesagt und getan.

Dann lies mal deinen unleserrlichen Spaghettisalat.
Das selbsterklärende i kann 1, 2 oder 3 sein. Wenn es 3 ist, dann wird 
es wieder 0. Und der Zustand als String gespeichert. Muss man dazu 
Basic-Programmierer sein?

von Gerald O. (garry)


Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> Manfred schrieb:
>> Es kommt auf die Anwendung an, ich würde sie nicht grundsätlich
>> verteufeln.
>
> Man kann sich natürlich für jede Anwendung immer wieder neu die Mühe
> machen, eine Tastenabfrage mit all ihren Seiteneffekten irgendwie da
> hinein zu verbasteln.
> Enorm zeit- und fehlersparender ist es allerdings, einmal eine
> universelle Tastenabfrage zu implementieren, die nicht in die Anwendung
> hinein verwebt werden muß, sondern völlig getrennt ihre Aufgabe
> erledigt.
> Die Trennung, die Abfrageroutine liefert Ereignisbits, die Anwendung
> fragt die Ereignisbits ab, macht dann wieder alles sehr übersichtlich.
> Man muß sich nur erstmal auf die Trennung von Aufgaben einlassen und
> nicht alles als großen monolithischen Block ansehen. Teile und herrsche.

Kann ich nur unterschreiben.
Und für die Auswertung dann mit state-machines arbeiten und nicht in 
unendlich verschachtelten if- und while-Konstrukten verlieren.

Garry

von Andy H. (schustermann)


Bewertung
0 lesenswert
nicht lesenswert
Jooo moin allerseits!

nun das Problem habe ich gelöst, dank der Hilfestellung meines 
Betreuers, der dann doch noch die Zeit gefunden hat mir zu antworten. 
Dank den ganzen Einschränkungen (ob sinnvoll oder nicht) saufen sie alle 
vor arbeit ab , da alles komplizierter geworden ist, um 'ne "billige" 
info zu vermitteln.

An alle herzlichen Dank für eure Hilfestellung.

ÄÄÄÄND SE OSKA GOS TUUU....
@Nick.M
...und (fast) genau so wirds gemacht.
Das wort fast, weil die boolean Abfrage nicht unbedingt sein musste

Sehr gut wie du es "trocken" beschrieben und auf den Punkt gebracht 
hast:

> "Das ganze ist wieder mal eine Zustandsmaschine."
Ja Absolut.

übrigens war das stichwort "basic" sehr hilfreich und "spaghettisalat"
passend =)

Sicherliche würden die anderen Codes auf funktionieren.

@Schlaumaier
Danke für dein Code, dieser hat zwar seinen gewissen scharm, aber leider 
beherrsche ich basic nicht, vielleicht kommt das noch ;)

@Peter
Zeitunabhängig ist auch ne gute Sache, aber da hapert es mir noch etwas 
an der praxis. Das mit der Zeitmessung schien mir die einfachere 
variante

An alle vielen Dank für eure comments!
Dann habt mal alle einen schicken Tag!

VG
Andy

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.