Arduino　OLED：プログラム検証

# 概要
ArduinoようOLEDを買いました。
ちょっとしたものを作るのに便利です。
プログラムを書いていて疑問が増えてきたので検証していきます。

配線等の使い方は下記がおすすめです。

https://ht-deko.com/arduino/oled_spi.html

プログラムについてはこちら

https://qiita.com/jakalada/items/793a6cf5ff2796db4e86

# 文字関係
## TextSize
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/ef512df6-bc97-3bce-b797-38a870b7c7dc.png)


```C
  display.clearDisplay();
  display.setCursor(0, 0);
  
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.println("hello");

  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.println("hello");

  display.setTextSize(3);
  display.setTextColor(WHITE);
  display.println("hello");

  display.setTextSize(4);
  display.setTextColor(WHITE);
  display.println("hello");

  display.display();
```

### ビットサイズも確認

|textSize|縦bit|横bit|
|-|-|-|
|4|32bit|24bit|
|3|25bit|18bit|
|2|16bit|12bit|
|1|8bit|6bit|

ぐらいの見積もり計算するのがおすすめです

textSize(1)で"2"を描画するとかなり見にくくなります。
![WIN_20231227_22_57_07_Pro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/0944a633-cd8f-d16f-0988-dc69d68eb6a8.jpeg)
textSize(1)はあまりおすすめしません。

#### textSize(4)
2個×5個
32bit×24bitぐらい
![WIN_20231227_14_28_49_Pro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/3c1d8dd4-5373-1d57-6297-dcc3c7ddd7e8.jpeg)


![WIN_20231227_14_30_41_Pro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/15894598-160e-2768-a541-09746e270119.jpeg)

#### textSize(3)
2.5個×7個
25bit×18bitぐらい
![WIN_20231227_14_33_26_Pro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/8a9701a3-55f3-0837-c54d-0b2f7ff71dda.jpeg)


![WIN_20231227_14_32_38_Pro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/c2359163-c9fb-8827-eda6-316af47b8112.jpeg)


#### textSize(2)
4個×10個
16bit×12bitぐらい
![WIN_20231227_14_34_25_Pro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/800ca30c-b196-c631-2188-4e41f75e8ff0.jpeg)

![WIN_20231227_14_35_09_Pro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/5606bb88-f7ef-c6e8-dd3a-41835799b0cc.jpeg)

#### textSize(1)
8個×21個
8bit×6bitぐらい
![WIN_20231227_14_36_49_Pro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/a1b8ddb0-0c92-dac5-59f4-fc014ce41130.jpeg)
![WIN_20231227_14_37_51_Pro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/e79eddda-ba33-7c52-8693-fed7860031ca.jpeg)


## setCursor:同じ場所に書く→かぶる

![WIN_20231226_22_12_54_Pro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/47c84bd0-b15f-5e55-29e5-f1f5710c4829.jpeg)

```C
  display.clearDisplay();
  display.setCursor(0, 0);
  
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.println("hello");

  display.setCursor(0, 0);
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.println("goodbye");


  display.display();
```
## setCursor:方向
setCursor(右方向、下方向）

## setCursor:setCursorの場所

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/da6916a8-560c-e494-32c0-462379f0bbcc.png)

* 1文字分カーソル移動ではなく、ドット移動の可能性が高い
* 上下移動と左右移動で比率が異なる

```C
  display.clearDisplay();
  display.setCursor(30, 30);  
  
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.println("hello");
```

## setCursor:文字サイズの影響を受けるかどうか

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/d203d9d1-23da-cce4-5dc2-a6313d3df1ce.png)
受けない

## 画面最大サイズ：
今持っているものは

* 右方向110
* 下方向60

```C
  for(int i = 0;i<=200; i++){
    display.clearDisplay();
    display.setTextSize(4);
    display.setCursor(i, 0);  
    display.setTextColor(WHITE);
    display.println("hello");
    display.display();
    Serial.println(i);
    delay(100);
  
  }
```

## 数値表示

```C
display.println()
```
の関係でintを直に入れられない

https://qiita.com/xxpisu/items/2c68722d7f1e38f7a4d0

```C
void num_to_string(int num, int digit) {
  char buffer_num[10];
  dtostrf(num, digit, 0, buffer_num);
  String num_string = String(buffer_num);
  return num_string;
}

int hoge = 10;
display.println(num_to_string(hoge,2));
```
こんな感じで関数を作ると楽かも

## 日本語表示
ライブラリが存在するがArduinoのメモリ容量的に厳しかった。導入は可能だった。

bitmapで表示するしかない？


## 文字を中央に配置したい
関数等は存在しない、文字数から先読みしてsetCursorするしかない。

# 点
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/6fb9f197-a25e-d7f3-5b11-7777836acd54.png)

横127,縦63のビットだと考えて数値を入力

```C
display.drawPixel(50, 10, WHITE); //右.下.COLOR
```

# 線
点と同じ

```C
  for(int i = 0;i<=150; i++){
    display.clearDisplay();
    display.drawLine(0, 0, i, 63, WHITE);
    
    display.display();
    Serial.println(i);
    delay(100);
  
  }
```

# bitmapイメージ

drawBitmapを使用する。

![WIN_20231226_22_55_13_Pro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/87866710-7c6c-ff9d-9c9d-8e1ad15a7ba4.jpeg)

```C
  unsigned char logo_bmp[] =
  { 0b00000111, 0b11100000,
    0b00000111, 0b11100000,
    0b00000111, 0b11100000,
    0b11100000, 0b00000111,
    0b11100000, 0b00000111,
    0b11100000, 0b00000111
  };

  display.clearDisplay();

  //(右、下、bmp、横幅、縦幅、1
  display.drawBitmap( 0,  0, logo_bmp, 16, 6, 1);

  display.display();
```

上下に隙間があるように見える・・・

bitイメージを作成するプログラム欲しいな・・・

## 画像変換プログラム結果：python使用


![WIN_20231227_00_22_09_Pro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/59de3524-5f7a-3581-80c7-c5b9881afeaf.jpeg)

若干わかりにくいし、元のかわいさが損なわれてしまった(目を閉じていると分かりにくくなるのかな)

![WIN_20231227_00_28_10_Pro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/dbfd5e0e-4ea2-2e3a-4abf-cf3d3a7fbe72.jpeg)

むずいなぁ


![WIN_20231227_00_37_18_Pro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/709be86d-a615-3273-fe4f-d7329c74f193.jpeg)

デフォルメ絵なら行けるかな

![WIN_20231227_00_41_23_Pro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/c328176f-4151-50bc-e593-5dc6f5875e93.jpeg)

細かい部分が混ざると潰れちゃう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/46f08379-3a2c-7547-90a1-4c8c462be4c5.png)
データの段階で中身がわかるの好き

----
データ（64*64）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/3d422857-1975-352e-8fe2-29a73ae1066c.png)

表示結果
![WIN_20231227_00_49_35_Pro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/d410fcce-a9b4-e61d-1b8a-2ce07bda9c75.jpeg)

表示されてない点があるなぁ


線の膨張を強めたら、表示される。
![WIN_20231227_00_52_35_Pro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/7b994493-505d-9e0d-4d7b-f2a82692ab18.jpeg)
目の周りとか細かいディテールがだせてないなぁ

まぁ、細かい絵はこのディスプレイじゃ無理だね。

漢字とかそうゆう表示機として使うべきだ

## 画像から配列生成プログラム

```python
def array_to_byte(array):
    string = "0b"
    for i in array:
        
        if i == 255:
            string = string + "1"
        else:
            string = string + "0"
            
    return string


import cv2
import numpy as np

width = 128
height = 64

img = cv2.imread('ueno2.png')

img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 

# 二値化(閾値100を超えた画素を255にする。)
ret, img_thresh = cv2.threshold(img_gray, 0, 255, cv2.THRESH_OTSU)

# 白黒反転
img_thresh = cv2.bitwise_not(img_thresh)

# 線を太くする
"""
bold = 1
#kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (bold, bold))
kernel = np.ones((bold,bold),np.uint8)
img_ker = cv2.dilate(img_thresh, kernel)
"""
img_ker = img_thresh

#　線を細くする 白黒反転しないときは使う
"""
thin = 0
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (thin, thin))
img_ker = cv2.erode(img_thresh, kernel)
"""

# サイズを合わせる
k =0.4
img_size = cv2.resize(img_ker,None,fx = k, fy = k)



# 切り抜き
x_a = -10
y_a = 0
center_x = int(img_size.shape[0]/2)
center_y = int(img_size.shape[1]/2)

width_2 = int(width/2)
height_2 = int(height/2)

img_crop = img_size[center_x - height_2 + y_a : center_x + height_2 + y_a
                    ,center_y - width_2 + x_a : center_y + width_2 + x_a]


#　表示用に拡大
img_show = cv2.resize(img_crop,None,fx = 5, fy = 5)

cv2.imshow("sample",img_show)


#bitimage　変数用に書き出し

x_num = int(width/8)

print("{",end="")
for y in range(height):
    for x in range(x_num):
        
        byte = img_crop[y][8*x:8*x+8]
        print(array_to_byte(byte), end="")
        
        if x == x_num-1 and y == height-1:
            #最後にはカンマつけない
            pass
        else:
            print(", ", end="")
        
        
    print(" ")
print("};",end="")


cv2.waitKey(0)
```

## 画像サイズが大きいとエラーが出る

画像サイズ64*64をbitmapdrawしようとしたところエラーが出た(32*32だと行けるんだけど)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/3a8e02d8-aa1f-6594-0c53-2fa0835300c9.png)

原因は

```C
static const unsigned char PROGMEM logo_bmp[] =
```
のようにプログラムメモリ上に置くといけるけど、

```C
unsigned char logo_bmp[] =
```
だとエラー吐く



# (追記)部品形状について
0.96inch,OLED,SSD1306という商品の中でもディスプレイのサイズが若干異なる場合がある。
ネジ穴の位置・ディスプレイの横幅が異なる場合がある。

商品化する予定の方はお気をつけください。

# (追記)メモリについて
128*64 = 8192bit = 1024byte = 1kB -> 50%以上のメモリ使用でAllocationエラーが起きる。
ガチでメモリがすくねぇ。

禄にプログラムが入らねぇ（笑）

float配列とか作るとすぐ超えるから注意ね
unsigned longとかでなんとかしな

もしくは

```C++
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels 
```
ピクセル量をへらすしかねぇな・・・これで半分500Byteにできる。
128のほうは減らすと描画範囲が減るので注意ね