こんばんは
今回は、前回紹介した極小有機EL(OLED)ディスプレイをArduinoで
ネットで公開されているOLED用ライブラリを一切使わずに(I2Cライブラリは使います) 表示させる実験をしました。
使ったOLEDはこちらです。
今回はかなり手間取りました。
なにしろ、ネットではライブラリを使う情報ばかりですから・・・
しかし、これらのライブラリは物凄く重いんですよね。
プログラムの動作が遅いんです。
特に、オーディオレベルメーターなどを表示させると使い物になりません。
そこで、AdafruitさんのページにあったSSD1306のデータシート
https://www.adafruit.com/products/326
とにらめっこして、ようやく自作プログラムで8バイトのビット列を表示することができました。
こんな感じです。
これ、ネットで出ているライブラリより、各段に速度が速くなりました!!
上下左右がパッと見わかる8バイトのビットマップを繰り返し水平垂直に表示させました。
ハッキリ言って、データシートを見てもなかなか意味が分からず、何度もトライしてみて確かめた次第です。
このディスプレイの表示方法はビット列の表示方法が特殊なんですね・・・
というか、私自身がグラフィックディスプレイの構造を良く知らなかったわけですが・・・
ビットを横に書き込んでいくのではなくて、縦に8ビットずつ書き込んでいくんですねぇ・・・・
いや~~、ハマリました・・・
これ、難しいですよ・・・
RAMへのビット書き込みでもハマリましたが、やっと動いたと思って、電源を入れなおしたら表示されないとかありました。
ハマリどころはチャージポンプ(charge pump)をONにしなければ表示してくれないんですよねぇ・・・
これは分からないですよ・・・
ということで、あまり訳が分からず動作できてしまいましたので、自作サンプルコードを載せておきます。
これは、8バイトのビットマップを縦横に連続で表示させ、1秒毎に黒画面で塗りつぶすというプログラムです。
参考までにどうぞ・・・
これを改良して、プログラムに載せれば、ライブラリより高速に動作します。
(ちょっと修正しました。2015/7/2現在)
ちなみに、このOLEDはamazonさんで購入できます。
以下の記事で新たに再検証しましたので、そちらをご覧ください。
有機EL ( OLED ) SSD1306 を再検証してみました ( I2C 通信用 )
下で紹介しているソースコードは昔の私の解釈ですので、誤動作する可能性があることをご了承ください。
(2017/10/16)
【ソースコード】 (※無保証 ※PCの場合、ダブルクリックすればコード全体を選択できます)
#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についてもうちょっと詳しく説明します。
→<次回>
それでは、また・・・
こちらをご覧ください。
https://www.mgo-tec.com/blog-entry-1616shinonome-ws-oled-news.html
コメント