PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Tastenentprellung +++ Fehlerhaft



frabe
15.04.2020, 13:07
Hallo zusammen.
Einige Schritte weiter, aber noch nicht perfekt - mein universeller "Tastenentpreller ohne delay".
Folgender code klappt manchmal, aber nicht immer.


const int EntprellZeit = 500; // [ms], Entprellzeit (Testhalber 500ms)

void loop() {
AusgSekTakt(); //Sek-Takt ohne delay

//Tastenabfrage
int TasteZustandAlt = 0; // Tastenzustand einmalig initialisieren

int TasteZustandNeu = digitalRead(TasteLiPin); // akt. Zustand der Taste auslesen
if(TasteZustandNeu != TasteZustandAlt) { // wenn Tastenzustand verändert
if(TasteLiEntprell() >= EntprellZeit) { // wenn Taste nach Entprellzeit entprellt
TasteZustandAlt = TasteZustandNeu; // neuen Tastenzustand übernommen

TextBlock("Taste im AKT. Zustand entprellt!");
}
}
}

//Zeitpunkt der ersten Tasten-Zustandsänderung
unsigned long TasteLiEntprell() {
static unsigned long StartZeitEntprell = 0; // [ms] Startzeit
static int TasteZustand = 0; // akt Zustand des Tasters
TZ(1);//Testanzeige

return Entprellen(TasteLiPin, TasteZustand, StartZeitEntprell);
}

//prüft Eingang auf AusgZustand und Zeit [ms]
unsigned long Entprellen(int Pin, int &TasteZustand, unsigned long &StartZeitEntprell) {
if (digitalRead(Pin) != TasteZustand) { // Zustandsänderung des Tasters
TasteZustand = ! TasteZustand; // Zustand invertieren
StartZeitEntprell = millis(); // Startzeit speichern
}
if (TasteZustand == 1) // wenn Taste gedrückt ist
return millis() - StartZeitEntprell; // Zeit zurück geben, seit Taste gedrückt wurde
else
return 0; // 0 zurück geben, wenn Taste nicht gedrückt, oder noch nicht entprellt
}


Fehler:
1. Sobald erstmalig korrekt 500ms-entprellt, zeigt das Prog bei jedem kleinen (<500ms) Tastendruck "Taste im AKT. Zustand entprellt!" an
2. Wenn die Taste länger als >Entprellzeit gedrückt wird, kommt dauernd "Taste im AKT. Zustand entprellt!",
obwohl folgende Zeile nur die Veränderung reagieren sollte.


"if(TasteZustandNeu != TasteZustandAlt)"


Ich bin mir nicht sicher, ob fälschlicher weise eine dauernde Neuinisialisierung mit "0" erfolgt - sollte eigentlich nur beim Ersten mal init.


static unsigned long StartZeitEntprell = 0;
static int TasteZustand = 0;

wkrug
15.04.2020, 15:13
Ich vermute mal, der Fehler liegt darin, das der Entprelltimer bei einem als gültig erkannten Tastendruck nicht zurück gesetzt wird.
Die Initialisierung des Timers gehört üblicherweise nicht in den Loop!
Du drückst eine Taste.
Dein Vergleich Neu Alt merkt das, der Entprelltimer ist auch abgelaufen, also wird der Tastendruck erkannt und übernommen.
Die Taste prellt nun - Es wird eine offene Taste erkannt und da der Timer nicht zurück gesetzt wurde auch akzeptiert.
So kann da ein paar mal hin und her gehen.

Würdest Du bei einem als gültig erkannten Tastendruck den Entprelltimer zurücksetzen würde für die nächste Zeit, bis zum Ablauf des Timers kein weiterer Tastendruck als gültig erkannt.

frabe
15.04.2020, 15:47
Die Initialisierung des Timers gehört üblicherweise nicht in den Loop!

" AusgSekTakt(); " ist ein einfacher Sek-Takt für einen Summer



und da der Timer nicht zurück gesetzt wurde

tuh ich das nicht mit?


StartZeitEntprell = millis();


- - - Aktualisiert - - -

...oder wo steht der Wald, bei all den Bäumen ;-) ...

inka
15.04.2020, 15:55
ich meine, ich stelle mir manchmal auch durchaus sportliche aufgaben (siehe mein outdoor-projekt (https://www.roboternetz.de/community/threads/74136-outdoor-I/page40?p=655521&viewfull=1#post655521)) - aber warum verwendest du nicht die bounce-library?

Holomino
15.04.2020, 16:11
//Tastenabfrage
int TasteZustandAlt = 0; // Tastenzustand einmalig initialisieren

Bei der Zeile stimmt ohne "static" schon der Kommentar nicht.

frabe
15.04.2020, 17:38
Hallo Inka, danke für den Hinweis
Ich würde den Prozess gerne verstehen... wenn ich diese Logik verstehe, bin ich schon mal einen großen Schritt weiter...
.. und nach Möglichkeit keine zusätzliche Lib einfügen; #include "OneButton.h" ... und mehrer Tastereingänge unabhängig abfragen

(vielleicht befinde ich mich auch auf dem Holzweg ;-)




Bei der Zeile stimmt ohne "static" schon der Kommentar nicht.

Hallo Holomio.
"static" innerhalb des loop?
Ist doch eine einmalige Initialisierung - oder was meinst du?

HaWe
15.04.2020, 20:10
die loop() ist eine "verkappte" while() / for( ;; ) -Schleife in einer unsichtbaren main() Funktion, in der eine Funktion loop() wiederholt aufgerufen wird - wenn hier Variablen nicht static sind, werden alle Variablenwerte beim erneuten loop()-Durchlauf vergessen.



void setup() { }

void loop() { }


int main() {
setup();
for( ;; ) {
loop();
}

}

frabe
15.04.2020, 21:01
ahaaa! Danke!
Dachte loop() = main()

Mit
static int TasteZustandAlt = 0;
funktioniert es überhaupt nicht.

HaWe
15.04.2020, 21:06
dann liegt der Fehler evtl woanders.
Aber deklariere es mal testweise global:
static int TasteZustandAlt = 0;

frabe
15.04.2020, 23:26
Klappt leider auch nicht.
Bleibt dann in einer Dauerschleife mit der Serial.print-Ausgabe: TZ(1); im us-Takt hängen.

Moppi
16.04.2020, 13:35
Ich habe mal ein paar Sekunden den Code angeschaut, deshalb hier zunächst eine Anmerkung, diesen "Tastenzustand einmalig initialisieren" machst Du in loop(), das ist dann nicht einmalig. "int TasteZustandAlt;" außerhalb von setup() und loop(), also global deklarieren. Dann in setup() "int TasteZustandAlt = 0", dann ist es einmalig. Ich fürchte der ganze Code ist nicht so recht durchdacht. Programmablaufpläne können Abhilfe schaffen, zunächst aufzuzeigen, was man tun will. In dem Vorgang der PAP-Erstellung geht man den gesamten Programmablauf theroretisch durch und anhand des PAP kann man sehen, ob das dann alles funktioniert. Es sind dort auch schon Logikfehler zu erkennen. Nachher setzt man den PAP in Progroammcode um.


MfG

HaWe
16.04.2020, 13:52
wenn man
static int TasteZustandAlt = 0;
als lokale Variable in loop() (oder in irgendeiner beliebigen anderen wiederholt aufgerufenen Funktion) im Funktionskopf definiert und initialisiert, wird es nur 1x einmalig bei der ersten Loop-Runde initialisiert, danach nicht mehr: ab dann behält der Wert bei jeder neuen Runde den letzten Wert der vorherigen Runde.

In diesem Falle funktioniert es aber ja auch nicht mit einer globalen Deklaration, daher liegt der Fehler woanders im Code.

Moppi
16.04.2020, 15:53
Das hat mit "static" erst mal nichts zu tun.
Das Problem mit dieser Variablen offenbart einen generellen Denkfehler - Logikfehler, in der Struktur des Programms.
Delay() hat seine Berechtigung. Wenn ich das weglassen will, geht das, aber dann muss der Programmcode in Teilstücke zerlegt werden, die einzeln abzuhandeln sind. Um die richtige Reihenfolge der Abarbeitung muss ich mich dann selber kümmern. Im Grunde ist am einfachsten, so etwas dann in Methoden und ein Objekt auszulagern, dann wird im Hauptprogramm nur eine Methode aufgerufen. Der Code ohne delay() ist dann im Objekt gekapselt. Damit macht sich vieles einfacher. Das einfach so in loop() und setup() unterzubringen ist später schlecht verwertbar.
Komplizierte Dinge werden einfacher, wenn man einen Plan hat. Der wird leider seltenst gemacht.


MfG

HaWe
16.04.2020, 16:37
Das hat mit "static" erst mal nichts zu tun.
Das Problem mit dieser Variablen offenbart einen generellen Denkfehler - Logikfehler, in der Struktur des Programms.
Delay() hat seine Berechtigung. Wenn ich das weglassen will, geht das, aber dann muss der Programmcode in Teilstücke zerlegt werden, die einzeln abzuhandeln sind. Um die richtige Reihenfolge der Abarbeitung muss ich mich dann selber kümmern. Im Grunde ist am einfachsten, so etwas dann in Methoden und ein Objekt auszulagern, dann wird im Hauptprogramm nur eine Methode aufgerufen. Der Code ohne delay() ist dann im Objekt gekapselt. Damit macht sich vieles einfacher. Das einfach so in loop() und setup() unterzubringen ist später schlecht verwertbar.
Komplizierte Dinge werden einfacher, wenn man einen Plan hat. Der wird leider seltenst gemacht.


MfG

selbstversändlich hat der Variablenwert von TasteZustandAlt in loop() was mit "static" zu tun, das macht genau den Unterschied aus, ob bei wiederholtem Aufruf der Variablenwert neu initialisiert wird oder den vorigen Wert erhält und damit weitergerechnet wird.
Lässt man also das "static" in loop() bei der Variablendefinition von TasteZustandAlt weg, wird sie niemals ihren Wert im nächsten loop()-Durchlauf behalten, mit "static" jedoch sehr wohl, und sie wird dann auch nicht immer wieder neu mit 0 initialisiert: dazu muss man sie auch nicht global definieren.
Der Fehler hier im Programm hat aber wie gesagt sicher nicht ausschließlich damit zu tun.

frabe
17.04.2020, 12:35
Erst einmal möchte ich euch für eure Gedanken danken!

Da es sich scheinbar nicht um einen einfachen Logik/Flüchtigkeitsfehler handeln, wird es DER falsche Weg zu sein.
Mal wieder wollte ich duzende von Fliegen mit einer Funktion erschlagen - Tastenentprellung+Tasetendruck-Zeitmessung+beliebig viele Eingänge, etc.
Daher werde ich eine andere Linie verfolgen - einfacher, leicht nachvollziehbar. Ich melde mich später sobald ich einen akzeptableren Ansatz habe.

Moppi
17.04.2020, 13:40
Vielleicht fängst Du einfach an. Als Beispiel habe ich gestern schnell was zusammengebastelt. Ohne großen Plan, lang ist das Programm nicht. Ob es funktioniert habe ich nicht probiert, müsste aber.
Zumindest wird der Ansatz klar. Ausbauen kann man das im Nachhinein immer. Aber alles Stück um Stück, eins nach dem andern. Dann wird es mit der Fehlersuche einfacher.



//öffentliche Variablen
const int Pin = 9;
const int pDelay = 250;
int ButState;


//funktionsinterne Variablen
int pState = -1;
unsigned long pMillis = millis();


void setup(){
}
void loop(){
checkButton();
}
void checkButton(){
if (pMillis <= millis()) {
ButState = pState;
pInit();
}else if (digitalRead(Pin) != pState) pInit();
}
void pInit(){
pMillis = millis() + pDelay;
pState = digitalRead(Pin);
}




Der Code enthält loop() und setup(), damit das mit der Arduino IDE einfach kompiliert werden kann. Den Code würde ich auch in ein Objekt in Methoden packen, dann kann man den später als LIB einfügen. Das macht das dann für zukünftige Projekte einfacher.


MfG

frabe
17.04.2020, 18:20
Jou, meine Lösung sieht folgend aus - DAS verstehe ich auch... ;-)



void loop() {
AusgSekTakt(); // Sek.Takt-Anzeige

static unsigned long TasteGedrueckt = 0;
static int TasteLiZustand = 0;

if(Entprell(TasteLiPin) == 1) {
if(TasteLiZustand == 0) {
TasteLiZustand = 1;
TasteGedrueckt = millis();
}
TZ3("Taste gedrueckt+entprellt seit ", millis() - TasteGedrueckt, " ms");
}
else TasteLiZustand = 0;
}

//Tastenentprellung
int Entprell(int pin){
static int TastenStatusNeu = 0;
static int TastenStatusAlt = 0;
static unsigned long TastStartZeit = 0;

TastenStatusNeu = digitalRead(pin);
if(TastenStatusNeu != TastenStatusAlt) {
TastenStatusAlt = TastenStatusNeu;
if(TastenStatusNeu == 1) {
TastStartZeit = millis();
}
}
if((millis() >= TastStartZeit + EntprellZeit) && TastenStatusNeu == 1)
return 1;
else
return 0;
}

Frage:
1. Hat es irgend welche Vor/Nachteile, ob "TasteGedrueckt", "TasteLiZustand " als static- oder global-Variable deklariert werden? Ohne static funktioniert der loop nicht.
2. Seht ihr irgend wo einen Fehler oder code-Unsauberkeiten?


Meine nächsten Baustellen;
Schritt 01: Rückgabe von 5 Zustands-Peaks; 0=LOW, 1= HIGH, 2=Flanke steigend, 3=Flanke fallend, 5=unbekannt
Schritt 02: Beliebig viele Tasten/Schalteingänge, teils zeitgleich innerhalb von [ms], entprellen.

Moppi
17.04.2020, 18:40
Mal ne ganz ... Frage: warum steht "AusgSekTakt();" zusammen mit Variablendefinitionen UND dem eigentlichen Code alles in loop()?
Diesen Code kannst Du nie so in ein anderes Programm exportieren später - Probleme vorprogrammiert.
Es gibt so was wie einen Programmierstil. Ordnung ist hier die halbe Zeit, der Fehlersuche.



MfG

HaWe
17.04.2020, 19:51
natürlich funktioniert es lokal definiert nicht ohne static, das hatten wir doch schon ausgiebig besprochen!
Globale Variablen aber sind quasi automatisch static, bzw. hier stellt sich das Problem nicht, denn static hat für globale Variaben eine andere Bedeutung (betr. den file scope, was hier nicht stört, wenn es auch global als static definiert würde).
Man könnte auch sagen, lokale static Variablen sind globale Variablen mit einem auf eine spezielle Funktion lokal eingeschränkten scope.

PS,
da ja Arduino C++ nutzt und nicht ANSI C:
hier gibt es zusätzlich "static" auch für class-Attribute

frabe
17.04.2020, 20:03
Mal ne ganz ... Frage: warum steht "AusgSekTakt();" zusammen mit Variablendefinitionen UND dem eigentlichen Code alles in loop()?


Hallo.
AusgSekTakt() ... ist eine Funktion, die sekündlich tickt+leuchtet und eine Sekundenanzeige im Seriellen Monitor anzeigt - ursprünglich mal als Test-bimbam.
die static Var. im loop() sind zur schnelleren Übersicht (da wo sie gebraucht werden), als in glob.Var.-Bereich ganz oben im Haeder.
Stilbruch?
Wie gehts besser?

Moppi
18.04.2020, 13:08
Ich denke mal, wissen tu ich es ja nicht, dass Du diese Geschichte später woanders einsetzen willst, sprich, das muss alles ausgelagert werden, dass es später eingebunden werden kann. Da fängt man wohl mit einem Programmgerüst dafür an, würde ich jetzt so machen. Ich mache ein Beispiel. Dauert etwas ...

Programmierst Du auch mit Arduino IDE ?

MfG

- - - Aktualisiert - - -

Es gibt bei Klassen Methoden und Varibalen, die nach außen nutzbar sein sollen und damit "sichtbar" sind, also aufgerufen werden können und es gibt das Gegenteil, Methoden und Variablen, die nur innerhalb der Klasse verwendet werden und damit "privat" sind, also nicht nach außen sichtbar.

Folgende Dateien könnten im Verzeichnis "libraries" im Arduino-Ordner gespeichert werden (dann dort Verzeichnis "MeinCode" und darin beide Dateien, *.h und *.cpp), damit sie in anderem Arduino-Code eingebunden werden können.


Beispiel für "MeinCode.h"



#ifndef MeinCode_h


#define MeinCode_h
#include <Arduino.h>


class MeinCode //Klasse "MeinCode"
{
//Alle öffentlichen Variablen und Methoden hier bekanntgeben
public:
byte val1, val2; //Variablen
MeinCode(unsigned long bps); //Methode "MeinCode" - Hauptkonstruktor ... wird beim Instanziieren automatisch mit der Klasse aufgerufen
boolean SendRequest(void); //Methode von "MeinCode"

//alle nicht öffentlichen Variablen und Methoden hier bekanntgeben
private:
void ClearRBuffer(void); //Methode
boolean get2Chars(void); //Methode
int a; //Variable
unsigned long lastMillis; //Variable
byte tv1, tv2; //Variablen
};


#endif



Beispiel für "MeinCode.cpp"



#include <Arduino.h>
#include <MeinCode.h>

//-----------------------------------------------------
//Hauptkonstruktor
//-----------------------------------------------------
MeinCode::MeinCode(unsigned long bps)

{
.....
}
//-----------------------------------------------------
boolean MeinCode::SendRequest(void)
{
ClearRBuffer();
....
return ...;
}
//-----------------------------------------------------
void MeinCode::ClearRBuffer(void)
{
....
}
//-----------------------------------------------------
boolean MeinCode::get2Chars(void)
{
....
return ....;
}


Eingebunden und verwendet wird das später, dann z.B. so.



#include <MeinCode.h>


MeinCode meineInstanz(); //Hauptkonstruktor aufrufen, Instanz erzeugen (initialisieren von irgendwas im Code der Klasse "MeinCode")


void setup() {


}


void loop() {


//Methoden (Funktionen) der Klasse "MeinCode" können über meine Instanz angesprochen werden
if(meineInstanz.SendRequest()){
. ...
}

//Variablen können wie Methoden meiner Instanz angesprochen werden
Serial.print(meineInstanz.val1);


}



Für mehr Informationen siehe hier z.B. (da gibts noch zahlreiche andere Links im Netz) http://www.mintgruen.tu-berlin.de/robotikWiki/doku.php?id=techniken:objektorient



MfG

frabe
21.04.2020, 09:45
GM Moppi.
Vielen Dank für deine Ausführungen!

Tatsächlich beschäftige ich mir hier erst einmal mit Grundlagen, wie Kontaktentprellungen, Mittelwerte, Analogein-/ausgänge, etc.
Diese werde ich dann in universelle und "griffige" Funktionen stecken, um sie dann später in diversen Programmen nach belieben zu verwenden.
Hierbei hatte ich daran gedacht, die Funktionen irgend wie in eine Bibliothek zu fassen um via Copy/Paste die Funktionen einzubinden.
Die von dir beschriebene Methode klingt da irgendwie "flexibler" und professioneller...
Aber erst wenn die Funktionen super stabil laufen - dauert bei mir also noch etwas.

Ja, ich programmiere den Teensy 3.2 über Arduino 1.8.5/Teensyduino 1.47.

Moppi
21.04.2020, 13:26
Ich verstehe Deine Einwände und kann das nachvollziehen. Kann Dir aber aus Erfahrung sagen, dass das nachträgliche Umstricken von Code, in eine andere Form u.U. nicht ganz trivial ist. Ich habe Deinen Code gesehen und Dir einen Vorschlag unterbreitet, der eigentlich eine super Sache ist. Weil Du brauchst irgendein Programmgerüst - setup() + loop() ist keines in dem Sinn. Du musst den Code in eine gescheite Form bringen, damit der gut wartbar ist und weiterzuverwenden. Und damit man gut durchblickt. War eigentlich nur als Abkürzung für Dich gedacht. Aber Du kannst das machen, wie Du möchtest. Erfahrung muss man selber sammeln. Kann Dir nur einen Rat noch mit auf den Weg geben: wenn Du den Code aufbaust, probiere ihn aus, immer und immer wieder, ob er funktioniert. So erkennst Du frühzeitig, wenn etwas nicht funktioniert und kannst stark einkreisen, in welchem Programmabschnitt sich ein Problem befindet. Übung macht hier den Meister, im wahrsten Sinn des Wortes. Zahlreiche Verstrickungen, um Ecken (Variablen in einer Funktion definieren, dann aber als statisch, um am Ende dann über Zeiger/Verweise die Variable an weitere Funktionen zu übergeben, usw.) macht es nicht gerade einfacher einen Fehler zu finden, auch wenn der Code nicht so groß ist. Deswegen bin ich auch kein großer Anhänger von Kompilerdirektiven.

Freundlichen Gruß

frabe
21.04.2020, 15:12
...Kompilerdirektiven

Habe ich die benutzt?

Du hast vollkommen Recht - werde ich auch machen, brauche aber noch allgemeingültige/universelle Vereinbarungen für mich selber.
Z.B. bin ich mir nicht sicher, ob die Entprellzeit im den Globalvariablen-Bereich

const int EntprellZeit = 30; // [ms], Entprellzeit (typ.Prellzeit 0,1-30ms)
oder besser (kontrollierter, leserlicher) in der Funktion Entprell() aufgehoben ist

static int EntprellZeit = 30; // [ms], Entprellzeit (typ.Prellzeit 0,1-30ms)

Mit meinem derzeitigen code bin ich schon sehr zufrieden - gibt 3 Zustände zurück - 0..LOW, 1...HIGH, 2...in Entprellung


//==========MAIN==========//
void loop() {
static int AusgImpuls = 0; // Ausg-AusgImpuls [ms]
AusgTakt(AusgImpuls, 1000); // Taktdauer [ms], Intervall [ms]

static int TasteLiZustand = 0; // akt. Zustand 0/1 der Taste

if(Entprell(TasteLiPin) == 1) { // sobald Taste HIGH und entprellt
AusgImpuls = 900; // Ausg-AusgImpuls bei Taste HIGH
TasteLiZustand = 1; // speichert das Taste "1" ist
}
else if(Entprell(TasteLiPin) == 0) { // sobald Taste LOW und entprellt
AusgImpuls = 10; // Ausg-AusgImpuls bei Taste LOW
TasteLiZustand = 0; // speichert das Taste LOW ist
}
else
TZ("Medlung: Kontakt derzeit in Entprellung");
}

//----------STANDARD-FUNKTIONEN----------//
//Kontaktentprellung durchführen, Zustand zurück geben
//Rückgabe 3 Zustände; "0"...LOW+Kontakt entprellt / "1"...HIGH+Kontakt entprellt / "2"...Zustand unbekannt, in Entprellung
int Entprell(int Pin) {
static int KontaktStatusNeu = 0; // akt.Zustand
static int KontaktStatusAlt = 0; // vorheriger Zustand
static unsigned long KontaktStartZeit = 0; // Startzeit der ersten Kontaktzustandsänderung

KontaktStatusNeu = digitalRead(Pin); // speichert akt. Kontaktzustand
if(KontaktStatusNeu != KontaktStatusAlt) { // wenn sich Kontaktzustand ändert
KontaktStartZeit = millis(); // speichert aktualisierte Startzeit
KontaktStatusAlt = KontaktStatusNeu; // geänderter Zustand gespeichert
}
if(KontaktStatusNeu == 0 && (millis() >= KontaktStartZeit + EntprellZeit)) // wenn Entprellzeit überschritten und Kontakt LOW
return 0; // "0" zuück, Kontakt LOW und entprellt
else
if(KontaktStatusNeu == 1 && (millis() >= KontaktStartZeit + EntprellZeit)) // wenn Entprellzeit überschritten und Kontakt HIGH
return 1; // "1" zurück, Kontakt HIGH und entprellt
else
return 2; // "2" zurück, noch nicht entpellt, Kontaktzustand unbekannt
}


Fehlt nur noch, dass mehrer Taster/Kontakt gleichzeitig entprellt werden können.
Danach werde ich die Zustands- und Entprellgeschichte in eine Bibliothek (*.h, *.cpp) einrichten.

- - - Aktualisiert - - -

...ETWAS SPÄTER:

Habe derzeit das Problem, dass innerhalb einer Entprellphase, keine andere Entprellung erfolge kann.
Solang eine Entprellung läuft, werden alle anderen Kontakte/Tasten "verschluckt".
Ursache ist, dass die Funktion Entprellung() eine Startzeit speichert und diese berechnet.

Können diese 30ms-Überlappungen in der Praxis vernachlässigt werden?
Oder sollte/muss ich für jede Taste/Kontakt eine eigene Funktion vorhalten, in der die Entprell-Startzeit gespeichert wird?

HaWe
21.04.2020, 16:12
du kannst, wie schon mal vorgeschlagen wurde, entweder einen C-Strukturtyp mit allen wesentlichen Variablen anlegen und dann für jeden Taster davon einen "Variablen-Ableger" erstellen oder eine C++ Klasse erstellen mit allen Variablen und Methoden, und davon für jeden Taster eine eigene Objekt-Instanz erstellen.
Wenn du das selber schaffst, wirst du sicher viel lernen.
Der einfachere Weg geht ntl über fertige Libs, denn du bist ntl nicht der erste, der sich darüber Gedanken macht - auch das wurde ja bereits vorgeschlagen.

frabe
24.04.2020, 11:09
GM!
Kontaktentprellung klappt, auch mit mehereren Kontakten unabhängig.
Nun versuche ich universelle Blocks aufzubauen - Bibliothekaufbau kommt zum Schluss.

Bei static Variablen bin ich mir der Namesgebung unschlüssig.
Kann es ein Problem geben, wenn ich die gleichen Var.Namen in unterschiedlichen Funktionsblöcken vergebe?
Bsp: (beide Var "KontakPin" haben nichts miteiander zu tun)


int Funktion1() {
static int KontaktPin;
...sonst was...
}

int Funktion2() {
static int KontaktPin;
...sonst was...
}

HaWe
24.04.2020, 11:52
hallo,
nein, in unterschiedlichen Funktionen dürfen die lokalen static Variablen heißen wie sie wollen, auch identisch, genauso als wären sie nicht static.

frabe
24.04.2020, 12:15
Passt!
Beliebig viele Tasten/Kontakte verwendbar, nacheiender oder ~gleichzeitig~.
Pro Taste/Kontakt wird ledigtlich der "Zwischenspeicher" TasteMi, TasteLi kopiert und umbennat.
Entpreller() setzt die Entprellzeit (Bsp.5ms) aus Sicherheitsgründen hinter die letzte Zustandsänderung.



void loop() {
switch(TasteLi(TasteLiPin)) {
case 0: Ausgang(LEDrtPin, 0); TZ("T/LINKS auf -0- entprellt!"); break;
case 1: Ausgang(LEDrtPin, 1); TZ("T/LINKS auf -1- entprellt!"); break;
case 2: TZ("Meldung: T/LINKS IN Entprellung"); break;
}

switch (TasteMi(TasteMiPin)) {
case 0: Ausgang(LEDgePin, 0); TZ("T/MITTE auf -0- entprellt!"); break;
case 1: Ausgang(LEDgePin, 1); TZ("T/MITTE auf -1- entprellt!"); break;
case 2: TZ("Meldung: T/MITTE IN Entprellung"); break;
}
}

//Kontakt Zustandsänderung, nur FunktionsName ändern, Rest ist Universell
int TasteLi(int KontPin) { //Prüfung; gibt 4 Zustand zurück; 0...Entprellt+LOW, 1...Entprellt+HIGH, 2...IN Entprellung, 3...keine Zustandsänderung
static unsigned long StartZeit = 0;
static int KontZustAlt = digitalRead(KontPin);
static int EntprellStatus = digitalRead(KontPin);
return Entpreller(KontPin, StartZeit, KontZustAlt, EntprellStatus);
}

//Kontakt Zustandsänderung, nur FunktionsName ändern, Rest ist Universell
int TasteMi(int KontPin) { //Prüfung; gibt 4 Zustand zurück; 0...Entprellt+LOW, 1...Entprellt+HIGH, 2...IN Entprellung, 3...keine Zustandsänderung
static unsigned long StartZeit = 0;
static int KontZustAlt = digitalRead(KontPin);
static int EntprellStatus = digitalRead(KontPin);
return Entpreller(KontPin, StartZeit, KontZustAlt, EntprellStatus);
}

//Kontakt-Entprellung; gibt 4 Zustände zurück; 0...Entprellt+LOW, 1...Entprellt+HIGH, 2...derzeit in Entprellung, 3...keine Zustandsänderung
int Entpreller(int KontPin, unsigned long &StartZeit, int &KontZustAlt, int &EntprellStatus) {
int KontZustNeu = 0;
if((KontZustNeu = digitalRead(KontPin)) == EntprellStatus) {
return 3;
}
if(KontZustNeu != KontZustAlt) {
StartZeit = millis();
KontZustAlt = KontZustNeu;
}
if(KontZustAlt == 0 && (millis() >= StartZeit + EntprellZeit))
EntprellStatus = 0;
else if(KontZustAlt == 1 && (millis() >= StartZeit + EntprellZeit))
EntprellStatus = 1;
else
EntprellStatus = 2;

return EntprellStatus;
}


PS:
Was haltet ihr von dem code?
Wie kann ich das ganze jetzt in eine Bib. packen?
Vermutlich kann nur Entpreller() ausgelagert werden - oder?