三浦研究所

社会人エンジニア1年目が考える日々の研鑽、日常について書き、お互いに刺激しあえるようなブログを目指しています。

【低価格マイコン】【実装】Arduino NanoでOLED (SSD1306)を動かす

f:id:bamboomush:20210104123601p:plain

 Arduino Nanoを用いてOLEDを実装したので、そのやり方について紹介したいと思います。

この記事を読むことで、超安価なマイコンであるArduino NanoでOLEDが動かせるようになります。

動かしている動画が以下のものです。

youtu.be

OLEDを動かせることで、画面に文字を表示したり、絵を表示するようなGUIを作ったり、センサから取得してきたデータを表示したりできます。これにより、自作IoT機器やロボットがより華やかになること間違いなしです!

 

ESP32版はこちら

www.takeshi-1222.com

 

◆Arduino関係の実装記事◆ 
  • DCモータ実装

www.takeshi-1222.com

  •  サーボモータ実装

www.takeshi-1222.com

 

Arduino Nano, OLEDの簡単な説明

Arduino Nano

Arduino Nanoは超安価で購入ができるマイコンで、電気やプログラミングの深い知識を持っていない電子工作初心者でも扱いやすい、オープンソースマイコンです。

Arduinoと比較すると、性能は劣るものの、安価で広い用途で使用可能なので初心者に適しています。

ちなみに、上記が純正品ですが、互換品である以下も性能面では変わらないので強いこだわりがない限りは、互換品の方がおすすめです。

OLED

OLEDは世間でいうところの有機ELディスプレイです。最近のテレビのディスプレイによく使われており、液晶ディスプレイと比べて、高コントラストで人気です。液晶 (LCD)に比べ、単価は、OLEDの方が高いが、小型で様々な映像表現ができます。

 これがあることでセンサ情報に対して、視覚的にわかりやすい情報を提示できるようにできます。これの真骨頂はセンサと組み合わせなどで実現できますので、その記事も今後書きます。

実験構成

 今回の実験に使用する部品は以下のものです。
  • Arduino Nano (互換品)
  • OLEDディスプレイ (SSD1306)
  • ジャンパ線多数

Arduino Nano、OLEDディスプレイは上記のものを使用しています。

 

ジャンパ線は何を使用してもいいですが、一応リンクを張っておきます。(メスメスのみで配線可能です)

実験

配線

ピンアサインは以下のようになっています。

Arduino NANO Pinout
@Arduino NANO Pinout Diagram | Microcontroller Tutorials

まず配線は以下のようにします。

f:id:bamboomush:20210104172351p:plain

配線ができると以下のような画像のようになります。

f:id:bamboomush:20210104134049j:plain

実行コード

ここまで出来たら以下のコードを実行することで動作確認ができます。

#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 32 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
// The pins for I2C are defined by the Wire-library. 
// On an arduino UNO:       A4(SDA), A5(SCL)
// On an arduino Nano:       A4(SDA), A5(SCL)
// On an arduino MEGA 2560: 20(SDA), 21(SCL)
// On an ESP32: 21(SDA), 22(SCL)
// On an arduino LEONARDO:   2(SDA),  3(SCL), ...
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define NUMFLAKES     10 // Number of snowflakes in the animation example

#define LOGO_HEIGHT   16
#define LOGO_WIDTH    16

#define XPOS   0 // Indexes into the 'icons' array in function below
#define YPOS   1
#define DELTAY 2

static const unsigned char PROGMEM logo_bmp[] =
{ B00000000, B11000000,
  B00000001, B11000000,
  B00000001, B11000000,
  B00000011, B11100000,
  B11110011, B11100000,
  B11111110, B11111000,
  B01111110, B11111111,
  B00110011, B10011111,
  B00011111, B11111100,
  B00001101, B01110000,
  B00011011, B10100000,
  B00111111, B11100000,
  B00111111, B11110000,
  B01111100, B11110000,
  B01110000, B01110000,
  B00000000, B00110000 };

void testdrawstyles(void) {
  display.clearDisplay();

  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);        // Draw white text
  display.setCursor(0,0);             // Start at top-left corner
  display.println(F("Hello, world!"));

  display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); // Draw 'inverse' text
  display.println(3.141592);

  display.setTextSize(2);             // Draw 2X-scale text
  display.setTextColor(SSD1306_WHITE);
  display.print(F("0x")); display.println(0xDEADBEEF, HEX);

  display.display();
  delay(2000);
}

void testanimate(const uint8_t *bitmap, uint8_t w, uint8_t h) {
  int8_t f, icons[NUMFLAKES][3];

  // Initialize 'snowflake' positions
  for(f=0; f< NUMFLAKES; f++) {
    icons[f][XPOS]   = random(1 - LOGO_WIDTH, display.width());
    icons[f][YPOS]   = -LOGO_HEIGHT;
    icons[f][DELTAY] = random(1, 6);
    Serial.print(F("x: "));
    Serial.print(icons[f][XPOS], DEC);
    Serial.print(F(" y: "));
    Serial.print(icons[f][YPOS], DEC);
    Serial.print(F(" dy: "));
    Serial.println(icons[f][DELTAY], DEC);
  }

  for(;;) { // Loop forever...
    display.clearDisplay(); // Clear the display buffer

    // Draw each snowflake:
    for(f=0; f< NUMFLAKES; f++) {
      display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, SSD1306_WHITE);
    }

    display.display(); // Show the display buffer on the screen
    delay(200);        // Pause for 1/10 second

    // Then update coordinates of each flake...
    for(f=0; f< NUMFLAKES; f++) {
      icons[f][YPOS] += icons[f][DELTAY];
      // If snowflake is off the bottom of the screen...
      if (icons[f][YPOS] >= display.height()) {
        // Reinitialize to a random position, just off the top
        icons[f][XPOS]   = random(1 - LOGO_WIDTH, display.width());
        icons[f][YPOS]   = -LOGO_HEIGHT;
        icons[f][DELTAY] = random(1, 6);
      }
    }
  }
}

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

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
    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(2000); // Pause for 2 seconds

  // Clear the buffer
  display.clearDisplay();

  // Draw a single pixel in white
  display.drawPixel(10, 10, SSD1306_WHITE);

  // Show the display buffer on the screen. You MUST call display() after
  // drawing commands to make them visible on screen!
  display.display();
  delay(2000);

  testdrawstyles();    // Draw 'stylized' characters

  // Invert and restore display, pausing in-between
  display.invertDisplay(true);
  delay(1000);
  display.invertDisplay(false);
  delay(1000);

  testanimate(logo_bmp, LOGO_WIDTH, LOGO_HEIGHT); // Animate bitmaps
}

void loop() {
}

上記のソースコードでは、OLEDディスプレイ上に文字を出力した後に、雪が降るアニメーションを表示します。実際には、ここにセンサ情報を出力したいです。

まとめ

今回は、Arduino NanoでOLEDを動かすために必要なものの紹介と、サンプルプログラムの紹介をしました。

参考資料

ESP32でOLEDディスプレイ「SSD1306」にHello-world表示してみた | Wak-tech