3

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()
Adam Haile
  • 211
  • 3
  • 8

1 Answers1

1

I've heard of this problem before (How does python GPIO bouncetime parameter work?). I think the best solution in the end was to program around the issue, adding code to detect the extra bounces (button presses).

Fred
  • 4,592
  • 19
  • 29