I'm trying to make an interrupt based matrix keypad reader that is loosely based off of this library. However, I'm getting some really weird effects when trying to use GPIO.add_event_detect in that:
- Despite wanting the falling edge, I get the rising edge as well
- In some cases, the callback continues to fire until I release the key. Weirdly, this seems to only happen on column 3 (GPIO #22) and not the others, usually.
In my code, I'm removing the callback events as soon as I enter the callback because I have to switch the columns that were inputs with callbacks to outputs so that I can read the rows and determine the key that was pressed. It always figures out the correct key, it's just that it either fires off continuously and/or gets another call back on the rising edge (key released)... I've accommodated for the rising edge issue in code but I don't get why it should happen in the first place.
Code below, please excuse my many debug print statements:
#!/usr/bin/python
import RPi.GPIO as GPIO
class keypad():
def __init__(self):
GPIO.setmode(GPIO.BCM)
# CONSTANTS
self.KEYPAD = [
[1,2,3],
[4,5,6],
[7,8,9],
["*",0,"#"]
]
self.ROW = [18,23,24,25]
self.COLUMN = [4,17,22]
self.__setInterruptMode()
def __colRise(self, channel):
print ""
print "Chan: " + str(channel)
print "State: " + str(GPIO.input(channel))
if GPIO.input(channel) > 0:
return
#remove interrupt temporarily
#GPIO.remove_event_detect(channel)
for c in range(len(self.COLUMN)):
print "Remove: " + str(self.COLUMN[c])
GPIO.remove_event_detect(self.COLUMN[c])
#get column number
colVal = -1
for c in range(len(self.COLUMN)):
if channel == self.COLUMN[c]:
colVal = c
print "ColVal: " + str(colVal)
if colVal >=0 and colVal < len(self.COLUMN):
#set rows as intputs
for r in range(len(self.ROW)):
GPIO.setup(self.ROW[r], GPIO.IN, pull_up_down=GPIO.PUD_UP)
#set triggered column as output
GPIO.setup(channel, GPIO.OUT)
GPIO.output(channel, GPIO.LOW)
# Scan rows for pushed key/button
rowVal = -1
for r in range(len(self.ROW)):
tmpRead = GPIO.input(self.ROW[r])
if tmpRead == 0:
rowVal = r
print "RowVal: " + str(rowVal)
if rowVal >= 0 and rowVal <= 3:
print str(self.KEYPAD[rowVal][colVal])
else:
print "Invalid Row!"
else:
print "Invalid Col!"
#re-enable interrupts
self.__setInterruptMode()
def __setInterruptMode(self):
#set the first row as output low
#only first one needed as it will ground to all columns
for r in range(len(self.ROW)):
GPIO.setup(self.ROW[r], GPIO.OUT)
GPIO.output(self.ROW[r], GPIO.LOW)
#set columns as inputs and attach interrupt handlers on rising edge
for c in range(len(self.COLUMN)):
GPIO.setup(self.COLUMN[c], GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(self.COLUMN[c], GPIO.FALLING, bouncetime=500, callback=self.__colRise)
def cleanup(self):
GPIO.cleanup()
print "Cleanup done!"
import time
if __name__ == '__main__':
key = keypad()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
key.cleanup()