I2C極小OLED(有機EL)SSD1306をArduinoでライブラリを使わずに動作させてみました

記事公開日:2015年7月1日
最終修正日:2018年9月26日
※OLED SSD1306 の I2C ライブラリプログラミング方法について、勘違いしていたところがありました。
以下の記事で新たに再検証しましたので、そちらをご覧ください。
有機EL ( OLED ) SSD1306 を再検証してみました ( I2C 通信用 )
(2017/10/16)

こんばんは
今回は、前回紹介した極小有機EL(OLED)ディスプレイをArduinoで
ネットで公開されているOLED用ライブラリを一切使わずに(I2Cライブラリは使います) 表示させる実験をしました。
使ったOLEDはこちらです。


今回はかなり手間取りました。
なにしろ、ネットではライブラリを使う情報ばかりですから・・・
しかし、これらのライブラリは物凄く重いんですよね。
プログラムの動作が遅いんです。
特に、オーディオレベルメーターなどを表示させると使い物になりません。
そこで、AdafruitさんのページにあったSSD1306のデータシート
https://www.adafruit.com/products/326
とにらめっこして、ようやく自作プログラムで8バイトのビット列を表示することができました。
こんな感じです。
OLED_test010
スポンサーリンク


これ、ネットで出ているライブラリより、各段に速度が速くなりました!!
上下左右がパッと見わかる8バイトのビットマップを繰り返し水平垂直に表示させました。
ハッキリ言って、データシートを見てもなかなか意味が分からず、何度もトライしてみて確かめた次第です。
このディスプレイの表示方法はビット列の表示方法が特殊なんですね・・・
というか、私自身がグラフィックディスプレイの構造を良く知らなかったわけですが・・・
ビットを横に書き込んでいくのではなくて、縦に8ビットずつ書き込んでいくんですねぇ・・・・
いや~~、ハマリました・・・
これ、難しいですよ・・・
RAMへのビット書き込みでもハマリましたが、やっと動いたと思って、電源を入れなおしたら表示されないとかありました。
ハマリどころはチャージポンプ(charge pump)をONにしなければ表示してくれないんですよねぇ・・・
これは分からないですよ・・・
ということで、あまり訳が分からず動作できてしまいましたので、自作サンプルコードを載せておきます。
これは、8バイトのビットマップを縦横に連続で表示させ、1秒毎に黒画面で塗りつぶすというプログラムです。
参考までにどうぞ・・・
これを改良して、プログラムに載せれば、ライブラリより高速に動作します。
(ちょっと修正しました。2015/7/2現在)
ちなみに、このOLEDはamazonさんで購入できます。

※OLED SSD1306 の I2C ライブラリプログラミング方法について、勘違いしていたところがありました。
以下の記事で新たに再検証しましたので、そちらをご覧ください。
有機EL ( OLED ) SSD1306 を再検証してみました ( I2C 通信用 )

下で紹介しているソースコードは昔の私の解釈ですので、誤動作する可能性があることをご了承ください。
(2017/10/16)
#include <Wire.h>
#define OLED_ADDR (0x3C) //OLED address 製品に記載の数値は7bitなので、8bitに変換して1bit右へずらした値(78>>3c)
 
byte DotB1[8]={
  B11111111,
  B00000111,
  B11111111,
  B00000011,
  B00000101,
  B00001001,
  B00010001,
  B00100001
};
 
void setup(){
  Wire.begin();
  setup_i2c();
  Display_Black();
}
 
void loop(){
  Display_Picture();
}

void setup_i2c(){
  Wire.beginTransmission(OLED_ADDR);
  Wire.write(B00000000); //control byte, Co bit = 0 (continue), D/C# = 0 (command)
    Wire.write(0xAE); //display off
    Wire.write(0xA8); //Set Multiplex Ratio  0xA8, 0x3F
      Wire.write(B00111111); //64MUX
    Wire.write(0xD3); //Set Display Offset 0xD3, 0x00
      Wire.write(0x00);
    Wire.write(0x40); //Set Display Start Line 0x40
    Wire.write(0xA0); //Set Segment re-map 0xA0/0xA1
    Wire.write(0xC0); //Set COM Output Scan Direction 0xC0,/0xC8
    Wire.write(0xDA); //Set COM Pins hardware configuration 0xDA, 0x02
      Wire.write(B00010010);
    Wire.write(0x81); //Set Contrast Control 0x81, 0x7F(明るさ設定)
      Wire.write(255); //0-255
    Wire.write(0xA4); //Disable Entire Display On(ディスプレイ全体ON)
    Wire.write(0xA6); //Set Normal Display 0xA6, Inverse display 0xA7
    Wire.write(0xD5); //Set Display Clock Divide Ratio/Oscillator Frequency 0xD5, 0x80
      Wire.write(B10000000);
    Wire.write(0x2E); //Deactivate scrollスクロール表示解除
    Wire.write(0x20); //Set Memory Addressing Mode
      Wire.write(0x10); //Page addressing mode
    Wire.write(0x21); //set Column Address
      Wire.write(0); //Column Start Address←水平開始位置はここで決める(0~127)
      Wire.write(127); //Column Stop Address 画面をフルに使う
    Wire.write(0x22); //Set Page Address
      Wire.write(0); //垂直開始位置(ページ)
      Wire.write(7); //垂直終了位置(ページ)
    Wire.write(0x8D); //Set Enable charge pump regulator 0x8D, 0x14
      Wire.write(0x14);
    Wire.write(0xAF); //Display On 0xAF
  Wire.endTransmission();
}

void Display_Black(){
  byte i, j, k;

  for(i = 0; i < 8; i++){//8ページ分塗りつぶす
    Wire.beginTransmission(OLED_ADDR);
      Wire.write(B10000000); //control byte, Co bit = 1 (One command only), D/C# = 0 (command)
      Wire.write(0xB0 | i); //set page start address←垂直開始位置はここで決める8bitで1ページ(B0~B7)
    Wire.endTransmission();
    
    for(j = 0; j < 16; j++){//column = 8byte x 16 ←8バイト毎に水平に連続で16個表示
      Wire.beginTransmission(OLED_ADDR);
      Wire.write(B01000000); //control byte, Co bit = 0 (continue), D/C# = 1 (data)
      for(k = 0; k < 8; k++){ //なぜか一気に128列まで出力できなかったので、8byte毎にした
        Wire.write(0x00);
      }
      Wire.endTransmission();
    }
    yield();
  }
}

void Display_Picture(){
  byte i,j,k;
  byte on_off; //画面の白黒 塗り替え数値
  for(on_off = 0; on_off < 2; on_off++){
    for(i=0; i<8; i++){
      Wire.beginTransmission(OLED_ADDR);
      Wire.write(B00000000); //control byte, Co bit = 0 (continue), D/C# = 0 (command)
      Wire.write(0xB0 | i); //set page start address←垂直開始位置はここで決める(B0~B7)
      Wire.write(0x21);//set column addres
      Wire.write(0x00 | 0);//start column addres←水平開始位置はここで決める(0~126)
      Wire.write(B01111111);//Column Stop Address 画面をフルに使う
      Wire.endTransmission();
      for(j=0; j<16; j++){//column = 8byte x 16 ←8バイト毎に水平に連続で16個表示
        Wire.beginTransmission(OLED_ADDR);
        Wire.write(B01000000); //control byte, Co bit = 0 (continue), D/C# = 1 (data)
        if(on_off == 1){
          for(k=0; k<8; k++){
            Wire.write(0x00); //黒画面に塗り替え
          }
        }else{
          for(k=0; k<8; k++){
            Wire.write(DotB1[k]);
          }
        }
        Wire.endTransmission();
      }
    }
    delay(1000); //1秒ごとに画面を塗り替え
  }
}

これが、何かのお役に立てれば幸いです。
次回はこのOLEDについてもうちょっと詳しく説明します。
<次回>
それでは、また・・・

最新記事では超小型の有機EL(OLED)SSD1306 を使ったNTP時計付き電光掲示板も作りました。
こちらをご覧ください
→ESP-WROOM-02 と 極小OLED (有機EL) で Yahooニュース電光掲示板とNTP時計を表示させてみました

スポンサーリンク

mgo-tec電子工作 関連コンテンツ ( 広告含む )

投稿者:

mgo-tec

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

コメントを残す

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

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

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください