ラズPicoにディスプレイ〜その2〜
2023年10月20日(金)は、7割ほどの出席率でした。
- 18時00分~18時25分 タイピング練習
- 18時25分~19時50分 SSD1306互換OLEDのプログラミング
- 19時50分~20時00分 あとかたづけ
本日も引き続き、SSD1306互換OLEDのプログラミングに取り組みました。手が速いメンバーでOLEDの表示が終わったら、自分の課題に取り組みます。
Contents
タイピング練習
今回のタイピングの練習は、英語入力です。使う教材は、下のサイトのWebアプリです。
https://manabi.benesse.ne.jp/gakushu/typing/
おおよそ100字/分の入力速度で、95%くらいの正タイプ率だと実用十分です。拙速に入力速度向上を目指しても、実用場面であまり役に立ちません。現実には、間違って入力した文字は「消してから入力し直さないといけない」からです。
まずは、手元を見ずに、正タイプ率を95%くらいに持っていくことが重要です。時間はかかりますが、結果として早くタッチタイピングを習得できます。
SSD1306互換OLEDのプログラミング〜その2〜
前回でOLEDの表示ができたメンバーは、OLEDに別の情報を表示することに取り組みます。
前回の取り組みは、下記からどうぞ。
表示機能を応用してプログラムす
OLEDを活用した表示はいろいろありますが、まずはこれだけ。
- 「RaspberryPi Pico」以外の文字列を表示する
- 文字列を右下に表示する
- 温度を表示する
ちなみに、わたしも答えを知りません。「できない」という意味ではなくて、この日のクラブ活動までに実際にコードを書いて確かめたわけではないので、「確実に動く保証のあるコードを知りません」。
もちろん「こう書いたら動くだろうな……」という仮説を持っています。仮説にそって、わたしもメンバーと一緒に考えながらプログラミングしています。
OLED(SSD1306)に「RaspberryPi Pico」以外の文字列を表示する
OLED(SSD1306)の表示は、前回同様「最新Pico W対応!ラズパイPico完全ガイド(福田和宏著)」を参考に、下記のコードで動きます。
from machine import Pin, I2C
from ssd1306 import SSD1306_I2C
WIDTH = 128
HEIGHT = 64
i2c = I2C(0)
i2c.scan()
print('i2c address : '+hex(i2c.scan()[0]).upper())
print('i2c configuration: '+str(I2C))
oled = SSD1306_I2C(WIDTH, HEIGHT, i2c)
oled.fill(0)
oled.text('Raspberry Pi', 5, 5)
oled.text('Pico', 5, 15)
oled.show()
表示文字列を示すところは、16行目17行目です。したがって、「RaspberryPi Pico」の表示を変えたければ、同行のこの部分を変更します。
たとえば、「This is a pen.」と表示したければ、下記のように書き換えます。
oled.text('This is a', 5, 5)
oled.text('pen', 5,15)
つまり、「oled.text()」の中の1番目の引数を文字列で指定すればOKです。
ちなみに、日本語は表示できません。なんで?というのは良い質問です。その答えは「日本語が表示できるように作られていないから」です。自分でも試してみてください。
OLED(SSD1306)で文字列の表示位置を変える
表示する文字列を変えたら、次は文字列の表示位置を変えます。oled.text()の書式は、下記のとおりです。
oled.text(表示文字列, 横方向の開始位置, 縦方向の開始位置)
したがって、5と15の数字を変更すれば、表示位置を変えられます。たとえば、下記のように変更します。
oled.text('Raspberry Pi', 20,40)
oled.text('Pico', 20, 50)
これを実行すると、文字列が右下に移動したはずです。
ちなみに、インポートしたssd1306.pyを読んでいけば、引数の何がどのような意味を持つ設定値なのかわかります。そして、インポートモジュールが読めなくても、サンプルコードから何が設定してあるのかを読み取れます。
わからなければ、実際にコードを書き換えて試してみればよいのです。プログラムはいくら失敗してもコストがかかりません。自分なりに仮説を立てながら、いろいろ試してみると早く上達します。
OLED(SSD1306)で温度を表示する
最後は、温度表示をしてみます。できあがりは下の写真。小学生のメンバーが作ったプログラムで動いています。2行〜4行の「20.02224」が室温です。
温度を取得するには、Raspberry Pi Pico Python SDK(公式ドキュメント)のプログラムを使います。このプログラムは、クラブに入ったときの導入で写経するプログラムです。
import machine
import utime
sensor_temp = machine.ADC(4)
conversion_factor = 3.3 / (65535)
while True:
reading = sensor_temp.read_u16() * conversion_factor
temperature = 27 - (reading - 0.706)/0.001721
print(temperature)
utime.sleep(2)
temp.pyの10行目で定義しているtemperatureを、さきほどのoled.text()の第一引数に指定すればOKです。
graphdisp.pyとtemp.pyを適切に組み合わせてプログラムをしてください。コードに書く内容は、ほぼここに書いた2つのファイルのとおりです。1箇所注意点がありますが、それは次の項に書きます。答えを求めるのではなくて、自分なりの仮説を立てて、コードを考えてみてください。
OLED(SSD1306)が表示されないよくあるエラー(例外)
プログラミングにエラーはつきもの。エラーを解決するのを楽しめると、プログラムが一層楽しくなります。ここでは、OLED(SSD1306)を動かす上で、わたしがクラブで見かけたエラー(例外)と解決方法を書きます。
・ModuleNotFoundError: No module named 'ssd1306.py'
SSD1306のモジュールを適切に保存できていません。ラズPicoに保存したつもりで、パソコン本体に保存していたり、名前を間違っていたり、何かしらのまちがいがあります。もう一度保存場所を確認してください。
・IndexError: list index out of range
graphdisp.pyの10行目でこのエラーが出たら、OLEDとラズPicoのI2C接続がなされていません。配線・結線が正しいか確認してください。配線・結線が正しければ、接触不良の可能性があります。線を変えるか、ブレッドボードの線を差し込んでいる位置を変えてください。
だいたい自分の結線ミスが原因です。まず、自分の目と腕を疑ってください。
・TypeError: can't convert 'float' object to str implicitly
温度表示をするときに、ただ2つのファイルを写して順番を変えるだけだとこのエラーがでます。oled.text()の第一引数には、文字列を与えないといけないからです。
公式ドキュメントで取得したtemperatureは浮動小数点型(float型)なので、これを文字列に変換する必要があります。例えば、下のように書きます。
temperature = 27 - (reading - 0.706)/0.001721
oled.text(str(temperature), 5, 5)
一方、temperatureを定義したときに文字列型に変換しても良さそうです。具体的には、下記のコードです。
temperature = str(27 - (reading - 0.706)/0.001721)
oled.text(temperature, 5, 5)
これでも良さげですが、温度は数値として扱いたいことが多いので、cast1.pyのほうが使いやすく読みやすいコードです。もちろん、temperatureを文字列としてしか扱わないよ! という場面ではcast2.pyも間違いではありません。要は、どのようにかける場合であっても理由があるということです。
今後の展望
さて、一通りOLED(SSD1306)を使えるようになりました。メンバーの中には、まだ最後まで到達していない人もいるので、来週も進捗に合わせてサポートします。次は、テンキーと合わせて電卓を作ってみようかと思います。
それとは別に、スロットを作りたいと要望がありました。パソコンの画面で作りたいということでしたが、OLEDで作っても面白そうです。例のごとく、わたしも答えを知りません。メンバーと一緒に考えてみたいと思います。