Tablet mit Hilfe von DIY Touchsensor ein/ausschalten

Hallo,

da mir hier schon einige Male geholfen wurde als mir das nötige Verständnis gefehlt hat, hoffe ich auch dieses Mal auf ein paar Tipps von euch.

Mein Projekt das jetzt schon einige Monate (mit Unterbrechungen) andauert, ist eine Küchenlichtsteuerung. Das meiste habe ich bereits fertig, aber jetzt bin ich mal wieder an einem Punkt wo ich dringlichst Hilfe brauche. Zu der Küchenlichtsteuerung gehört auch ein, in den Küchenschrank eingelassenes, Tablet. Ich möchte dieses Tablet ein/ausschalten wenn ich auf den Rahmen (Metall) des Tablets tippe. Der Metallrahmen dient dabei, mit Hilfe der CapacitiveSensor-library, als übergroßer Touchsschalter. Wenn ich ich innerhalb einer bestimmten Zeit, dreimal auf den Rahmen tippe soll der Arduino ein kurzes Signal auf den Tabletschalter geben, wobei sich das Tablet dann ein- oder ausschaltet - so jedenfalls die Therorie.

Mein erster Versuch funktioniert, aber nur innerhalb der eingestellten 3000 Millisekunden in der man drei Mal gedrückt haben muss. Außerhalb passiert nich mehr viel weil sich die Zeit (StartTime) nicht auf 0 zurückstellt sonder nur eine 0 in der Console angezeigt wird. Wahrscheinlich eine Milchmädchenrechnung meinerseits.

#include <CapacitiveSensor.h>

int mode = 0;
bool touch = false;
unsigned long startTime = 0;
unsigned long currentTime = 0;
unsigned long millisA=0;
unsigned long millisB=0;

CapacitiveSensor   cs_4_2 = CapacitiveSensor(4,2); 


void setup()                    
{
   cs_4_2.set_CS_AutocaL_Millis(0xFFFFFFFF);     // turn off autocalibrate on channel 1 - just as an example
   Serial.begin(9600);

}

void loop()                    
{
  int total1 =  cs_4_2.capacitiveSensor(30);  // Wert der Touchschalters ( 0-keine Berührung 55-bei Berührung )
  unsigned long start = millis();
  
    if (total1>=25)              // Wert des Touchschalters übersteigt 25
    {touch=true;}
    if (total1<=25)              // Wert des Touchpads ist unter 25 (ohne berührung immer 0)
    {touch=false;}
    
    
    if (touch==true)
      { 
        startTime=millis();  
        mode++;                    // "mode" erhöht sich mit jeder berührung des Touchpads
        delay(150);                // kurze Zeitspanne zum Entprellen des Touchschalters
        }
      
     
      if ((mode==3)&&(startTime<=3000)) // Zeit in der dreimal gedrückt werden muss
      {
        digitalWrite(13,HIGH);    // Pin 13 wird HIGH geschaltet
        delay(100);               // Zeitspanne in dem das Signal HIGH ist
        mode=0;                   // "mode" wird wieder zurückgesetzt
        startTime=0;              // "startTime" sollte wieder zurückgesetzt werden
        }

     else if(mode==3)      
     {
       mode=0;                  // "mode" wird wieder zurückgesetzt
       startTime=0;             // "startTime" sollte wieder zurückgesetzt werden
       } 
      
     else                       // wenn "mode =!3 wird Pin 13 LOW geschaltet
     {
       digitalWrite(13,LOW);
       }

 //////   Serielle Ausgabe ///////


  if (millis()-millisB>=500)
  {   
    Serial.print("mode:");
    Serial.println(mode);
    Serial.print("start Time:");
    Serial.println(startTime);
    Serial.print("curent Time");
    Serial.println(currentTime);
    Serial.print("Touchsensor:");
    Serial.println(total1);
    Serial.println();
    millisB=millis();
    }
  
  }

Ein weiteres Problem taucht auf wenn ich die Delays durch Millis ersetze, dann zählt der “mode++” ab und an nicht mit wenn ich auf den Touchrahmen drücke. Also das analoge Signal vom Touch kommt zwar aber der “mode” bleibt manchmal gleich oder hakt eben. Das ergibt für mich überhaupt keinen Sinn weil wenn ich wieder ein Delay einfüge funktioniert alles prima. Ideen?

void loop()                    
{
  int total1 =  cs_4_2.capacitiveSensor(30);

  
    if (total1>=0)
     {touch=true;}
    if (total1<=10)
    {touch=false;}
    
   if (millis()-millisA>=100) // kurze Zeitspanne zum Entprellen des Touchschalters
          {
          if (touch==true)
            { 
            startTime=millis();  
            mode++;
           // delay(100);
            }
          millisA=millis(); 
          }
      
    if ((mode==3)&&(startTime<=3000))
      
      {
        digitalWrite(13,HIGH);
        // delay(250);
        mode=0;
        }   

    else if(mode==3)      
     {
       mode=0;                  
       startTime=0;            
       } 
      
     else                      
     {
       digitalWrite(13,LOW);
       }

  
 //////   Serielle Ausgabe ///////


  if (millis()-millisC>=10){   
   // Serial.print("mode:");
    Serial.println(mode);
   // Serial.print("start Time:");
   // Serial.println(startTime);
   // Serial.print("curent Time");
   // Serial.println(currentTime);
    //Serial.print("Touchsensor:");
    Serial.println(total1);
   // Serial.println();
    millisC=millis();
    }
 
  }

Du musst die Zeiten relativ machen. D.h. startTime-millis()<=3000 statt (startTime<=3000)) und startTime=millis();statt startTime=0;. Mit startTime<3000 fragst du nur nach Tastendruck in den ersten drei Betriebssekunden des Arduinos.

Dein Sketch etwas vereinfacht zum drüber Diskutieren:

int mode = 0;
bool aktTouch, altTouch;
unsigned long startTime;
unsigned long currentTime;
unsigned long millisA = 0;
byte entprellZeit = 0;

void setup() {
  pinMode(2, INPUT_PULLUP);
  pinMode(13, OUTPUT);
  aktTouch = digitalRead(2);
  altTouch = aktTouch;
}

void loop() {
  aktTouch = digitalRead(2);
  currentTime = millis();
  delay(10);
  if ((aktTouch && !altTouch) && (currentTime - millisA > entprellZeit)) {
    entprellZeit = 10;
    millisA = currentTime;
    if (mode == 0) startTime = currentTime;
    mode++;
  }
  altTouch = aktTouch;

  if (mode == 3 || ((currentTime - startTime) >= 3000)) {
    if (!((currentTime - startTime) >= 3000)) {
      digitalWrite(13, !digitalRead(13));
    }
    entprellZeit = 0;
    mode = 0;
  }
}

Mangels Touchsensor habe ich einen digitalen Eingang genommen, ist von der Logik aber gleich.

Danke Super Gefühl wenn es endlich so läuft wie es soll, da ist der ganze Ärger den man hatte fast vergessen :wink:
Allerding hab ich noch Probleme die Delays wegzubekommen, da der Sketch ist nur ein Teil eines größeren ist muss ich sie noch entfernen. Der funktionierende Sketch:

void loop()                    
{
  int total1 =  cs_4_2.capacitiveSensor(30);

  if (total1>10)                 // Wert des Touchsensors über 25 
     {
      touch=true;
     }
  if (total1<=0)                 // Wert des Touchsensors unter 25
     {
      touch=false;
     }
      

  if (millis()-millisA>=300)       // wenn länger als 300ms gedrückt wird fällt "mode" auf 0 zurück um einen Dauerdruck zu vermeiden
     { 
      if (touch==true)
         { 
          mode=0; 
         }                 
     millisA=millis();
     }
      

  if (touch==true)
   {  
    mode++;                        // "mode" erhöht sich mit jedem Druck
    delay(150);                    // Zeit zum Entprellen des Schalters
   }                 
        
  else if (millis()-millisC>=2500) // wenn innerhalb von 2000ms nicht "mode==3" erreicht wird fällt er auf 0 zurück
    { 
     mode=0;
     millisC=millis();
    }    

  if (mode==3)                    // Aktion nach dreimaligem drücken 
     {
      digitalWrite(13,HIGH);      // Pin 13 wird HIGH geschaltet
      delay(500);                 // Zeitspanne in dem das Signal HIGH ist
      mode=0; 
      millisC=millis();
     }
 
  else                      
      {
       digitalWrite(13,LOW);
      }
}

Der Sketch ohne delays nach meiner einfachen Logik:

void loop()                    
{
  int total1 =  cs_4_2.capacitiveSensor(30);

  if (total1>10)                 // Wert des Touchsensors über 25 
     {
      touch=true;
     }
  if (total1<=0)                 // Wert des Touchsensors unter 25
     {
      touch=false;
     }
      

  if (millis()-millisA>=300)       // wenn länger als 300ms gedrückt wird fällt "mode" auf 0 zurück um einen Dauerdruck zu vermeiden
     { 
      if (touch==true)
         { 
          mode=0; 
         }                 
     millisA=millis();
     }
      

  if ((touch==true)&&(millis()-millisB>=150)) // ***** statt delay(150) *****
   {  
    mode++;                        // "mode" erhöht sich mit jedem Druck
    //delay(150);                    // Zeit zum Entprellen des Schalters
    millisB=millis();
   }                 
        
  else if (millis()-millisC>=2500) // wenn innerhalb von 2000ms nicht "mode==3" erreicht wird fällt er auf 0 zurück
    { 
     mode=0;
     millisC=millis();
     millisB=millis();
    }    

  if (mode==3)                    // Aktion nach dreimaligem drücken 
     {
      if (millis()-millisD>=500)   // ***** statt delay(500) ***** Zeitspanne in dem das Signal HIGH ist
        {
         digitalWrite(13,HIGH);      // Pin 13 wird HIGH geschaltet
         // delay(500);                 // Zeitspanne in dem das Signal HIGH ist
         mode=0; 
         millisD=millis();
        }
      millisC=millis();
     }
 
  else                      
      {
       digitalWrite(13,LOW);
      }
       Serial.println(mode);
}

ersetze ich das delay (150) zum entprellen des Tasters springt die Aufzählung “mode” beim Hochzählen auf 0 zurück oder holpert.
ersetze ich das delay(500) für das kurze Aufblitzen des Signals passiert nichts mehr.
…ich versteh es leider nicht.

@agmue Vielen Dank das schaue ich mir morgen mal genauer an

Ich sitz ungelogen seit heute vormittag und versuche die Delays rauszubekommen, ich krieg echt noch ne Kriese mit diesen millis @agmue vielen lieben Dank dafür aber das komm ich teilweise überhaupt nicht mehr mit. Denke ich brauch jetzt erst mal ne kleine Pause eh ich noch was kaputt mach. Falls jemand gerade lange Weile hat kann er ja mal drüberschauen und mir sagen wie ich die Entprellezeit wegbekomme, das andere Delay hab ich Gott sei Dank selbst hinbekommen.

void loop()                    
{
  int total1 =  cs_4_2.capacitiveSensor(30);

  if (total1>10){                    // Wert des Touchsensors 
       touch=true;
       }
  
  if (total1<=0){                    // Wert des Touchsensors 
     touch=false;
     }
      
  if (millis()-millisB>=300)          // wenn länger als 300ms gedrückt wird fällt "mode" auf 0 zurück um einen Dauerdruck zu vermeiden
     { 
      if (touch==true)
         {mode=0; 
         }                 
     millisB=millis();
     }
     
  if (touch==true)
   {mode++;                          // "mode" erhöht sich mit jedem Druck
    delay(150);                       // Zeit zum Entprellen des Schalters
   }                 
        
  else if (millis()-millisC>=1200)    // wenn innerhalb von 1200ms nicht "mode==3" erreicht wird fällt er auf 0 zurück
    {mode=0;
     millisC=millis();
    } 
       
 if (millis()-millisD>=250)             // Zeitspanne in dem das Signal HIGH ist
    {if (mode==3) 
       {millisD=millis();
        digitalWrite(13,HIGH);         // Pin 13 wird HIGH geschaltet
        mode=0; 
        millisC=millis();
       }

 else if (mode==0)
     {millisC=millis();
      digitalWrite(13,LOW);
     }
     
 else                      
      {digitalWrite(13,LOW);
      }
 }

ich würde es ja wie folgend machen aber da funktioniert der Sketch nicht mehr richtig, der “mode” setzt sich schon vor den eingestellten 1200ms zurück

if (touch==true){
    if (millis()-millisA>=150)               // Zeit zum Entprellen des Schalters
     {
      mode++;                                 // "mode" erhöht sich mit jedem Druck
      millisA=millis();                      
     }
  }

Ich glaube, in if (touch==true) steckt ein Gedankenfehler. Frage: Wie häufig wird loop durchlaufen, während Du auf die Taste drückst? Testprogramm:

unsigned long zaehler;
void setup()
{
  Serial.begin(9600);
  Serial.println("Anfang");
  pinMode(2, INPUT_PULLUP);
}

void loop() {
  if (digitalRead(2)) {
    zaehler++;
  } else {
    if (zaehler > 0) {
      Serial.println(zaehler);
      zaehler = 0;
    }
  }
}

Was Du willst ist die positive Flanke (!altTouch && aktTouch), also die Änderung von "nicht gedrückt" zu "gedrückt".

Ich habe keine richtige Taste sondern nur ein Software Touch Sensor, siehe: Capacitive Sensing Library Wenn ich also den Touch Sensor berühre, ändert sich der Ausgabewert "int total1" von 0 in -+50, lass ich den Sensor los geht es wieder zurück auf 0. Jenachdem wie lang ich draufdrücke kommen bei deinem Testprogramm folgende Werte raus:

Anfang
29
46
56
36
56
60
53
65
72
71
73
69
77
81
78
77
597
609
508
82
96
102
84
83
63
78
64
90
75
450
870
1482
550
137
106
85
85
70
79
78
78

Deswegen komm ich wahrscheinlich um eine Entprellzeit von 150ms nicht herum. Mit dem letzten Sketch (mit delay) funktioniert es fast perfekt.

Also ich drücke dreimal innerhalb von 1200ms auf das "Tochpad" und das Signal (digitalWrite) wird kurz eingeschaltet. Soweit so gut... aber bei 100 Testdurchläufen tauchen schon erste Fehler auf, ca. 5 /100 - Mit Fehler meine ich dass während des Hochzählens des "mode++" der Zähler wieder zurück auf 0 springt bevor er den "mode==3" erreicht. Übersetzt, ich muss statt den Drei, viermal oder fünfmal drücken ehe das Signal kommt. Wenn ich das delay in meinem letzten Sketch durch millies ersetze erhöht sich dieses Fehlerquote auf 50/50. Denke die Funktion mit den 1200ms arbeitet nicht korrekt. Ich kann es aber leider nicht erkennen ..ich hoffe dass du mir irgendwie folgen konntest...

edth: Deswegen komm ich wahrscheinlich um eine Entprellzeit von 150ms nicht herum.

Ich stelle mal die Behauptung auf, Dein Touch Sensor kann nicht prellen, was noch zu untersuchen wäre. Selbst mein schlechtester Taster kommt mit 30 ms Entprellzeit aus.

Was Du versuchst, ist, die Länge Deines Tastendrucks zu kompensieren. Wenn Du die Flanke auswerten würdest, wäre dies eindeutiger. Ersetze touch durch aktTouch und dann (ungetestet):

  if (!altTouch && aktTouch)
   {mode++;                          // "mode" erhöht sich mit jedem Druck
    delay(150);                       // Zeit zum Entprellen des Schalters
   }                 
        
  else if (millis()-millisC>=1200)    // wenn innerhalb von 1200ms nicht "mode==3" erreicht wird fällt er auf 0 zurück
    {mode=0;
     millisC=millis();
    } 
       altTouch=aktTouch;

agmue: Ich stelle mal die Behauptung auf, Dein Touch Sensor kann nicht prellen, was noch zu untersuchen wäre. Selbst mein schlechtester Taster kommt mit 30 ms Entprellzeit aus. Was Du versuchst, ist, die Länge Deines Tastendrucks zu kompensieren.

Du hast recht, entprellen ist wohl etwas unglücklich ausgedrückt aber ich dachte dass es vom Prinzip her das gleiche ist. Wenn ich deinen Code nehme funktioniert es ohne delay ...endlich Vielen Dank dafür !!! Kannst du mir evtl. noch den Codeschnipsel in ein...zwei Sätzen erklären? altTouch und aktTouch werden im Setup gleichgesetzt ok, wie kann dann die if Bedingung im loob funktionieren?

void setup()                    
{
   altTouch = aktTouch;
}

void loob() 

if (!altTouch && aktTouch)
   {mode++;

edth:
Kannst du mir evtl. noch den Codeschnipsel in ein…zwei Sätzen erklären?

Ich kann es ja mal versuchen.

Die Initialisierung verhindert ein Erkennen der Flanke direkt nach dem Programmstart

void setup() {
...
  aktTouch = digitalRead(2);
  altTouch = aktTouch;
}

Aktualisierung in loop()

void loop() {
  aktTouch = digitalRead(2); 
...

Alter Wert LOW, neuer Wert HIGH, also steigende Flanke:

... aktTouch && !altTouch ...

Alten Wert aktualisieren.

altTouch = aktTouch;

Ein Trick steckt noch in der Variablen entprellZeit, weil dies eben keine Konstante ist. Durch Verändern des Wertes auf 0 oder 10 kann ich die Verzögerung aus- oder einschalten.

Nun ist dies kein Lehrsketch, da müßte ich dann nochmal drüber grübeln. :slight_smile:

Okay, vielen Dank nochmal für deine Hilfe.. dafür gibts es ein Bier, schau mal in deinem Postfach nach :)