macsbug

Just another WordPress.com site

Modification of SSD1306 library to be used for I2C OLED

leave a comment »

ESP8266 で I2C OLED 128×64 SSD1306 を動かす方法の備忘録。     2016.03.21
 
ESP8266 で OLED を動かす代表的なライブラリは 2つあります。今回は の方法です。
. squix78:esp8266-oled-ssd1306 ( SSD1306 + SSD1306Ui ):squix78氏に感謝。
 
2. cmmakerclub:ESP_Adafruit_SSD1306:cmmakerclubに感謝。
_  adafruit:Adafruit-GFX-Library:adafruitに感謝。
 


 
前回は 2. の ESP_Adafruit_SSD1306 と Adafruit-GFX-Library のコンパイルエラーを修正。
_    内容は「Adafruit-GFX.h」ライブラリーを追加修正しました。
 
今回は . で 線を描画できない無い為 ライブラリーに「drawLine」命令を追加しました。
_  線の描画が可能になり 文字と線を混在して表示でき いろいろな物が出来る様になる。
_  例: display.drawLine(x0,y0,x1,y1);



 
準備:
Mac OSX Mountain Lion
Arduino IDE 1.6.5_r5
_ Library Manager:Adafuruit GFX Library by Adafuruit Version 1.1.5 INSTALLED
_ Boards Manager:esp8266 by ESP8266 Community version 2.0.0 INSTALLED
 
前回の Adafruit-GFX.h:
squix78/esp8266-oled-ssd1306:SSD1306.h
squix78/esp8266-oled-ssd1306:SSD1306.cpp
 
ESP8266 (ESP-WROOM-02):AliExpress=1個435円(TELEC 技適済)。
I2C OLED 128×64 SSD1306:ebay=1個613円。


 
手順:SSD1306.h と SSD1306.cpp に「drawLine」を追加します。( 計3つ)


 
1. SSD1306.h へ追加:「void drawLine」をリストの最後に追加します。

// Draw the border of a drawLine at the given location          // add drawLine
void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1);  // add drawLine

 
2. SSD1306.cpp へ追加:drawLine 内で使用する _swap_ の処理。
_  リストの冒頭にある(#include “SSD1306.h”、#include )の下に以下を追加します。

#ifndef _swap_int16_t                                           // add drawLine
#define _swap_int16_t(a, b) { int16_t t = a; a = b; b = t; }    // add drawLine
#endif 

 
3. SSD1306.cpp へ追加:以下の「drawLine」をリストの最後に追加します。

// add drawLine
void SSD1306::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1) {
  int steep = abs(y1 - y0) > abs(x1 - x0);
  if (steep) {
    _swap_int16_t(x0, y0);
    _swap_int16_t(x1, y1);
  }

  if (x0 > x1) {
    _swap_int16_t(x0, x1);
    _swap_int16_t(y0, y1);
  }

  int dx, dy;
  dx = x1 - x0;
  dy = abs(y1 - y0);

  int err = dx / 2;
  int ystep;

  if (y0 < y1) {
    ystep = 1;
  } else {
    ystep = -1;
  }

  for (; x0<=x1; x0++) {
    if (steep) {
      setPixel(y0, x0);
    } else {
      setPixel(x0, y0);
    }
    err -= dy;
    if (err < 0) {
      y0 += ystep;
      err += dx;
    }
  }
}


 
詳細:
以下、基本も無く用語も適当かも知れませんので ご了承ください。
ライブラリーなど到底出来ないレベルで諦めていましたが なんとなくトライ。
ヒントは 「Adafruit-GFX」ライブラリーは「線」が引けると言う事。
この「線」の中味を「移植」すれば良いのではないかと 無い脳味噌で考えてみました。

「線」を描画する「drawLine」命令がある本体は「Adafruit-GFX」らしい。
そしてプログラムは cpp に書いてあるらしい。

移植を開始:
1.「Adafruit-GFX.cpp」 を「drawLine」で検索すると 196行目に「drawLine」命令がある。
_ この「drawLine」ルーチンをコピーします。(196-234行目)
_ 「drawLine」ルーチンを「SSD1306.cpp」の一番下に追加します。

2. 上記ルーチンの違いを修正します。
_ 理由は 「SSD1306.cpp」では「color」関数を使用しない為です。
_ 「,uint16_t color」「,color」「,color」 の3つを削除します。

3.「SSD1306.cpp」の定数の定義を設定します。
_ 「Adafruit-GFX.cpp」で追加した以下をコピーします。_swap_関数を宣言している所。
_ 3行を前回の Adafruit-GFX.cpp と同様に「SSD1306.cpp」の冒頭に追加します。

#ifndef _swap_int16_t 
#define _swap_int16_t(a, b) { int16_t t = a; a = b; b = t; }
#endif 


4.「SSD1306.h」には 関数の定義があり この中へ関数を記述します。
_ 中程にある drawRect 関数と同様に「void drawLine」を記述します。

void drawRect(int x, int y, int width, int height);
void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1);


5. 補足:
_ cmmakerclub の記述方式は「int16_t」を使用し squix78氏は「int」を使用しています。
_ squix78氏に会わせるならば「int16_t」を「int」にするとリストが奇麗になります。
_ どちらの記述でも動き 私は「int」形式にしました。

void drawLine(int x0, int y0, int x1, int y1);

 
感想:
ESP8266でトップレベルに入る squix78氏が何故 線を描画する命令を入れなかったか
わかりません。もしかすると、既にライブラリーの中に入っているかも知れません。
それでしたら取り越し苦労ですね。それとも 必要ないよ とかでしょうか。
デモプログラムには 線を描画する場面はありませんでした。
結果 squix78氏のライブラリーで drawLine により「3D Cube」が動いたので良しとします。
それにしても display.drawLine の後に delay(1) を入れなければならないのは何故なんだ。

drawLine:「Adafruit-GFX」の drawLine は とても参考になります。2点間の線の描画は
_  x0,y0,x1,y1 の + – を考慮する必要があり _swap_int16_t(x0, y0); で処理しています。
_ 2点間の増分と余りを計算する為に微分を使用しています。dx,dy,err の様です。
_ 解りやすい記述ですので 独自のルーチンが記述できるかもしれません。
_ こういう記述を見ていると これを作る人がいて 凄いな〜と実に関心致します。

素人がライブラリーに手を加えて 後で作者が新バージョンを出すと 手も足も
出なくなる恐れがありますね。
 


 
サンプル:3D Cube by macsbug


// Add drawLine to SSD1306.h and SSD1306.cpp : by macsbug
// https://github.com/squix78/esp8266-oled-ssd1306
#include <Wire.h>                                           // with mod SSD1306.cpp
#include "SSD1306.h"                                        // with mod SSD1306.h
#include "SSD1306Ui.h"                                      // OLED
extern "C" {
  #include "user_interface.h" 
}
SSD1306 display(0x3c,12,13);                                // OLED Initialize
float r, x1, z1, y2;                                        //
int f[8][2];                                                // Draw box
int x = 64;                                                 // 64=128/2
int y = 32;                                                 // 32= 64/2
int c[8][3] = {                                             // Cube
    {-20,-20, 20},{20,-20, 20},{20,20, 20},{-20,20, 20},    //
    {-20,-20,-20},{20,-20,-20},{20,20,-20},{-20,20,-20} };  //

void setup() {                                              //
  Wire.begin(12,13);                                        // SDA=GPIO012,SCL=13
  display.init();                                           // OLED
  display.setFont(ArialMT_Plain_16);                        //
  display.setTextAlignment(TEXT_ALIGN_LEFT);                //
  display.flipScreenVertically();                           // OLED
  display.displayOn();                                      // OLED
  display.clear();                                          // OLED
}                                                           //

void loop() {                                               //
  for (int a = 0; a <= 360; a = a + 3 ) {                   // 0-360 degree step 3
   for (int i = 0; i < 8; i++) {                            //
    r       = a * 0.0174532;                                // 1 degree
    x1      = c[i][2] * sin(r) + c[i][0] * cos(r);          // rotate X
    z1      = c[i][2] * cos(r) - c[i][0] * sin(r);          // rotate Z
    y2      = c[i][1] * cos(r) - z1      * sin(r);          // rotate Y
    f[i][0] = x1      * cos(r) - y2      * sin(r)  + x;     // X
    f[i][1] = x1      * sin(r) + y2      * cos(r)  + y;     // Y
    f[i][2] = c[i][1] * sin(r) + z1      * cos(r);          // Z
   }                                                        //
   display.clear();                                         //
   display.drawString(0,0,"3D Cube");                       //
   display.drawLine(f[0][0],f[0][1],f[1][0],f[1][1]);       //
   display.drawLine(f[1][0],f[1][1],f[2][0],f[2][1]);       //
   display.drawLine(f[2][0],f[2][1],f[3][0],f[3][1]);       //
   display.drawLine(f[3][0],f[3][1],f[0][0],f[0][1]);       //
   display.drawLine(f[4][0],f[4][1],f[5][0],f[5][1]);       //
   display.drawLine(f[5][0],f[5][1],f[6][0],f[6][1]);       //
   display.drawLine(f[6][0],f[6][1],f[7][0],f[7][1]);       //
   display.drawLine(f[7][0],f[7][1],f[4][0],f[4][1]);       //
   display.drawLine(f[0][0],f[0][1],f[4][0],f[4][1]);       //
   display.drawLine(f[1][0],f[1][1],f[5][0],f[5][1]);       //
   display.drawLine(f[2][0],f[2][1],f[6][0],f[6][1]);       //
   display.drawLine(f[3][0],f[3][1],f[7][0],f[7][1]);       //
   display.drawLine(f[1][0],f[1][1],f[3][0],f[3][1]);       // cross
   display.drawLine(f[0][0],f[0][1],f[2][0],f[2][1]);       // cross
   display.display();                                       //
  }                                                         //
  delay(1);                                                 //
}                                                           //


Written by macsbug

3月 20, 2016 @ 6:34 am

カテゴリー: ESP8266

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。