2

I've built to build a timer that shows the content in a 16x2 LCD.

So far so good. Now, what I want to achieve is that when I push a button, pause the timer.

I'm using ruby, with the library rpi_gpio and

This is my code:

require 'rpi_gpio'
require 'charlcd'

RPi::GPIO.set_numbering :bcm

RPi::GPIO.setup 18, :as => :input, :pull => :up

lcd = CharLcd.new
lcd.begin(16, 2)
lcd.clear

total_seconds = 0
start_time = Time.now

t = Thread.new do
    loop do
        sleep 1
        total_seconds = Time.now - start_time
        hours = (total_seconds/ 3600).to_i
        minutes = ((total_seconds % 3600) / 60).to_i
        seconds = ((total_seconds % 3600) % 60).to_i

        lcd.clear
        tim =  hours.to_s.rjust(2, '0') + ':' + minutes.to_s.rjust(2, '0') + ':' + seconds.to_s.rjust(2, '0')
        lcd.message(tim) 
    end
end

while RPi::GPIO.high? 18 do
end
t.kill

lcd.clean_pins()

The problem comes when, as far as I know, the only way to control when button is pushed is with a loop, and I think two loops (the one of the timer and the one that controls the button) make slow the printing of the message in the LCD display.

I'm record this video to show you guys the behavior:

https://youtu.be/4P2OsyGr0D4

I'd be grateful if somebody could help me out with this, or give me another solution.

Thanks in advanced.

  • 1
    I'm not a ruby user but it looks to me like you are busy looping the processor with that last while. On a Pi 2, the timer thread should still run okay, but this will completely screw up a single core machine. There's no way someone intended the library to be used that way. There should be means of waiting on an blocking call for an event involving the pin. This may be identical to using "poll" or "select" on a (set of) file/socket handles, if you've ever done any basic networking. The event here might be called an interrupt (although it is sort of a misnomer). – goldilocks Dec 31 '15 at 12:50
  • 1
    Ah...I notice the github page says "Features...Upcoming: event-driven input" :( This is sort of understandable, however. The main reason to use the raspberry pi specific gpio libs is to do things you cannot do with the generic linux sysfs interface -- e.g., PWM. You don't need them for buttons. I found this gem (ruby gpio) which uses the generic sysfs method and "watches pins and trigger[s] handlers accordingly". Investigate that, it should allow you to set up a handler function which will fire when the gpio state changes. – goldilocks Dec 31 '15 at 13:12
  • 1
    That gem has a github page too, look here under Usage at the watch_for() ("watch the pin asynchronously"). BTW, I am pretty sure you should be able to use both these libraries at the same time as long they are using separate pins. So you can do PWM and buttons. – goldilocks Dec 31 '15 at 13:17
  • Hey @goldilocks thanks for your answer, and sorry for the delay, I've been out of home for holidays. While I was investigating for Ruby gems for this, I found the one you mention. The thing is that, in background, this gem also use a while so I suppose that the problem stills happen -> github.com/sausheong/ruby-gpio/blob/master/lib/ruby-gpio.rb#L61 – JV Lobo Jan 10 '16 at 15:05
  • Wow -- that would make it a real piece of crap, since this is totally unnecessary. If you understand what passive polling is (I am positive you can do it in ruby, since it is a standard feature of any high level language), it can be applied to nodes in /sys/class/gpio as explained here ("write these strings to select the signal edge(s) that will make poll(2) on the "value" file return"). poll() and select() are standard C functions; glancing around an equivalent in ruby would be IO.select() – goldilocks Jan 10 '16 at 15:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.