OLEDで竈門禰豆子を描画する
鬼滅の刃面白いですよね。私はアニメ組なので無限列車編手前までの情報しか知らないのですが、今年は無限列車編の映画化決定という事でワクワクが止まりませんね!
とはいっても映画化までには時間があるので鬼滅の刃の中でも一番かわいい禰豆子をOLEDに描画して持ち歩きたいと考えたわけですね。
OLED(Organic Light Emitting Diode)とは俗に言う有機ELってやつですね。その中でも入手しやすいSSD1306ドライバを使用している128×64のOLEDを使用していきます。なお、禰豆子を表示するライブラリが見つからなかったのでWireライブラリのみを使用して地道に描画していきたいと思います。
SSD1306の描画制御
OLEDに描画するための制御はSSD1306というチップを使用しています。制御単位としては縦が0ページから7ページ(1ページ当たり8行)、横が0から127セグメントあります。
描画データの書き込みは1byte単位で行います。
通信方式はI2CタイプのOLEDデバイスを使用する前提で書いていきます。表示速度を求める時にはSPI方式の物を使用しましょう。今回はキャラクターを描画するだけなので表示速度は要求しません。
I2Cの制御方式に関しては以前の記事でまとめてありますので参照よろしくお願いいたします。
描画データ作成
SSD1306に描画するためにはbitmapデータを作成する必要があります。人によって作り方はあると思いますが私はエクセルのマクロを使用して作成を行いました。SSD1306は0ページから7ページまで制御できるようですが、今回私が購入したOLEDは0~3ページのみしか表示できませんでした。なので禰豆子を表示する描画範囲は4ページ×80セグメントとします。
■ ベースとなるイラスト
■ エクセルのシートに32×80の枠を作ります(行の高さは列に比べて広めにする)
■ エクセルの背景に基となるイラストを設定
■ 描画するところを塗りつぶす
■ マクロを使用して塗りつぶしたセルを1として1byteデータを組み合わせる
描画コードの作成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
#include <Wire.h> const uint8_t adrr=0x3C; const uint8_t freq=100000; int8_t i,j,k; byte bitmap; uint8_t sample[4][10][8]={ {{0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000001}, {0b00000000,0b00000011,0b00001111,0b00011111,0b00111111,0b01111111,0b11111111,0b11111111}, {0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111}, {0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111}, {0b11111100,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111}, {0b00000000,0b00000000,0b11000001,0b11110001,0b11110010,0b11101000,0b11100000,0b11100111}, {0b10000000,0b11000000,0b00100000,0b00100000,0b00100000,0b01000000,0b10001000,0b10101000}, {0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000}, {0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000}, {0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000}}, {{0b00000011,0b00000111,0b00000111,0b00000111,0b00000111,0b00001111,0b00001111,0b00001111}, {0b11111111,0b11111111,0b11111100,0b11111000,0b11110000,0b11100000,0b11100000,0b11100000}, {0b11101001,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b01111000}, {0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000011}, {0b00111111,0b00000110,0b00000001,0b00000000,0b00000000,0b00000000,0b00000000,0b11111000}, {0b11100010,0b11110000,0b11111100,0b11111111,0b01111111,0b01111111,0b00111111,0b00111111}, {0b00010000,0b00100000,0b00100000,0b00000000,0b10000000,0b10000000,0b10000000,0b10000000}, {0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000}, {0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000}, {0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000}}, {{0b00011111,0b00011111,0b00011111,0b00011111,0b00111111,0b00111111,0b00111111,0b01111111}, {0b11100001,0b11000110,0b11011000,0b11000000,0b11000001,0b11000010,0b11000101,0b11101000}, {0b10000000,0b00000000,0b00000000,0b00000000,0b11110000,0b00101000,0b00010100,0b01101000}, {0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000001,0b00000010,0b00000000}, {0b00000110,0b00000001,0b00000000,0b01111000,0b10100100,0b01000010,0b10000011,0b10110000}, {0b00111111,0b00111111,0b00111111,0b00111111,0b00111111,0b10011111,0b00011111,0b10101111}, {0b11000000,0b11000000,0b11000000,0b11100000,0b11100000,0b11100000,0b11110000,0b11110000}, {0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000}, {0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000}, {0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000}}, {{0b01111111,0b01111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111}, {0b10101010,0b10100010,0b11010001,0b11000000,0b11000000,0b11110011,0b11011101,0b11000100}, {0b01100000,0b00001000,0b10010000,0b11100000,0b00000000,0b10111111,0b01001000,0b01001000}, {0b00000000,0b00000000,0b00000000,0b00100000,0b00000000,0b11111011,0b00000000,0b00000000}, {0b10110000,0b01000010,0b00100100,0b00111000,0b00000000,0b11111111,0b00101001,0b00000001}, {0b00111111,0b01001111,0b01001111,0b10011111,0b00111111,0b11111111,0b01111111,0b01111111}, {0b11111000,0b11111000,0b11111000,0b11111000,0b11111000,0b11111000,0b11111000,0b11111000}, {0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000}, {0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000}, {0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000}}, }; void Int(){ Wire.begin();//マスター Wire.setClock(freq); Wire.beginTransmission(adrr); Wire.write(0b00000000);//連続コマンド Wire.write(0xA8); Wire.write(0x3F); Wire.write(0b00000000);//連続コマンド Wire.write(0xD3); Wire.write(0x00); Wire.write(0b10000000);//1byteコマンド Wire.write(0x40); Wire.write(0b10000000);//1byteコマンド Wire.write(0xA1); Wire.write(0b10000000);//1byteコマンド Wire.write(0xC8); Wire.write(0b00000000);//連続コマンド Wire.write(0xDA); Wire.write(0x02); Wire.write(0b00000000);//連続コマンド Wire.write(0x81); Wire.write(0x7F); Wire.write(0b10000000);//1byteコマンド Wire.write(0xA4); Wire.write(0b10000000);//1byteコマンド Wire.write(0xA6); Wire.write(0b00000000);//連続コマンド Wire.write(0xD5); Wire.write(0x80); Wire.write(0b00000000);//連続コマンド Wire.write(0x8D); Wire.write(0x14); Wire.write(0b10000000);//1byteコマンド Wire.write(0xAF); Wire.endTransmission(); } void Clr(){ for(i=0;i<8;i++){//0から7べージループ Wire.beginTransmission(adrr); Wire.write(0b10000000);//1byteコマンド Wire.write(0xB0|i); Wire.write(0b00000000);//連続コマンド Wire.write(0x21);//開始列、終了列指定 Wire.write(0);//開始列 Wire.write(127);//終了列 Wire.endTransmission(adrr); for(j=0;j<16;j++){//8bit*16=128 Wire.beginTransmission(adrr); Wire.write(0b01000000);//連続データ for(k=0;k<8;k++){ Wire.write(0x00); } Wire.endTransmission(adrr); } } } void Dsp(){ int8_t m, n, r, o; bool buff=0; byte bitmap; for(o=0;o<4;o++){ Wire.beginTransmission(adrr); Wire.write(0b10000000);//1byteコマンド Wire.write(0xB0|o);//開始ページ Wire.write(0b00000000);//連続コマンド Wire.write(0x21);//列セット Wire.write(24);//開始列 Wire.write(127);//終了列 Wire.endTransmission(adrr); delay(1000); for(r=0;r<10;r++){ Wire.beginTransmission(adrr); Wire.write(0b01000000);//連続データ delay(500); for(m=7;m>=0;m--){ for(n=0;n<8;n++){ buff = (sample[o][r][n]>>m)&1; bitmap |= (buff<<n); buff=0; } Wire.write(bitmap); bitmap=0; } Wire.endTransmission(adrr); } } } void setup() { Int(); Clr(); Dsp(); } void loop() { // put your main code here, to run repeatedly: } |
やっていることは単純で、ディスプレイのイニシャライズを行い、作成したビットマップを表示しているだけです。表示方法は1byteずつ送って8×8のブロックを完成させて、それを横に10回繰り返し1ページを書き上げます。あとはそれを4ページ分繰り返す感じです。
いかがでしょうか?似ていますか?
このような要領で自分の好きなキャラクターを描画可能です。ライブラリー化すればキャラ毎の表示もできそうですね。
描画ポイント
SSD1306で描画するとき、例えば0b00111010のデータを書き込んだ時ビットの並びと同じように横に表示されるわけではなく2種類の制御コマンドとbitデータの書き換えを行う必要があります。
表示位置制御コマンド
- Re-map : A0h/A1h 横(セグメント)方向の反転
- Set COM Output scan direction : C0h/C8h 縦(ページ)方向の反転
今回は左上から開始なのでA1h, C8hのコマンドを送ってあげればいいわけです。
しかし、まだこの状態だと90度回転していて都合が悪いので、描画データと同じ方向にデータを修正してあげる必要があります。どうするかというと、配列を使用して変換してあげましょう。
1 2 3 4 5 6 7 8 9 10 11 |
byte sample = 0b01100001; bool buff[8]; for(int i=1;i<9;i++){ buff[i]= sample>>(abs(1-i)) & 1; } Wire.beginTransmission(adrr); Wire.write(0b01000000);//連続データ送る for(i=1;i<9;i++){ Wire.write(buff[i]); } Wire.endTransmission(adrr); |
こんな感じで書き換えてやる必要があります。書き換え方は何でもいいと思います。
ちなみに本記事で取り扱った8×8単位での描画方法はどうやって変換したかというと、、、
以下の図のように各byteの8bit目を抽出して1byteのデータに並べ替える。次は7bit目を抽出して並べ替える。次は、、、のような感じで書き換えております。
おわりに
今回は鬼滅の刃の竈門禰豆子をOLEDディスプレイに描画してみました。bitマップ化する時がちょっとややこしいですが、自分の好きなキャラクターが表示されたときはとっても幸せです。
合わせてSSD1306での描画ポイントも紹介しました。この方法がすべてではないので、もっと効率の良いやり方がありましたら是非ご教授お願いしたいという事で終わりにしたいと思います。
ではでは~
コメント