2

I have made a script (below) which which controls a LED through two functions, blink_fast() and blink_slow(). My goal is to control the "mode" of the LED by using a physical push-button wired to GPIO.

The script includes an event detection and callback, per this guide, and the button does work to trigger the event, and the callback will correctly print to console when the event is detected. The problem is that the event does not interrupt the current "cycle" of blinking. For example, if the button is pressed shortly after the blink_slow function, the program will finish out its 6 second blink cycle before changing to the blink_fast mode. I would like the device to switch immediately when the button is pressed.

I have tried placing the mode_switch function inside the callback, but that did not help.

How can I get the event to immediately interrupt the current blink cycle before starting the new one?

Thanks in advance!

import RPi.GPIO as GPIO
from time import sleep

BUTTON_GPIO = 16

blueLED = 17
state_flag = False

def button_pressed_callback(channel):
    global state_flag
    print("button press detected")
    state_flag = (not state_flag)

def blink_slow():   
    GPIO.output(blueLED, GPIO.HIGH)
    sleep(3)
    GPIO.output(blueLED, GPIO.LOW)
    sleep(3)

def blink_fast():   
    GPIO.output(blueLED, GPIO.HIGH)
    sleep(.2)
    GPIO.output(blueLED, GPIO.LOW)
    sleep(.2)

def mode_switch():

    while state_flag == True:
        blink_fast()
    while state_flag == False:
        blink_slow()

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(blueLED,GPIO.OUT)
GPIO.setup(BUTTON_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_UP)

GPIO.add_event_detect(BUTTON_GPIO, GPIO.FALLING,
    callback=button_pressed_callback, bouncetime=300)

while True: 
    mode_switch()
1
  • 2
    No Pi handy at this time but first thought is state_flag in mode_switch is not global. Add global state_flag to the function. Also add a sleep into the while true loop at the end to give the processor time to do other tasks :)
    – user115418
    May 3, 2020 at 3:36

1 Answer 1

1

You need to design the structure of your script to support this usage.

Generally wherever you have a time.sleep() you will need to replace that with a loop testing for an early completion signal.

E.g. change

def blink_slow():   
    GPIO.output(blueLED, GPIO.HIGH)
    sleep(3)
    GPIO.output(blueLED, GPIO.LOW)
    sleep(3)

to something like

SHORT_DELAY=0.05

def abortable_sleep(seconds):
   global abort_flag
   loops = int(seconds/SHORT_DELAY)
   for i in range(loops):
      if abort_flag:
         break
      time.sleep(SHORT_DELAY)

def blink_slow():   
   global abort_flag
   GPIO.output(blueLED, GPIO.HIGH)
   abortable_sleep(3)
   GPIO.output(blueLED, GPIO.LOW)
   abortable_sleep(3)
   abort_flag = False

Set the abort flag in the callback.

This is the change I would make to the existing design.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.