2022年6月11日 星期六

ePy-Lite人機介面實作 – 使用PCF8574實現4*4 KeyPad

ePy-Lite人機介面實作 使用PCF8574實現4*4 KeyPad

電路圖


程式列表

Python – PCF8574.py

 

"""

  Reference:

    MicroPython PCF8574 8-Bit I2C I/O Expander with Interrupt

     https://github.com/mcauser/micropython-pcf8574

    I2CKeyPad

     https://github.com/RobTillaart/I2CKeyPad

"""

 

from machine import I2C, Pin

 

I2C_KEYPAD_NOKEY  =  16

I2C_KEYPAD_FAIL   =  17

keyDe = ['1','2','3','A',

         '4','5','6','B',

         '7','8','9','C',

         '*','0','#','D',

         'N','F']

 

keymap = [0x77,0xB7,0xD7,0xE7,

          0x7B,0xBB,0xDB,0xEB,

          0x7D,0xBD,0xDD,0xED,

          0x7E,0xBE,0xDE,0xEE]

 

class PCF8574:

 

  def __init__(self, i2c, address=0x20):

    self._i2c = i2c

    self._address = address

    self._port = bytearray(1)

    if i2c.scan().count(address) == 0:

      raise OSError('PCF8574 not found at I2C address {:#x}'.format(address))

    self._lastKey = I2C_KEYPAD_NOKEY

 

    #  mask = 4 rows as input pull up, 4 columns as output

    self._port[0] = 0xF0

    self._write()

 

  def port(self, value=None):

    if value is None:

      self._read()

      return self._port[0]

    else:

      self._port[0] = value & 0xFF

      self._write()

 

  def pin(self, pin, value=None):

    pin = self.validate_pin(pin)

    if value is None:

      self._read()

      return (self._port[0] >> pin) & 1

    else:

      if value:

        self._port[0] |= (1 << (pin))

      else:

        self._port[0] &= ~(1 << (pin))

      self._write()

 

  def toggle(self, pin):

    pin = self.validate_pin(pin)

    self._port[0] ^= (1 << (pin))

    self._write()

 

  def validate_pin(self, pin):

    # pin valid range 0..7

    if not 0 <= pin <= 7:

      raise ValueError('Invalid pin {}. Use 0-7.'.format(pin))

    return pin

 

  def _read(self):

    self._i2c.recv(self._port,self._address)

 

  def _write(self):

    self._i2c.send(self._port,self._address)

 

  def getKey(self,key):

    return keyDe[key]

 

  # to check "press any key"

  def isPressed(self):

    #  mask = 4 rows as input pull up, 4 columns as output

    self._port[0] = 0xF0

    self._write()

    self._read()

    rows = self._port[0]

    if (rows == 0xFF) :

      return False

    return (rows != 0xF0);

 

  def getKey4x4(self):

    #  key = row + 4 x col

    key = 0

 

    #  mask = 4 rows as input pull up, 4 columns as output

    self._port[0] = 0xF0

    self._write()

    self._read()

    rows = self._port[0]

 

    #  check if single line has gone low.

    if (rows == 0xF0):

      return I2C_KEYPAD_NOKEY

    elif (rows == 0x70):

      key = 0

    elif (rows == 0xB0):

      key = 1

    elif (rows == 0xD0):

      key = 2

    elif (rows == 0xE0):

      key = 3

    else:

      return I2C_KEYPAD_FAIL;

 

    # 4 columns as input pull up, 4 rows as output

    self._port[0] = 0x0F

    self._write()

    self._read()

    cols = self._port[0]

 

    # check if single line has gone low.

    if (cols == 0x0F):

      return I2C_KEYPAD_NOKEY

    elif (cols == 0x07):

      key += 0

    elif (cols == 0x0B):

      key += 4

    elif (cols == 0x0D):

      key += 8

    elif (cols == 0x0E):

      key += 12

    else:

      return I2C_KEYPAD_FAIL

 

    self._lastKey = key

 

    return key   # 0..15

 

  def getKey4_4(self):

    key = I2C_KEYPAD_NOKEY

    portout = bytearray(1)

 

    for i in range(4) :

      portout[0] = ~(1<<i)

      self._port[0] = portout[0]

      self._write()

      self._read()

      portin = self._port[0]

 

      if portin != portout[0] :

        try:

          key = keymap.index(portin)

        except:

          key = I2C_KEYPAD_FAIL

        break

 

    return key   # 0..15

 

Python – epy-Lite_PCF8574.py

"""

  epy-Lite_PCF8574.py

 

  ePy-Lite     PCF8574        KEYPAD

  ----------  +--------+    +--------+

  3V3         | VCC   0|----|R       |

  P17_SCL0    | SCL   1|----|O       |

  P16_SDA0    | SDA   2|----|W       |

  GND         | GND   3|----|S       |

              |        |    |        |

              | INT   4|----|C       |

              |       5|----|O       |

              |       6|----|L       |

              |       7|----|S       |

              +--------+    +--------+

"""

 

from machine import Switch  #Get button KEY library

from machine import I2C, Pin, LED

from machine import Timer

import utime

import pcf8574

 

KEYPAD_ADDRESS = 0x20

 

def tick3(timer):

  global TimerDone

  TimerDone = True

  return TimerDone

 

def key_int():

  global KeyADone

  KeyADone = True

 

# Start Function

if __name__ == '__main__':

  ledY = LED('ledy')

  ledY.off()

 

  KeyA = Switch('keya')    #Create button A

  KeyA.callback(key_int)

  KeyADone = False

 

  timer = Timer(3,freq=10)

  timer.callback(tick3)

  TimerDone = False

 

  # Declaration I2C

  i2c_0 = I2C(0,I2C.MASTER,baudrate=100000)  #Create I2C0 Master Mode, Baudrate=100kHz

  pcf = pcf8574.PCF8574(i2c_0, KEYPAD_ADDRESS)

  LastKey = pcf8574.I2C_KEYPAD_NOKEY

  keyChange = False

 

  print("--- Start ---")

  while True:

    if TimerDone == True:

      TimerDone = False

      # read all pins at once as 8-bit int

      # print(pcf.port())

 

      getKey=pcf.getKey4x4()

      # getKey=pcf.getKey4_4()

      # print(getKey)

      if (getKey < pcf8574.I2C_KEYPAD_NOKEY) :

        NewKey = pcf.getKey(getKey)

        if NewKey != LastKey :

          LastKey = NewKey

          keyChange = True

          print("press " + NewKey + " key")

        else :

          print("press old key")

      elif ((getKey == pcf8574.I2C_KEYPAD_NOKEY)and(keyChange == True)) :

        keyChange = False

        print("release")

 

    if KeyADone == True:      #Press A Key

      break

 

  i2c_0.deinit()

  KeyA.callback(None)

  print("--- End ---")

 

Python – epy-Lite_PCF8574_Int.py

"""

  epy-Lite_PCF8574_Int.py

 

  ePy-Lite     PCF8574        KEYPAD

  ----------  +--------+    +--------+

  3V3         | VCC   0|----|R       |

  P17_SCL0    | SCL   1|----|O       |

  P16_SDA0    | SDA   2|----|W       |

  GND         | GND   3|----|S       |

              |        |    |        |

  P18         | INT   4|----|C       |

              |       5|----|O       |

              |       6|----|L       |

              |       7|----|S       |

              +--------+    +--------+

"""

 

from machine import Switch  #Get button KEY library

from machine import I2C, Pin, LED

from machine import Timer

import utime

import pcf8574

 

KEYPAD_ADDRESS = 0x20

 

def tick3(timer):

  global TimerDone

  TimerDone = True

  return TimerDone

 

def key_int():

  global KeyADone

  KeyADone = True

 

def pin_callback_fun(pin):

  global KeyPadIntDone

  ledY.toggle()

  KeyPadIntDone = True

 

# Start Function

if __name__ == '__main__':

  ledY = LED('ledy')

  ledY.off()

 

  KeyA = Switch('keya')    #Create button A

  KeyA.callback(key_int)

  KeyADone = False

 

  timer = Timer(3,freq=10)

  timer.callback(tick3)

  TimerDone = False

 

  # Declaration I2C

  i2c_0 = I2C(0,I2C.MASTER,baudrate=100000)  #Create I2C0 Master Mode, Baudrate=100kHz

  pcf = pcf8574.PCF8574(i2c_0, KEYPAD_ADDRESS)

  LastKey = pcf8574.I2C_KEYPAD_NOKEY

  keyChange = False

 

  KeyPadInt = Pin(Pin.epy.P18,Pin.IN,Pin.PULL_UP)

  KeyPadInt.irq(handler=pin_callback_fun , trigger=Pin.IRQ_FALLING)

  KeyPadIntDone = False

 

  print("--- Start ---")

  while True:

    if TimerDone == True:

      TimerDone = False

 

    if KeyPadIntDone == True:

      KeyPadIntDone = False

      getKey=pcf.getKey4x4()

      # getKey=pcf.getKey4_4()

      if (getKey < pcf8574.I2C_KEYPAD_NOKEY) :

        NewKey = pcf.getKey(getKey)

        if NewKey != LastKey :

          LastKey = NewKey

          keyChange = True

          print("press " + NewKey + " key")

        else :

          print("press old key")

      elif ((getKey == pcf8574.I2C_KEYPAD_NOKEY)and(keyChange == True)) :

        keyChange = False

        print("release")

 

    if KeyADone == True:      #Press A Key

      break

 

  i2c_0.deinit()

  KeyA.callback(None)

  print("--- End ---")

執行結果