ESP8266ボードのArduino化ではWeMos D1ボードにてI2C接続の1602LCDをArduino環境で動かしたが、前回設定したMicroPython環境でもLCDを使えるようにする。
またNTPサーバから時刻を取得しLCDへの時計表示にもトライする。
ハードウエアの接続
LCDに繋いだPCF8574のI2Cをボードに接続するだけだが、一応表にしておく。
WeMos D1 | LCD(PCF8574) |
---|---|
D1(D15?) | SDA |
D2(D14?) | SCL |
LCD表示モジュールの取得とサンプルプログラムの実行
モジュールを探したところhttps://github.com/dhylands/python_lcdが見つかったのでZIPダウンロードして展開。lcdサブディレクトリに各種ボード用のモジュールがあるが、esp8266用に必要なのは以下の3つ。
- lcd_api.py
- esp8266_i2c_lcd.py
- esp8266_i2c_lcd_test.py(main.pyにリネームしておく)
この3つのファイルをWebREPLでボードにアップロードしてボードをリセットすると、テストプログラムが動作する。以下、テストプログラムのリスト。
esp8266_i2c_lcd_test.py(main.pyにリネーム)
"""Implements a HD44780 character LCD connected via PCF8574 on I2C.
This was tested with: https://www.wemos.cc/product/d1-mini.html"""
from time import sleep_ms, ticks_ms
from machine import I2C, Pin
from esp8266_i2c_lcd import I2cLcd
# The PCF8574 has a jumper selectable address: 0x20 - 0x27
DEFAULT_I2C_ADDR = 0x27
def test_main():
"""Test function for verifying basic functionality."""
print("Running test_main")
i2c = I2C(scl=Pin(5), sda=Pin(4), freq=400000)
lcd = I2cLcd(i2c, DEFAULT_I2C_ADDR, 2, 16)
lcd.putstr("It Works!\nSecond Line")
sleep_ms(3000)
lcd.clear()
count = 0
while True:
lcd.move_to(0, 0)
lcd.putstr("%7d" % (ticks_ms() // 1000))
sleep_ms(1000)
count += 1
if count % 10 == 3:
print("Turning backlight off")
lcd.backlight_off()
if count % 10 == 4:
print("Turning backlight on")
lcd.backlight_on()
if count % 10 == 5:
print("Turning display off")
lcd.display_off()
if count % 10 == 6:
print("Turning display on")
lcd.display_on()
if count % 10 == 7:
print("Turning display & backlight off")
lcd.backlight_off()
lcd.display_off()
if count % 10 == 8:
print("Turning display & backlight on")
lcd.backlight_on()
lcd.display_on()
#if __name__ == "__main__":
test_main()
カウンターのカウントアップとバックライトのOn/Offを行っている。
esp8266_i2c_lcd_test.pyはmain.pyにリネームせずにアップロードしても良いが、
その場合は自動では実行されないので、コンソールから手動で呼び出す。
NTPサーバと内臓RTCの時刻を同期する
esp8266は内蔵RTCを持っているが、ボードにはバッテリーが付いておらず、電源On/Offでリセットされてしまう(おまけに精度が悪いらしい)。
そこで、MicroPythonに標準で付いているntptimeモジュールを使ってNTPサーバから現在時刻を取得しRTCを同期させる。以下のコードでは、NTPで取得した時刻で内蔵RTCを設定してから、内蔵RTCの時刻を取得してコンソールにprintしている。
main.py
from time import sleep_ms
import ntptime
import utime
# JST(日本標準時)はUTC+9時間
UTC_OFFSET = 9
def ntpset_main():
# NTPサーバへの接続が完了するまで待つ
sleep_ms(1000)
ntptime.settime()
tm = utime.localtime(utime.mktime(utime.localtime()) + UTC_OFFSET*3600)
print(tm)
#if __name__ == "__main__":
ntpset_main()
ntptime.settime()の前に待ちを入れないと失敗するので注意。また、MicroPythonはタイムゾーンが未実装なので手動で調整する。
LCDクロックにしてみる
というわけで、LCD表示と時刻の取得が出来るようになったので、Arduinoで作った「LCDクロックを作ってみる」と全く同じ表示にトライしたが、MicroPythonでも完全に同じ表示に出来た。
main.py
from time import sleep_ms
from machine import I2C, Pin
from esp8266_i2c_lcd import I2cLcd
import ntptime
import utime
# The PCF8574 has a jumper selectable address: 0x20 - 0x27
DEFAULT_I2C_ADDR = 0x27
# JST(日本標準時)はUTC+9時間
UTC_OFFSET = 9
# 曜日
daysOfTheWeek = "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
def lcdclock_main():
i2c = I2C(scl=Pin(5), sda=Pin(4), freq=400000)
lcd = I2cLcd(i2c, DEFAULT_I2C_ADDR, 2, 16)
lcd.putstr("LCD Clock\nNow Booting...")
sleep_ms(1000)
ntptime.settime()
lcd.clear()
while True:
lcd.move_to(0, 0)
tm = utime.localtime(utime.mktime(utime.localtime()) + UTC_OFFSET*3600)
lcd.putstr("%4d/%02d/%02d" % (tm[0:3]))
lcd.putchar('(')
lcd.putstr(daysOfTheWeek[tm[6]])
lcd.putchar(')')
lcd.move_to(0, 1)
lcd.putstr("%2d:%02d:%02d" % (tm[3:6]))
sleep_ms(1000)
#if __name__ == "__main__":
lcdclock_main()
MicroPythonではstrftimeが実装されていない。そのうえ{}と書式設定を使った新しいスタイルのテキスト整形も実装されておらず、%を使った古いテキスト整形を使う必要がある。
それでも、テキスト整形の仕組みが全く無かったArduinoと比べて読みやすく、非常にコンパクトなコードになった。
画面出力は全く同じだし、撮り直すの面倒なので以前の写真をそのまま再掲(笑)
Arduinoではデバッガが無いためプログラムを少しずつ実行する事が出来なかったのと対照的に、MicroPythonでは対話型インタープリタでコードの断片をちょこちょこ実行して試しながらスクリプトを書けるので効率的にプログラミング出来る。そのうえコンパイル不要でアップロードしてすぐ試せるので大幅に時間が節約出来ると思う。
個人的に、今後MicroPythonは電子工作に欠かせないツールになる予感がする。
コメント