公開日:2022/08/13
title.png

22nd Season


#22-2 OLEDディスプレイを使う

 下図の様なOLEDディスプレイを衝動買いしてしまいました。

a222_oledisp.jpg

 背景の方眼が1cm□なので、すごく小さいことがわかりますか?写真は、はめ込み合成ではなく、ちゃんと表示した状態で撮影した物です。通販サイトでは、「はめ込み合成」になっていて、正面のガラス面いっぱいにグラフィックが表示されている写真がありますが、あれは嘘です。
 上の図で、ほぼ全面を使って文字を表示していますので、上の写真がOLEDディスプレイの表示可能範囲(128×32ドット)を示しています。

OLEDとは、どんな表示器?

 OLEDは「Organic Light Emitting Diode」の略語です。「有機材料で光る素子」って事みたいなんだけど、有機材料なのにダイオードって、何だかピンと来ません。本当に、電気的特性が「ダイオード」として矛盾が無いのかな??調べても良く解りませんでした。
 まあ、それは置いておいて。

 TFT等の液晶ディスプレイの場合、液晶で光を遮ることで表示しているので、自然光をパネルの背後で反射させるタイプから始まって、そうでない場合にはバックライトを装備して透過光を作り出しています。
 バックライトは周りの自然光に負けないくらい十分明るい必要があります。明るく光らせるにはそれだけ大きな電力(電流)が必要となります。バックライトで表示するTFT液晶などは、表示する内容にかかわらず、ほぼ一定の電流が流れます。

 一方、OLEDは画素自体が発光するのでバックライトが必要ありません。コントラストも高くて見やすいのが特長です。
 自己発光するOLEDの場合、全ての画素が消灯する真っ黒な画面では電流が流れません。グラフィックや文字などを表示して光る画素が増えてくると、それに比例して消費電流が大きくなり、全画面を真っ白に光らせた時が最大電流となります。
 文字などを表示する場合、普通は光点より黒点の方が多いので(黒地に白文字の場合)、消費電流は比較的小さくて済むと言う利点があります。

 ガラスなどの堅い素材に作り込む必要のあるTFT等の液晶表示器と違って、プラスティックのような柔らかい素材にも作り込めることから、曲げたり折りたたんだりできるタイプの表示器を製作できることも特徴の一つです。

OLEDディスプレイ

 今回はこちらのショップで購入しました。販売サイトに記載されていた情報をまとめておきます。

  販売サイト記載の情報:

 販売サイトに載っていた、モジュールの回路図によると、マーク662Kのレギュレータチップを通って、Vdd=3.3VがSSD1306に供給されていました。I2C端子は、いつもの「大きなお世話」でボード上4.7kΩ抵抗を通してVdd=3.3Vにプルアップされています。
 従って、このモジュールに接続すべきはVCC=5V(※)で、I2C端子は3.3Vである必要があります。DUE等の3.3V定格ボードで使うのがベストマッチです。

※VCC=5Vです。VCC=3.3Vを接続してしまうと、レギュレータのドロップアウト電圧Vdoの分、Vddが低下してしまいます。

 UNOなど5V定格ボードでは、I2Cの信号線2本にレベルシフタ(L/S)を挿入して使わなくてはなりません。

表示制御

 Arduino DUE等のMCUボードと、OLEDディスプレイをI2Cで接続します。あとは電源とGNDだけなので、いたってシンプルです。

 I2Cの通信プロトコルは以下の通りとなります。

  S [ADR,W] [Co,D/C#,0b00_0000] [DATA1] … P

※I2Cバスサイクル表記方法についてはこちらを参照してください。

 制御コマンドについては、データシートを検索して参照してください。

初期化

 SSD1306の初期化手順は、データシートの最後にくっついていたアプリケーションノートにフロウがありました。
 フロウと言うか、設定すべきコマンドがパラメータと共に記載されているので、初期化ルーチンその物と言って過言ではありませんでした。すごく便利o(1^−^)o。
 よく見てみると、ほとんどがリセット解除後の初期値を再設定しているだけなので、本当に必要だったのはフロウの中の一部だけでした。意図せず何か変な設定をしてしまった場合にも、初期化ルーチンをコールすると回復可能な様に、フロウに従って全手順を記述して使うことにしました(完成プログラム(pedometer.ino)中のole_init()関数を参照)。

 フロウ中、リセット解除後の初期値と異なる設定の中で特に重要なのはチャージポンプを有効に設定する事です。

  // enable charge pump regulator (0x8d,0x14)
  ole_i2c_cmnd (ole_CHG_PUMP,0x14);


 本当は、SSD1306に外部から7〜16[V]のOLED駆動用電源を供給する必要があります。しかし、モジュールの回路図上、そんな高圧電源は用意されていません。このため、チャージポンプを有効化してSSD1306に7.5V電圧を発生させるよう指示しないと、OLEDパネルが光りません。


 なお、OLEDディスプレイは、リセット解除後の初期値では以下写真のような方向で天地🔝が表示されます。

a222_oledisp.jpg

 設置方向次第では、180°回転したい場合もあると思いますので、以下の定数で回転できるようになっています。

  const bool ole_FLIP_H=false;  // ole: flip horizontal display
  const bool ole_FLIP_V=ole_FLIP_H;  // ole: flip vertical display


 水平方向だけ、垂直方向だけ、を反転してしまうと文字が裏返ってしまうので無効な設定です。上コードの様に、水平・垂直方向を揃って反転させるか、反転させないか、を選択して、180°回転させることができます。

使い方

 購入したOLEDディスプレイはグラフィック表示器なのだけど、お手軽にサクッと使いたいのでキャラクタ液晶として使いたいと思います。どうせ、128×32ドットの単色表示では、大したグラフィックも使えないしね。

 8×8ドットフォントを使うと16×4文字表示できるけど、今回のOLEDディスプレイは表示領域も小さくて、文字が小さすぎてしまうので、8×16ドットフォントを使って16×2文字表示にします。

 つまり、これ(↓)と同じ表示領域を持ったキャラクタ液晶として使います。

ar31_lcdout.jpg

 上の液晶モジュールは、デカイし、接続信号多いし、5Vだし、相当使い難い表示器だったのですが、キャラクタのみ、16×2文字表示は、手ごろで使い易い表示器でもありました。……長所・短所がバランスしている感じ。
 OLEDディスプレイなら、接続は4端子だし、小さいし、色々な応用に使い易いと思います。

描画方法

 ドライバチップSSD1306自体は、128×64ドットのグラフィック画面を持っています。今回の表示パネルは128×32ドットなので、縦方向の一部範囲を選択して表示することになります。
 SSD1306内蔵グラフィックRAM(GRAM)の構造は、128カラム×8ページとなっています。

 よって、作成すべき8×16ドットのフォントデータは以下図の様になります。

    カラム→
↓ビット
0 1 2 3 4 5 6 7
下位
ページ
0 0 0 0 0 0 0 0 0
1 0 0 0 1 0 0 0 0
2 0 0 0 1 0 0 0 0
3 0 0 1 0 1 0 0 0
4 0 0 1 0 1 0 0 0
5 0 0 1 0 1 0 0 0
6 0 1 0 0 0 1 0 0
7 0 1 0 0 0 1 0 0
上位
ページ
0 0 1 0 0 0 1 0 0
1 0 1 1 1 1 1 0 0
2 1 0 0 0 0 0 1 0
3 1 0 0 0 0 0 1 0
4 1 0 0 0 0 0 1 0
5 1 0 0 0 0 0 1 0
6 0 0 0 0 0 0 0 0
7 0 0 0 0 0 0 0 0
フォント
データ
下位バイト 00 c0 38 06 38 c0 00 00
上位バイト 3c 03 02 02 02 03 3c 00

 縦方向の16ドット分を1ワードのデータとして保持します。データサイズは8ワード/1文字です。7ビットASCIIコードの印刷可能文字95文字分のフォントデータは1,520バイトとなります。以下にサンプルコードを示します。

  const uint16 ole_font[ ]=  // ole: ascii 8*16 dot font data
  {
      :
    0x3c00, 0x03c0, 0x0238, 0x0206, 0x0238, 0x03c0, 0x3c00, 0x0000,  // 'A'
      :
  };



 GRAMへの描画は、垂直アドレッシングモードを使って順次書き込んでいくと、連続してフォントの描画が可能となります(下図)。

a222_vertadr.png
SSD1306データシートから引用

 該当箇所のコード(抜粋)は以下の様になります。

  // vertical addressing mode
  ole_i2c_cmnd (ole_MADR_MOD,0x01);  // 垂直アドレッシングモード設定
  // ここまで初期設定、最初の1回で良い。


  // set rect
  ole_i2c_cmnd (ole_COL_ADR,cx*ole_FON_H,ole_SIZ_H - 1);  // 描画カラム範囲指定
  ole_i2c_cmnd (ole_PAG_ADR,cy*2,cy*2 + 1);  // 描画ページ範囲指定
  // この後、フォントデータを次々と書き込んでいくと、連続して文字を描画できる。
    : (以下は参考コード)
  for (idx=0; idx<8; idx++)
  {
    Wire.write (ole_font[bptr + idx]&0xff);  // 下位バイト(ページ)
    Wire.write ((ole_font[bptr + idx]>>8)&0xff);  // 上位バイト(ページ)
  }


 ArduinoのWireライブラリを使う場合には、バッファサイズがBUFFER_LENGTH=32バイトに制限されているので、このサイズを超えないように分割して送信しなくてはならないことに注意してください。

フォントデータの生成

 フォントは、Windowsのフォントを使って生成します。以下にフォントを生成するスクリプトをリンクしておきます。

  フォント生成用スクリプト:ascii_font_gen.olv

※スクリプト(.olv)の実行には拙作Olive+をWindowsにインストールする必要があります。

 今回のプログラムでは、フリー(パブリックドメイン)の16ドットビットマップフォント「JFドット東雲ゴシック16」の7ビットASCIIコード範囲を使いました。


 もし、日本語を表示したい場合には:

 等(↑)の手段があります。用途に応じて、0.91インチの小さなOLEDディスプレイに日本語表示など、いかがですか?

※OLEDディスプレイへの日本語表示を「#22-5 超音波距離計」にて評価してみました。ご確認ください。

使ってなんぼ

 OLEDディスプレイの制御プログラムが完成し、実際に表示できることも確認できました。と、なったら、折角作った制御プログラムは「使ってなんぼ」なので、早速「万歩計」に応用してみました。

 こちら(「#21-8 万歩計を作ろう」)で作成した万歩計にOLEDディスプレイを接続して、歩数や消費カロリ、歩行速さ、歩いた時間を表示してみました。以下にOLEDディスプレイ対応版の万歩計プログラムをリンクしておきます。

  プログラム:pedometer.ino

 いつもの様に(?!)、「ライブラリ化」するつもりはサラサラ無いので(1^^;)っ、完成プログラムから必要な関数を抜き出して使ってください。
 接頭子「ole_」が、定数名や変数名、関数名に付いているので、少しは分離しやすくなっているはずです。

実験、まずは表示だけ

 こちらの記事を参考に、Arduino DUEとMPU9250(加速度センサ)を使い、万歩計を作成してください。以下にOLEDディスプレイを追加した新しい回路図を示します。

a218_schem.png


 以下図は、完成したOLEDディスプレイ付き万歩計の外観図となります。

a222_expr.jpg

 「#21-8 万歩計を作ろう」の完成図と比べて、OLEDディスプレイが追加になっただけ、なのですが、表示があると、ぐっとそれらしくなります。


 万歩計機能の検証がメインの動画ですが、以下にリンクしておきます。今回は、OLEDディスプレイの表示に着目してご覧ください。




 お手軽に使えて、腰にぶら下げてもかさばらない、適切な表示器が無くて未完成だった万歩計を完成することができました。

今回のお買い物

 今回のお買い物は、以下の通りです。

 「万歩計に最適な表示器が無いぞ〜」と思って、amazonで衝動買いしてしまいました。でも、満足です。


 万歩計の拡張については、次回改めて解説する場を設けたいと考えています。


btn_arduino.png

btn_prev.png btn_next.png

home