前回、I2Cインターフェースで接続したOLEDで作成したタイムコーダーを今回はI2Cにネイティブ対応したOLEDで作り直します。I2Cインターフェースモジュールを使用した場合、通信速度が上がらず、計測間隔が長くなっていたのを改善します。また、LCD1602のようなキャラクターOLEDを使うことで、ビットマップ型のSDD1332よりも表示間隔が短くできるので、今回の用途にはキャラクタータイプの方が適しています。
前回の話:
タイムコーダーを作る【2】RaspberryPi4+I2C+OLEDで表示高速化
タイムコーダーを作る【1】 RaspberryPi4+I2Cで液晶LCD1602を使う時は 3.3V版を使う
のつづき
I2Cインターフェースモジュールは、LCDに送るメッセージを4ビットに分割して、コントロール信号も別に操作する必要があり、さらにI2Cのアドレスも送るのでLCDメッセージ1バイトを送信するのになんと12バイトが必要となっていました。
これを、OLEDのICがI2Cを直接解釈できるならば、このオーバーヘッドが大きく改善できるはずです。
今回、
秋月電子さんのSO1602AWWB-UC-WB-Uをためしたところ、一発で動作したのでこちらを利用することにしました。回路的にはどちらのモジュールもほとんど同じで、OLEDモジュール(画面)とそのコントローラーは同じ
US2066を使用しています。実は基板上にはほとんど回路が有りません。
SOC1602Fもエポキシ基板上の回路も大したものは乗っていないので実は簡単なことで改善できそうなんですが私の実力では解明できませんでした。
RaspberyPiで動作出来た方、是非アドバイスをお願いいたします。
今回は、キャラクターOLEDでネイティブでI2Cを解釈できる、SO1602AWWB-UC-WB-Uを使用して作り直してみます。
■制作・回路
注意点は、RaspberryPiでOLEDを使用する時外部電電源が必要になります。RaspberryPi上の3.3V出力は絶対定格が50mAと低く、全点灯したときのOLEDの最大消費電流が80mAなので、定格を超えてしまいます。これが、LCD(SC1602BBWB-XA-GB-G)の消費電流がパネル3.0mA、バックライト20mA前後で有ることを考えると結構大きな電流を消費しているのがわかります。
今回、不足分を補うため外部電源として手元にあった3.3VなACアダプターを利用し、ブレッドボードに供給しています。
■ソースコード
I2Cネイティブで動作するUS2066では、今までのプログラムが大幅に簡略化出来ます。
また、視認性や速度が重要となるならUS2066を使用したキャラクターOLEDモジュールは良い選択肢になります。
ソースコードはライブラリとそれを呼び出すプログラムとの2つで構成されます。
今回時計プログラムを掲載していますが、他の記事のGNSS/GPSを使用した内部時計の同期を使えば電波時計になります。
時計プログラム
[us2066clock.py]
#! /usr/bin/env python3
import smbus, time
import datetime
import us2066
#get us2006_lib into oled(Instance)
oled = us2066.Us2066(0x3c)
oled.brightness(255)
#write strings data(1st row)
now = datetime.datetime.now()
#write strings data(2nd row)
micro = 1000000
pos_micro = 0
while True:
now = datetime.datetime.now()
if micro > now.microsecond:
oled.pos(0, 0)
current = now.strftime("%y%m%d %H:%M:%S")
oled.print(current) # date times
oled.pos(pos_micro, 1)
micro = now.microsecond
if pos_micro == 0:
oled.pos(pos_micro, 1)
str_milli = str(micro)[0:3]
oled.print(str_milli) #write strings
pos_micro = (pos_micro + 3)
if pos_micro >= 15:
pos_micro = 0
time.sleep(0.00)
#モニタの表示アドレス(2行16列の場合)
# [1][2][3][4][5][6][7][8][9][10][11][12][13][14][15][16]
# 1行目:[0x00][0x01][0x02][0x03]・・・[0x0F]
# 2行目:[0x20][0x21][0x22][0x23]・・・[0x2F]
ライブラリ本体
同じフォルダに保存してご利用ください。
[us2066.py]
# -*- coding: utf-8 -*-
#I2C Interface library
# For US2066 OLED/PLED Segment/Common Driver with Controller
#
#SOC series
# SUNLIKE SO1602A,SO2002A,SO2004A,
# SO1602AWWB-UC-WB-U
# not work: Surenoo SOC1602F
import smbus
import time
name = 'us2066'
class Us2066:
i2c = None
address = None
def __init__(self, address):
print("us2066.__init__()", address)
self.i2c = smbus.SMBus(1)
self.set_address(address)
self.init()
self.off()
self.clear()
self.home()
self.on()
def init(self):
#LCD Intialize
self.command(0x2A)
self.command(0x71)
self.command(0x00) #Disable Internal Regulator
self.command(0x28) #
def set_address(self, address):
print("set_address()", address)
self.address = address
def wait_busy(self):
busy = 0x80
while busy & 0x80:
busy = self.i2c.read_byte_data(self.address, 0x00)
time.sleep(0)
def command(self, code):
#print("command()", code)
self.i2c.write_byte_data(self.address, 0x00, code)
#time.sleep(0.002)
def print(self, message):
#print("write()", message)
mojilist = []
for char in message:
mojilist += self.CHAR_TABLE[char]
#time.sleep(0.00002)
self.wait_busy()
self.i2c.write_i2c_block_data(self.address, 0x40, mojilist)
def off(self):
self.wait_busy()
self.command(0x08) #Display Off
def on(self):
self.wait_busy()
self.command(0x0c) # Diplay ON = 1100b
def clear(self):
self.wait_busy()
self.command(0x01) #Clear =1b
def home(self):
self.wait_busy()
self.command(0x02) #Return home =2b
def pos(self, xxx, yyy):
self.wait_busy()
self.command(0x80 + 0x20 * yyy + xxx)
def brightness(self, bright):
self.wait_busy()
self.command(0x80) # set RE=1
self.command(0x2A)
self.command(0x80) # set SD=1
self.command(0x79)
self.command(0X81) # set Brightness
self.command(bright)
self.command(0x80) # set SD=0
self.command(0x78)
self.command(0x80) # set RE=0
self.command(0x28)
CHAR_TABLE = {
u'†': [0x11],
u'§': [0x12],
u'¶': [0x13],
u'Γ': [0x14],
u'Δ': [0x15],
u'θ': [0x16],
u'Λ': [0x17],
u'Ξ': [0x18],
u'Π': [0x19],
u'Σ': [0x1a],
u'Φ': [0x1c],
u'Ψ': [0x1d],
u'Ω': [0x1e],
u'α': [0x1f],
u' ': [0x20],
u'!': [0x21],
u'"': [0x22],
u'#': [0x23],
u'$': [0x24],
u'%': [0x25],
u'&': [0x26],
u"'": [0x27],
u'(': [0x28],
u')': [0x29],
u'*': [0x2a],
u'+': [0x2b],
u',': [0x2c],
u'-': [0x2d],
u'.': [0x2e],
u'/': [0x2f],
u'0': [0x30],
u'1': [0x31],
u'2': [0x32],
u'3': [0x33],
u'4': [0x34],
u'5': [0x35],
u'6': [0x36],
u'7': [0x37],
u'8': [0x38],
u'9': [0x39],
u':': [0x3a],
u';': [0x3b],
u'<': [0x3c],
u'=': [0x3d],
u'>': [0x3e],
u'?': [0x3f],
u'@': [0x40],
u'A': [0x41],
u'B': [0x42],
u'C': [0x43],
u'D': [0x44],
u'E': [0x45],
u'F': [0x46],
u'G': [0x47],
u'H': [0x48],
u'I': [0x49],
u'J': [0x4a],
u'K': [0x4b],
u'L': [0x4c],
u'M': [0x4d],
u'N': [0x4e],
u'O': [0x4f],
u'P': [0x50],
u'Q': [0x51],
u'R': [0x52],
u'S': [0x53],
u'T': [0x54],
u'U': [0x55],
u'V': [0x56],
u'W': [0x57],
u'X': [0x58],
u'Y': [0x59],
u'Z': [0x5a],
u'[': [0x5b],
u'¥': [0x5c],
u']': [0x5d],
u'^': [0x5e],
u'_': [0x5f],
u'`': [0x60],
u'a': [0x61],
u'b': [0x62],
u'c': [0x63],
u'd': [0x64],
u'e': [0x65],
u'f': [0x66],
u'g': [0x67],
u'h': [0x68],
u'i': [0x69],
u'j': [0x6a],
u'k': [0x6b],
u'l': [0x6c],
u'm': [0x6d],
u'n': [0x6e],
u'o': [0x6f],
u'p': [0x70],
u'q': [0x71],
u'r': [0x72],
u's': [0x73],
u't': [0x74],
u'u': [0x75],
u'v': [0x76],
u'w': [0x77],
u'x': [0x78],
u'y': [0x79],
u'z': [0x7a],
u'{': [0x7b],
u'|': [0x7c],
u'}': [0x7d],
u'→': [0x7e],
u'←': [0x7f],
u'。': [0xa1],
u'「': [0xa2],
u'」': [0xa3],
u'、': [0xa4],
u'・': [0xa5],
u'ヲ': [0xa6],
u"ァ": [0xa7],
u'ィ': [0xa8],
u'ゥ': [0xa9],
u'ェ': [0xaa],
u'ォ': [0xab],
u'ャ': [0xac],
u'ュ': [0xad],
u'ョ': [0xae],
u'ッ': [0xaf],
u'ー': [0xb0],
u'ア': [0xb1],
u'イ': [0xb2],
u'ウ': [0xb3],
u'エ': [0xb4],
u'オ': [0xb5],
u'カ': [0xb6],
u'キ': [0xb7],
u'ク': [0xb8],
u'ケ': [0xb9],
u'コ': [0xba],
u'サ': [0xbb],
u'シ': [0xbc],
u'ス': [0xbd],
u'セ': [0xbe],
u'ソ': [0xbf],
u'タ': [0xc0],
u'チ': [0xc1],
u'ツ': [0xc2],
u'テ': [0xc3],
u'ト': [0xc4],
u'ナ': [0xc5],
u'ニ': [0xc6],
u'ヌ': [0xc7],
u'ネ': [0xc8],
u'ノ': [0xc9],
u'ハ': [0xca],
u'ヒ': [0xcb],
u'フ': [0xcc],
u'ヘ': [0xcd],
u'ホ': [0xce],
u'マ': [0xcf],
u'ミ': [0xd0],
u'ム': [0xd1],
u'メ': [0xd2],
u'モ': [0xd3],
u'ヤ': [0xd4],
u'ユ': [0xd5],
u'ヨ': [0xd6],
u'ラ': [0xd7],
u'リ': [0xd8],
u'ル': [0xd9],
u'レ': [0xda],
u'ロ': [0xdb],
u'ワ': [0xdc],
u'ン': [0xdd],
u'゛': [0xde],
u'゜': [0xdf],
u''': [0xf0],
u'"': [0xf1],
u'°': [0xf2],
u'×': [0xf7],
u'÷': [0xf8],
u'≧': [0xf9],
u'≦': [0xfa],
u'≪': [0xfb],
u'≫': [0xfc],
u'≠': [0xfd],
u'√': [0xfe],
u' ̄': [0xff],
u'ガ': [0xb6, 0xde],
u'ギ': [0xb7, 0xde],
u'グ': [0xb8, 0xde],
u'ゲ': [0xb9, 0xde],
u'ゴ': [0xba, 0xde],
u'ザ': [0xbb, 0xde],
u'ジ': [0xbc, 0xde],
u'ズ': [0xbd, 0xde],
u'ゼ': [0xbe, 0xde],
u'ゾ': [0xbf, 0xde],
u'ダ': [0xc0, 0xde],
u'ヂ': [0xc1, 0xde],
u'ヅ': [0xc2, 0xde],
u'デ': [0xc3, 0xde],
u'ド': [0xc4, 0xde],
u'バ': [0xca, 0xde],
u'ビ': [0xcb, 0xde],
u'ブ': [0xcc, 0xde],
u'ベ': [0xcd, 0xde],
u'ボ': [0xce, 0xde],
u'パ': [0xca, 0xdf],
u'ピ': [0xcb, 0xdf],
u'プ': [0xcc, 0xdf],
u'ペ': [0xcd, 0xdf],
u'ポ': [0xce, 0xdf],
}
■結果
やはりI2Cにネイティブで対応したUS2066は高速で、ディスプレイの書き換えが1msec弱となりました。しかし、1msecでは逆にシャッター速度が遅いときに読めなくなります。表題の写真に掲載しているものは、視認性を上げるために遅くさせています。4msecあたりの間隔で書き換えを行っているのが見て取れるかと思います。
上記の写真では、下段の数字が3桁ごとのmsec時間を表示しています。
わざわざ3桁づつ横に出力しているのは、カメラのシャッターの開放時間と書き換え時間が重なると文字が重なり読めなくなるためです。
この写真では、2段め左から3桁づつ読み
324
3**
312
316
320
と読めます。
読みにくかった3**は4msec毎に書き換えされていることから
328
あたりと推測できます。
なので現在時刻は。
2021/9/24 20:04:56.328-331
と推測できます。
かなり精度よくOLEDから時刻を読むことができるようになったので、次はGNSS/GPSからの時刻を精度良くRaspberryPiに反映させることが重要となってきました。
そうなってくると、GNSS/GPSユニットから送られてくる時刻情報と、実際の時刻とのずれを計測して補正する必要があります。
現状そこまで精度が必要ないので、次期課題としておきます。