ESP-WROOM-02 ( ESP8266 )の GPIO を増設して キャラクタディスプレイ 8bitモード制御してみた

記事公開日:2016年10月20日
最終修正日:2018年3月7日
ディスプレイのリセット操作を追加しました。リセットしないと、電源ONのまま他のプログラムから書き換えた時にディスプレイが文字化けします。
それに伴い、初期化操作も若干変更しました。(2016/10/23)

こんばんは。

ここ最近、電子工作分野でシリアルでは最高速と思われる SPIインターフェースを勉強していて、いろいろ応用が利くことが分かってきました。

それで、今回はそのSPIインターフェースを使ってちょっと変わったことをしてみたいと思います。
そこで、秋月電子通商さんでこういうものを見つけました。

8ビット SPI I/O エキスパンダ MCP23S08-E/P
Character_spi_01

これは、マイクロチップ社の MCP23S08 というもので、マイコンのSPIインターフェースで制御して、Input および Output を増設することができるものです。
つまり、これを使えば、GPIOのピンの数が圧倒的に少ない ESPr Developer ( ESP-WROOM-02, ESP8266 ) でもいろいろなことが実現できそうです。
これの類似品で、I2C通信のものがありますが、I2Cの最高周波数は1.7MHzなので、圧倒的に速い10MHzのSPI通信のものを使った方が良いです。
これはAmazonさんでは見つかりませんでしたので、秋月さんで購入するしかありませんでした。

さて、これを使えば、今まで出来なかったキャラクタLCDなどを8bitモードで動かすことができます。4bitよりも高速なはずです。
要するに、疑似パラレル通信みたいなものですね。
当然、SPI通信の高速化が実現できなければ、これを使ってもあまり意味ありません。
特に、グラフィック文字列のスクロールをする場合に高速で処理できるかどうかが問題になります。

話は変わりますが、以前、ある方からお問い合わせいただきました。
それは、以下の記事

Web News記事自動取得 OLED ( 有機EL )ミニ電光掲示板に16×16フリー日本語フォント( 東雲 ) を使う


で、もっと大きい文字の電光掲示板が出来ないかということでした。
大きい文字ということは、ピクセル(ドット)が大きくなければなりません。
現在は技術が発達し過ぎて、極小ピクセルのディスプレイばかりです。
大き目のピクセル(ドット)のグラフィックス液晶や有機EL ( OLED )ディスプレイは意外と見当たりません。
LEDドットマトリックスという選択肢もあるのですが、16×16ドットの電光掲示板を作るとなると、なかなか簡単にはいきません。
電力も食うし、LEDドライバを複数連結しなければなりません。
以下の記事で8×8ドットのLED電光掲示板を作りましたが、

自作LED電光掲示板に Yahooニュースや 天気予報 を表示させ、さらに NTP 時計機能追加しました


複雑な文字は判読し辛いものでした。

そこで、ある方から この有機ELディスプレイを提案していただきました。
ストロベリーリナックス ( Strawberry Linux )
グラフィック有機ELモジュール100x16

Character_spi_08

これはキャラクタモードですが、グラフィックモードにできます。
これを知った時は、ドット(ピクセル)が大きくて、老眼気味の私にとってもクッキリ判別できて、とてもスバラシイと思いました。
しかし、ESPr Developer ( ESP-WROOM-02, ESP8266 )ではGPIOのピン数が少なすぎて無理だろうし、信号変換してピン数を増やしても、逆に速度が遅くなってあまり現実的ではないなぁ・・・と思っていました。

それがそれが、なんとなんと・・・!!!

SPIのI/Oエクスパンダを使えば、16×16日本語漢字フォントが高速でスクロールするではないですか・・・!!!

有機EL ( OLED )なので、LEDドットマトリックスを同じくらい遠くからでもハッキリ認識できます。

まだ実験中ですが、ディスプレイいっぱいに16×16ドット日本語漢字を表示させるとこんな感じになりました。
Character_spi_09
どうですか?
文字がかなり大きくて、老眼でもバッチリ認識できます!!
これは電光掲示板として使えますよ!!!

そして、全ドット点灯時の最大消費電流は 50mA なので、ESPr Developer ( ESP-WROOM-02開発ボード ) のUSB電源で足ります。
他のバックライト付き液晶LCDでは消費電流が 100mA 超える場合がありますので、やっぱり有機ELがイイですね。

日本語文字スクロールについては次回以降の記事で紹介しますが、今回はまず、SPI通信GPIOエクスパンダ MCP23S08 を使って 8bit のキャラクタモードで動かす方法を紹介していこうと思います。
ただ、注意していただきたいのは、元々これはグラフィック有機ELなので、キャラクタモードで使用する場合は文字間隔がありません。
キャラクタモードしか使わない場合は他の液晶ディスプレイの方が良いかもしれません。

スポンサーリンク

1.準備するもの

8ビット SPI I/Oエキスパンダ MCP23S08-E/P

秋月電子通商さんで販売しています。Microchip製です。
これは5V駆動ですのでご注意ください
SPI通信の最大速度は10MHz です。

グラフィック有機ELモジュール100x16

ストロベリーリナックス ( Strawberry Linux )さんで販売しています。
コントローラーは WS0010 を使ってます。
ここでは2016/10/19時点でクレジットカード支払いは出来なくなっていますのでご注意ください。

ESPr Developer ( ESP-WROOM-02 開発ボード )
スイッチサイエンス製
Amazon.co.jp


これについては何度も当ブログで紹介しておりますが、日本の電波法をクリアした技適認証済み Wi-Fi モジュールです。ESP-WROOM-02 が安定して動作して、とても使いやすいです。
Arduino IDE で開発ができて、とてもお勧めです。
これの使い方については以下のページを参照してください。

ESPr Developer ( ESP-WROOM-02 開発ボード )の使い方をザッと紹介

0.1uF セラミックコンデンサー
I/Oエクスパンダの MCP23S08 チップの電源誤作動を防ぐためのパスコンです。
積層セラミックでも良いです。

サンハヤト製ニューブレッドボード 【SAD-101】
このブレッドボードがお勧めです。
Amazon.co.jp


これは下図の様にESPr Developer を差し込んでも両サイドに2列の空きがあります。
とても重宝しております。

ZeroPlus42

その他、ジャンパワイヤー、USBケーブル、Windows PC等

2.有機ELディスプレイの組み立て

Strawberry Linux の有機EL ( OLED )のピンソケットをハンダ付けしていきます。

まず、購入するとこういうパッケージになってます。
Character_spi_05

ピンヘッダとピンソケットが付属で付いていますが、今回はブレッドボードとジャンパーワイヤーで接続しやすいピンソケットをハンダ付けします。
こんな感じでやっていきます。
Character_spi_06

ハンダ付けし終わるとこんな感じです。ピンボケでスイマセン。
Character_spi_07

3.接続する

では、下図の様にブレッドボード上で接続してみてください。
かなり沢山の配線が必要になりますね。
おそらく、他のオーソドックスなキャラクタLCD液晶でも同じ接続で動作すると思います。
下図の様にMCP23S08 の電源ピンのできるだけ近い位置に0.1uFのセラミックコンデンサーを付けてください。
電源ノイズ誤作動防止のためのパスコンです。

特に注意しなければならないのは、MCP23S08 も 有機EL ( OLED )も5V駆動というところです。
OLEDは3.3VでもOKなのですが、MCP23S08 が5V対応のため、I/Oピンからも5V出力されます。よって、OLED も5V電源としました。

Character_spi_02

ピンアサインは以下の通りです。
MCP23S08 の #4, #5 ピンのところはチップのアドレス設定ができるようになってます。
SPIでは必要ないような気がしますが、一応、アドレス00番にしておくために、グランドに接続しておきます。
ESPr Developer ( ESP-WROOM-02, ESP8266 ) の#15, #12 は今後SDカードスロットを接続するために開けておきます。

実際にMCP23S08 から文字データbit を送るピンは#10~#17となります。

ESPr 5V —- MCP #18  , OLED  #1
ESPr GND —- MCP #9 , OLED  #2
ESPr GPIO #16  —- OLED #6 ( E )
ESPr GPIO #14  —- MCP #1 (SCK)
ESPr GPIO #13  —- MCP #2 (MOSI )
ESPr GPIO # 5   —- OLED #5 (R/W)
ESPr GPIO # 4   —- MCP #6 ( RESET )
ESPr GPIO # 2   —- OLED #4 ( RS )
ESPr GPIO # 0   —- MCP #7 ( CS )

MCP #4  —- GND
MCP #5  —- GND
MCP #10  —- OLED #7 DB0
MCP #11  —- OLED #8 DB1
MCP #12  —- OLED #9 DB2
MCP #13  —- OLED #10 DB3
MCP #14  —- OLED #11 DB4
MCP #15  —- OLED #12 DB5
MCP #16  —- OLED #13 DB6
MCP #17  —- OLED #14 DB7

キャラクタLCDや、この有機EL のピンの動作概要はこうなってます。

E ピン —- OLED #7~#14 のデータをHIGH→LOWに変化させて確定させるピン

R/W ピン —- データをOLED にRead (読み込む)か Write (書き込む)かを選択するピン

RS ピン —- OLED に制御コマンドを送るのか、実データを送るのかを選択するピン

DB0 ~ DB7 —- 実際のデータを受け取るピン

4.Arduino IDE 設定

最新のArduino IDE に ESP8266 ボードをインストールしておいてください。
その方法は以下のページを参照してください。
Arduino IDE に Staging(Stable)版ESP8266 ボードをインストールする方法

5.プログラミング

まずは、以下のスケッチをArduino IDEに入力してみてください。

ディスプレイのリセット操作を追加しました。リセットしないと、電源ONのまま他のプログラムから書き換えた時にディスプレイが文字化けします。
それに伴い、初期化操作も若干変更しました。(2016/10/23)
/* ESPr Developer or ESP-WROOM-02 or ESP8266
 * GPIO Expander = MCP23S08 ( Microchip )
 * OLED = WS0010 ( Strawberry Linux )
 */
#include <SPI.h>

//GPIOエクスパンダ MCP23S08 のSPIインターフェースピン設定
const uint8_t sclk = 14;
const uint8_t mosi =13; //Master Output Slave Input ESP8266=Master,MCP23S08=slave 
const uint8_t MCP_CS = 0;
const uint8_t MCP_RST_pin =  4;
//OLED ピン設定 (8bitモード用)
const uint8_t OLED_RS_pin = 2;
const uint8_t OLED_RW_pin =  5;
const uint8_t OLED_E_pin = 16;

char c1[64] = "Character Display..."; //1列最大64文字格納。そのうち20文字表示
char c2[64] = "Hello. World. TEST.";

void setup() {
  int i;
  delay(1000);

  MCP23S08_Ini(); //GPIOエクスパンダ初期化  
  OLED_Ini(); //OLED初期化
  
  for(i=0; i<20; i++){ //1列最大64文字格納。そのうち20文字表示
    OLED_DataWrite(c1[i]);
  }
  for(i=0; i<44; i++){ //44文字右へカーソル移動すると2列目の頭に移動する
    OLED_CommandWrite(B00010100);//Cursor Right Shift
  }
  for(i=0; i<19; i++){
    OLED_DataWrite(c2[i]);
  }
}

void loop() {
  
}

void MCP23S08_Ini(){ //GPIOエクスパンダ MCP23S08初期化
  pinMode(MCP_CS, OUTPUT);
  pinMode(MCP_RST_pin, OUTPUT);
  
  SPI.begin();
  SPI.setFrequency(10000000); //MCP23S08 Max 10MHz
  SPI.setDataMode(SPI_MODE0);

  digitalWrite(MCP_RST_pin, HIGH);
  delay(100);
  digitalWrite(MCP_RST_pin, LOW);
  delay(100);
  digitalWrite(MCP_RST_pin, HIGH);
  delay(100);
  
  digitalWrite(MCP_CS, LOW);
    delay(1);
    SPI.write(B01000000); //デバイスオペコードB01000000 & チップaddress 000
    SPI.write(0x05); //MCP設定レジスタIOCON 
    SPI.write(B00100000); //シーケンシャル動作禁止、SDAスルーレート許可、ハードウェアアドレスピン禁止、INT出力LOW、アクティブドライブ
    delay(1);
  digitalWrite(MCP_CS, HIGH);
  
  digitalWrite(MCP_CS, LOW);
    delay(1);
    SPI.write(B01000000); //デバイスオペコードB01000000 & チップaddress 000
    SPI.write(0x00); // I/O方向レジスタ(IODIR)設定
    SPI.write(B00000000); //8pin ALL OUTPUT
    delay(1);
  digitalWrite(MCP_CS, HIGH);
}

void OLED_Ini(){ //OLED WS0100 初期化
  pinMode(OLED_RW_pin, OUTPUT);
  pinMode(OLED_RS_pin, OUTPUT);
  pinMode(OLED_E_pin, OUTPUT);
  
  digitalWrite(OLED_E_pin, LOW);
  digitalWrite(OLED_RW_pin, LOW);
  digitalWrite(OLED_RS_pin, LOW);

  //OLEDリセット
  delayMicroseconds(10);
  OLED_CommandWrite(B00000001);//Display Clear
  delay(10);
  OLED_CommandWrite(B00010011);//Character MODE ON, Power is turned OFF
  delay(10); //リセットは一旦電源を切るべし
  OLED_CommandWrite(B00001000);//Display OFF, Cursor OFF, Brinking OFF 
  delay(1000);
  //ここからディスプレイ初期化設定
  OLED_CommandWrite(B00010111);//Character MODE ON, Power is turned ON
  delay(10);
  OLED_CommandWrite(B00111000);//Function Set 8bit-mode 2Line-display
  delay(10);
  OLED_CommandWrite(B00001111);//Display On, Cursor ON, Brinking on 
  delay(10);
  OLED_CommandWrite(B00000001);//Display Clear
  delay(10);
  OLED_CommandWrite(B00000010);//Return HOME
  delay(10);
  OLED_CommandWrite(B00000110);//Entry Mode Set, Increment, No-Shift
  delay(10);
}

void OLED_CommandWrite(uint8_t b){
  digitalWrite(OLED_RS_pin, LOW);
  MCP23S08_SpiCommandWrite(b);
  digitalWrite(OLED_E_pin, HIGH);//EピンをHIGH→LOWへ変化させると書き込み完了
  digitalWrite(OLED_E_pin, LOW);
}

void OLED_DataWrite(uint8_t b){
  digitalWrite(OLED_RS_pin, HIGH);
  MCP23S08_SpiCommandWrite(b);
  digitalWrite(OLED_E_pin, HIGH);//EピンをHIGH→LOWへ変化させると書き込み完了
  digitalWrite(OLED_E_pin, LOW);
}

void MCP23S08_SpiCommandWrite(uint8_t b){
  digitalWrite(MCP_CS, LOW);
    SPI.write(B01000000);
    SPI.write(0x0A);
    SPI.write(b);
  digitalWrite(MCP_CS, HIGH);
}

ではまず、SPI通信でMCP23S08 を動作させるプログラミング方法を説明します。
データシートは秋月電子通商さんのこちらのページにありますので合わせて参照してみてください。

MCP23S08 初期化手順

1.リセットする

50-55行:
ESPr Developer のGPIO #4 を
HIGH → LOW → HIGH
としてリセットしておきます。

ESPr Developer からSPI通信で、8bit のデータを以下の順番で送ります。

2.CSピンをLOWにする

57行:
まず、コマンドを書き込むためにはMCP23S08のCSピンをLOWレベルにします。

3.デバイスオペコード送信

59行:
01000000 を送ります。
MCP23S08 の#4, #5ピンでGNDに接続していて、このチップのアドレス00番となっています。
そのため、1ビット目と2ビット目が00となります。
アドレスを11番にすると、01000110となります。
ですから、このアドレスは4種類設定できますので、MCP23S08を4つ連結できることになります。
CSピンでチップを切り替えるのではなく、アドレスで切り替えられるみたいですね。

4.IOCONレジスタアドレス送信

60行:
続けて0x05 を送信します。
これは、MCP23S08 のレジスタアドレスで、IOCONレジスタといいます。
まず、アドレスを送信して、次に示すように設定ビットを送ります。

5.IOCONレジスタ設定

61行:
IOCONレジスタアドレスを送信した後に設定データを送ります。
ここでは、00100000 を送ります。
●シーケンシャル動作禁止
●SDAスルーレート許可
●ハードウェアアドレスピン禁止
●アクティブドライブ
●INT出力LOW
詳しい動作はデータシートに書いてありますので参照してみてください。

6.MCP23S08 のCSピン HIGH

63行:
レジスタ書き込みが終わったら、一旦CSピンをHIGHレベルにして、一つのコマンド書き込みが終了となります。

7.Input / Output 方向レジスタ設定

65-71行:
同じようにCSピンをLOWにしてデバイスオペコードを送信して、その後に I/O 方向レジスタをセットします。
アドレスは 0x00 です。
そのアドレスを送信した後、#10~#17ピンをOUTPUTに設定しますので、8ピン全てゼロの 00000000 を送信します。
終わりにCSピンをHIGHレベルにしてMCP23S08の初期化は終了です。

有機EL ( OLED ) キャラクタモード設定

次に、Strawberry Linux の有機EL ( OLED )のキャラクタモードの設定を説明します。
Eピン、RSピン、R/WピンはESPr Developer ( ESP8266 )側から直で設定しますが、DB0~DB7はMCP23S08 から操作します。
このキャラクタモード設定は一般的なキャラクタ液晶LCDと操作方法は全く同じです。

ディスプレイのリセット操作を追加しました。リセットしないと、電源ONのまま他のプログラムから書き換えた時にディスプレイが文字化けします。
それに伴い、初期化操作も若干変更しました。(2016/10/23)

では、まずは初期化の前にディスプレイの内部リセット操作をします。
WS0010 のデータシートにあるように、Internal RESET を設定します。

1.ディスプレイクリア

85行:
この関数は、106~111行で関数化してます。
OLEDの設定コマンドをSPIで送る関数です。
RSピンをLOWレベルにすると、設定用コマンド受け入れ状態になります。
そうしたら、MCP23S08の#10~#17を 00000001 というビットになるように出力させます。それは、120~126行で関数化してます。
MCP23S08 のデバイスオペコードを設定した後、レジスタアドレス0x0Aを送れば、ラッチ出力するピンを操作できます。
そこで、00000001 というビットに設定すれば、OLED のDB0~DB7 にビットを送れます。
その後、一般的なキャラクタ液晶の特徴なのですが、EピンをHIGHからLOWへ切り替えると書込みされる仕組みになってます。シリアル通信に慣れてしまうと、このパラレル通信操作はちょっと不思議な感じがしました。
以上で、ディスプレイがクリアされます。
詳細はWS0100 のデータシートを参照してください。

2.電源OFF

コマンド送信の間はデータシートにあるようにビジー時間があるので、とりあえずdelay(10) を置いてます。
その後、コマンドビットを送信します。
87行:
リセットする場合、ESPr Developer のリセットスイッチを押してもディスプレイはリセットされません。
ここでコマンドを送って電源をOFFにします。
0ビット目と1ビット目を1にすれば、電源入り切りのモードになります。
2ビット目 = 電源OFF
3ビット目 = キャラクタモード

3.ディスプレイ・カーソル・点滅OFF

89行:
電源を切ってから、なぜかこの設定をするようです。
データシートに書いてあったのでそうしてます。
0ビット目 = カーソル点滅OFF
1ビット目 = カーソルOFF
2ビット目 = ディスプレイOFF

以上でディスプレイはリセットされますので、次からは初期化設定となります。

4.電源ON、キャラクタモードON

92行:
ここでまずOLEDの電源をONにして、OLED をグラフィックモードにするかキャラクタモードにするか設定します。
0ビット目 = 1
1ビット目 = 1
2ビット目 = 電源ON
3ビット目 = キャラクタモードON

キャラクタモードの場合 = 00010111
グラフィックモード = 00011111

5.Function Set 設定

94行:
0ビット目 = キャラクタフォント設定
1ビット目 = キャラクタフォント設定
2ビット目 = 5×8ドット
3ビット目 = 2-line モード
4ビット目 = 8bitモード

6.Display ON/OFF カーソル設定

96行:
0ビット目 = カーソル点滅ON
1ビット目 = カーソルON
2ビット目 = ディスプレイON

7.Display Clear

98行:
ディスプレイをALLクリアします。

8.Return HOME

100行:
これはホームポジションにするためのコマンドらしいです。
00000010 を送ります。

9.Entry Mode Set

102行:
0ビット目 = ディスプレイシフトモードOFF
1ビット目 = カーソルインクリメントモード

以上で MCP23S08 と 有機EL ( OLED ) の初期化完了です。

ASCII 文字データ送信

初期化が完了すれば、あとは実際の半角英数字のASCIIコードを送信するだけでディスプレイに文字が表示されます。
27~29行で、文字列をOLED_DataWrite という関数を作って送信します。
113~118行の関数を見てください。
OLED のRSピンをHIGHレベルにしたらASCIIコードデータの受け入れ可能状態になります。
そこで、MCP23S08 で8bit のASCIIコードを生成させて、OLED のEピンをHIGH→LOWを変化させれば書き込み完了となり、ディスプレイに文字が表示されます。
1文字表示されれば、自動で次のカーソルへ移動(右へ移動)します。ですから、連続で文字を送ればそのまま表示してくれます。

このOLED は1列に64文字RAMに格納できます。
実際に表示されるのは20文字までで、その後の44文字は書き込んでも表示されません。
ですから、30~32行目でカーソルを44文字分移動させてます。
それ以降に文字を書き込むと2行目に表示されるという仕組みです。

6.コンパイル書き込み実行

では、Arduino IDE でコンパイル書き込み実行させてみてください。
こんな感じに表示されればOKです。
Character_spi_04

いかがでしょうか?
ちゃんと表示されましたでしょうか?
先でも述べましたが、これはもともとグラフィック有機ELなので、キャラクタモードにすると文字間隔の隙間がありません。
キャラクタモードとしてはちょっと使いにくいかもしれませんね。

7.まとめ

ESPr Developer ( ESP-WROOM-02, ESP8266 ) ではこういうキャラクタLCDを8bitモードで使うことは困難だと思っていましたが、SPIのI/O エクスパンダを使えば使えるということが分かりました。
しかも、驚くことに高速で表示できることです。
これはいろいろと応用ができそうです。
しかもこのI/Oエクスパンダは4つまで連結できますし、16bitのものまでありますから、ますます幅が広がります。

ここまでできれば、グラフィックモードにして日本語文字表示させることもそれほど難しくありません。
次回は16×16ドットの日本語漢字を表示させてみたいと思います。

ではまた・・・。

スポンサーリンク

mgo-tec電子工作 関連コンテンツ ( 広告含む )
Amazon.co.jp 当ブログのおすすめ

投稿者:

mgo-tec

Arduino , ESP32 ( ESP-WROOM-32 ) , ESP8266 ( ESP-WROOM-02 )等を使って、主にスマホと連携した電子工作やプログラミング記事を書いてます。ライブラリも作ったりしてます。趣味、独学でやってますので、動作保証はしません。 電子回路やプログラミングの専門家ではありません。 畑違いの仕事をしていて、介護にドップリ浸かりそうな年配者です。 少しだけ電気の知識が必要な仕事なので、電気工事士や工事担任者等の資格は持っています。

コメントを残す

メールアドレスが公開されることはありません。

*画像の文字を入力してください。(スパム防止の為)