Program Resource

開発者向け各種コード、アルゴリズム、リソース情報ライブラリ もしくはねふぁの覚え書き

他の周辺デバイスを使いながらちょっとした表示を行うのに便利なSwitchScienceのI2C接続のキャラクターディスプレイを先日紹介したが、今回は同様に小型でI2C接続な128×64ドットのOLEDディスプレイについて説明する。

DSC03592

小型・省電力で、I2C接続のため電源線と含め4線しか使わないためピンの競合の心配なく他の周辺デバイスを使いながらデバッグや情報を表示するのに便利なディスプレイである。

ただ、SwitchScienceのキャラクターディスプレイと異なり、文字フォントデータは内蔵されていないため、ドット単位での描画となる。その代り、自由にグラフィックの描画や自由なサイズのテキスト出力が出来る。フリーのライブラリもあり、簡単に絵を出力できるが、その分データ領域やメモリ領域を食うと言うデメリットもある。

 ピン配置がVCC/GND/SCL/SDAの並びのため、使い易くするためピンを少し加工する。

ニッパでプラスチックを真ん中で折り、VCC/GNDを外向きに曲げる(画面を割らない様注意)。

DSC03593

DSC03595

短めのケーブルを準備する。

DSC03596

後はArudinoに挿すだけ。

DSC03597

電源を逆に挿すと白煙と共に壊れてしまうので、接続には注意。

ライブラリはAdafruitのssd1306のライブラリや、u8glibのライブラリが利用できる。u8libのライブラリの方が使用メモリが少なくお勧めである。Adruino UNOの場合、Adafuitのライブラリを使った場合それだけでプログラム領域60%以上、メモリ70%以上も取ってしまう。

とりあえず使い方は簡単なのでそれぞれの使い方について説明する。

AdafruitのライブラリはAdafruit_GFXとAdafruit_ssd1306のライブラリをインポートする。

https://github.com/adafruit/Adafruit-GFX-Library

https://github.com/adafruit/Adafruit_SSD1306

インストール後、スケッチサンプルからssd1306_128x64_i2cを開く。開いた後、setup()関数内にある下記行の0x3Dを0x3Cに変更する。

 display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3D (for the 128x64)

後はビルドし実行するだけで動作する。

DSC03598

DSC03599

DSC03601

続いてu8glib。こちらはArduino UNOでプログラム領域30%程度、メモリ12%程度で済む。

https://code.google.com/p/u8glib/

上記ページのU8glib:にあるBinary download linksのU8glib for Arduinoを開き、Donwloadsにあるu8glib_arduino_v1.17.zip(バージョンは異なる可能性がある)をダウンロードし、ライブラリとしてインポートする。

インポート後、Hello World等の適当なサンプルスケッチを開き、下記行のコメントを外す。

U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE|U8G_I2C_OPT_DEV_0); // I2C / TWI

似ている定義があるので間違えない様注意。後はビルドし実行するだけで完了。

DSC03603

サンプルのGraphics Testを実行してみた動画。結構描画が早い。

DSC03608

DSC03609

DSC03610

DSC03611

SwitscienseのI2Cディスプレイ同様、WiFiシールドと組み合わせて、IPアドレスやWeb経由で入力したテキストを表示する様にしてみた。

DSC03612

さすがにArduino UNOでWiFiシールドとOLEDディスプレイを動かすのはメモリ的に厳しく、色々削ってかなりぎりぎりの所で動いている。以下、サンプルコード。

#include <Adafruit_CC3000.h>
#include <Wire.h>
#include <SPI.h>
#include "U8glib.h"
#include "utility/debug.h"
#include "utility/socket.h"

#define ADAFRUIT_CC3000_IRQ   3  // MUST be an interrupt pin!
#define ADAFRUIT_CC3000_VBAT  5
#define ADAFRUIT_CC3000_CS    10
Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT, SPI_CLOCK_DIV2);

#define WLAN_SSID       "myssid"      // cannot be longer than 32 characters!
#define WLAN_PASS       "mykey"
#define WLAN_SECURITY   WLAN_SEC_WPA2

#define LISTEN_PORT 80
char in_buffer[48];
int in_size = 0;
char req_page[32];
char in_ch;
char last_ch;
char subch[24];
char decch[24];
char *cmd;
char oledstrbuff[6][16];

Adafruit_CC3000_Server httpServer(LISTEN_PORT);

U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE|U8G_I2C_OPT_DEV_0);	// I2C / TWI 

void oled_drawstr(int line,char *text){
  strcpy(oledstrbuff[line],text);
  u8g.firstPage();
  do {
    u8g.setFont(u8g_font_6x10);
    u8g.setFontRefHeightExtendedText();
    u8g.setDefaultForegroundColor();
    u8g.setFontPosTop();
    for (int i=0;i<6;i++)
      u8g.drawStr(0,10*i,oledstrbuff[i]);
  } while (u8g.nextPage());
}

void setup(void)
{
  oled_drawstr(0,"Booting");
  pinMode(6, OUTPUT);
  Serial.println(F("\nInitializing..."));
  if (!cc3000.begin()) {
    while (1);
  }
  oled_drawstr(1,"Connect AP...");
  if (!cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY)) {
    while (1);
  }
  oled_drawstr(1,"Connect AP OK");
  delay(500);
  oled_drawstr(2,"DHCP");
  while (!cc3000.checkDHCP()) {
    delay(100); // ToDo: Insert a DHCP timeout!
  }
  while (! displayConnectionDetails()) {
    delay(1000);
  }

  httpServer.begin();
  digitalWrite(6, HIGH);
}

void loop(void)
{
  Adafruit_CC3000_ClientRef client = httpServer.available();
  if (client) {
    digitalWrite(6, LOW);
    if (client.available() > 0) {
      in_ch = client.read();
      if (in_size < 47 && in_ch != '\r' && in_ch != '\n')
        in_buffer[in_size++] = in_ch;
      if (in_ch == '\r') {
        in_buffer[in_size] = '\0';
        cmd = getparam(in_buffer, ' ', 0);
        if (strcmp(cmd, "GET") == 0)
          strcpy(req_page, getparam(in_buffer, ' ', 1));
        in_size = 0;
        if (last_ch == '\r') //double linefeed, end of request
          replypage(&client);
      }
      if (in_ch == '\r' || in_ch == '\n')
        last_ch = '\r';
      else
        last_ch = ' ';
    }
    digitalWrite(6, HIGH);
  }
}

//return n-th char array separated with specified character
char *getparam(char *txt, char seperator, int index) {
  int strcnt = 0;
  int indcnt = 0;
  memset(subch, 0, 24);
  for (int i = 0; i < strlen(txt); i++) {
    if (txt[i] == seperator) {
      indcnt++;
      if (indcnt > index)
        break;
    } else if (indcnt == index) {
      subch[strcnt++] = txt[i];
    }
  }
  return &subch[0];
}

char *decodechar(char *txt){
  memset(decch,0,24);
  int deccnt = 0;
  char hexbuf[3] = {0,0,0};

  for (int i=0;i<strlen(txt);i++){
    if (txt[i] == '+'){
      decch[deccnt++] = ' ';
    }else if (txt[i] == '%'){
      hexbuf[0] = txt[i+1];
      hexbuf[1] = txt[i+2];
      decch[deccnt++] = strtol(hexbuf,NULL,16);
      i+=2;
    }else{
      decch[deccnt++] = txt[i];
    }
  }
  return decch;
}

void replypage(Adafruit_CC3000_ClientRef *pclient) {
  if (strcmp(getparam(req_page, '=', 0), "/?t") == 0) {
    char char_param[10];
    strcpy(char_param,decodechar(getparam(req_page, '=', 1)));
    oled_drawstr(5, char_param);
  }

  pclient->println("HTTP/1.1 200 OK");
  pclient->println("Content-Type: text/html");
  pclient->println("");
  pclient->fastrprint("<html><title>Arduino Web</title><body>");
//  char buffer[96];
//  sprintf(buffer, "Requested : %s", req_page);
//  pclient->fastrprint(buffer);
  pclient->fastrprint("<BR><form method=\"GET\" action=\"/\">");
  pclient->fastrprint("<input type=\"text\" maxlength=\"8\" name=\"t\"><input type=\"submit\" value=\"Go\"></form>");
  pclient->fastrprint("</body></html>");
  delay(1000);
  pclient->close();
}

bool displayConnectionDetails(void)
{
  uint32_t ipAddress, netmask, gateway, dhcpserv, dnsserv;

  if (!cc3000.getIPAddress(&ipAddress, &netmask, &gateway, &dhcpserv, &dnsserv)) {
    oled_drawstr(3, "IP Request Fail");
    return false;
  } else {
    char ipadd[16];
    sprintf(ipadd,"%d.%d.%d.%d",(uint8_t)(ipAddress >> 24),(uint8_t)(ipAddress >> 16),(uint8_t)(ipAddress >> 8),(uint8_t)(ipAddress));
    oled_drawstr(3, "IP Address:");
    oled_drawstr(4, &ipadd[0]);
    return true;
  }
}

同OLEDディスプレイを使ってArduinoで簡易オシロスコープを作っている人もいるので、アイデア次第で色々用途が広がりそうだ。

[GPG] 小型I2C 128x64 OLED ディスプレイ Arduino等の電子工作用 (ホワイト)
小型I2C 128×64 OLED ディスプレイ Arduino等の電子工作用 (ホワイト)


I2C 128×64 OLEDディスプレイをArduinoで使う」 に1件のコメント

  1. […] U∞g:U∞g galkery。解り易い実例。 ProgramResource.net:I2C 128×64 OLEDディスプレイをArduinoで使う。 Arduino […]

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です


*