Raspberry PiでLCDディスプレイに文字を表示する:クラスモジュール化
前回まででLCDに文字を表示する所まで一通り作り終えました:
前回まで作ってきたコードはサンプル的な関数ベースだったので、これをクラスとしてまとめ、モジュール化して再利用できるようにしてみます。それを次の計画で使いたいのです(^-^;
クラス化の指針
複数のLCDを想定
そもそもですが、クラス化するというのはその裏に「インスタンス(オブジェクト)が複数ある」という意図が含まれています(例外もありますが)。今回の場合、1台のLCDディスプレイを一つのオブジェクトとして捉えます。よってラズパイに複数のLCDが搭載されていてもそれぞれをオブジェクトとして独立に使えるようにクラスを設計しなければなりません。
個々のLCDを規定する物
個々のLCDに命令を与えるには、そのLCDを識別する何かが必ず必要ですよね。前回までの情報からそれが「I2Cバス番号」と「LCD固有ID」の2つである事が分かります。よってこの2つはメンバ変数として保持する事になります。これらは途中で変更する事はおそらく無いので、コンストラクタで与えて固定してしまいましょう。
文字表示メソッド
LCD(キャラクタLCD)なので文字を表示するのがメインです。コンソールへの文字表示と同じ感覚と考えるならprintメソッドとかになるでしょうか。必要な物は何でしょう?まず表示行数lineはいりますね。またそのlineでの文字の表示の開始位置(offset)は指定したい所です。ざっくりとした定義はこんな感じでしょうか:
#文字表示
def print( line, offset, str ):
クリア系
文字を表示する時に既に表示されている文字をクリアしないと部分的に上書きされて変な表示になってしまいます。クリアは「全クリア」「行クリア」くらいあればとりあえず十分かなと思います。
#全クリア
def clearAll():
#行クリア
def clearLine( line ):
表示行数指定
LCDは表示行数を切り替えられます。これは指定出来るようにします:
#表示行数の設定
def setLineNum( num ):
バックライト切り替え
バックライトはON/OFF出来た方が良いですね:
def setBacklignt( isOn ):
4bitモード限定で
LCDは4bitモードと8bitモードがありますが、I2Cを通す場合は4bitモードのみなので、今回のクラスでは4bitモード前提とします。
カーソルとブリンカーは見送り
カーソルとブリンカーは今回は実装を見送ります。これらを入れると設計が複雑になってしまうので。
LCDクラスの実装
では上の指針に沿ってLCDクラスを実装してみます。まずlcdmng.pyというファイルを新規に追加します。このファイル名lcdmngがモジュール名としてインポートされます。
全体的なコードは以下の通りです:
# LCDクラス
# I2Cインターフェイス付属が前提
import smbus2
import time
class LCD:
__busId = 1 # I2CバスId
__i2cId = 0 # I2Cバス内のI2C固有ID
__backlight = 0 # バックライトフラグ
__bus = None # smbus2オブジェクト
# コンストラクタ
# busId : I2CバスID(通常1)
# i2cId : I2Cバス上のI2C機器固有ID(i2cdetectで表示されるID)
# lineNum: 表示行数(def = 1)
def __init__( self, busId, i2cId, lineNum = 2, backlight = True ):
self.__busId = busId
self.__i2cId = i2cId
self.__bus = smbus2.SMBus( busId )
# 初期化
self.__sendLCDCommand( 0x33 )
self.__sendLCDCommand( 0x32 )
self.setLineNum( lineNum )
self.setBacklight( backlight, True )
self.__entryMode()
self.clearAll()
# 表示行数を設定
# num: 表示行数
def setLineNum( self, num ):
interfaceMode = 0 # 常に4bitモード
lineMode = 0 if num == 1 else 0b00001000 # 2行モード
fontMode = 0 # スモールフォントモード
functionSetParam = 0b00100000 | interfaceMode | lineMode | fontMode
self.__sendLCDCommand( functionSetParam )
time.sleep( 0.0002 ) # 39us以上
# 文字表示
def print( self, line, offset, str ):
# 表示ラインのベースアドレス
addrBase = line * 0x40
addrBase += offset
# アドレス位置を指定
# Set DDRAM Address -> 0b00|1000|0000
cmd = 0b0010000000 | addrBase
self.__sendLCDCommand( cmd )
# 1文字ずつ送信
for s in str:
# 文字を送信
# Write Data to RAM -> 0b10|char_code
code = ord( s )
cmd = 0b1000000000 | code
self.__sendLCDCommand( cmd )
time.sleep( 0.0001 ) # 43us以上
# 全クリア
def clearAll( self ):
# ディスプレイクリア命令
clearDisplay = 0b0000000001
self.__sendLCDCommand( clearDisplay )
time.sleep( 0.002 ) # 1.53ms以上待つ(重要)
# 1行クリア
# line: 行数(0基底)
def clearLine( self, line ):
# 1行分(64文字)をスペースで埋める
self.print( line, 0, " " * 64 )
# バックライト切り替え
# isOn : ONならTrue
# immediate: 即反映するならTrue、別命令時に反映ならFalse
def setBacklight( self, isOn, immediate = True ):
self.__backlight = 0x08 if isOn else 0
if immediate:
self.__sendLCDCommand( 0 )
# エントリーモード
def __entryMode( self, incShift = True, dispShift = False ):
incShiftFlag = 0b00000010 if incShift else 0 # インクリメントシフト
dispShiftFlag = 0b00000001 if dispShift else 0 # ディスプレイシフト
entryModeCmd = 0b00000100 | incShiftFlag | dispShiftFlag
self.__sendLCDCommand( entryModeCmd )
time.sleep( 0.0001 )
# LCDのコマンドを送信
# cmd: 10bitのLCD用ビット列( RS R/W D7 D6 D5 D4 D3 D2 D1 D0 )
def __sendLCDCommand( self, cmd ):
# RS, R/Wフラグを生成
# RSのmask: 0b10|0000|0000 -> 0x200
rs = 0b0001 if ( cmd & 0x200 ) != 0 else 0
# R/WフラグはI2Cの1bit目
# R/Wのmask: 0b01|0000|0000 -? 0x100
rw = 0b0010 if ( cmd & 0x100 ) != 0 else 0
# EnableシグナルはI2Cの2bit目
enableSignal = 0b00000100
# 1回目D4〜D7のbit列を作成
# D4〜D7のmask: 0b00|1111|0000 -> 0x0F0
high = ( cmd & 0x0F0 ) | self.__backlight | enableSignal | rw | rs
self.__bus.write_byte( self.__i2cId, high )
time.sleep( 0.0005 ) # 500nsEnableのまま
self.__bus.write_byte( self.__i2cId, self.__backlight ) # Enable OFF
# 2回目D0〜D3のbit列を作成して送信
low = ( ( cmd << 4 ) & 0x0F0 ) | self.__backlight | enableSignal | rw | rs
self.__bus.write_byte( self.__i2cId, low )
time.sleep( 0.0005 ) # 500nsEnableのまま
self.__bus.write_byte( self.__i2cId, self.__backlight ) # Enable OFF
個々の細かい所はこれまで説明してきた事の反復になってしまうため、詳しくは過去記事をご覧下さい:
コンストラクタ(__init__)内で初期化処理をしています。これについては初期化の記事でじっくり説明しております:
クラスの使い方
使い方は極めてシンプル:
import lcdmng
lcd1 = lcdmng.LCD( 1, 0x27 )
lcd1.clearAll()
lcd1.print( 0, 0, "HELLO" )
lcd1.print( 1, 2, "WORLD!" )
lcdmngモジュールをインポートしてLCDクラスを使えるようにします。次にLCDオブジェクトを作成するためコンストラクタにI2CバスID(1)とLCDの固有番号(0x27)を与えます。固有番号は使うLCDで異なる可能性がある為、必ずi2cdetectコマンドをターミナルで叩いて確認しましょう。一応画面を全クリアして(clearAllメソッド)、後はprintメソッドを呼ぶだけです。
終わりに
今回はLCDに文字を表示する機能をクラスにまとめてみました。これでLCDを扱いたい時にlcdmngモジュールを用意するだけで済むようになりました。折角なので色々活用してみたい所です。
ではまた(^-^)/
この記事が気に入ったらサポートをしてみませんか?