So erstellen Sie einen Berührungsschalter zur Verwendung mit einem Raspberry Pi

Ich versuche, meine eigene Wecklampe zu machen. Ich habe eine Lampe mit einem großen Metallsockel, um alle Komponenten darin zu verstecken. Ich habe auch ein Velleman K8064 DC Controlled Dimmer Kit , das ich zusammengestellt habe und funktioniert. Ich habe einen Raspberry Pi, um alles zu steuern (ich plane auch, den Pi als Android Dock zu verwenden)

Ich möchte, dass der Sockel der Lampe als Berührungsschalter funktioniert, um die Lampe ein- und auszuschalten. Ich habe versucht, einen Berührungsschalter, den ich auf www.talkingelectronics.com gefunden habe, mit einem Steckbrett zu versehen , aber beim Testen ist die Lampe immer an.

Kann mir jemand einen Schaltplan eines einfacheren Berührungsschalters zeigen, der mit einem Himbeer-Pi funktioniert?

Antworten (4)

Wenn Sie Low-Level-Zugriff auf die kratzigen GPIOs haben, gibt es eine einfache Möglichkeit, dies zu tun. Sie benötigen lediglich einen Widerstand. Ja, du hast richtig gelesen.

Schließen Sie einfach einen Stift an den Lampensockel an und binden Sie den Widerstand zwischen Sockel und v C C , das ist die 3,3-V-Schiene, denken Sie daran, dass die Pins nicht 5-Volt-tolerant sind.

Hier ist in Pseudocode, was Sie softwareseitig tun müssen:

while(1) {
    timer.reset()
    gpiox.direction = GPIO.OUT
    gpiox.write(GPIO.LOW)
    while(gpiox.read != GPIO.LOW)
    gpiox.direction = GPIO.IN
    timer.start()
    while(gpiox.read == GPIO.LOW)
    timer.stop()
    out = timer.read()
    if (out > THRESHOLD)
        pressed = true
    else
        pressed = false
}

Was ist los? Zuerst setzt du einen Timer zurück. Es muss schnell sein, so etwas wie ein CPU-Timer, der bei jedem Taktzyklus oder so inkrementiert wird.

Sie setzen Ihren Pin als Ausgang, schreiben eine Null darauf und warten dann, bis er wirklich auf Null geht. Dies kann je nach Treiber/HAL, den Sie verwenden, innerhalb des Schreibvorgangs erfolgen, aber damit dies funktioniert, müssen Sie keinen verwenden. Nachdem der Pin wirklich Null ist, setzen Sie ihn als Eingang und starten den Timer. Die parasitäre Kapazität des Lampensockels und des Stifteingangs und, falls vorhanden, Ihres Fingers beginnt sich über den Widerstand aufzuladen. Wenn die Spannung über der Kapazität als logisch hoch gelesen wird, stoppen Sie den Timer: Der Trick besteht darin, dass die Kapazität größer ist, wenn Ihr Finger vorhanden ist, sodass das Laden auf die logische Eins viel länger dauert, sodass Sie dies erkennen können Fingeranwesenheit durch Ablesen des Timers.

Auf welche Probleme könnten Sie stoßen?
Nun, vielleicht haben Sie einfach keinen so niedrigen Zugriff auf die kratzigen GPIO-Pins ... Aber das müssen Sie herausfinden. Vielleicht haben Sie keinen solchen Low-Level-Timer. Das größte Problem ist, dass die Kapazität des Lampensockels möglicherweise sehr groß ist, sodass eine Berührung keinen großen Unterschied macht.

Diese Methode ist auf jeden Fall einen Versuch wert, da sie ein paar Cent kostet. Über den Widerstand möchten Sie etwas, das die Kapazität langsam genug auflädt, damit Ihr Timer tatsächlich die benötigte Zeit messen kann, aber schnell genug, um den "Knopf" möglicherweise 20 Mal pro Sekunde tatsächlich abzutasten. Lampe plus Körper plus Stift kann etwa 1 nF betragen, Sie möchten a τ = R C von etwa 20ms so

R = τ C = 20 10 3 S 1 10 9 F = 20 M Ω
Nun, das ist zu viel. Sie benötigen einen schnellen Timer und gehen auf etwas herum 1 M Ω

Aber wie funktioniert es?
Alles um uns herum hat eine Kapazität in Bezug auf etwas anderes. Es ist üblich, Masse als "etwas anderes" zu bezeichnen, also hat alles eine Kapazität in Bezug auf Masse. Betrachten wir die folgende Schaltung:

schematisch

Simulieren Sie diese Schaltung – Mit CircuitLab erstellter Schaltplan

C ich N ist die Eingangskapazität des digitalen Ports plus die Kapazität des Lampensockels gegen Masse, normalerweise etwa 100 pF, während C H (wie in „Mensch“) ist die Fähigkeit, die wir gegenüber dem Boden haben. Wenn Sie den Lampensockel berühren, schließen Sie den Schalter mit der Aufschrift "Touch", während die Himbeere nur einwirken kann S W ich N . Sie beginnen mit S W ich N geschlossen, also v C ich N = 0 . Wenn sich die Himbeere öffnet S W ich N die Eingangskapazität beginnt sich aufzuladen v C C durch R P mit Zeitaufwand τ = R P C ich N . Das V(t)-Gesetz ist ziemlich bekannt:

v C ich N ( T ) = v C C ( 1 e T τ )
Die Himbeere erkennt einen hohen Eingang, wenn die Spannung etwas in der Nähe erreicht 2 3 v C C , das dauert also:

T H ICH G H = τ ln ( v C C v C C 2 3 v C C ) = τ ln ( 3 )

An diesem Punkt würde es den Timer anhalten und prüfen, wie lange es gedauert hat: ob etwas in der Nähe ist 1.1 τ es findet keine Berührung statt. Die Himbeere würde schließen S W ich N und warten Sie, bis sich der Kondensator entladen hat, dh warten Sie, bis der Stift Null anzeigt, um schließlich den Schalter zu öffnen und von vorne zu beginnen.
Aber was ist, wenn wir schließen? S W H ? Also, τ Änderungen: τ ' = R P ( C ich N + C H ) jetzt und ggf C ich N klein genug ist, und hoffentlich ist es das auch, T A u ' vielleicht sogar zehnmal größer als τ . Die Himbeere startet ihren Timer, aber jetzt dauert es erheblich länger, eine hohe Eingabe zu lesen:

T H ICH G H ' = . . . = τ ' ln ( 3 ) 10 τ ln ( 3 ) = 10 τ

Die vorletzte Beziehung ist eine Art "Wir hoffen, das stimmt"-Beziehung. Wenn die Himbeere schließlich eine hohe Eingabe liest, stoppt sie den Timer und sagt: Nun, das dauert ziemlich lange, lasst uns das Licht für meinen Programmierer umschalten! Und das ist so ziemlich alles.

Und warum funktioniert deine Lösung?
Das liegt daran, dass Ihr Körper als Antenne fungiert. Sie speisen im Grunde die Netzfrequenz in den Himbeer-Eingangsstift ein, und das kann dazu führen, dass der Eingang als einer gelesen wird, aber das wäre eine unzuverlässige Möglichkeit, Ihre Lampe umzuschalten. Soweit ich gelesen habe, arbeitet Ihr System ziemlich zufällig ... Versuchen Sie es mit dem richtigen Weg.

Ich mag Ihre Idee, aber glauben Sie, dass der Raspberry Pi leistungsfähig genug sein wird, um als Touch-Schalter und PWM verwendet zu werden? Ich hatte auch gehofft, den Pi als Android-Dock zu verwenden, damit ich auch Musik abspielen kann.
Es ist auf jeden Fall stark genug, die Frage ist: Können Sie auf einem so niedrigen Niveau arbeiten?
Ich glaube schon, ich probiere es aus und melde mich wieder.
Ich probiere das gerade aus und habe ein wenig Probleme, die elektronische Seite der Dinge zu verstehen. Gehe ich recht in der Annahme, dass die Spannung abfällt, wenn ich die Lampe berühre? Wenn ja, sollte der Ausgang nicht hoch beginnen und dann die Lampe berührt werden und die Spannungen niedrig werden, sollte der Raspberry Pi die Lampe einschalten?
@TheLukeMcCarthy du hast nicht recht. Die Spannung oszilliert, wenn Sie die Basis berühren, ändert sich die Zeitkonstante. Wenn Sie daran sehr interessiert sind, kann ich in den nächsten Tagen einige Grafiken hinzufügen.
Ich bin daran interessiert, mehr zu erfahren, aber das klingt nach einer Menge Ärger für Sie. Wenn Sie eine gute, einfache Website kennen, die das Konzept erklärt, wäre das ein guter Anfang.
Ich würde gerne helfen und meine Antwort verbessern, da sie auch einige Stimmen erhält und die Leute im Internet von Zeit zu Zeit hier landen könnten. Ich werde es tun, sobald ich kann.
@TheLukeMcCarthy bitte schön

Ich habe eine C-Implementierung (siehe unten) basierend auf dem Pseudocode in Vladimirs Antwort geschrieben .

Funktioniert wie ein Zauber auf meinem Pi Zero W, ich benutze es, um die Hintergrundbeleuchtung eines LCD-Displays umzuschalten, indem ich seine Lünette berühre. Ich habe einen 1-MΩ-Widerstand verwendet, der im Leerlauf ~ 20 μs zum Aufladen und beim Berühren 45-110 μs benötigt. Es kann sogar Berührungen durch die nichtleitende Beschichtung auf der Lünette erkennen, daher sollte der Pi vor statischer Entladung geschützt werden.

Bisher hatte ich keine Probleme mit wiederholten Berührungen, die nicht erkannt wurden.


// Filename: touch_toggle.c

/* Compile with gcc -lwiringPi touch_toggle.c -o touch_toggle
 * Run with sudo ./touch_toggle
 * Do not touch while starting the program so it can initialize properly
 */

/* SCHEMATIC
 * 
 * ,----------------------,
 * |   Raspberry Pi       |
 * |                      |
 * | TOUCH_PIN        VCC |
 * `-----+-------------+--'
 *       |             |
 *       +---[1MΩ]-----+
 *       |
 *   Touch surface
 * 
 */
#include <wiringPi.h>
#include <stdio.h>
// Note: Pin numbers are in BCM notation (pin number format is set by wiringPiSetupGpio)
// See pinout.xyz
#define TOUCH_PIN 20
#define OUTPUT_PIN 21
// How long to pull the touch pin low
// Controls loop speed and affects CPU usage
#define DELAY 15

int main(void) {
    wiringPiSetupGpio();
    unsigned int timer;
    unsigned int threshold = 0;
    unsigned char state = 0; // Currently being touched?
    unsigned char out_state = 0; // State of output pin
    signed char hysteresis = 0; // Counter for consecutive readings
    pullUpDnControl(TOUCH_PIN, PUD_OFF); // Not sure if this would ever be set, just to be safe
    pinMode(OUTPUT_PIN, OUTPUT);
    digitalWrite(OUTPUT_PIN, out_state);

    // Measure capacitance to calibrate touch sensitivity
    for (char i=0; i < 10; i++) {
        // Pull touch pin low to discharge
        pinMode(TOUCH_PIN, OUTPUT);
        digitalWrite(TOUCH_PIN, LOW);
        // Wait a bit
        delay(DELAY);
        // Start timer
        timer = micros();
        pinMode(TOUCH_PIN, INPUT);
        // Wait for pin to become high
        while (!digitalRead(TOUCH_PIN));
        // Get time elapsed
        threshold += micros() - timer;
    }
    // Set threshold to twice the average capacitance
    threshold /= 5; // This number might need to be increased if the touch is not sensitive enough
    printf("threshold=%d\n",threshold);

    while (1) {
        pinMode(TOUCH_PIN, OUTPUT);
        digitalWrite(TOUCH_PIN, LOW);
        delay(DELAY);

        timer = micros();
        pinMode(TOUCH_PIN, INPUT);
        while (!digitalRead(TOUCH_PIN));
        timer = micros() - timer;

        if (timer > threshold) {
            if (hysteresis < 0) hysteresis = 0;
            hysteresis++;
        } else {
            if (hysteresis > 0) hysteresis = 0;
            hysteresis--;
        }

        // 3 consecutive readings are required to toggle touch state
        if (hysteresis > 2) {
            if (state == 0) {
                out_state = !out_state;
                digitalWrite(OUTPUT_PIN, out_state);
                state = 1;
                
                // Print when touch starts and the measured value
                // Can be commented out
                printf("START %d", timer);
                fflush(stdout); // Display instantly (by default only flushed on newline)
            }
            hysteresis = 0;
        } else if (hysteresis < -2) {
            if (state == 1) {
                state = 0;
                
                printf(" END\n");
            }
            hysteresis = 0;
        }
    }
    return 0;
}

Code auch unter: https://pastebin.com/FrsYCtXu

Vielen Dank an Vladimir für seine Antwort, die es mir ermöglicht hat, auf diese Lösung zu kommen.

schematisch

Simulieren Sie diese Schaltung – Mit CircuitLab erstellter Schaltplan

Der Python-Code lautet wie folgt

import time  
import RPi.GPIO as GPIO  

GPIO.setmode(GPIO.BCM)  

touchSwitch = 23  
outputPin = 24  

GPIO.setup(touchSwitch, GPIO.IN)
GPIO.setup(outputPin, GPIO.OUT)  
GPIO.output(outputPin, False)  

while True:  
    switchTouched = GPIO.input(touchSwitch)  

    if switchTouched:  
        print "touch detected"  
        time.sleep(0.3) # sleep again here so not to toggle the lamp to quickly  
    else:  
        print "not touched"  

    time.sleep(0.15) # 0.10 seems to give the best results but 0.15 uses less CPU  

Das Problem bei dieser Lösung besteht darin, dass beim Halten der Berührungsplatte nach etwa 5 bis 12 Erkennungen einer Berührung die Berührung eine Zeit lang nicht erkannt wird und dann erneut erkannt wird. Da ich es nur für eine Touch-Lampe verwende, ist die Lösung gut genug für meine Bedürfnisse.

Möglicherweise möchten Sie die Erde berühren (Wandplattenschraube oder ähnliches), bevor Sie die Lampe berühren. Nur um zu verhindern, dass ein statischer Funke Ihren GPIO23-Eingang ruiniert. Herzlichen Glückwunsch, es macht immer Spaß, zu einer sehr einfachen Lösung zu gelangen.
@Marla denkst du, ich sollte einen Widerstand verwenden, um den R-Pi zu schützen? Das einzige Problem, das ich sehen würde, ist, dass die Spannung beim Berühren der Lampe nur auf ~ 0v5 geht. Die gerade hoch genug ist, um eine hohe Spannung am R-Pi zu registrieren.

Dies scheint ohne Verzögerung zu funktionieren (unter Verwendung der Schaltung von TheLukeMcCarthy, aber mit GPIO 18 als Eingang und GPIO 17 als Ausgangspin)

#include <wiringPi.h>
int main (void)
{
    register unsigned char on = 0 ;
    wiringPiSetup () ;
    pinMode ( 1, INPUT) ;
    pinMode ( 0, OUTPUT) ;
    pinMode ( 4, OUTPUT) ;
    digitalWrite ( 4, LOW) ;
    digitalWrite ( 0, LOW) ;

    while ( 1 )
    {
            if ( digitalRead (1) )
            {
                    if ( on )
                    {
                            on=0;
                            digitalWrite ( 4, LOW) ;
                    }
                    else
                    {
                            on=1;
                            digitalWrite ( 4, HIGH) ;
                    }
                    delay ( 300 ) ;
            }
            delay ( 50 ) ;
    }

    return 0 ;
}
Es könnte sich lohnen, in dieser Antwort einen Verweis auf die obige Schaltung hinzuzufügen, damit klarer wird, worauf sie sich bezieht, wenn sich die Reihenfolge der Antworten ändert.