AVR0シリーズでOLEDディスプレイを使う方法(1)

マイコン/Arduino

AVR0シリーズでOLED表示器を使いたい!

電子工作界隈でよく使われている小型ディスプレイに、SSD1306というコントローラーを搭載したOLED(有機発光ダイオード)があります。フルカラーではありませんが、単色で安くてくっきりと表示できるので定番の一つです。

通常、ArduinoからこれらのOLEDを使用する場合はAdafuiteなどのライブラリを使用するのが普通で簡単です。が、ATTINYx0xシリーズ(AVR0シリーズ)ではこれらのライブラリが正常に動作しないため、ハードルが少し高くなっています。そこで、今回はごく簡単にAVR0シリーズからSSD1306搭載のOLEDを制御する方法を紹介します。

今回は様々な機能やエラー検知等はごっそり削ってあります。ただシンプルに文字を表示するだけです。

プログラムリスト

以下にプログラムリストを掲載します。プログラムは以下の3つのファイルから構成されています。

  • i2coled_avr0.ino
  • TINY_SSD1306.h
  • font6x8.h

フォントデータに関してはTiny4Kに使われているデータをほぼそのまま使わせてもらいました。ありがとうございます。

ちなみに、ここで想定しているのは、0.96インチの128×64ピクセルのOLEDです。これをI2CでATTINY404と接続しています。電源は単4電池2本で十分動きました。

本体

#include "Wire.h"
#include "TINY_SSD1306.h"

void setup() {
  Wire.begin();
  TINY1306 oled = TINY1306();
  oled.init();
  oled.ClearGrMem();
  oled.display();

  oled.setPage(0);
  char cstr01[] = "TSUZUREYA.NET";
  oled.println6x8(cstr01);

  oled.setPage(4);
  char cstr02[] = "poweredByGonsuke";
  oled.println6x8(cstr02);

  oled.display();
}

void loop()
{
  delay(5000);
}

基本的に、指定できるのは

  • ページ番号(=行番号)
  • 各行に表示する文字(char*型)

の2つだけです。そんなに難しくないので見ればわかるかとは思いますが

oled.setPage(0);

でページ(行番号)を指定しています。次に

 char cstr01[] = "TSUZUREYA.NET"; 
 oled.println6x8(cstr01);

char配列型に表示させたい文字をいれて、println6x8に渡せばOKです。全て書き終えたら

oled.display();

で実際に表示されます。今のところ、文字のサイズを変えたり細かく開始位置を指定するような機能はありません。1行づつ表示するだけです。


▲実行結果


OLEDディスプレイクラス

お行儀がわるいですが、ヘッダーファイルに全部書いてます。

ファイル名はTINY_SSD1306.hとして、プログラム本体と同じフォルダにおいてください。

#include "Wire.h"
#include "font6x8.h"

class TINY1306 {
  private:
    void printOneChar6x8(char chr);
  public:
    uint8_t oledAddr;
    uint8_t oledWidth; // OLEDの幅(ピクセル数)
    uint8_t oledPages; // OLEDのページ数
    TINY1306();
    void init();
    void setPage(int p);
    void display();
    void ClearGrMem();
    void println6x8(char* chr);
};

TINY1306::TINY1306()
{
  oledAddr = 0x3C;
  oledWidth = 128;
  oledPages = 8;
}

void TINY1306::init()
{
  Wire.beginTransmission(oledAddr);
  Wire.write(0x00); // 複数バイトコマンドタグ
  Wire.write(0xC8); // [C0]/C8:上下の描画方向
  Wire.write(0xA1); // [A0]/A1:左右の描画方向
  Wire.write(0xA8); Wire.write(0x3F); // 画面の解像度 [3F]:64Line / 1F:32Line
  Wire.write(0xDA); Wire.write(0x12); // [12]:Sequential / 02:Alternative
  Wire.write(0xD3); Wire.write(0x00); // 縦方向のオフセット
  Wire.write(0x40); // 縦方向の描画開始位置
  Wire.write(0xA6); // 表示方法 - A7にすると画面反転
  Wire.write(0x8D); Wire.write(0x14);
  Wire.endTransmission();
  /*参考
    ゆるく楽しむ プログラミング&電子工作 様
    http://try3dcg.world.coocan.jp/note/i2c/ssd1306.html
  */
}

void TINY1306::setPage(int p)
{
  Wire.beginTransmission(oledAddr);
  Wire.write(0x00);
  Wire.write(0xB0 | (p & 0x07));
  Wire.write(0x00);
  Wire.write(0x10);
  Wire.endTransmission();
}

void TINY1306::display()
{
  Wire.beginTransmission(oledAddr);
  Wire.write(0x80);
  Wire.write(0xAF);
  Wire.endTransmission();
}

void TINY1306::ClearGrMem()
{
  for (uint8_t m = 0; m < oledPages; m++) {
    setPage(m);
    Wire.beginTransmission(oledAddr);
    Wire.write(0x40);
    for (uint8_t x = 0; x < oledWidth; x++) {
      if (Wire.write(0x00) == 0) {
        Wire.endTransmission();
        Wire.beginTransmission(oledAddr);
        Wire.write(0x40);
        Wire.write(0x00);
      } 
    }
    Wire.endTransmission();
  }
}

void TINY1306::printOneChar6x8(char chr)
{
  int i = ((int)chr - 32) * 6; //ASCIIコードから変換
  Wire.beginTransmission(oledAddr);
  Wire.write(0x40);
  for (int j = 0; j < 6; j++)
  {
    Wire.write(font6x8[i + j]);
  }
  Wire.endTransmission();
}

void TINY1306::println6x8(char* chr)
{
  for (uint8_t i = 0; i < strlen(chr); i++) {
    printOneChar6x8(chr[i]);
  }
}

ポイントはここでしょうか

int i = ((int)chr - 32) * 6; //ASCIIコードから変換

Tiny4KOKLEDから拝借してきたフォントデータは、各文字のアスキーコードから32を引き、6倍したところがその文字のスタート位置になっています。ですのでそこから6バイト分読み込めばOKということになります。

フォント

Tiny4KOLEDライブラリの6×8フォントを拝借しました。

フォントデータをPROGMEMに置くと何故かバグってうまく動かないので普通にconstです。これで半日ハマりました。

ファイル名はfont6x8.hとして、プログラム本体と同じフォルダに保存してください。

/*
* This fonts is 6x8size font for SSD1306 display controlled by AVR0 Series.
*
* Based on Tiny4kOLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x32 displays
* from 2017-04-25 at https://github.com/datacute/Tiny4kOLED
*
*/

/* Standard ASCII 6x8 font */
//PROGMEMにおくと何故かうまく動作しない
const uint8_t font6x8 [] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0 
0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, // ! 1 
0x00, 0x00, 0x07, 0x00, 0x07, 0x00, // " 2 
0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14, // # 3 
0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12, // $ 4 
0x00, 0x23, 0x13, 0x08, 0x64, 0x62, // % 5 
0x00, 0x36, 0x49, 0x55, 0x22, 0x50, // & 6 
0x00, 0x00, 0x05, 0x03, 0x00, 0x00, // ' 7 
0x00, 0x00, 0x1c, 0x22, 0x41, 0x00, // ( 8 
0x00, 0x00, 0x41, 0x22, 0x1c, 0x00, // ) 9 
0x00, 0x14, 0x08, 0x3E, 0x08, 0x14, // * 10
0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, // + 11
0x00, 0x00, 0x00, 0xA0, 0x60, 0x00, // , 12
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, // - 13
0x00, 0x00, 0x60, 0x60, 0x00, 0x00, // . 14
0x00, 0x20, 0x10, 0x08, 0x04, 0x02, // / 15
0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, // 0 16
0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, // 1 17
0x00, 0x42, 0x61, 0x51, 0x49, 0x46, // 2 18
0x00, 0x21, 0x41, 0x45, 0x4B, 0x31, // 3 19
0x00, 0x18, 0x14, 0x12, 0x7F, 0x10, // 4 20
0x00, 0x27, 0x45, 0x45, 0x45, 0x39, // 5 21
0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30, // 6 22
0x00, 0x01, 0x71, 0x09, 0x05, 0x03, // 7 23
0x00, 0x36, 0x49, 0x49, 0x49, 0x36, // 8 24
0x00, 0x06, 0x49, 0x49, 0x29, 0x1E, // 9 25
0x00, 0x00, 0x36, 0x36, 0x00, 0x00, // : 26
0x00, 0x00, 0x56, 0x36, 0x00, 0x00, // ; 27
0x00, 0x08, 0x14, 0x22, 0x41, 0x00, // < 28
0x00, 0x14, 0x14, 0x14, 0x14, 0x14, // = 29
0x00, 0x00, 0x41, 0x22, 0x14, 0x08, // > 30
0x00, 0x02, 0x01, 0x51, 0x09, 0x06, // ? 31
0x00, 0x32, 0x49, 0x59, 0x51, 0x3E, // @ 32
0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C, // A 33
0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, // B 34
0x00, 0x3E, 0x41, 0x41, 0x41, 0x22, // C 35
0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C, // D 36
0x00, 0x7F, 0x49, 0x49, 0x49, 0x41, // E 37
0x00, 0x7F, 0x09, 0x09, 0x09, 0x01, // F 38
0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A, // G 39
0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, // H 40
0x00, 0x00, 0x41, 0x7F, 0x41, 0x00, // I 41
0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, // J 42
0x00, 0x7F, 0x08, 0x14, 0x22, 0x41, // K 43
0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, // L 44
0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F, // M 45
0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F, // N 46
0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, // O 47
0x00, 0x7F, 0x09, 0x09, 0x09, 0x06, // P 48
0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E, // Q 49
0x00, 0x7F, 0x09, 0x19, 0x29, 0x46, // R 50
0x00, 0x46, 0x49, 0x49, 0x49, 0x31, // S 51
0x00, 0x01, 0x01, 0x7F, 0x01, 0x01, // T 52
0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F, // U 53
0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F, // V 54
0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F, // W 55
0x00, 0x63, 0x14, 0x08, 0x14, 0x63, // X 56
0x00, 0x07, 0x08, 0x70, 0x08, 0x07, // Y 57
0x00, 0x61, 0x51, 0x49, 0x45, 0x43, // Z 58
0x00, 0x00, 0x7F, 0x41, 0x41, 0x00, // [ 59
0x00, 0x02, 0x04, 0x08, 0x10, 0x20, // \ 60
0x00, 0x00, 0x41, 0x41, 0x7F, 0x00, // ] 61
0x00, 0x04, 0x02, 0x01, 0x02, 0x04, // ^ 62
0x00, 0x40, 0x40, 0x40, 0x40, 0x40, // _ 63
0x00, 0x00, 0x01, 0x02, 0x04, 0x00, // ' 64
0x00, 0x20, 0x54, 0x54, 0x54, 0x78, // a 65
0x00, 0x7F, 0x48, 0x44, 0x44, 0x38, // b 66
0x00, 0x38, 0x44, 0x44, 0x44, 0x20, // c 67
0x00, 0x38, 0x44, 0x44, 0x48, 0x7F, // d 68
0x00, 0x38, 0x54, 0x54, 0x54, 0x18, // e 69
0x00, 0x08, 0x7E, 0x09, 0x01, 0x02, // f 70
0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C, // g 71
0x00, 0x7F, 0x08, 0x04, 0x04, 0x78, // h 72
0x00, 0x00, 0x44, 0x7D, 0x40, 0x00, // i 73
0x00, 0x40, 0x80, 0x84, 0x7D, 0x00, // j 74
0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, // k 75
0x00, 0x00, 0x41, 0x7F, 0x40, 0x00, // l 76
0x00, 0x7C, 0x04, 0x18, 0x04, 0x78, // m 77
0x00, 0x7C, 0x08, 0x04, 0x04, 0x78, // n 78
0x00, 0x38, 0x44, 0x44, 0x44, 0x38, // o 79
0x00, 0xFC, 0x24, 0x24, 0x24, 0x18, // p 80
0x00, 0x18, 0x24, 0x24, 0x18, 0xFC, // q 81
0x00, 0x7C, 0x08, 0x04, 0x04, 0x08, // r 82
0x00, 0x48, 0x54, 0x54, 0x54, 0x20, // s 83
0x00, 0x04, 0x3F, 0x44, 0x40, 0x20, // t 84
0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C, // u 85
0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C, // v 86
0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, // w 87
0x00, 0x44, 0x28, 0x10, 0x28, 0x44, // x 88
0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C, // y 89
0x00, 0x44, 0x64, 0x54, 0x4C, 0x44, // z 90
0x00, 0x08, 0x36, 0x41, 0x41, 0x00, // { 91
0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, // | 92
0x00, 0x00, 0x41, 0x41, 0x36, 0x08, // } 93
0x00, 0x08, 0x04, 0x08, 0x10, 0x08, // ~ 94
};

注意など

これだけでもATTINY404の場合フラッシュ容量のおよそ半分は占めていますし、小数点計算などをさせるとあっという間に容量が足りなくなります。ATTINY804やATTINY1604あたりを使う方がいいかもしれません。

参考

ゆるく楽しむ プログラミング&電子工作 様

ゆるく楽しむプログラミングと電子工作

Tiny4kOLED

GitHub - datacute/Tiny4kOLED: Library for an ATTiny85 to use an SSD1306 powered, double buffered, 128x32 pixel OLED, over I2C
Library for an ATTiny85 to use an SSD1306 powered, double buffered, 128x32 pixel OLED, over I2C - datacute/Tiny4kOLED

 

コメント