2

Hello is there a alternative to time.sleep? Because I want to let my LEDs blink in the exact amount of Hz what is not able because to call time.sleep needs time too, so the blinking needs more time than expected.

#!/usr/bin/python
    import RPi.GPIO as GPIO
    import time
    from threading import Thread

    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(32, GPIO.IN)

    def blink(port, hz):
        GPIO.setup(port, GPIO.OUT)
        while True:
            if GPIO.input(32) == 1:                 //lever activated?
                GPIO.output(port, GPIO.HIGH)
                time.sleep(0.5/hz)
                GPIO.output(port, GPIO.LOW)
                time.sleep(0.5/hz)
            else:
                GPIO.output(port, GPIO.LOW)
    #to make it easier to add new LED
    def start(port, hz):
        Thread(target=blink, args=(port, hz)).start()
    #to add LED insert start(GPIOport, Hz)
    start(15, 2)
    start(16, 4)
    start(18, 6)
    start(22, 12)
    start(29, 24)
Kai
  • 147
  • 1
  • 2
  • 11
  • How precise does this need to be? Because there are hard limits to how precise you can be when running under a preemptive multitasking OS like Linux... – Matteo Italia Mar 19 '18 at 06:52
  • @MatteoItalia Should be as precise as possible. p.s. I´m running the script on a RasPi with Raspbian Stretch Lite – Kai Mar 19 '18 at 07:03
  • 1
    To be as precise as possible you have to ditch Linux and write your code in assembly on the bare metal counting the machine cycles (possibly on a simpler machine than a modern Cortex A). Again, what kind of precision is actually needed here? – Matteo Italia Mar 19 '18 at 07:04
  • @MatteoItalia I can´t really say it, I was only told to do it not with sleep because it is not precise enough. But I don´t know what ways and what levels of precision are available – Kai Mar 19 '18 at 07:14
  • See https://stackoverflow.com/a/33054922/137386 – sebasgo Mar 19 '18 at 08:53

1 Answers1

1

To keep the frequency, use sleep like this:

time.sleep(desired_time - time.time())

This way the small delays will not add up.

dtm = time.time()
pulse = 0.5/Hz
while True:
    dtm += pulse
    time.sleep(dtm - time.time())
    # LED ON
    dtm += pulse
    time.sleep(dtm - time.time())
    # LED OFF

If the exact duty cycle (i.e. on/off ratio) is not a concern, you could simplify the loop:

while True:
    time.sleep(pulse)
    # LED ON
    dtm += 2*pulse
    time.sleep(dtm - time.time())
    # LED OFF

UPDATE, stop/resume blinking, see comments, presudocode

 pulse = 0.5/Hz
 while True:
     dtm = time.time()
     while input32 == 1:
          ... blink LEDs ...
     while not input32 == 1:
         time.sleep(0.1)
VPfB
  • 14,927
  • 6
  • 41
  • 75
  • Now gives me this Error when turning the lever on: Exception in thread Thread-1: Traceback (most recent call last): File "/usr/lib/python2.7/threading.py", line 801, in __bootstrap_inner self.run() File "/usr/lib/python2.7/threading.py", line 754, in run self.__target(*self.__args, **self.__kwargs) File "hz3.py", line 16, in blink time.sleep(dtm - time.time()) IOError: [Errno 22] Invalid argument – Kai Mar 19 '18 at 08:51
  • @Kai That probably means `dtm` was not updated, the time is in the past and sleeptime is negative. – VPfB Mar 19 '18 at 08:57
  • put dtm = time.time() above every dtm += pulse. Now it works, thank you! – Kai Mar 19 '18 at 09:09
  • @Kai No, please don't do that. Do `dtm = time.time()` just once before you start looping (and also when you pause and resume) – VPfB Mar 19 '18 at 09:37
  • and how can I fix the Error, I have no clue – Kai Mar 20 '18 at 06:36
  • @Kai The handling of lever (input 32) should be rewritten. You have a busy wait loop there if the value is not 1. E.g. break from the LED blinking loop when the lever is not activated and enter it again when it is activated. I have updated the answer. – VPfB Mar 20 '18 at 07:46