他の周辺デバイスを使いながらちょっとした表示を行うのに便利なSwitchScienceのI2C接続のキャラクターディスプレイを先日紹介したが、今回は同様に小型でI2C接続な128×64ドットのOLEDディスプレイについて説明する。
小型・省電力で、I2C接続のため電源線と含め4線しか使わないためピンの競合の心配なく他の周辺デバイスを使いながらデバッグや情報を表示するのに便利なディスプレイである。
ただ、SwitchScienceのキャラクターディスプレイと異なり、文字フォントデータは内蔵されていないため、ドット単位での描画となる。その代り、自由にグラフィックの描画や自由なサイズのテキスト出力が出来る。フリーのライブラリもあり、簡単に絵を出力できるが、その分データ領域やメモリ領域を食うと言うデメリットもある。
ピン配置がVCC/GND/SCL/SDAの並びのため、使い易くするためピンを少し加工する。
ニッパでプラスチックを真ん中で折り、VCC/GNDを外向きに曲げる(画面を割らない様注意)。
短めのケーブルを準備する。
後はArudinoに挿すだけ。
電源を逆に挿すと白煙と共に壊れてしまうので、接続には注意。
ライブラリは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)
後はビルドし実行するだけで動作する。
続いて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
似ている定義があるので間違えない様注意。後はビルドし実行するだけで完了。
サンプルのGraphics Testを実行してみた動画。結構描画が早い。
SwitscienseのI2Cディスプレイ同様、WiFiシールドと組み合わせて、IPアドレスやWeb経由で入力したテキストを表示する様にしてみた。
さすがに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で簡易オシロスコープを作っている人もいるので、アイデア次第で色々用途が広がりそうだ。
[…] U∞g:U∞g galkery。解り易い実例。 ProgramResource.net:I2C 128×64 OLEDディスプレイをArduinoで使う。 Arduino […]