SSD1306のOLEDでゆるキャラを表示する

秋月電子通商でSSE1306搭載のOLEDを買ってきました。

https://akizukidenshi.com/catalog/g/g112031/

とりあえずいろいろ表示して遊んでみます。

## やること

OLEDに好きな画像を貼り付けできるようにする。

1.画像の準備
2.プログラムの作成
3.テスト

環境はwin11,　Arduino IDE2.3.4,　Arduino UNO R4です



```
display.drawPixel(Y, X, WHITE);
```
この関数で特定のビットに白いドットを打ち込めるようなので、画像データを行列に変換しディスプレイに表示させます。

## 画像データの準備

ネットで”白黒”、”画像が小さい”ことを条件にいい感じの画像を探します。
いいものが見つかったらディスプレイに表示できるよう、加工していきます。
今回、細かい作業を必要としていないのですべてweb上のもので結構です。
また、紹介するウェブサイトはあくまで一例ですのでお好みでどうぞ。

画像に色がついている場合は、[tech-lagoon.com](https://tech-lagoon.com/imagechef/image-to-monochrome.html#google_vignette "tech-lagoon.com")で色を白黒に2極化します。
[iloveimg.com](https://www.iloveimg.com/ja/crop-image "iloveimg.com")でいい感じにトリミングし、そのまま128x64pixelに収まるように圧縮します。

[convertio.co](https://convertio.co/ja/jpg-bmp/ "convertio.co")でbitmapという画像形式に変換します。
bitmapは数ある画像形式の中でデータの単調さでかなり上位に君臨します。
特に2色のbitmapの場合、1bit=1pixelとなり、白黒をそのまま0,1に変えてくれます。

この性質を用いて、bitmap型の画像を[affi-sapo-sv.com](https://affi-sapo-sv.com/tools/programming-assistance-tools/hex-editor.php "affi-sapo-sv.com")で読み取るだけで画像の数値化ができます。
バイナリエディタで取り出した16進数のデータをワードに移し、データの後ろから必要な画像のpixel分だけ取り出します。
今回は64x75pixelなので64×75÷4=1200文字のデータを取り出します。

もし、横幅が64pixelに満たない場合は背景色で嵩増ししてください。
縦が128pixelに満たない場合はそのままでいいです。

これで画像のデータが用意できました。

## プログラムの作成

adafruitのライブラリを使用します。

https://zenn.dev/suzuky/articles/8d03cf5e370887

この記事を参考にサンプルプログラムを走らせます。
問題なく動きました。
動作確認したライブラリのバージョンは、
Adafruit GFX Library 1.12.0
Adafruit SSD1306 2.5.13
です。

ではいい感じに書き換えていきます。
```C:SSD1306_image
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

const int T=146; //画像データの分割数
unsigned long DETA[T]= 
{
0b11111111111111111111111111111111,0b11111111111111111111111111111111,
0b11111111111110001111111111111111,0b11111111111111111111111111111111,
0b11111111110000000111111111111111,0b11111111111111111111011111111111,
0b11111111100000000000000000000000,0b00000000000011111110000111111111,
0b11111110000011000000000000000000,0b00000000000000000010000001111111,
0b11111100001111000000111111111111,0b11111111000000000000000000111111,
0b11111100011111000111111111111111,0b11111111111111100000011000011111,
0b11111000111111111111111111111111,0b11111111111111111000011100011111,
0b11110001111111111111111111111111,0b11111111111111111110111110001111,
0b11110001111111111111111111111111,0b11111111111111111111111110001111,
0b11100011111111111111111111111111,0b11111111111111111111111111000111,
0b11100011111111111111111111111111,0b11111111111111111111111111000111,
0b11000111111111111111111111111111,0b11111111111111111111111111100011,
0b11000111111111111111111111111111,0b11111111111111111111111111100011,
0b11001111111111111111111111111111,0b11111111111111111111111111110011,
0b11001111111111111111111111111111,0b11111111111111111111111111110001,
0b11001111111111111111111111111111,0b11111111111111111111111111110001,
0b11000111111111111111111111111111,0b11111111111111111111111111110001,
0b11000111111111111111111111111111,0b11111111111111111111111111110001,
0b11100111111111111111111111111111,0b11111111111111111111111111111001,
0b11100011111111111111111111111111,0b11111111111111111111111111111001,
0b11100011111111111111111111111111,0b11111111111111111111111111111001,
0b11110001111111111111111111111111,0b11111111111111111111111111111001,
0b11110001111111111111111111111111,0b11111111111111111111111111111001,
0b11111000111111111111111111111111,0b11111111111111111111111111111001,
0b11111000111111111111111111111111,0b11111111111111111111111111110001,
0b11000000011111111111111111111111,0b11111111111111111111111111110001,
0b11000000011111111111111111111111,0b11111111111111111111111111110001,
0b11000000001111111111111111111111,0b11111111111111111111111111110001,
0b11100110001111111111111111111111,0b11111111111111111111111111110001,
0b11100011111111111111111111111111,0b11111111111111111111111111110001,
0b11100001111111111111111111111111,0b11111111111111111111111111110001,
0b11110001111111111111111111111111,0b11111111111111111111111111110011,
0b11111000111111111111111111111111,0b11111111111111111111111111100011,
0b11111100111111111111111111111111,0b11111111111111111111111111100011,
0b11111100011111111111111111111111,0b11111111111111111111111111100011,
0b11111110011111111111111111111111,0b11111111111111111111111111000111,
0b11111110001111111111111111111111,0b11111111111111111111111111000111,
0b11111111001111111111111111111111,0b11111001111111111111111111000111,
0b11111111000111111101010111111111,0b11100110011111111111111111001111,
0b11111111000111111111111111111111,0b11001111011111111111111110001111,
0b11111111000111111111111111111111,0b11011111101111111111111110001111,
0b11111111100111111111111111111111,0b11011111101111110101011110011111,
0b11111111100011111111110011111111,0b10001111101111111111111100011111,
0b11111111100011111111111000111111,0b11100000001111111111111100011111,
0b11111111100011111111111110001111,0b11111111111111111111111000111111,
0b11111111100011111111111111100011,0b11111111111111111111111000111111,
0b11111111110011111111111111110000,0b11111111111111110001111000111111,
0b11111111110011111111111110000000,0b11111111110000000001110001111111,
0b11111111110011111111100000000111,0b11111111110000111111110001111111,
0b11111111110001111111100111111111,0b11111111111000011111110011111111,
0b11111111110001111111111111111111,0b11111111111110000111100011111111,
0b11111111110001111111111111111111,0b11111111111111100001100111111111,
0b11111111110001111111111111111111,0b11111111111111111001000111111111,
0b11111111111001111111111110000011,0b11111111111111111111001111111111,
0b11111111111000111111100000110011,0b11111111111111111110001111111111,
0b11111111111000110011001111111111,0b11111111110001111100011111111111,
0b11111111111000000011111111111111,0b11111111111100111100011111111111,
0b11111111001000000011111111111111,0b11111111111110011000111111111111,
0b11111111000000000111111111111111,0b11111111111111011000111111111111,
0b11111111000000000011111111111111,0b11111111111111110001111111111111,
0b11111111110000100000111111111111,0b11111111111111100000111111111111,
0b11111111110001110000011111111111,0b11111111111111000000111111111111,
0b11111111111000111000001111111111,0b11111111111110000000011111111111,
0b11111111110000010000001111111111,0b11111111111100000000011111111111,
0b11111111110000000000011111111111,0b11111111111000000111111111111111,
0b11111111110000000000000111111111,0b11111111100000000111111111111111,
0b11111111111011000000000001111111,0b11111100000000000111111111111111,
0b11111111111111000000100000000000,0b00000000000100001111111111111111,
0b11111111111111100001111000000000,0b00000000111110011111111111111111,
0b11111111111111100001111111000000,0b00001111111110011111111111111111,
0b11111111111111100011111111111111,0b11111111111111111111111111111111,
0b11111111111111111111111111111111,0b11111111111111111111111111111111,
};

void setup() {
  Serial.begin(115200);

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { 
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }

  // Show initial display buffer contents on the screen --
  // the library initializes this with an Adafruit splash screen.
  display.display();
  delay(1000); // Pause for 1 seconds
}

void loop() {
  display.clearDisplay();  //ディスプレイリセット
  display.display();
  Serial.println(".");
  int yoko;
  for(int i =0; i<T; i++){         //分割された画像データの数(146個)だけ繰り返す
    int i2 = i / 2;                 //64pixelを32pixelに分割しているので÷2
    for(int j =0; j<32; j++){       //分割された画像データの大きさ(32bit)だけ繰り返す。
      int n = 0x1 & (DETA[i] >> j);  //DETAのj桁目を抽出
      Serial.print(n);               //デバッグ用serial
      if(n==0){                       //n==1に変更すると色が反転します。
        display.drawPixel(i2 + 30, j + yoko, WHITE);//i2に足されている30は画像を中央に動かすため
      }
    }
    if(yoko==0){ //yokoが0なら32、32なら0を挿入
      yoko= 32;
    }else{
      yoko= 0;
      Serial.println(",");//デバッグ用serial
    }  
    display.display();//画面更新
  }
  delay(500);
}
```

2秒間のAdafruitロゴの後、画像の投影が始まります。
下から徐々に生成され完成したのち、消灯してまた徐々に生成されます

## 解説
### 画像データ

画像データをわかりやすさのため、2進数標記に変更しました。

2進数標記のデータを使う場合、今回使うのは32bitマイコンなので32文字ずつカンマで区切り、すべての数値の前に2進数入力であることを表す0bを挿入します。
16進数標記のデータを使う場合、32bit分の4文字ずつカンマで区切り、すべての数の前に16進数入力であることを表す0xを挿入します。
| / | 16bitマイコン | 32bitマイコン |
|:-:|:-:|:-:|
| 2進数標記  | 0b 16文字 | 0b 32文字 |
| 16進数標記 | 0x 2文字  | 0x 4文字  |

uint64_tを使えば64bitの数字を保存できるのですが、bit演算の部分でうまくいかないので32bitに区切っています。

もし16bitマイコンを使う場合は16bitで区切ってください。

### 演算部分
bitmapのbitを一つずつ読み取り、for文でSSD1306に入力します。

説明はプログラムに多くコメントしてあるので、必要なら解読してください。

変数 yokoにより右側のデータか、左側のデータかを区別しています。
16bitマイコンを使う際はこの部分に修正が必要になります。

デバッグ用serialは、画像データと同様のものが送信されてきます。


## 最後に
ここまで長々とプログラムを書きましたが、実は画像表示用の関数がすでに存在します。
それでもここまで労力をかけた理由は、自作したほうが自由にいじれるのと、私の技術力向上のためです。
SSD1306のOLEDの使い方は他にもいっぱいあるようなのでもう少し遊びたい思います。