SSブログ

よくある安いI2C OLEDについて調べてみた。 [Arduino]

以下3つのよくあるI2CのOLEDだけど、いろいろ調べたらほぼ同じ操作でいけると判明。

・0.96インチ , 128x64 , SSD1306
・1.3インチ, 128x64, SH1106
・1.5インチ, 128x128, SH1107

3oleds_qr.jpg

★共通なところ
・5VのArduinoで、プルアップ抵抗なしで動く。
・アドレスが 0x78 (Wireライブラリでは 0x3C と1ビットずらす)
・画像メモリーの使い方、縦8ドットで1バイトが横に128個。これが縦に8ページ(あるいは16ページ)
・コマンドも大体同じっぽい

★それぞれで違うところ
*** 0.96'', 128x64 , SSD1306 ***
 初期化コマンドは、0x8D, 0x14 の Enable charge pump と、0xAF の switch on OLEDの2つだけでとりあえず表示できる。
 メモリがページをまたいでリニアになっているので、自然に折り返しできる。
 ピンは GND VCC SCL SDA の順。
*** 1.3'', 128x64, SH1106 ***
 初期化コマンドは、0xAF だけでとりあえずOK。
 メモリはページをまたげない。
 制御チップは132x64ドットでできているようだが、OLEDは128x64でできているので左右に2ドットずつ表示されない領域がある。
 ピンは VCC GND SCL SDA の順。電源が0.96インチと逆で間違えると壊れるので注意。
*** 1.5'', 128x128, SH1107 ***
 こちらも初期化コマンドは、0xAF だけでとりあえずOK。
 同様にメモリはページをまたげない。
 ピンは VCC GND SCL SDA の順。電源注意。
 これはGME128128-01-IIC Ver 2.0での話。Ver 3は SSD1327 ?

// tinyOLEDdemo - controlling an I²C OLED (SSD1306/SH1106/SH1107) with an ATtiny202
//
// A big thank you to Stefan Wagner 
// Project Files (Github):  https://github.com/wagiminator
// License: http://creativecommons.org/licenses/by-sa/3.0/

#include <avr/io.h>
#include <util/delay.h>

const uint8_t img_i[] = {   32,   32, // px
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x82, 0xee, 0xfe, 0xfe, 0xfc, 0xf8, 0x70, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0,
  0xf8, 0x7e, 0xff, 0xff, 0xef, 0xc7, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x20, 0x20, 0x30, 0x10, 0x18, 0x1c, 0x0e, 0x0f, 0x07, 0x07, 0x03, 0x01, 0x01,
  0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x1e, 0x3f, 0x7f, 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
const uint8_t img_qr[] = {  23,   23, // px
  0xff, 0x01, 0x7d, 0x45, 0x45, 0x45, 0x7d, 0x01, 0xff, 0x2b, 0xcb, 0x71, 0xdf, 0x01, 0xff, 0x01,
  0x7d, 0x45, 0x45, 0x45, 0x7d, 0x01, 0xff, 0xff, 0x59, 0x55, 0x7d, 0x71, 0x49, 0x67, 0x55, 0xf9,
  0x3d, 0xc2, 0x8b, 0x57, 0x91, 0x3d, 0x77, 0xc9, 0x27, 0xb9, 0x93, 0x71, 0xf7, 0xff, 0xff, 0xc0,
  0xdf, 0xd1, 0xd1, 0xd1, 0xdf, 0xc0, 0xff, 0xc1, 0xf3, 0xfa, 0xcd, 0xd5, 0xc8, 0xc5, 0xea, 0xe6,
  0xe8, 0xd8, 0xcb, 0xec, 0xff
};
// ---- I2C Master Implementation (Write only) ---------------------------------

#define I2C_FREQ  800000UL                        // I2C clock frequency in Hz
void I2C_init(void) {                             // I2C init function
  TWI0.MBAUD   = ((F_CPU / I2C_FREQ) - 10) / 2;   //   set TWI master BAUD rate (simplified BAUD calculation)
  TWI0.MCTRLA  = TWI_ENABLE_bm;                   //   enable TWI master
  TWI0.MSTATUS = TWI_BUSSTATE_IDLE_gc;            //   set bus state to idle
}
void I2C_start(uint8_t addr) {                    // I2C start transmission
  TWI0.MADDR = addr;                              //   start sending address
}
void I2C_stop(void) {                             // I2C stop transmission
  while (~TWI0.MSTATUS & TWI_WIF_bm);             //   wait for last transfer to complete
  TWI0.MCTRLB = TWI_MCMD_STOP_gc;                 //   send stop condition
}
void I2C_write(uint8_t data) {                    // I2C transmit one data byte to the slave, ignore ACK bit
  while (~TWI0.MSTATUS & TWI_WIF_bm);             //   wait for last transfer to complete
  TWI0.MDATA = data;                              //   start sending data byte 
}

// ---- OLED Implementation ----------------------------------------------------

#define OLED_ADDR       0x78             // OLED write address (Wire lib.:0x3c)
#define OLED_CMD_MODE   0x00             // set command mode
#define OLED_DAT_MODE   0x40             // set data mode

const uint8_t OLED_INIT_CMD[] = {        // OLED init settings
//0xA8, 0x7F,           // set multiplex (HEIGHT-1): 0x1F(128x32), 0x3F(128x64), 0x7F(128x128)
//0x22, 0x00, 0x0f,     // set min and max page: 0x07(128x64), 0x0F(128x128)
//0x20, 0x00,           // set horizontal memory addressing mode
//0xDA, 0x12,           // set COM pins hardware configuration to alternative
  0x8D, 0x14,           // enable charge pump (for SSD1306)
  0xAF                  // switch on OLED
};

void OLED_init(void) {                    // OLED init function
  I2C_init();                             //   initialize I2C first
  I2C_start(OLED_ADDR);                   //   start transmission to OLED
  I2C_write(OLED_CMD_MODE);               //   set command mode
  for (uint8_t i=0; i<sizeof(OLED_INIT_CMD); i++) I2C_write(OLED_INIT_CMD[i]); //   send the command bytes
  I2C_stop();                             //   stop transmission
}

void OLED_cursor(uint8_t xpos, uint8_t ypos) {// OLED set the cursor
  xpos +=2;                               //  (for SH1106 (132x64)
  I2C_start(OLED_ADDR);                   //   start transmission to OLED
  I2C_write(OLED_CMD_MODE);               //   set command mode
  I2C_write(xpos & 0x0F);                 //   set low nibble of start column
  I2C_write(0x10 | (xpos >> 4));          //   set high nibble of start column
  I2C_write(0xB0 | (ypos & 0x0f));        //   set start page
  I2C_stop();                             //   stop transmission
}

void OLED_clear(uint16_t p) {             // OLED clear screen with pattern
  if( p < 256 ) p |= p << 8;
  for(uint8_t pg=0; pg<16; pg++){
    OLED_cursor(0, pg);                   //   set cursor at upper left corner
    I2C_start(OLED_ADDR);                 //   start transmission to OLED
    I2C_write(OLED_DAT_MODE);             //   set data mode
    for(uint8_t c=64; c; c--) {
      I2C_write(p & 0xff);                //   fill the screen
      I2C_write(p >> 8  );
    }
    I2C_stop();                           //   stop transmission
  }
}

void OLED_image(uint8_t xpos, uint8_t ypos, uint8_t *d) {// OLED set image
  const uint8_t w=*d++, h=*d++;
  for(uint8_t y=0; y<(h+7)/8; y++) {
    OLED_cursor(xpos, ypos + y);          //   set the cursor
    I2C_start(OLED_ADDR);                 //   start transmission to OLED
    I2C_write(OLED_DAT_MODE);             //   set data mode
    for(uint8_t x=0; x<w; x++) I2C_write( *d++ );
    I2C_stop();                           //   stop transmission    
  }
}

void OLED_image2x(uint8_t xpos, uint8_t ypos, uint8_t *d) {// OLED set 2x image
  const uint8_t x2[]={ 0x0,0x3,0xc,0xf,0x30,0x33,0x3c,0x3f,0xc0,0xc3,0xcc,0xcf,0xf0,0xf3,0xfc,0xff };
  const uint8_t w=*d++, h=*d++;
  for(uint8_t y=0; y<(h+3)/4; y++) {
    OLED_cursor(xpos, ypos + y);          //   set the cursor
    I2C_start(OLED_ADDR);                 //   start transmission to OLED
    I2C_write(OLED_DAT_MODE);             //   set data mode
    for(uint8_t x=0, t; x<w; x++) {
      I2C_write( t = x2[ d[x+(y/2)*w] >> (y%2*4) & 0xf ] );
      I2C_write( t );
    }
    I2C_stop();                           //   stop transmission    
  }
}

void OLED_image4x(uint8_t xpos, uint8_t ypos, uint8_t *d) {// OLED set 2x image
  const uint8_t x4[]={ 0x0,0xf,0xf0,0xff };
  const uint8_t w=*d++, h=*d++;
  for(uint8_t y=0; y<(h+1)/2; y++) {
    OLED_cursor(xpos, ypos + y);          //   set the cursor
    I2C_start(OLED_ADDR);                 //   start transmission to OLED
    I2C_write(OLED_DAT_MODE);             //   set data mode
    for(uint8_t x=0, t; x<w; x++) {
      I2C_write( t = x4[ d[x+(y/4)*w] >> (y%4*2) & 0b11 ] );
      I2C_write( t );
      I2C_write( t );
      I2C_write( t );
    }
    I2C_stop();                           //   stop transmission    
  }
}

// ---- Main Function ----------------------------------------------------------

void setup() {
  _delay_ms(100);                         // add delay
  OLED_init();                            // setup I2C OLED
}

void loop() {
  OLED_clear(0x1144);                     // clear screen with pattern
  OLED_image( 48, 2, img_i );
  _delay_ms(1000);
  OLED_image2x( 32, 1, img_i );
  _delay_ms(1000);
  OLED_image4x(  0, 0, img_i );
  _delay_ms(2000);
  OLED_clear(0xff);                       // clear screen with white
  OLED_image( 52, 2, img_qr );
  _delay_ms(1000);
  OLED_image2x( 41, 1, img_qr );
  _delay_ms(1000);
  OLED_image4x( 18, 1, img_qr );
  _delay_ms(4000);
}


nice!(0)  コメント(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。