Tuesday, July 7, 2015

Python - GPIO control on Pidora for Raspberry Pi Model B+

Introduction

On the Raspberry Pi Model B+ board, there are many GPIO ports, here we make a simple test, and try to understand how to control GPIO ports by python?


Concept of hardware control

Generally, an IO port of an IC (e.g. MCU, ARM, GPU) could be have multiple functions. So, when we write a control program to control these IO ports, it can be in 3 steps:
1) Configure the hardware function
2) Execute the control function
3) Release the hardware function



Install RPi.GPIO package

There are many libraries(such as RPi.GPIO, WiringPi, or pigpio library) can do the GPIO control. At here, we are using RPi.GPIO library.

Usually, read or write GPIO, the user must be root.

Install packages:
# yum update
# yum install python-setuptools
# yum install python-pip
# easy_install pyerial   <== serial communication package
# yum install python-devel
# pip install RPi.GPIO   <== GPIO control package
# pip install cython
# reboot


Write a GPIO input/output control program

We write a simple test program to test the GPIO functions. We define functions:
GPIO12 (pin32) - output pin
GPIO13 (pin33) - input pin

Example code:
====================================================================
import time
import RPi.GPIO as GPIO
import kbhit # read keybard value, source code is at bottom

def InputEvent(channel):
     # got input event
     print "[INPUT] Got input event."

if __name__ == '__main__':
    # configure the GPIO hardware condition
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(12, GPIO.OUT) # GPIO12, pin32, output control
    GPIO.setup(13, GPIO.IN, pull_up_down=GPIO.PUD_UP) # GPIO13, pin33, input control
    GPIO.add_event_detect(13, GPIO.FALLING, callback=InputEvent)

    kb = KBHit()

    bPin32On = False

    while True:
        # if the 'ESC' key is pressed, stop the while loop
        if kb.kbhit():
            c = kb.getch()
            if ord(c) == 27: # ESC 
                break        # Set On/Off pin32
        print "[OUTPUT] Set output event."
        if bPin32On: # True
            GPIO.output(12,GPIO.HIGH)
        else: # False
            GPIO.output(12,GPIO.LOW)
        # switch signal
        bPin32On = not bPin32On 
        time.sleep(2.0)

    kb.set_normal_term()

    # release the hardware configuration 
    GPIO.cleanup()
====================================================================


Get the keyboard value

The KBHit class is used to monitor the non-blocking keyboard event.
Source code:
====================================================================
import os

# Windows
if os.name == 'nt':
    import msvcrt
# Posix (Linux, OS X)
else:
    import sys
    import termios
    import atexit
    from select import select

class KBHit:
     def __init__(self):
    '''Creates a KBHit object that you can call to do various keyboard things.
    '''
    if os.name == 'nt':
        pass
    else: 
        # Save the terminal settings
        self.fd = sys.stdin.fileno() 
        self.new_term = termios.tcgetattr(self.fd)
        self.old_term = termios.tcgetattr(self.fd)
        # New terminal setting unbuffered
        self.new_term[3] = (self.new_term[3] & ~termios.ICANON & ~termios.ECHO) 
        termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.new_term) 
        # Support normal-terminal reset at exit
        atexit.register(self.set_normal_term)

    def set_normal_term(self):
        ''' Resets to normal terminal. On Windows this is a no-op.          ''' 
        if os.name == 'nt': 
            pass 
        else:
            termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old_term)

    def set_curses_term(self):
        '''          switch to unbuffered terminal 
        :return:
        ''' 
        if os.name == 'nt':
            pass
        else:
            termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.new_term)

    def putch(self, ch):
        if os.name == 'nt':
            msvcrt.putch(ch.encode('ascii', 'ignore'))
        else:
            sys.stdout.write(ch)

    def getch(self):
        ''' Returns a keyboard character after kbhit() has been called.
          Should not be called in the same program as getarrow(). 
        '''
        s = ''

        if os.name == 'nt':
            return msvcrt.getch().decode('utf-8')
        else:
            return sys.stdin.read(1)

    def getche(self): 
        ch = self.getch()
        self.putch(ch) 
        return ch

    def getarrow(self):
        ''' Returns an arrow-key code after kbhit() has been called. Codes are
        0 : up
        1 : right
        2 : down 
        3 : left
        Should not be called in the same program as getch().
        '''

        if os.name == 'nt':
            msvcrt.getch() # skip 0xE0 
            c = msvcrt.getch()
            vals = [72, 77, 80, 75]
        else:
            c = sys.stdin.read(3)[2]
            vals = [65, 67, 66, 68]

        return vals.index(ord(c.decode('utf-8')))

    def kbhit(self):
        ''' Returns True if keyboard character was hit, False otherwise.
        '''
        if os.name == 'nt':
            return msvcrt.kbhit()
        else:
            dr,dw,de = select([sys.stdin], [], [], 0)
        return dr != []
====================================================================


Conclusion

Python is a powerful programming tool, it can satisfy the most requirements of our daily tasks. If you want to get the high performance of a program, assember, C, or C++ would be the best choice.


Reference
RPi.GPIO
Python.org

No comments: