「#ラズパイ」タグアーカイブ

【ラズパイ】スイッチを動かしてみる。

前回までの状況はこちら。

前回はスイッチをはんだ付けして、ブレッドボードに取り付けました。

今回はこのスイッチを動かしてみます。

import RPi.GPIO as GPIO
import time

X_p = 0
Y_p = 0
Z_p = 0
A_p = 0
B_p = 0
C_p = 0
D_p = 0

def PinsInit(x, y, z, a, b, c, d):
    global X_p
    global Y_p
    global Z_p
    global A_p
    global B_p
    global C_p
    global D_p

    X_p = x
    Y_p = y
    Z_p = z
    A_p = a
    B_p = b
    C_p = c
    D_p = d

    GPIO.setup(X_p, GPIO.OUT)
    GPIO.setup(Y_p, GPIO.OUT)
    GPIO.setup(Z_p, GPIO.OUT)
    GPIO.setup(A_p, GPIO.IN)
    GPIO.setup(B_p, GPIO.IN)
    GPIO.setup(C_p, GPIO.IN)
    GPIO.setup(D_p, GPIO.IN)

    GPIO.output(X_p, GPIO.HIGH)
    GPIO.output(Y_p, GPIO.HIGH)
    GPIO.output(Z_p, GPIO.HIGH)

def SW_Sample():
    col = 1
    swState = [0] * 12
    while True:
        if col == 1:
            GPIO.output(X_p, GPIO.LOW)
            GPIO.output(Y_p, GPIO.HIGH)
            GPIO.output(Z_p, GPIO.HIGH)
        elif col == 2:
            GPIO.output(X_p, GPIO.HIGH)
            GPIO.output(Y_p, GPIO.LOW)
            GPIO.output(Z_p, GPIO.HIGH)
        else:
            GPIO.output(X_p, GPIO.HIGH)
            GPIO.output(Y_p, GPIO.HIGH)
            GPIO.output(Z_p, GPIO.LOW)

        # 1押下
        if swState[1] == 0 and col == 1 and GPIO.input(D_p) == 0:
            # チャタリング回避
            time.sleep(0.05)
            if GPIO.input(D_p) == 0:
                print("push 1")
                swState[1] = 1
        # 1押下戻し
        elif swState[1] == 1 and col == 1 and GPIO.input(D_p) == 1:
            print("release 1")
            swState[1] = 0
        # 2押下
        if swState[2] == 0 and col == 2 and GPIO.input(D_p) == 0:
            # チャタリング回避
            time.sleep(0.05)
            if GPIO.input(D_p) == 0:
                print("push 2")
                swState[2] = 1
        # 2押下戻し
        elif swState[2] == 1 and col == 2 and GPIO.input(D_p) == 1:
            print("release 2")
            swState[2] = 0
        # 3押下
        if swState[3] == 0 and col == 3 and GPIO.input(D_p) == 0:
            # チャタリング回避
            time.sleep(0.05)
            if GPIO.input(D_p) == 0:
                print("push 3")
                swState[3] = 1
        # 3押下戻し
        elif swState[3] == 1 and col == 3 and GPIO.input(D_p) == 1:
            print("release 3")
            swState[3] = 0
        # 4押下
        if swState[4] == 0 and col == 1 and GPIO.input(C_p) == 0:
            # チャタリング回避
            time.sleep(0.05)
            if GPIO.input(C_p) == 0:
                print("push 4")
                swState[4] = 1
        # 4押下戻し
        elif swState[4] == 1 and col == 1 and GPIO.input(C_p) == 1:
            print("release 4")
            swState[4] = 0
        # 5押下
        if swState[5] == 0 and col == 2 and GPIO.input(C_p) == 0:
            # チャタリング回避
            time.sleep(0.05)
            if GPIO.input(C_p) == 0:
                print("push 5")
                swState[5] = 1
        # 5押下戻し
        elif swState[5] == 1 and col == 2 and GPIO.input(C_p) == 1:
            print("release 5")
            swState[5] = 0
        # 6押下
        if swState[6] == 0 and col == 3 and GPIO.input(C_p) == 0:
            # チャタリング回避
            time.sleep(0.05)
            if GPIO.input(C_p) == 0:
                print("push 6")
                swState[6] = 1
        # 6押下戻し
        elif swState[6] == 1 and col == 3 and GPIO.input(C_p) == 1:
            print("release 6")
            swState[6] = 0
        # 7押下
        if swState[7] == 0 and col == 1 and GPIO.input(B_p) == 0:
            # チャタリング回避
            time.sleep(0.05)
            if GPIO.input(B_p) == 0:
                print("push 7")
                swState[7] = 1
        # 7押下戻し
        elif swState[7] == 1 and col == 1 and GPIO.input(B_p) == 1:
            print("release 7")
            swState[7] = 0
        # 8押下
        if swState[8] == 0 and col == 2 and GPIO.input(B_p) == 0:
            # チャタリング回避
            time.sleep(0.05)
            if GPIO.input(B_p) == 0:
                print("push 8")
                swState[8] = 1
        # 8押下戻し
        elif swState[8] == 1 and col == 2 and GPIO.input(B_p) == 1:
            print("release 8")
            swState[8] = 0
        # 9押下
        if swState[9] == 0 and col == 3 and GPIO.input(B_p) == 0:
            # チャタリング回避
            time.sleep(0.05)
            if GPIO.input(B_p) == 0:
                print("push 9")
                swState[9] = 1
        # 9押下戻し
        elif swState[9] == 1 and col == 3 and GPIO.input(B_p) == 1:
            print("release 9")
            swState[9] = 0
        # *押下
        if swState[10] == 0 and col == 1 and GPIO.input(A_p) == 0:
            # チャタリング回避
            time.sleep(0.05)
            if GPIO.input(A_p) == 0:
                print("push *")
                swState[10] = 1
        # *押下戻し
        elif swState[10] == 1 and col == 1 and GPIO.input(A_p) == 1:
            print("release *")
            swState[10] = 0
        # 0押下
        if swState[0] == 0 and col == 2 and GPIO.input(A_p) == 0:
            # チャタリング回避
            time.sleep(0.05)
            if GPIO.input(A_p) == 0:
                print("push 0")
                swState[0] = 1
        # 0押下戻し
        elif swState[0] == 1 and col == 2 and GPIO.input(A_p) == 1:
            print("release 0")
            swState[0] = 0
        # #押下
        if swState[11] == 0 and col == 3 and GPIO.input(A_p) == 0:
            # チャタリング回避
            time.sleep(0.05)
            if GPIO.input(A_p) == 0:
                print("push #")
                swState[11] = 1
        # #押下戻し
        elif swState[11] == 1 and col == 3 and GPIO.input(A_p) == 1:
            print("release #")
            swState[11] = 0

        col += 1
        if col > 3:
            col = 1
def __main__():
    GPIO.setmode(GPIO.BCM)
    GLCD.PinsInit(20, 7, 8, 9, 18, 19, 10, 11, 12, 13, 14, 15, 16, 17)
    GLCD.GLCDInit()
    GLCD.GLCDDisplayClear()

    roop = 10 * 60 * 60
    try:
        while True:
            SW.PinsInit(21, 22, 23, 24, 25, 26, 27)
            SW.SW_Sample()
            time.sleep(0.1)
    except KeyboardInterrupt:
        GLCD.GLCDDisplayClear()
        GPIO.cleanup()

__main__()

思った以上に長くなった。

まずピン設定ですが、X,Y,Zに繋がるピンが出力用、A,B,C,Dに繋がるピンが入力用になります。

そして、X,Y,ZはHIGHで初期化します。

サンプル処理では、whileの無限ループの中で、

X=LOW、Y=HIGH、Z=HIGH

X=HIGH、Y=LOW、Z=HIGH

X=HIGH、Y=HIGH、Z=LOW

を繰り返します。

その中で、A~Dの中にLOWの信号があれば、X,Y,ZのLOW出力の状態とA~DのLOW入力の状態を

この表に当てはめて、押下されたボタンを特定します。

ただ、無限ループで動いているので、普通に信号だけを見ていると、ものすごい数の入力をプログラムが検出してしまうので、スイッチの状態を保持し、その値と変化があるか、ということを確認する必要があります。

また、物理スイッチが入ったとき、信号が一瞬の短い間、HIGH/LOWを繰り返すような信号になります。

これをチャタリングといいます。

何も対策していないと、スイッチ1回しか押していなくても、プログラムは数回スイッチを押したと判断してしまうことがあります。

なので、それを回避するために、スイッチの検出を行った後、50ミリ秒後にもう一度信号を確認、信号に変化が無ければスイッチオンとする、という風にする必要があります。

実行結果はこうなりました。

pi@raspberrypi:~/RaspiDisplayMonitor $ python3 main.py
push 1
release 1
push 2
release 2
push 3
release 3
push 4
release 4
push 5
release 5
push 6
release 6
push 7
release 7
push 8
release 8
push 9
release 9
push *
release *
push 0
release 0
push #
release #
push 1
push #
release 1
release #
push 2
push 8
release 8
push 9
release 9
release 2

同時押しも動きましたね。

これで基本的な動きは出来ました。

次回は、これをモジュール化して今までのプログラムと組み合わせていましょう。

【ラズパイ】スイッチを設置して使用できるようにする。

次は、スイッチを繋げてみます。

購入したのはスイッチが12個付いている簡易的なキットです。

この基板に部品を設置して、はんだ付けします。

ダイオード。

向きに注意。

向きを間違えると動きません。

黒い印が付いている方がカソードになります。

基板に向きがきちんと書かれているので、それに従って配置します。

抵抗。

で、これがスイッチ。

はんだ付け完了。

ブレッドボードに設置。

さらに配線も接続します。

もうこれ以上部品を設置するのは不可能ですね。

ちなみに、配線は以下の様になっています。

12SWとあるのが、今回追加したスイッチモジュールです。

スイッチが押されたかの確認は、

X=LOW、Y=HIGH、Z=HIGH

X=HIGH、Y=LOW、Z=HIGH

X=HIGH、Y=HIGH、Z=LOW

の状態を繰り返し、そのときのA,B,C,Dの出力状態(押されたときにLOWになる)を確認します。

XYZとABCDの組み合わせはこんな感じです。

回路はこんな感じ。

これを見たところ、おそらく、スイッチを押していないときは、▼から入ってきた入力がそのままA~Dに流れていく(HIGH)のでしょう。

そして、X~YがLOWの時にスイッチを押すと、▼の入力がスイッチの方へ流れていくので、その結果、A~DがLOWとなるのでは、と思います。

まぁ、この回路を流用すれば、自分で部品を調達してスイッチ回路を組むことも可能でしょう。

次回はこれを動かすためのプログラムコードを作成します。

【ラズパイ】【GLCD】倉田ましろを書いてみる。

こちらのネームクリップの絵がシンプルなデザインなので、この絵を表示させてみたいと思いました。

https://bang-dream.com/goods/1883

InkScapeで画像からトレースして線を書いて、

ドット絵ナニカのサイトで64×64ドットの画像に変換してExcelで出力。

http://dot-e-nanika.com

これを8×8に区分けして、16進数のドットパターンデータに変換(手作業)。

Array = [
    [
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
        0x40, 0x40, 0x20, 0x20, 0x10, 0x10, 0x20, 0x20,
        0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    ],
    [
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40,
        0x20, 0x10, 0x08, 0x04, 0x02, 0x82, 0x81, 0x40,
        0x40, 0x20, 0x20, 0x10, 0x08, 0x04, 0x03, 0x00,
        0x80, 0x41, 0x3B, 0x20, 0x20, 0x20, 0x20, 0x40,
        0x40, 0x40, 0x40, 0x80, 0x80, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    ],
    [
def drowMashiro():
    for page in range(8):
        for addr in range(64):
            if addr < 32:
                SelectIC(1)
                SetPage(page)
                SetAddress(addr + 32)
            else:
                SelectIC(2)
                SetPage(page)
                SetAddress(addr - 32)
            WriteData(mashiro.Array[page][addr])

で、表示できました。

なかなか良い感じに映っております。

【ラズパイ】GLCDに時刻・気温・湿度・天候情報を表示する

前回までやっていたGLCDをライブラリ化して、gitHubを更新しました。

https://github.com/takishita2nd/GLCD

このGLCDライブラリを使ってGLCDに時刻、気温、湿度、天候情報を表示させたいと思います。

まず、温度、湿度を表示させるために、AM2320周りもライブラリ化しました。

import time
import smbus

i2c = smbus.SMBus(1)
address = 0x5c

def GetTemp():
    loop = True
    block = []
    while loop:
        try:
            i2c.write_i2c_block_data(address, 0x00,[])
            i2c.write_i2c_block_data(address, 0x03,[0x02, 0x02])

            time.sleep(0.05)

            block = i2c.read_i2c_block_data(address, 0, 4)
            loop = False
        except IOError:
            pass
    temp =  block[2] << 8 | block[3]
    return format(temp / 10)

def GetHum():
    loop = True
    block = []
    while loop:
        try:
            i2c.write_i2c_block_data(address, 0x00,[])
            i2c.write_i2c_block_data(address, 0x03,[0x00, 0x02])

            time.sleep(0.05)

            block = i2c.read_i2c_block_data(address, 0, 4)
            loop = False
        except IOError:
            pass
    hum =  block[2] << 8 | block[3]
    return format(hum / 10)

天候データはopenWeatherのWebAPIを利用します。

https://openweathermap.org

openWeatherにした理由は、今のGLCDが半角アスキー文字しか表示できないので、どうしても英語で表示させる必要があります。

なので、海外の英語のAPIを利用させて貰いました。

アクセス回数を絞れば無料で利用できます。

import json
import urllib.request

weather = ""
temp_min = 0
temp_max = 0
temp = 0

def RequestAPI():
    global weather
    global temp_max
    global temp_min
    global temp

    url = 'http://api.openweathermap.org/data/2.5/weather?lat=XXX&lon=XXX&units=metric&appid=XXXXXXXX'
    req = urllib.request.Request(url)
    with urllib.request.urlopen(req) as res:
        body = json.load(res)
        weather = body['weather'][0]['main']
        temp_min = body['main']['temp_min']
        temp_max = body['main']['temp_max']
        temp = body['main']['temp']

def GetWeather():
    return weather

def GetTemp():
    return temp

def GetTempMin():
    return temp_min

def GetTempMax():
    return temp_max

個人情報を含んでいるので、クエリパラメータは書き換えてあります。

これらを使って、GLCDに表示させます。

import RPi.GPIO as GPIO
import time
import datetime
import calendar
import GLCD
import AM2320
import Weather


def __main__():
    GLCD.PinsInit(20, 7, 8, 9, 18, 19, 10, 11, 12, 13, 14, 15, 16, 17)
    GLCD.GLCDInit()
    GLCD.GLCDDisplayClear()

    roop = 10 * 60 * 60
    try:
        while True:
            if roop >= 10 * 60 * 60:
                Weather.RequestAPI()
                weather = Weather.GetWeather()
                temp = Weather.GetTemp()
                roop = 0

            GLCD.GLCDPuts(1, 0, "Date :")
            GLCD.GLCDPuts(10, 8, datetime.datetime.now().strftime('%Y:%m:%d %A'))
            GLCD.GLCDPuts(1, 16, "Weather :")
            GLCD.GLCDPuts(10,24, weather)
            GLCD.GLCDPuts(10,32, "Temp : " + format(temp) + 'C')
            GLCD.GLCDPuts(1, 40, "Time : " + datetime.datetime.now().strftime('%H:%M:%S'))
            GLCD.GLCDPuts(1, 48, "Humidity    : " + AM2320.GetHum() + '%')
            GLCD.GLCDPuts(1, 56, "Temperature : " + AM2320.GetTemp() + 'C')

            roop += 1
            time.sleep(0.1)
    except KeyboardInterrupt:
        GLCD.GLCDDisplayClear()
        GPIO.cleanup()

__main__()

フーフーって聞こえているのは、AM2320に息を吹きかけています。

なんか良い感じだぞ。

配線の見た目をなんとかすれば、そのままインテリアとして使えるかもしれない。

【ラズパイ】【温湿度計】温湿度計AM2320を使用する。

さて、GLCDもある程度やり尽くしたので、新しいデバイスを使用することにしました。

温湿度計AM2320です。

設置。

配線はこんな感じ。

このデバイスはI2Cバスを使用して温湿度を取得することができます。

I2Cバスってなんぞや?ということなんですが、SDL/SDAの2ピンを使ってデータを送受信できるみたいです。

具体的には、SDLにクロック信号と組み合わせてSDAにデータを送信して・・・

って難しいことを考えなくても、ラズパイにはI2Cに対応したモジュール・ライブラリがあるんです。

ちょっと設定を弄るんですけどね。

こちらのサイトを参考にさせて頂きました。

https://qiita.com/twinoze/items/c960eea23c57e342ea4b

先人の知恵を借りるのは大事。

sudo raspi-config

でコンフィグメニューが出るので、

これでI2Cが有効になります。

i2cdetect -y 1

5cと表示できれば認識しているとのことです。

が、100%認識できるかというと、大体50%ぐらいの確立で認識できないケースがありました。

バスリピータを使えば回避できるとのことですが、こう何度も発注を繰り返すと送料が高く付いてしまうので、プログラム側で回避することにしました。

このようにサンプルコードを作成しました。

import time
import smbus

i2c = smbus.SMBus(1)
address = 0x5c

loop = True
block = []
while loop:
    try:
        i2c.write_i2c_block_data(address, 0x00,[])
        i2c.write_i2c_block_data(address, 0x03,[0x00, 0x04])

        time.sleep(0.05)

        block = i2c.read_i2c_block_data(address, 0, 6)
        loop = False
    except IOError:
        pass

hum = block[2] << 8 | block[3]
temp = block[4] << 8 | block[5]

print('hum : ' + format( hum/10) + ' %Rh')
print('temp: ' + format(temp/10) + ' digC')

smbusというライブラリを使えば、I2Cバスへのアクセスが簡単になります。

タイミングチャートとか意識する必要なく、全部ライブラリでやってくれます。

やるべきことは、

  • 初期化
  • ファンクションコード0x03にスタートアドレスとレジスタ数を書き込み
  • データを読み取り

これだけ。

これはデータシートにある、

この部分に合致しています。

そして、I2Cにアクセスできない場合がある問題はtry/catch処理で回避させました。

エラーが発生したら、アクセスが成功するまで再試行を繰り返します。

これで100%アクセスに成功できます。

さて、次回はこれをライブラリ化させてGLCDに表示させましょうか。

【ラズパイ】【GLCD】画面に時刻を表示する

前回までの状況はこちら。

最新ソースをgitHubにアップしました。

https://github.com/takishita2nd/GLCD

ここまで来たら、時刻を表示するくらい簡単にできると思うんよ。

def __main():
    PinsInit(20, 7, 8, 9, 18, 19, 10, 11, 12, 13, 14, 15, 16, 17)
    GLCDInit()
    GLCDDisplayClear()
    GLCDBox(0, 0, 127, 62)
    GLCDLine(0, 15, 127, 15)

    try:
        while True:
            GLCDPuts(30, 38, datetime.datetime.now().strftime('%H:%M:%S'))
            time.sleep(0.1)
    except KeyboardInterrupt:
        GLCDDisplayClear()
        GPIO.cleanup()

うん、これでラズパイで時計が作れる。

【ラズパイ】【GLCD】画面に直線を引く

前回までの状況はこちら。

最新ソースをgitHubにアップしました。

https://github.com/takishita2nd/GLCD

今回は画面に直線を引きます。

始点と終点の座標を与えると、直線を引くようにします。

傾きがあった場合でも引けるようにします。

といっても、サンプルをPythonに書き換えただけですが。

def GLCDLine(Xp0, Yp0, Xp1, Yp1):
    #差分の大きい方を求める
    steep = (abs(Yp1 - Yp0) > abs(Xp1 - Xp0))
    #X,Yの入れ替え
    if steep == True:
        x = Xp0
        Xp0 = Yp0
        Yp0 = x
        x = Xp1
        Xp1 = Yp1
        Yp1 = x
    if Xp0 > Xp1:
        x = Xp0
        Xp0 = Xp1
        Xp1 = x
        x = Yp0
        Yp0 = Yp1
        Yp1 = x
    #傾き計算
    deltax = Xp1 - Xp0
    deltay = abs(Yp1 - Yp0)
    er = 0
    y = Yp0
    ystep = 0
    #傾きでステップの正負を切り替え
    if Yp0 < Yp1:
        ystep = 1
    else:
        ystep = -1
    #直線を点で描画
    for x in range(Xp0, Xp1 + 1):
        if steep == True:
            GLCDPutPixel(y, x)
        else:
            GLCDPutPixel(x, y)
        er += deltay
        if (er << 1) >= deltax:
            y += ystep
            er -= deltax

まずどちらの方向に描画していくか(縦or横)を判定します。

基本的に絶対値が大きい方向に描画していきます。

縦方向に描画していく場合はx/yを入れ替えます。

あとは傾きに応じてy/xを加算しながらx/y方向に描画していきます。

def __main():
    PinsInit(20, 7, 8, 9, 18, 19, 10, 11, 12, 13, 14, 15, 16, 17)
    GLCDInit()
    GLCDDisplayClear()
    GLCDBox(0, 0, 127, 63)
    GLCDLine(0, 15, 127, 15)

    try:
        while True:
            time.sleep(1.0)
    except KeyboardInterrupt:
        GLCDDisplayClear()
        GPIO.cleanup()
def __main():
    PinsInit(20, 7, 8, 9, 18, 19, 10, 11, 12, 13, 14, 15, 16, 17)
    GLCDInit()
    GLCDDisplayClear()
    GLCDBox(0, 0, 127, 63)
    GLCDLine(0, 15, 127, 18)

    try:
        while True:
            time.sleep(1.0)
    except KeyboardInterrupt:
        GLCDDisplayClear()
        GPIO.cleanup()

【ラズパイ】【GLCD】画面に四角の線を引く※追記あり

前回までの状況はこちら。

最新ソースをgitHubにアップしました。

https://github.com/takishita2nd/GLCD

画面に四角を書きます。

これもこちらのAudiunoのサンプルコードをPython用に書き換えた物です。

def GLCDBox(Xp0, Yp0, Xp1, Yp1):
    for i in range(Xp0, Xp1 + 1):
        GLCDPutPixel(i, Yp0)
        GLCDPutPixel(i, Yp1)
    for i in range(Yp0 + 1, Yp1):
        GLCDPutPixel(Xp0, i)
        GLCDPutPixel(Xp1, i)

def GLCDPutPixel(Xp, Yp):
    #ラインの選択処理
    L = 1 << (Yp % 8)
    #LCDに表示するアドレスの位置をセットする
    SetLocation(Xp, Yp)
    #LCD画面の現在表示内容に指定位置のビット(L)をON(XOR)させ、そのデータをLCDに送る
    L = ReadData() | L
    SetAddress(SetCol)
    WriteData(L)

def ReadData():
    #データピンを入力に設定
    for i in range(8):
        GPIO.setup(DATA_p[i], GPIO.IN)
    #読み込みモードにする
    GPIO.output(RW_p, GPIO.HIGH)
    GPIO.output(RS_p, GPIO.HIGH)
    #データを読み込む
    GPIO.output(E_p, GPIO.HIGH)
    GPIO.output(E_p, GPIO.LOW)
    ans = 0
    GPIO.output(E_p, GPIO.HIGH)
    for i in range(8):
        ans = ans | (GPIO.input(DATA_p[i]) << i)
    GPIO.output(E_p, GPIO.LOW)
    #書き込みモードにする
    GPIO.output(RW_p, GPIO.LOW)
    #データピンを出力に設定
    for i in range(8):
        GPIO.setup(DATA_p[i], GPIO.OUT)
    return ans

ピクセルを置く際には、一度表示させているデータを取得し、そのデータのORをとって表示させます。

※サンプルではここがXORになっていたけど、どっちが正しいんだろ?

READする時は、ピンのモードを出力から入力に切り替える必要があります。

実行結果はこうなりました。

んんー?なんかおかしいぞ?

もしかして、信号の読み取りでおかしなデータを読み込んでいるんじゃ無いか?

タイミングチャートを確認する。

ここを確認すると、E信号のHIGHにしてからLOWにするまでの時間(tWH、tWL)が最低450nsと書かれています。

なので、この間に0.5ms(500ns)をsleepを入れてみます。※追記あり

EWAIT = 0.0005
def ReadData():
    #データピンを入力に設定
    for i in range(8):
        GPIO.setup(DATA_p[i], GPIO.IN)
    #読み込みモードにする
    GPIO.output(RW_p, GPIO.HIGH)
    GPIO.output(RS_p, GPIO.HIGH)
    #データを読み込む
    GPIO.output(E_p, GPIO.HIGH)
    time.sleep(EWAIT) #★
    GPIO.output(E_p, GPIO.LOW)
    ans = 0
    GPIO.output(E_p, GPIO.HIGH)
    time.sleep(EWAIT) #★
    for i in range(8):
        ans = ans | (GPIO.input(DATA_p[i]) << i)
    GPIO.output(E_p, GPIO.LOW)
    #書き込みモードにする
    GPIO.output(RW_p, GPIO.LOW)
    #データピンを出力に設定
    for i in range(8):
        GPIO.setup(DATA_p[i], GPIO.OUT)
    return ans

def command(value, mode):
    GPIO.output(RS_p, mode)
    for i in range(8):
        GPIO.output(DATA_p[i], (value >> i) & 0x01)
    GPIO.output(E_p, GPIO.HIGH)
    time.sleep(EWAIT) #★
    GPIO.output(E_p, GPIO.LOW)

モッサリしてる。

もう一度タイミングチャートを確認。

tNはEをHIGHにしてからデータ端子0-7が出力されるまでの時間です。

この表を見れば最大25nsと書いてあります。

なので、E信号のsleep時間を0.03ms(30ns)まで縮めてみましょう。※追記あり

EWAIT = 0.00003

だいぶマシになったのではないでしょうか

動作も安定してオールOKです。

いやーすごい濃いことやってるなー

※追記

ああああ!

単位間違えてるじゃん!

これじゃあμsじゃん!

正しくnsに修正。

EWAIT = 0.0000005

【ラズパイ】【GLCD】ASCII文字列を表示する

前回までの状況はこちら。

今回は複数の文字を表示させます。

これもサンプルコードをPython用に書き換えました。

def GLCDPuts(Xp, Yp, text):
    x = Xp
    for s in text:
        GLCDPutc(x, Yp, s)
        x += 6

やってることはそんなに難しくはありませんでした。

文字と文字の間隔は1ドット空けています。

def __main():
    PinsInit(20, 7, 8, 9, 18, 19, 10, 11, 12, 13, 14, 15, 16, 17)
    GLCDInit()
    GLCDDisplayClear()
    GLCDPuts(40, 10, "ABCDE")

    try:
        while True:
            time.sleep(1.0)
    except KeyboardInterrupt:
        GPIO.cleanup()

【ラズパイ】【GLCD】ASCII文字を表示する

前回までの状況はこちら。

PythonコードをgitHubにアップしました。

https://github.com/takishita2nd/GLCD

サンプルソースにフォントのビットパターンデータがありましたので、これを置換処理を使ってPython用に書き換えました。

https://github.com/takishita2nd/GLCD/blob/master/Font.py

これを使用して、ディスプレイにアスキー文字を表示させます。

    [ 0x7e, 0x11, 0x11, 0x11, 0x7e ], # A   0x41

1文字8×5のサイズになっているようです。

お試しで表示させてみました。

chara = [0x7e, 0x11, 0x11, 0x11, 0x7e]

def __main():
    PinsInit(20, 7, 8, 9, 18, 19, 10, 11, 12, 13, 14, 15, 16, 17)
    GLCDInit()
    GLCDDisplayClear()
    addr = 0
    SelectIC(1)
    SetPage(0)
    for c in chara:
        SetAddress(addr)
        WriteData(c)
        addr += 1

    try:
        while True:
            time.sleep(1.0)
    except KeyboardInterrupt:
        GPIO.cleanup()

このデータを表示するサンプルコードをPython用に書き換えました。

def GLCDPutc(Xp, Yp, c):
    code = ord(c)
    #ページ内のラインを選択
    L = Yp % 8
    #8×5のキャラクター文字を描画する
    for i in range(5):
        SetLocation(Xp + i, Yp)
        f = Font.Array[code - 0x20][i] << L
        WriteData(f)
        if (L != 0) & (SetPg < 7):
            SetPage(SetPg + 1)
            SetAddress(SetCol)
            f = Font.Array[code - 0x20][i] >> (8 - L)
            WriteData(f)
def SetLocation(Xp, Yp):
    global SetPg
    global SetCol
    cs = 0
    #チップの選択とカラムのアドレスの処理を行う
    if Xp < 64:
        #左側(IC1)を選択
        cs = 1
        SetCol = Xp
    else:
        #右側(IC2)を選択
        cs = 2
        SetCol = Xp - 64
    #ページとラインの選択
    SetPg = Yp // 8
    #LCDに描画するアドレスの位置を設定
    SelectIC(cs)
    SetPage(SetPg)
    SetAddress(SetCol)

好きな場所に文字を書くことができます。

ページ跨ぎとか、チップ跨ぎにも対応しているようです。

def __main():
    PinsInit(20, 7, 8, 9, 18, 19, 10, 11, 12, 13, 14, 15, 16, 17)
    GLCDInit()
    GLCDDisplayClear()
    GLCDPutc(20, 5, "B")

    try:
        while True:
            time.sleep(1.0)
    except KeyboardInterrupt:
        GPIO.cleanup()