Socket通信(2)

PythonでSocket通信プログラムを書いてRaspberry Piで動かすことはできたが、コンソール間で文字列の送受信を行うだけではRaspberry Piを使う意味があまり無い。
やはりGPIOポートを使って何か外部装置を動かさないと面白くないので、以前試したI2C液晶を出力、押しボタンスイッチを入力として、ブレッドボード上に配線。2013-03-04 14.25.06

押しボタンスイッチはGPIOポートの17(11番ピン)と22(13番ピン)に接続して、押されていない時は10kΩのプルダウン抵抗で0V、押した時は+3.3Vが入力ポートに与えられるようにした。
pulldown

PythonでGPIOを使用する場合は、予めライブラリをインストールしておく必要がある。

pi@raspberrypi ~/PythonProjects $ sudo apt-get update
pi@raspberrypi ~/PythonProjects $ sudo apt-get install python-dev
pi@raspberrypi ~/PythonProjects $ sudo apt-get install python-rpi.gpio

プログラムは以下の通り

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import smbus    # sudo apt-get install python-smbus
import time
import socket
import select
import Queue
import sys
import RPi.GPIO as GPIO # sudo apt-get install python-rpi.gpio

class i2clcd:
    i2c = smbus.SMBus(1)   
    addr = 0x3e
    contrast = 42   # 0~63
    cur = 0
    buf = []
    def __init__(self):
        self.i2c.write_byte_data(self.addr, 0, 0x38)    # function set(IS=0)
        self.i2c.write_byte_data(self.addr, 0, 0x39)    # function set(IS=1)
        self.i2c.write_byte_data(self.addr, 0, 0x14)    # internal osc
        self.i2c.write_byte_data(self.addr, 0,
                    (0x70 | (self.contrast & 0x0f)))    # contrast
        self.i2c.write_byte_data(self.addr, 0, 0x7F)    # internal osc
        self.i2c.write_byte_data(self.addr, 0,
                    (0x54 | ((self.contrast >> 4) & 0x03)))      # contrast/icon/power
        self.i2c.write_byte_data(self.addr, 0, 0x5E)    # internal osc
        self.i2c.write_byte_data(self.addr, 0, 0x6c)    # follower control
        time.sleep(0.2)
    
    def clear(self):
        self.i2c.write_byte_data(self.addr, 0, 0x38)    # function set(IS=0)
        self.i2c.write_byte_data(self.addr, 0, 0x0C)    # Display On
        self.i2c.write_byte_data(self.addr, 0, 0x01)    # Clear Display
        self.i2c.write_byte_data(self.addr, 0, 0x06)    # Entry Mode Set
        time.sleep(0.2)

    def puts(self, msg):
        self.i2c.write_byte_data(self.addr, 0, 0x38)    # function set(IS=0)
        [self.i2c.write_byte_data(self.addr, 0x40, ord(c)) for c in msg]

    def setaddress(self, line, col):
        self.i2c.write_byte_data(self.addr, 0, 0x38)    # function set(IS=0)
        self.i2c.write_byte_data(self.addr, 0,
                    0x80 | (0x40 if line > 0 else 0) | col)
    
    def setcg(self, no, cg):
        self.i2c.write_byte_data(self.addr, 0, 0x38)    # function set(IS=0)
        self.i2c.write_byte_data(self.addr, 0, 0x40 | (no << 3))
        [self.i2c.write_byte_data(self.addr, 0x40, c) for c in cg]

    def putcg(self, line, col, no):
        self.setaddress(line, col)
        self.i2c.write_byte_data(self.addr, 0x40, no)
    
    def putc(self, c):
        if c >= chr(0x20) and c <= chr(0x7e):
            self.setaddress(1, self.cur)
            self.i2c.write_byte_data(self.addr, 0x40, ord(c))
            self.buf.append(c)
            self.cur = self.cur + 1
        if ord(c) == 0x0a or self.cur >= 16:
            self.i2c.write_byte_data(self.addr, 0, 0x38)    # function set(IS=0)
            self.i2c.write_byte_data(self.addr, 0, 0x01)    # Clear Display
            self.puts(self.buf)
            self.buf = []
            self.cur = 0

def socketio(sock, lcd):
    ilst = [sock, sys.stdin]
    olst = []
    ique = Queue.Queue() 
    oque = Queue.Queue() 
    connect = False
    sw1 = False
    sw2 = False
    while True:
        # socket i/o
        rlst, wlst, xlst = select.select(ilst, olst, [], 0)
        for si in rlst:
            # accept?
            if si == sock:
                if not connect:
                    # connect
                    conn, address = si.accept()
                    print 'connect', address
                    connect = True
                    ilst.append(conn)
                    olst.append(conn)
                else:
                    # discard
                    conn, address = si.accept()
                    conn.shutdown(socket.SHUT_RDWR)
                    conn.close
            elif si == sys.stdin:
                data = sys.stdin.readline()
                oque.put(data)
            else:
            # recv?
                data = si.recv(1024)
                if data:
                    ique.put(data)
                else:
                    # disconnect
                    print 'disconnect'
                    connect = False
                    ilst.remove(si)
                    olst.remove(si)
                    si.close
                    with ique.mutex:
                        ique.queue.clear()
                    with oque.mutex:
                        oque.queue.clear()
        for so in wlst:
            if not oque.empty():
                # send
                data = oque.get_nowait()
                so.send(data)
        # lcd
        if not ique.empty():
            data = ique.get_nowait()
            [lcd.putc(c) for c in data]
        # push sw
        if GPIO.input(17):
            if not sw1:
                oque.put('SW1 On\r\n')
            sw1 = True
        else:
            if sw1:
                oque.put('SW1 Off\r\n')
            sw1 = False
        if GPIO.input(22):
            if not sw2:
                oque.put('SW2 On\r\n')
            sw2 = True
        else:
            if sw2:
                oque.put('SW2 Off\r\n')
            sw2 = False
                        
def start(host, port):
    lcd = i2clcd()
    lcd.clear()
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(17, GPIO.IN) # GPIO17 Pin11
    GPIO.setup(22, GPIO.IN) # GPIO22 Pin15
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        sock.bind((host, port))
        sock.listen(1)
        socketio(sock, lcd)
    except KeyboardInterrupt:
        print '\nbreak'
        sock.shutdown(socket.SHUT_RDWR)
        sock.close()

if __name__ == "__main__":
    start('', 5555)

Socketから受信した文字列はI2C液晶に表示して、押しボタンスイッチが押されたら対応する文字列をクライアント側へ送信している。クライアント側のtelnet画面には、このような感じで表示されるはず。swclient

やっている事は基本的には同じだが、入出力がLCDとスイッチに変わると電子工作らしさが出てきて面白い。

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中