Hallo,
ich möchte gerne eine generische Methode schreiben, in der ich mehrere
Schalter Entstelle. Hierzu nutze ich ein Struct indem ich meine Schalter
definiere. Das ganze funktioniert auch teilweise. Ich kann mein Struct
der Methode übergeben. Allerdings funktioniert es komischerweise nicht
mit dem letzten "stateLast".
Nutze ich "buttons[2].stateLast" (so wie es aktuell in dem Code Steht)
funktioniert es. Nutze ich "button.stateLast", funktioniert es leider
nicht.
Weiss jemand woran es liegt? Alle anderen buttons[2] habe ich bereits
durch die, für die Methode, Lokale "button" variable ersetzt.
Grüße
Karl
Wenn du Check(buttons[2]) aufrufst, dann wird die Funktion Check()
aufgerufen und ihr wird eine Kopie von buttons[2] übergeben,
Wenn du in der Funktion dann zum Schluß button.stateLast=reading
ausführst, wird .stateLast in der Kopie gesetzt, aber nicht im Original
buttons[2].
Mit Ende von Check() verschwindet die Kopie und mit ihr der in
.stateLast gesetzte Wert. Der im Original buttons[2].stateLast gesetzte
Wert hat sich nicht geändert.
Beim nächsten Aufruf wird wieder eine Kopie angelegt, und die bekommt
vom letzten button.stateLast nichts mit, das war ja nur in der ersten
Kopie.
Was du wahrscheinlich willst, ist auf dem Original .stateLast zu setzen,
damit es beim nächsten Aufruf von Check() noch da ist.
Check() soll also nicht eine Kopie bekommen, sondern auf dem Original
arbeiten, damit sich .stateLast des Aufrufers ändert.
Damit eine Funktion etwas vom Aufrufer übergebenes ändern kann, gibt es
in C Zeiger: man übergibt nicht eine Kopie, sondern einen Zeiger auf das
Original.
Also statt:
1
digitalWrite(LED_BUILTIN,Check(buttons[2]));
muß man schreiben:
1
digitalWrite(LED_BUILTIN,&Check(buttons[2]));
Dazu muß die Funktion natürlich etwas anders deklariert sein; sie
bekommt ja jetzt nicht mehr ein struct button_t übergeben, sondern die
Adresse eines struct button_t (oder einen Zeiger auf ein struct
button_t).
Statt
1
boolCheck(structbutton_tbutton)
2
{
3
...
heißt es jetzt:
1
boolCheck(structbutton_t*pButton)
2
{
3
...
Zudem muß man in der Funktion jetzt jeden Zugriff der Art:
1
...button.irgendwas...
ersetzen durch:
1
...(*pButton).irgendwas...
oder (vollkommen gleichwertig, nur schöner zu lesen):
1
...pButton->irgendwas...
Insbesondere heißt es dann zum Schluß:
1
...
2
pButton->stateLast=reading;
3
returnreturnval;
4
---
Damit wird dann wirklich .stateLast im buttons[2] des Aufrufers
geändert, und wird beim nächsten Aufruf von Check() wieder wirksam.
HTH
Ich würde die Funktion deutlich praxisgerechter implementieren. Ich
würde daher das Entprellen in einem konstanten Intervall
(Timerinterrupt) machen. Das hat den Vorteil, daß man Ereignisse
auswerten kann, auch wenn die Taste schon wieder losgelassen wurde. Auch
kann man dann lange Drücke oder Repeat auswerten.
Die Mainloop will in der Regel auch nicht den Zustand wissen, sondern
die Flanke (Taste wurde gedrückt) behandeln.
Karl-Heinz schrieb:> Anstatt digitalWrite(LED_BUILTIN, &Check(buttons[2]));>> Müsste es digitalWrite(LED_BUILTIN, Check(&buttons[2]));>> sein, oder? :)
Ja, war bei mir falsch.
(Wollte natürlich nur testen, ob jemand mitdenkt ... :-)
EAF schrieb:> Das ist C++ also besser keine Zeiger, sondern Referenzen.
Stimmt, in C++ nimmt man dann natürlich Referenzen.
Nur zum Verständnis: das ist aber dann nur eine andere und einfachere
Schreibweise für die gezeigte Version mit den Zeigern. Intern wird für
eine Referenzvariable ja auch nur ein Zeiger übergeben, und das * vor
dem Zugriff automatisch generiert.
Hallo Karl-Heinz,
du musst dein struct zu einer Klasse (class) machen und alle benötigten
Funktionen (Methoden) müssen in die Klasse. struct nimmt man mehr zum
Daten zusammenfassen. Kannst aber auch erstmal bei struct bleiben, dann
ist alles public und räumst hinterher auf. Ich finde es nur einfacher
wenn man sich vorher Gedanken macht was public und was privat sein soll.
Denn das aufräumen kann hinterher auch lästig werden. Am Ende kann man
dann wirklich ein Array aus Taster Instanzen erstellen und mittels for
Schleife iterieren.
Also, du schreibst dir eine Klasse mit Konstruktor und denkst dabei nur
an einen einzigen Taster. Das ist der Bauplan für deine Taster Instanz.
Das alles wäre C++ OOP.
Veit D. schrieb:> du musst dein struct zu einer Klasse (class) machen
Der Unterschied zwischen struct und class ist in C++ lediglich, ob die
Elemente public oder private sind, bevor man es explizit hinschreibt.
Und es ändert nichts daran, daß man ein Objekt davon als Referenz oder
per Zeiger übergeben muß, wenn man in einer Funktion etwas daran ändern
will.
Klaus W. schrieb:> Veit D. schrieb:>> du musst dein struct zu einer Klasse (class) machen>> Der Unterschied zwischen struct und class ist in C++ lediglich, ob die> Elemente public oder private sind, bevor man es explizit hinschreibt.
Das weiß ich. Nur gibt es eine ungeschriebene Regel wofür man struct und
class verwendet. Das hatte ich erwähnt.
> Und es ändert nichts daran, daß man ein Objekt davon als Referenz oder> per Zeiger übergeben muß, wenn man in einer Funktion etwas daran ändern> will.
Das ist aber alles halbgares Zeug wenn die Methoden außerhalb der Klasse
liegen usw. Bis zur richtigen gekapselten Lib ist es nicht weit. Wenn
der TO Arduino hat kann er C++ programmieren.
Hallo,
vergiss nicht, jeder hat einmal angefangen, auch du. Wenn der TO etwas
lernen möchte greift er das auf. Wenn er das Arduino Ökosystem einfach
nur nutzen möchte nimmt er die Bounce2 Lib.