0.96インチ、128X64ドットのOLEDディスプレイの描画テストをArduinoを用いてテストしました。2cm程度の非常に小さいものなので、もともと数字等を静的に表示するための製品かとは思います。
配線は簡単で、電源とI2Cをつなぐだけです。ソフトのほうも通常はAdafruit社のライブラリを使えばよいでしょう。今回はデータシートを見て自前で書いてみました。
SSD1306イニシャライズ
I2CはArduinoのWireを使います。
void init_SSD1306(){ Wire.beginTransmission(OLED_I2C_ADDRES); Wire.write(0x80); Wire.write(0xAE); //set display off Wire.write(0x00); Wire.write(0xA8); Wire.write(0x3F); //set multiplex ratio Wire.write(0x00); Wire.write(0xD3); Wire.write(0x00); //set display offset Wire.write(0x80); Wire.write(0x40); //set display start line Wire.write(0x80); Wire.write(0xA0); //set segment re-map Wire.write(0x80); Wire.write(0xC0); //set com output scan direction Wire.write(0x00); Wire.write(0xDA); Wire.write(0x12); //set com pins hardware configuration Wire.write(0x00); Wire.write(0x81); Wire.write(0x7F); //set contrast control Wire.write(0x80); Wire.write(0xA4); //entire display on Wire.write(0x80); Wire.write(0xA6); //set normal/inverse display Wire.write(0x00); Wire.write(0xD5); Wire.write(0x80); //set display clock Wire.endTransmission(); Wire.beginTransmission(OLED_I2C_ADDRES); Wire.write(0x00); Wire.write(0x20); Wire.write(0b00); //horizontal addressing mode Wire.write(0x00); Wire.write(0x22); Wire.write(0); Wire.write(7); //page 0-7 Wire.write(0x00); Wire.write(0x21); Wire.write(0); Wire.write(127); //colum 0-127 Wire.write(0x00); Wire.write(0x8D); Wire.write(0x14); Wire.write(0x80); Wire.write(0xAF); //set display on Wire.endTransmission(); }
I2Cの通信の仕様に関してはデータシートのP20 I2C-bus Write dataに説明があります。デバイスのアドレスは基板の裏側の抵抗の位置によって2通りあるようです。このアドレスを1bit左にずらして末尾にR/Wの0をつけて(私の場合は0x3C)を最初に送信します。これに続けて諸々を送信するのですが、これはデータシートの最後についているApplication noteのP5に沿ってやっています。
各コマンドはデータシートのP28~に記載されていて、上のコードでは2列目(Wire.write(0xAE)
など)となります。1列目の0x80、0x00はコマンドに先立って送るControl byteといわれているもので、P20に説明がありますがわかりにくいです。0x80なら続けて1個0x00なら続けて複数個が送られる、と解釈しました。
Application noteにないコマンドで追加で送っているのは17-19行目の0x20,0x21,0x22です。この辺の説明はP34-36にあります。Horizontal addressing modeというものに設定していて、全画面の画素データを連続で送れるというものです。画面の成り立ちはP25に図があります。縦方向がpage、横方向がsegmentで分割されていて、1pageの縦は8bit(1byte)でこれを単位にアクセスします。
画素へのアクセス
#define HEIGHT 64 #define WIDTH 128 #define WIRE_MAX 30 #define NEGATIVE 0 #define POSITIVE 1 uint8_t buf[WIDTH * HEIGHT/8];
buf[]はすべての画素のデータを保持しておくための配列です。描画の計算はいつもこのbufに対して行い、最後にまとめてデバイスに転送します。
void draw_Pixel(uint8_t x, uint8_t y, uint8_t pos_neg){ if(x<0 || x>127 || y<0 || y>63)return; if(pos_neg) buf[x + (y/8)*WIDTH] |= (1 << (y&7)); //set 1 to segment after bit shift else buf[x + (y/8)*WIDTH] &= ~(1 << (y&7)); //set 0 to segment after bit shift }
一つの点(ピクセル)を描く関数です。直線や円を描くときもここにやってきます。pos_negはその画素を点灯するか消灯するかを表します。bufの該当部分(1 byte)にORで書き込みます。縦方向の座標yがsegmentの中の何ビット目なのかを計算しているのが(1 << (y&7))の部分です。
void flash(){ uint16_t count = 0; uint8_t bytesOut = 1; Wire.beginTransmission(OLED_I2C_ADDRES); Wire.write(0b01000000); //send byte data for all segments while(count<128*8) { if(bytesOut >= WIRE_MAX) { Wire.endTransmission(); Wire.beginTransmission(OLED_I2C_ADDRES); Wire.write(0b01000000); bytesOut = 1; } Wire.write(buf[count]); count++; bytesOut++; } Wire.endTransmission(); }
flash()はbuf[]に画素の設定をすべて終わった段階で呼び出します。左上の画素(0,0)から右下の画素(127,64)までデータシートP35の図の要領でデバイスに送信します。少し妙な形になっているのは、Wire.beginTransmissionとWire.endTransmissionの間で最高32byteしか送れないためで、途中にWire.endTransmissionをはさむためです。
デモ動画とソースコード
*今回スクロールのテストは実施しませんでした。
#include "Wire.h" #define HEIGHT 64 #define WIDTH 128 #define WIRE_MAX 30 #define NEGATIVE 0 #define POSITIVE 1 const char Font[192][5] PROGMEM = { { 0x00, 0x00, 0x00, 0x00, 0x00 }, // " " 0x20 { 0x00, 0x00, 0x4f, 0x00, 0x00 }, // ! 0x21 { 0x00, 0x07, 0x00, 0x07, 0x00 }, // " 0x22 { 0x14, 0x7f, 0x14, 0x7f, 0x14 }, // # 0x23 { 0x24, 0x2a, 0x7f, 0x2a, 0x12 }, // $ 0x24 { 0x23, 0x13, 0x08, 0x64, 0x62 }, // % 0x25 { 0x36, 0x49, 0x55, 0x22, 0x50 }, // & 0x26 { 0x00, 0x05, 0x03, 0x00, 0x00 }, // ' 0x27 { 0x00, 0x1c, 0x22, 0x41, 0x00 }, // ( 0x28 { 0x00, 0x41, 0x22, 0x1c, 0x00 }, // ) 0x29 { 0x14, 0x08, 0x3e, 0x08, 0x14 }, // * 0x2A { 0x08, 0x08, 0x3e, 0x08, 0x08 }, // + 0x2B { 0x00, 0x50, 0x30, 0x00, 0x00 }, // , 0x2C { 0x08, 0x08, 0x08, 0x08, 0x08 }, // - 0x2D { 0x00, 0x60, 0x60, 0x00, 0x00 }, // . 0x2E { 0x20, 0x10, 0x08, 0x04, 0x02 }, // / 0x2F { 0x3e, 0x51, 0x49, 0x45, 0x3e }, // 0 0x30 { 0x00, 0x42, 0x7f, 0x40, 0x00 }, // 1 0x31 { 0x42, 0x61, 0x51, 0x49, 0x46 }, // 2 0x32 { 0x21, 0x41, 0x45, 0x4b, 0x31 }, // 3 0x33 { 0x18, 0x14, 0x12, 0x7f, 0x10 }, // 4 0x34 { 0x27, 0x45, 0x45, 0x45, 0x39 }, // 5 0x35 { 0x3c, 0x4a, 0x49, 0x49, 0x30 }, // 6 0x36 { 0x01, 0x71, 0x09, 0x05, 0x03 }, // 7 0x37 { 0x36, 0x49, 0x49, 0x49, 0x36 }, // 8 0x38 { 0x06, 0x49, 0x49, 0x29, 0x1e }, // 9 0x39 { 0x00, 0x36, 0x36, 0x00, 0x00 }, // : 0x3A { 0x00, 0x56, 0x36, 0x00, 0x00 }, // ; 0x3B { 0x08, 0x14, 0x22, 0x41, 0x00 }, // < 0x3C { 0x14, 0x14, 0x14, 0x14, 0x14 }, // = 0x3D { 0x00, 0x41, 0x22, 0x14, 0x08 }, // > 0x3E { 0x02, 0x01, 0x51, 0x09, 0x06 }, // ? 0x3F { 0x32, 0x49, 0x79, 0x41, 0x3e }, // @ 0x40 { 0x7e, 0x11, 0x11, 0x11, 0x7e }, // A 0x41 { 0x7f, 0x49, 0x49, 0x49, 0x36 }, // B 0x42 { 0x3e, 0x41, 0x41, 0x41, 0x22 }, // C 0x43 { 0x7f, 0x41, 0x41, 0x22, 0x1c }, // D 0x44 { 0x7f, 0x49, 0x49, 0x49, 0x41 }, // E 0x45 { 0x7f, 0x09, 0x09, 0x09, 0x01 }, // F 0x46 { 0x3e, 0x41, 0x49, 0x49, 0x7a }, // G 0x47 { 0x7f, 0x08, 0x08, 0x08, 0x7f }, // H 0x48 { 0x00, 0x41, 0x7f, 0x41, 0x00 }, // I 0x49 { 0x20, 0x40, 0x41, 0x3f, 0x01 }, // J 0x4A { 0x7f, 0x08, 0x14, 0x22, 0x41 }, // K 0x4B { 0x7f, 0x40, 0x40, 0x40, 0x40 }, // L 0x4C { 0x7f, 0x02, 0x0c, 0x02, 0x7f }, // M 0x4D { 0x7f, 0x04, 0x08, 0x10, 0x7f }, // N 0x4E { 0x3e, 0x41, 0x41, 0x41, 0x3e }, // O 0x4F { 0x7f, 0x09, 0x09, 0x09, 0x06 }, // P 0X50 { 0x3e, 0x41, 0x51, 0x21, 0x5e }, // Q 0X51 { 0x7f, 0x09, 0x19, 0x29, 0x46 }, // R 0X52 { 0x46, 0x49, 0x49, 0x49, 0x31 }, // S 0X53 { 0x01, 0x01, 0x7f, 0x01, 0x01 }, // T 0X54 { 0x3f, 0x40, 0x40, 0x40, 0x3f }, // U 0X55 { 0x1f, 0x20, 0x40, 0x20, 0x1f }, // V 0X56 { 0x3f, 0x40, 0x38, 0x40, 0x3f }, // W 0X57 { 0x63, 0x14, 0x08, 0x14, 0x63 }, // X 0X58 { 0x07, 0x08, 0x70, 0x08, 0x07 }, // Y 0X59 { 0x61, 0x51, 0x49, 0x45, 0x43 }, // Z 0X5A { 0x00, 0x7f, 0x41, 0x41, 0x00 }, // [ 0X5B { 0x02, 0x04, 0x08, 0x10, 0x20 }, // "\" 0X5C { 0x00, 0x41, 0x41, 0x7f, 0x00 }, // ] 0X5D { 0x04, 0x02, 0x01, 0x02, 0x04 }, // ^ 0X5E { 0x40, 0x40, 0x40, 0x40, 0x40 }, // _ 0X5F { 0x00, 0x01, 0x02, 0x04, 0x00 }, // ` 0X60 { 0x20, 0x54, 0x54, 0x54, 0x78 }, // a 0X61 { 0x7f, 0x48, 0x44, 0x44, 0x38 }, // b 0X62 { 0x38, 0x44, 0x44, 0x44, 0x20 }, // c 0X63 { 0x38, 0x44, 0x44, 0x48, 0x7f }, // d 0X64 { 0x38, 0x54, 0x54, 0x54, 0x18 }, // e 0X65 { 0x08, 0x7e, 0x09, 0x01, 0x02 }, // f 0X66 { 0x0c, 0x52, 0x52, 0x52, 0x3e }, // g 0X67 { 0x7f, 0x08, 0x04, 0x04, 0x78 }, // h 0X68 { 0x00, 0x44, 0x7d, 0x40, 0x00 }, // i 0X69 { 0x20, 0x40, 0x44, 0x3d, 0x00 }, // j 0X6A { 0x7f, 0x10, 0x28, 0x44, 0x00 }, // k 0X6B { 0x00, 0x41, 0x7f, 0x40, 0x00 }, // l 0X6C { 0x7c, 0x04, 0x18, 0x04, 0x78 }, // m 0X6D { 0x7c, 0x08, 0x04, 0x04, 0x78 }, // n 0X6E { 0x38, 0x44, 0x44, 0x44, 0x38 }, // o 0X6F { 0x7c, 0x14, 0x14, 0x14, 0x08 }, // p 0X70 { 0x08, 0x14, 0x14, 0x18, 0x7c }, // q 0X71 { 0x7c, 0x08, 0x04, 0x04, 0x08 }, // r 0X72 { 0x48, 0x54, 0x54, 0x54, 0x20 }, // s 0X73 { 0x04, 0x3f, 0x44, 0x40, 0x20 }, // t 0X74 { 0x3c, 0x40, 0x40, 0x20, 0x7c }, // u 0X75 { 0x1c, 0x20, 0x40, 0x20, 0x1c }, // v 0X76 { 0x3c, 0x40, 0x30, 0x40, 0x3c }, // w 0X77 { 0x44, 0x28, 0x10, 0x28, 0x44 }, // x 0X78 { 0x0c, 0x50, 0x50, 0x50, 0x3c }, // y 0X79 { 0x44, 0x64, 0x54, 0x4c, 0x44 }, // z 0X7A { 0x00, 0x08, 0x36, 0x41, 0x00 }, // { 0X7B { 0x00, 0x00, 0x7f, 0x00, 0x00 }, // | 0X7C { 0x00, 0x41, 0x36, 0x08, 0x00 }, // } 0X7D { 0x08, 0x08, 0x2a, 0x1c, 0x08 }, // -> 0X7E { 0x08, 0x1c, 0x2a, 0x08, 0x08 }, // <- 0X7F { 0x00, 0x00, 0x0f, 0x08, 0x08 }, // 0x80 { 0x08, 0x08, 0x0f, 0x00, 0x00 }, // 0x81 { 0x2c, 0x32, 0x02, 0x32, 0x2c }, // ohm 0x82 { 0x44, 0x3c, 0x04, 0x7c, 0x44 }, // pi 0x83 { 0x63, 0x55, 0x49, 0x41, 0x41 }, // siguma0x84 { 0x14, 0x14, 0x7c, 0x14, 0x12 }, // sec 0x85 { 0x44, 0x3c, 0x14, 0x14, 0x74 }, // man 0x86 { 0x7c, 0x14, 0x1c, 0x14, 0x7c }, // en 0x87 { 0x10, 0x10, 0x54, 0x10, 0x10 }, // waru0x88 { 0x7f, 0x7f, 0x7f, 0x7f, 0x7f }, // 0x89 { 0x0f, 0x0f, 0x0f, 0x0f, 0x0f }, // 0x8A { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x8B { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x8C { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x8D { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x8E { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x8F { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x90 { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x91 { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x92 { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x93 { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x94 { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x95 { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x96 { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x97 { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x98 { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x99 { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x9A { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x9B { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x9C { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x9D { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x9E { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x9F { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0xA0 { 0x70, 0x50, 0x70, 0x00, 0x00 }, // . 0xA1 { 0x00, 0x00, 0x0f, 0x01, 0x01 }, // [ 0xA2 { 0x40, 0x40, 0x78, 0x00, 0x00 }, // ] 0xA3 { 0x10, 0x20, 0x40, 0x00, 0x00 }, // , 0xA4 { 0x00, 0x18, 0x18, 0x00, 0x00 }, // . 0xA5 { 0x0a, 0x0a, 0x4a, 0x2a, 0x1e }, // wo 0xA6 { 0x04, 0x24, 0x34, 0x14, 0x0c }, // a 0xA7 { 0x20, 0x10, 0x78, 0x04, 0x00 }, // i 0xA8 { 0x18, 0x08, 0x4c, 0x48, 0x38 }, // u 0xA9 { 0x48, 0x48, 0x78, 0x48, 0x48 }, // e 0xAA { 0x48, 0x28, 0x18, 0x7c, 0x08 }, // o 0xAB { 0x08, 0x7c, 0x08, 0x28, 0x18 }, // ya 0xAC { 0x40, 0x48, 0x48, 0x78, 0x40 }, // yu 0xAD { 0x54, 0x54, 0x54, 0x7c, 0x00 }, // yo 0xAE { 0x18, 0x00, 0x58, 0x40, 0x38 }, // tu 0xAF { 0x08, 0x08, 0x08, 0x08, 0x08 }, // - 0xB0 { 0x01, 0x41, 0x3d, 0x09, 0x07 }, // a 0xB1 { 0x20, 0x10, 0x7c, 0x02, 0x01 }, // i 0xB2 { 0x0e, 0x02, 0x43, 0x22, 0x1e }, // u 0xB3 { 0x42, 0x42, 0x7e, 0x42, 0x42 }, // e 0xB4 { 0x22, 0x12, 0x0a, 0x7f, 0x02 }, // o 0xB5 { 0x42, 0x3f, 0x02, 0x42, 0x3e }, // ka 0xB6 { 0x0a, 0x0a, 0x7f, 0x0a, 0x0a }, // ki 0xB7 { 0x08, 0x46, 0x42, 0x22, 0x1e }, // ku 0xB8 { 0x04, 0x03, 0x42, 0x3e, 0x04 }, // ke 0xB9 { 0x42, 0x42, 0x42, 0x42, 0x7e }, // ko 0xBA { 0x02, 0x4f, 0x22, 0x1f, 0x02 }, // sa 0xBB { 0x4a, 0x4a, 0x40, 0x20, 0x1c }, // si 0xBC { 0x42, 0x22, 0x12, 0x2a, 0x46 }, // su 0xBD { 0x02, 0x3f, 0x42, 0x4a, 0x46 }, // se 0xBE { 0x06, 0x48, 0x40, 0x20, 0x1e }, // so 0xBF { 0x08, 0x46, 0x4a, 0x32, 0x1e }, // ta 0xC0 { 0x0a, 0x4a, 0x3e, 0x09, 0x08 }, // ti 0xC1 { 0x0e, 0x00, 0x4e, 0x20, 0x1e }, // tu 0xC2 { 0x04, 0x45, 0x3d, 0x05, 0x04 }, // te 0xC3 { 0x00, 0x7f, 0x08, 0x10, 0x00 }, // to 0xC4 { 0x44, 0x24, 0x1f, 0x04, 0x04 }, // na 0xC5 { 0x40, 0x42, 0x42, 0x42, 0x40 }, // ni 0xC6 { 0x42, 0x2a, 0x12, 0x2a, 0x06 }, // nu 0xC7 { 0x22, 0x12, 0x7b, 0x16, 0x22 }, // ne 0xC8 { 0x00, 0x40, 0x20, 0x1f, 0x00 }, // no 0xC9 { 0x78, 0x00, 0x02, 0x04, 0x78 }, // ha 0xCA { 0x3f, 0x44, 0x44, 0x44, 0x44 }, // hi 0xCB { 0x02, 0x42, 0x42, 0x22, 0x1e }, // hu 0xCC { 0x04, 0x02, 0x04, 0x08, 0x30 }, // he 0xCD { 0x32, 0x02, 0x7f, 0x02, 0x32 }, // ho 0xCE { 0x02, 0x12, 0x22, 0x52, 0x0e }, // ma 0xCF { 0x00, 0x2a, 0x2a, 0x2a, 0x40 }, // mi 0xD0 { 0x38, 0x24, 0x22, 0x20, 0x70 }, // mu 0xD1 { 0x40, 0x28, 0x10, 0x28, 0x06 }, // me 0xD2 { 0x0a, 0x3e, 0x4a, 0x4a, 0x4a }, // mo 0xD3 { 0x04, 0x7f, 0x04, 0x14, 0x0c }, // ya 0xD4 { 0x40, 0x42, 0x42, 0x7e, 0x40 }, // yu 0xD5 { 0x4a, 0x4a, 0x4a, 0x4a, 0x7e }, // yo 0xD6 { 0x04, 0x05, 0x45, 0x25, 0x1c }, // ra 0xD7 { 0x0f, 0x40, 0x20, 0x1f, 0x00 }, // ri 0xD8 { 0x7c, 0x00, 0x7e, 0x80, 0x30 }, // ru 0xD9 { 0x7e, 0x40, 0x20, 0x10, 0x08 }, // re 0xDA { 0x7e, 0x42, 0x42, 0x42, 0x7e }, // ro 0xDB { 0x0e, 0x02, 0x42, 0x22, 0x1e }, // wa 0xDC { 0x42, 0x42, 0x40, 0x20, 0x18 }, // n 0xDD { 0x02, 0x04, 0x01, 0x02, 0x00 }, // " 0xDE { 0x07, 0x05, 0x07, 0x00, 0x00 } // . 0xDF }; const uint8_t OLED_I2C_ADDRES = 0x3C; uint8_t buf[WIDTH * HEIGHT/8]; void init_SSD1306(){ Wire.beginTransmission(OLED_I2C_ADDRES); Wire.write(0x80); Wire.write(0xAE); //set display off Wire.write(0x00); Wire.write(0xA8); Wire.write(0x3F); //set multiplex ratio Wire.write(0x00); Wire.write(0xD3); Wire.write(0x00); //set display offset Wire.write(0x80); Wire.write(0x40); //set display start line Wire.write(0x80); Wire.write(0xA0); //set segment re-map Wire.write(0x80); Wire.write(0xC0); //set com output scan direction Wire.write(0x00); Wire.write(0xDA); Wire.write(0x12); //set com pins hardware configuration Wire.write(0x00); Wire.write(0x81); Wire.write(0x7F); //set contrast control Wire.write(0x80); Wire.write(0xA4); //entire display on Wire.write(0x80); Wire.write(0xA6); //set normal/inverse display Wire.write(0x00); Wire.write(0xD5); Wire.write(0x80); //set display clock Wire.endTransmission(); Wire.beginTransmission(OLED_I2C_ADDRES); Wire.write(0x00); Wire.write(0x20); Wire.write(0b00); //horizontal addressing mode Wire.write(0x00); Wire.write(0x22); Wire.write(0); Wire.write(7); //page 0-7 Wire.write(0x00); Wire.write(0x21); Wire.write(0); Wire.write(127); //colum 0-127 Wire.write(0x00); Wire.write(0x8D); Wire.write(0x14); Wire.write(0x80); Wire.write(0xAF); //set display on Wire.endTransmission(); } void clear_All(){ memset(buf, 0, sizeof(buf)); } void draw_Char(uint8_t line, uint8_t colum, uint16_t letter, uint8_t c_size, uint8_t pos_neg ){ uint8_t orig; uint8_t orig_d; uint8_t page; uint8_t data[3]; int i; page = line/8; line = line%8; if(c_size==1){ for(i=0; i<5; i++){ orig = pgm_read_byte(&Font[letter][i]); data[0] = orig << line; draw_Byte(data[0], page, colum+i, pos_neg); data[0] = orig >> (8-line); draw_Byte(data[0], page+1, colum+i, pos_neg); } }else{ for(i=0; i<5; i++){ orig = pgm_read_byte(&Font[letter][i]); data[0] = (orig & 0b00000001)+((orig & 0b00000001)<<1)+ ((orig & 0b00000010)<<1)+((orig & 0b00000010)<<2)+ ((orig & 0b00000100)<<2)+((orig & 0b00000100)<<3)+ ((orig & 0b00001000)<<3)+((orig & 0b00001000)<<4); data[1] = ((orig & 0b00010000)>>4)+((orig & 0b00010000)>>3)+ ((orig & 0b00100000)>>3)+((orig & 0b00100000)>>2)+ ((orig & 0b01000000)>>2)+((orig & 0b01000000)>>1)+ ((orig & 0b10000000)>>1)+((orig & 0b10000000)); data[2] = data[1] >> (8-line); data[1] = (data[1] << line) + (data[0] >> (8-line)); data[0] = data[0] << line; draw_Byte(data[0], page, colum+2*i, pos_neg); draw_Byte(data[0], page, colum+2*i+1, pos_neg); draw_Byte(data[1], page+1, colum+2*i, pos_neg); draw_Byte(data[1], page+1, colum+2*i+1, pos_neg); draw_Byte(data[2], page+2, colum+2*i, pos_neg); draw_Byte(data[2], page+2, colum+2*i+1, pos_neg); } } } void fill_Circle(uint8_t x, uint8_t y, uint8_t rad, uint8_t pos_neg){ int8_t r = (int8_t)rad; int8_t d = 1 - r; int8_t dH = 3; int8_t dD = 5 - 2 * r; int8_t cy = r; int8_t cx; for(cx = 0; cx < cy; cx++){ if(d < 0){ d += dH; dH += 2; dD += 2; }else{ d += dD; dH += 2; dD += 4; --cy; } draw_Line(cy + x, cx + y, -cy + x, cx + y,pos_neg); draw_Line(cx + x, cy + y, -cx + x, cy + y,pos_neg); draw_Line(-cy + x, -cx + y, cy + x, -cx + y,pos_neg); draw_Line(-cx + x, -cy + y, cx + x, -cy + y,pos_neg); } } void draw_Circle(uint8_t x, uint8_t y, uint8_t rad, uint8_t pos_neg){ int8_t r = (int8_t)rad; int8_t d = 1 - r; int8_t dH = 3; int8_t dD = 5 - 2 * r; int8_t cy = r; int8_t cx; for(cx = 0; cx < cy; cx++){ if(d < 0){ d += dH; dH += 2; dD += 2; }else{ d += dD; dH += 2; dD += 4; cy--; } draw_Pixel(cy + x, cx + y,pos_neg); draw_Pixel(cx + x, cy + y,pos_neg); draw_Pixel(-cy + x, -cx + y,pos_neg); draw_Pixel(-cx + x, -cy + y,pos_neg); draw_Pixel(cx + x, -cy + y,pos_neg); draw_Pixel(cy + x, -cx + y,pos_neg); draw_Pixel(-cx + x, cy + y,pos_neg); draw_Pixel(-cy + x, cx + y,pos_neg); } } void fill_Rect(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t pos_neg){ uint8_t i,j; uint8_t temp; if(x0 > x1){temp = x0;x0=x1;x1=temp;} if(y0 > y1){temp = y0;y0=y1;y1=temp;} for(i=x0; i<=x1; i++){ draw_Line(i,y0,i,y1,pos_neg); } } void draw_Rect(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t pos_neg){ draw_Line(x0, y0, x1, y0, pos_neg); draw_Line(x1, y1, x1, y0, pos_neg); draw_Line(x1, y1, x0, y1, pos_neg); draw_Line(x0, y0, x0, y1, pos_neg); } void draw_Line(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t pos_neg){ uint8_t temp; uint8_t x, y; uint8_t ystep; uint8_t inclination = (abs(y1 - y0) > abs(x1 - x0)); if(inclination){ temp = x0; x0 = y0; y0= temp; temp = x1; x1 = y1; y1= temp; } if(x0 > x1){ temp = x0; x0 = x1; x1= temp; temp = y0; y0 = y1; y1= temp; } uint8_t deltaX = x1 - x0; uint8_t deltaY = abs(y1 - y0); int dummyY = deltaX/2; y = y0; if(y0 < y1)ystep = 1; else ystep = -1; for(x = x0; x < x1; x++){ if(inclination) draw_Pixel(y, x, pos_neg); else draw_Pixel(x, y, pos_neg); dummyY -= deltaY; if(dummyY < 0){ y += ystep; dummyY += deltaX; } } } void draw_Byte(uint8_t ptn, uint8_t page, uint8_t colum, uint8_t pos_neg){ if(colum<0 || colum>127 || page<0 || page>7)return; if(pos_neg) buf[colum + page*WIDTH] |= ptn; else buf[colum + page*WIDTH] &= ~ptn; } void draw_Pixel(uint8_t x, uint8_t y, uint8_t pos_neg){ if(x<0 || x>127 || y<0 || y>63)return; if(pos_neg) buf[x + (y/8)*WIDTH] |= (1 << (y&7)); //set 1 to segment after bit shift else buf[x + (y/8)*WIDTH] &= ~(1 << (y&7)); //set 0 to segment after bit shift } void flash(){ uint16_t count = 0; uint8_t bytesOut = 1; Wire.beginTransmission(OLED_I2C_ADDRES); Wire.write(0b01000000); //send byte data for all segments while(count<128*8) { if(bytesOut >= WIRE_MAX) { Wire.endTransmission(); Wire.beginTransmission(OLED_I2C_ADDRES); Wire.write(0b01000000); bytesOut = 1; } Wire.write(buf[count]); count++; bytesOut++; } Wire.endTransmission(); } void setup() { // put your setup code here, to run once: int i,j,k; Wire.setClock(400000); Wire.begin(); Wire.setClock(400000); delay(100); init_SSD1306(); /**************************************** * DEMO */ clear_All(); flash(); for(i=0;i<128;i+=4){ draw_Line(i,0,0,63,POSITIVE); flash(); } for(i=0;i<128;i+=4){ draw_Line(127,0,i,63,POSITIVE); flash(); } clear_All(); flash(); for(i=10;i<128;i+=20){ for(j=10;j<64;j+=20){ draw_Rect(i-8,j-8,i+8,j+8,POSITIVE); flash(); } } delay(200); clear_All(); flash(); for(i=10;i<128;i+=20){ for(j=10;j<64;j+=20){ fill_Rect(i-8,j-8,i+8,j+8,POSITIVE); flash(); } } delay(200); clear_All(); flash(); for(i=10;i<128;i+=20){ for(j=10;j<64;j+=20){ draw_Circle(i,j,8,POSITIVE); flash(); } } delay(200); clear_All(); flash(); for(i=10;i<128;i+=20){ for(j=10;j<64;j+=20){ fill_Circle(i,j,8,POSITIVE); flash(); } } delay(200); clear_All(); flash(); k=1; for(i=0;i<64;i+=8){ for(j=0;j<128;j+=8){ draw_Char(i,j,k++,1,POSITIVE); } } flash(); delay(400); clear_All(); flash(); k=1; for(i=0;i<64;i+=16){ for(j=0;j<128;j+=16){ draw_Char(i,j,k++,2,POSITIVE); } } flash(); delay(400); fill_Rect(0,0,127,63,POSITIVE); fill_Circle(64,32,18,NEGATIVE); flash(); } void loop() { // put your main code here, to run repeatedly: }