Freenove / Freenove_Ultimate_Starter_Kit_for_Raspberry_Pi

Apply to FNK0020
Other
562 stars 295 forks source link

Chapter 14 - Python version results in duplicate button events #7

Closed anthonywittig closed 6 years ago

anthonywittig commented 6 years ago

Hello,

When running the C code for chapter 14 everything works as expected. When running the Python code, the button has a duplicate event after the bouncetime. I was wondering if I was the only person to experience this behavior.

I modified the code as follows (see sections titled ### New code to test duplicate events) and for 10 seconds I see ~33 Skipping button press... output lines (corresponding to the bounce time of 300 and the 10 second ignore).

I've got a RPi 3 B+. Thanks for any insight you might be able to provide.

#!/usr/bin/env python3
########################################################################
# Filename    : Relay.py
# Description : Button control Relay and Motor
# Author      : freenove
# modification: 2018/08/02
########################################################################
import RPi.GPIO as GPIO
from datetime import datetime, timedelta

relayPin = 11    # define the relayPin
buttonPin = 12    # define the buttonPin
relayState = False

### New code to test duplicate events:
lastEventTime = datetime.now() - timedelta(seconds=10)
### End new code.

def setup():
        print ('Program is starting...')
        GPIO.setmode(GPIO.BOARD)       # Numbers GPIOs by physical location
        GPIO.setup(relayPin, GPIO.OUT)   # Set relayPin's mode is output
        GPIO.setup(buttonPin, GPIO.IN, pull_up_down=GPIO.PUD_UP)    # Set buttonPin's mode is input, and pull up to high

def buttonEvent(channel):
        global relayState

        ### New code to test duplicate events:
        global lastEventTime
        print ('buttonEvent GPIO%d'%channel)
        if lastEventTime + timedelta(seconds=10) > datetime.now():
                print('Skipping button press...')
                return
        lastEventTime = datetime.now()
        ### End new code.

        relayState = not relayState
        if relayState :
                print ('Turn on relay ... ')
        else :
                print ('Turn off relay ... ')
        GPIO.output(relayPin,relayState)

def loop():
        #Button detect
        GPIO.add_event_detect(buttonPin, GPIO.FALLING, callback=buttonEvent, bouncetime=300)
        while True:
                pass

def destroy():
        GPIO.output(relayPin, GPIO.LOW)     # relay off
        GPIO.cleanup()                     # Release resource

if __name__ == '__main__':     # Program start from here
        setup()
        try:
                loop()
        except KeyboardInterrupt:  # When 'Ctrl+C' is pressed, the child program destroy() will be  executed.
                destroy()

Output looks like this with a single button push:

Program is starting...
buttonEvent GPIO12
Turn on relay ... 
buttonEvent GPIO12
Skipping button press...
buttonEvent GPIO12
Skipping button press...
...
buttonEvent GPIO12
Turn off relay ... 

If I unplug the motor, there aren't any duplicate events.

SuhaylZhao commented 6 years ago

Hi,

We analyzed the problem carefully.

This is because the motor is a high-power electrical device, the power supply voltage is pulled down at the start of the moment, resulting in GPIO18 pin signal changes, the program misjudged, and then closed the relay. Debounce way with the language of C and Python are not the same, which leads to the differences.

We decided to modify the circuit and separate the control part from the load part to solve this problem.

Thanks.

anthonywittig commented 6 years ago

Thanks!