Double function GPIO on RPi

Share:
Condividi

I’m using the Raspberry Pi board in some projects. Many of these needs to run 24/7, so the hardware has battery backup in case of power fail. Sometimes, the device controlled by RPi board has to be powered off for maintenance, so it’s also necessary to turn off the control board, but there’s no video, no keyboard, neither mouse attached. The operator must connect all of these to perform a clean shutdown. Ok, that’s unacceptable: I decided to add a blinking led to inform the operator that the board is running and a switch to manually perform the shutdown, without the need for keyboard, mouse and video.
There was a problem: I just had ONE single GPIO free, the GPIO.4 , so I decided to use it for both led driving and pushbutton input. The principle is very simple: change the port direction and use it alternatively for led and for pushbutton. Here is the schematic:

rpi-led-sw-schAnd this is the prototype circuit mounted for testing purposes:

rpi-led-sw-picThe 1K resistor limits the current from GPIO.4 to about 1.5mA (the red led lights well) and the 470 Ohm resistor limits the current from the pin in case of software error (it happens, sometime) that sets the GPIO.4 as output and its value as high (3.3v). In such case, even if you press the pushbutton switch, the GPIO.4 is loaded with max 7mA (3.3V / 470 Ohm) that is acceptable for the output. When you press the button, the led turns ON even if the GPIO is in input mode, but the current that flows in the led is smaller than in case of GPIO is output-low, being the resistor value 1K + 470 Ohm (approx 1mA will flow thru the led). Note that the resistor values are important : you can’t decrease significantly the value of 470 Ohm, ’cause the current drawn from GPIO in case of “output high” will be out of GPIO current limits and you also can’t increase that value, ’cause the partition with led and 1K resistor will supply a voltage out of specs when pressing the pushbutton while the port is in input mode. With actual values, the voltage at GPIO pin when in input and with switch closed is about 0.5V that is in range for being read as logical “0″. Voltage over 0.8V may create unstable “0″ reads or can be interpreted as “1″ (switch open). Similarly, you can’t increase the value of 1K, ’cause the current that flows in the led (and its brightness) will proportionally decrease. So, the values proposed in the schematic are “well balanced”…

Now, we have a double function pin. Here is the listing of a Python script I realized to make all this principle working : it’s named “service.py”.

import RPi.GPIO as GPIO
import time
from subprocess import call

# reset counter for pushbutton pressed
cnt = 0
# set GPIO mode
GPIO.setmode(GPIO.BCM)
# main loop
while True:
	# GPIO.4 set as output
	GPIO.setup(4, GPIO.OUT)
	# GPIO.4 output set at low level (led ON)
	GPIO.output(4, False)
	# 200mS pause with led ON
	time.sleep(0.2)
	# GPIO.4 set as input with pull-up (led OFF)
	GPIO.setup(4, GPIO.IN, pull_up_down = GPIO.PUD_UP)
	# wait for 100 mS prior to read pushbutton status
	time.sleep(0.1)
	if GPIO.input(4):
		# if GPIO.4 is high (button NOT pressed)
		# reset counter for pushbutton pressed
		cnt = 0
	else:
		# if GPIO.4 is low (button pressed)
		# increment counter for pushbutton pressed
		cnt += 1
	# repeat pushbutton read after 100 mS (ensure isn't a spike)
	time.sleep(0.1)
	if GPIO.input(4):
		cnt = 0
	else:
		cnt += 1
	if cnt >= 10:
		# if continuously pressed for 5 seconds (cnt increments 2 times in a second)
		# GPIO.4 set as output
		GPIO.setup(4, GPIO.OUT)
		# GPIO.4 output set at low level (fix led ON as signal for user)
		GPIO.output(4, False)
		# terminate and shutdown
		call("sudo poweroff", shell=True)
		break  
	# if not terminated, wait the remaining time for 1 Sec main cycle
	time.sleep(0.6)

The main loop has 1 Sec total time : led turns ON for 200mS (so the GPIO is used as output and value is 0) then turns off when the port mode changes to input. After a delay of 100mS the pushbutton state is tested (twice) and a counter is incremented if the switch is closed; if the switch opens, the counter is reset to zero. When the counter reaches 10, so the button was continuously pressed for 5 seconds, the led is forced ON putting the GPIO in output mode with value 0. The shutdown command is then sent to the OS and the Raspberry turns off. At end of shutdown the led that was fixed ON will turn off, obviously.

Note: when you push the button, the led will turn ON ’cause you connect the cathode to gnd via 1K + 470 Ohm resistence, but you still can see the 200mS blinks due to difference of current flowing in the led when the GPIO is in input state and in output state with value = low (gnd).

Hope this will be useful for someone. It was for me :)