2024年9月24日 星期二

Control I2C SSD1306 by GPIO

#define OLED_SDA D2 // D2

#define OLED_SCL D1 // D1


#define OLED_ADDRESS 0x3c  // SSD1306 I2C 地址


// I2C 延遲,控制速度

#define I2C_DELAY 50  // 試著增加延遲


void i2c_start() {

  pinMode(OLED_SDA, OUTPUT);

  pinMode(OLED_SCL, OUTPUT);

  digitalWrite(OLED_SDA, HIGH);

  digitalWrite(OLED_SCL, HIGH);

  delayMicroseconds(I2C_DELAY);

  digitalWrite(OLED_SDA, LOW);

  delayMicroseconds(I2C_DELAY);

  digitalWrite(OLED_SCL, LOW);

}


void i2c_stop() {

  pinMode(OLED_SDA, OUTPUT);

  pinMode(OLED_SCL, OUTPUT);

  digitalWrite(OLED_SDA, LOW);

  digitalWrite(OLED_SCL, HIGH);

  delayMicroseconds(I2C_DELAY);

  digitalWrite(OLED_SDA, HIGH);

}



bool i2c_write_byte(uint8_t byte) {

  pinMode(OLED_SDA, OUTPUT);

  for (int i = 0; i < 8; i++) {

    digitalWrite(OLED_SCL, LOW);

    if (byte & 0x80) {

      digitalWrite(OLED_SDA, HIGH);

    } else {

      digitalWrite(OLED_SDA, LOW);

    }

    byte <<= 1;

    delayMicroseconds(I2C_DELAY);

    digitalWrite(OLED_SCL, HIGH);

    delayMicroseconds(I2C_DELAY);

  }

  digitalWrite(OLED_SCL, LOW);

  pinMode(OLED_SDA, INPUT);  // 切換到輸入檢查 ACK

  delayMicroseconds(I2C_DELAY);

  digitalWrite(OLED_SCL, HIGH);

  bool ack = !digitalRead(OLED_SDA);  // ACK 應該為低

  delayMicroseconds(I2C_DELAY);

  digitalWrite(OLED_SCL, LOW);

  return ack;  // 返回 ACK 檢查結果

}


void oled_command(uint8_t command) {

  i2c_start();

  uint8_t address = OLED_ADDRESS << 1;

  Serial.print("Sending Address: ");

  Serial.println(address, HEX);


  if (!i2c_write_byte(address)) {

    Serial.println("Address not acknowledged");

  }

  if (!i2c_write_byte(0x00)) {

    Serial.println("Control byte not acknowledged");

  }

  if (!i2c_write_byte(command)) {

    Serial.println("Command not acknowledged");

  }

  i2c_stop();

}





void oled_init() {

  oled_command(0xAE);  // 關閉顯示

  oled_command(0xA8);  // 設置多路復用比率

  oled_command(0x3F);  // 1/64

  oled_command(0xD3);  // 設置顯示偏移

  oled_command(0x00);  // 無偏移

  oled_command(0x40);  // 設置起始行位置

  oled_command(0xA1);  // 設置重映射

  oled_command(0xC8);  // 掃描方向

  oled_command(0xDA);  // 設置 COM 硬體配置

  oled_command(0x12);  // 代碼段

  oled_command(0x81);  // 設置對比度

  oled_command(0x7F);

  oled_command(0xA4);  // 關閉整體顯示

  oled_command(0xA6);  // 設置普通顯示

  oled_command(0xD5);  // 設置顯示時鐘分頻比/振盪器頻率

  oled_command(0x80);

  oled_command(0x8D);  // 啟用充電泵

  oled_command(0x14);

  oled_command(0xAF);  // 打開顯示

}


void oled_clear() {

  for (uint8_t page = 0; page < 8; page++) {

    oled_command(0xB0 + page);  // 設置頁地址

    oled_command(0x00);         // 設置低列地址

    oled_command(0x10);         // 設置高列地址

    i2c_start();

    i2c_write_byte(OLED_ADDRESS << 1);  // 發送地址

    i2c_write_byte(0x40);               // 控制位元 (0x40 表示後面是數據)

    for (uint8_t col = 0; col < 128; col++) {

      i2c_write_byte(0x00);             // 清空顯示

    }

    i2c_stop();

  }

}



// 定義 5x7 點陣字體

const uint8_t font5x7[][6] = {

  

{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // sp

{0x00, 0x00, 0x00, 0x2f, 0x00, 0x00}, // !

{0x00, 0x00, 0x07, 0x00, 0x07, 0x00}, // "

{0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14}, // #

{0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12}, // $

{0x00, 0x62, 0x64, 0x08, 0x13, 0x23}, // %

{0x00, 0x36, 0x49, 0x55, 0x22, 0x50}, // &

{0x00, 0x00, 0x05, 0x03, 0x00, 0x00}, // '

{0x00, 0x00, 0x1c, 0x22, 0x41, 0x00}, // (

{0x00, 0x00, 0x41, 0x22, 0x1c, 0x00}, // )

{0x00, 0x14, 0x08, 0x3E, 0x08, 0x14}, // *

{0x00, 0x08, 0x08, 0x3E, 0x08, 0x08}, // +

{0x00, 0x00, 0x00, 0xA0, 0x60, 0x00}, // ,

{0x00, 0x08, 0x08, 0x08, 0x08, 0x08}, // -

{0x00, 0x00, 0x60, 0x60, 0x00, 0x00}, // .

{0x00, 0x20, 0x10, 0x08, 0x04, 0x02}, // /

{0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E}, // 0

{0x00, 0x00, 0x42, 0x7F, 0x40, 0x00}, // 1

{0x00, 0x42, 0x61, 0x51, 0x49, 0x46}, // 2

{0x00, 0x21, 0x41, 0x45, 0x4B, 0x31}, // 3

{0x00, 0x18, 0x14, 0x12, 0x7F, 0x10}, // 4

{0x00, 0x27, 0x45, 0x45, 0x45, 0x39}, // 5

{0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30}, // 6

{0x00, 0x01, 0x71, 0x09, 0x05, 0x03}, // 7

{0x00, 0x36, 0x49, 0x49, 0x49, 0x36}, // 8

{0x00, 0x06, 0x49, 0x49, 0x29, 0x1E}, // 9

{0x00, 0x00, 0x36, 0x36, 0x00, 0x00}, // :

{0x00, 0x00, 0x56, 0x36, 0x00, 0x00}, // ;

{0x00, 0x08, 0x14, 0x22, 0x41, 0x00}, // <

{0x00, 0x14, 0x14, 0x14, 0x14, 0x14}, // =

{0x00, 0x00, 0x41, 0x22, 0x14, 0x08}, // >

{0x00, 0x02, 0x01, 0x51, 0x09, 0x06}, // ?

{0x00, 0x32, 0x49, 0x59, 0x51, 0x3E}, // @

{0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C}, // A

{0x00, 0x7F, 0x49, 0x49, 0x49, 0x36}, // B

{0x00, 0x3E, 0x41, 0x41, 0x41, 0x22}, // C

{0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C}, // D

{0x00, 0x7F, 0x49, 0x49, 0x49, 0x41}, // E

{0x00, 0x7F, 0x09, 0x09, 0x09, 0x01}, // F

{0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A}, // G

{0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F}, // H

{0x00, 0x00, 0x41, 0x7F, 0x41, 0x00}, // I

{0x00, 0x20, 0x40, 0x41, 0x3F, 0x01}, // J

{0x00, 0x7F, 0x08, 0x14, 0x22, 0x41}, // K

{0x00, 0x7F, 0x40, 0x40, 0x40, 0x40}, // L

{0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F}, // M

{0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F}, // N

{0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E}, // O

{0x00, 0x7F, 0x09, 0x09, 0x09, 0x06}, // P

{0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E}, // Q

{0x00, 0x7F, 0x09, 0x19, 0x29, 0x46}, // R

{0x00, 0x46, 0x49, 0x49, 0x49, 0x31}, // S

{0x00, 0x01, 0x01, 0x7F, 0x01, 0x01}, // T

{0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F}, // U

{0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F}, // V

{0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F}, // W

{0x00, 0x63, 0x14, 0x08, 0x14, 0x63}, // X

{0x00, 0x07, 0x08, 0x70, 0x08, 0x07}, // Y

{0x00, 0x61, 0x51, 0x49, 0x45, 0x43}, // Z

{0x00, 0x00, 0x7F, 0x41, 0x41, 0x00}, // [

{0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55}, // backslash

{0x00, 0x00, 0x41, 0x41, 0x7F, 0x00}, // ]

{0x00, 0x04, 0x02, 0x01, 0x02, 0x04}, // ^

{0x00, 0x40, 0x40, 0x40, 0x40, 0x40}, // _

{0x00, 0x00, 0x01, 0x02, 0x04, 0x00}, // '

{0x00, 0x20, 0x54, 0x54, 0x54, 0x78}, // a

{0x00, 0x7F, 0x48, 0x44, 0x44, 0x38}, // b

{0x00, 0x38, 0x44, 0x44, 0x44, 0x20}, // c

{0x00, 0x38, 0x44, 0x44, 0x48, 0x7F}, // d

{0x00, 0x38, 0x54, 0x54, 0x54, 0x18}, // e

{0x00, 0x08, 0x7E, 0x09, 0x01, 0x02}, // f

{0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C}, // g

{0x00, 0x7F, 0x08, 0x04, 0x04, 0x78}, // h

{0x00, 0x00, 0x44, 0x7D, 0x40, 0x00}, // i

{0x00, 0x40, 0x80, 0x84, 0x7D, 0x00}, // j

{0x00, 0x7F, 0x10, 0x28, 0x44, 0x00}, // k

{0x00, 0x00, 0x41, 0x7F, 0x40, 0x00}, // l

{0x00, 0x7C, 0x04, 0x18, 0x04, 0x78}, // m

{0x00, 0x7C, 0x08, 0x04, 0x04, 0x78}, // n

{0x00, 0x38, 0x44, 0x44, 0x44, 0x38}, // o

{0x00, 0xFC, 0x24, 0x24, 0x24, 0x18}, // p

{0x00, 0x18, 0x24, 0x24, 0x18, 0xFC}, // q

{0x00, 0x7C, 0x08, 0x04, 0x04, 0x08}, // r

{0x00, 0x48, 0x54, 0x54, 0x54, 0x20}, // s

{0x00, 0x04, 0x3F, 0x44, 0x40, 0x20}, // t

{0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C}, // u

{0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C}, // v

{0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C}, // w

{0x00, 0x44, 0x28, 0x10, 0x28, 0x44}, // x

{0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C}, // y

{0x00, 0x44, 0x64, 0x54, 0x4C, 0x44}, // z


  {0x7E, 0x10, 0x10, 0x10, 0x7E, 0x00},  // 'H'

  {0x7E, 0x4A, 0x4A, 0x4A, 0x42, 0x00},  // 'E'

  {0x7E, 0x40, 0x40, 0x40, 0x40, 0x00},  // 'L'

  {0x3C, 0x42, 0x42, 0x42, 0x3C, 0x00},  // 'O'

  {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},  // '#'

};



const char ssd1306oled_font[][6] PROGMEM = {

{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // sp

{0x00, 0x00, 0x00, 0x2f, 0x00, 0x00}, // !

{0x00, 0x00, 0x07, 0x00, 0x07, 0x00}, // "

{0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14}, // #

{0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12}, // $

{0x00, 0x62, 0x64, 0x08, 0x13, 0x23}, // %

{0x00, 0x36, 0x49, 0x55, 0x22, 0x50}, // &

{0x00, 0x00, 0x05, 0x03, 0x00, 0x00}, // '

{0x00, 0x00, 0x1c, 0x22, 0x41, 0x00}, // (

{0x00, 0x00, 0x41, 0x22, 0x1c, 0x00}, // )

{0x00, 0x14, 0x08, 0x3E, 0x08, 0x14}, // *

{0x00, 0x08, 0x08, 0x3E, 0x08, 0x08}, // +

{0x00, 0x00, 0x00, 0xA0, 0x60, 0x00}, // ,

{0x00, 0x08, 0x08, 0x08, 0x08, 0x08}, // -

{0x00, 0x00, 0x60, 0x60, 0x00, 0x00}, // .

{0x00, 0x20, 0x10, 0x08, 0x04, 0x02}, // /

{0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E}, // 0

{0x00, 0x00, 0x42, 0x7F, 0x40, 0x00}, // 1

{0x00, 0x42, 0x61, 0x51, 0x49, 0x46}, // 2

{0x00, 0x21, 0x41, 0x45, 0x4B, 0x31}, // 3

{0x00, 0x18, 0x14, 0x12, 0x7F, 0x10}, // 4

{0x00, 0x27, 0x45, 0x45, 0x45, 0x39}, // 5

{0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30}, // 6

{0x00, 0x01, 0x71, 0x09, 0x05, 0x03}, // 7

{0x00, 0x36, 0x49, 0x49, 0x49, 0x36}, // 8

{0x00, 0x06, 0x49, 0x49, 0x29, 0x1E}, // 9

{0x00, 0x00, 0x36, 0x36, 0x00, 0x00}, // :

{0x00, 0x00, 0x56, 0x36, 0x00, 0x00}, // ;

{0x00, 0x08, 0x14, 0x22, 0x41, 0x00}, // <

{0x00, 0x14, 0x14, 0x14, 0x14, 0x14}, // =

{0x00, 0x00, 0x41, 0x22, 0x14, 0x08}, // >

{0x00, 0x02, 0x01, 0x51, 0x09, 0x06}, // ?

{0x00, 0x32, 0x49, 0x59, 0x51, 0x3E}, // @

{0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C}, // A

{0x00, 0x7F, 0x49, 0x49, 0x49, 0x36}, // B

{0x00, 0x3E, 0x41, 0x41, 0x41, 0x22}, // C

{0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C}, // D

{0x00, 0x7F, 0x49, 0x49, 0x49, 0x41}, // E

{0x00, 0x7F, 0x09, 0x09, 0x09, 0x01}, // F

{0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A}, // G

{0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F}, // H

{0x00, 0x00, 0x41, 0x7F, 0x41, 0x00}, // I

{0x00, 0x20, 0x40, 0x41, 0x3F, 0x01}, // J

{0x00, 0x7F, 0x08, 0x14, 0x22, 0x41}, // K

{0x00, 0x7F, 0x40, 0x40, 0x40, 0x40}, // L

{0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F}, // M

{0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F}, // N

{0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E}, // O

{0x00, 0x7F, 0x09, 0x09, 0x09, 0x06}, // P

{0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E}, // Q

{0x00, 0x7F, 0x09, 0x19, 0x29, 0x46}, // R

{0x00, 0x46, 0x49, 0x49, 0x49, 0x31}, // S

{0x00, 0x01, 0x01, 0x7F, 0x01, 0x01}, // T

{0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F}, // U

{0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F}, // V

{0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F}, // W

{0x00, 0x63, 0x14, 0x08, 0x14, 0x63}, // X

{0x00, 0x07, 0x08, 0x70, 0x08, 0x07}, // Y

{0x00, 0x61, 0x51, 0x49, 0x45, 0x43}, // Z

{0x00, 0x00, 0x7F, 0x41, 0x41, 0x00}, // [

{0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55}, // backslash

{0x00, 0x00, 0x41, 0x41, 0x7F, 0x00}, // ]

{0x00, 0x04, 0x02, 0x01, 0x02, 0x04}, // ^

{0x00, 0x40, 0x40, 0x40, 0x40, 0x40}, // _

{0x00, 0x00, 0x01, 0x02, 0x04, 0x00}, // '

{0x00, 0x20, 0x54, 0x54, 0x54, 0x78}, // a

{0x00, 0x7F, 0x48, 0x44, 0x44, 0x38}, // b

{0x00, 0x38, 0x44, 0x44, 0x44, 0x20}, // c

{0x00, 0x38, 0x44, 0x44, 0x48, 0x7F}, // d

{0x00, 0x38, 0x54, 0x54, 0x54, 0x18}, // e

{0x00, 0x08, 0x7E, 0x09, 0x01, 0x02}, // f

{0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C}, // g

{0x00, 0x7F, 0x08, 0x04, 0x04, 0x78}, // h

{0x00, 0x00, 0x44, 0x7D, 0x40, 0x00}, // i

{0x00, 0x40, 0x80, 0x84, 0x7D, 0x00}, // j

{0x00, 0x7F, 0x10, 0x28, 0x44, 0x00}, // k

{0x00, 0x00, 0x41, 0x7F, 0x40, 0x00}, // l

{0x00, 0x7C, 0x04, 0x18, 0x04, 0x78}, // m

{0x00, 0x7C, 0x08, 0x04, 0x04, 0x78}, // n

{0x00, 0x38, 0x44, 0x44, 0x44, 0x38}, // o

{0x00, 0xFC, 0x24, 0x24, 0x24, 0x18}, // p

{0x00, 0x18, 0x24, 0x24, 0x18, 0xFC}, // q

{0x00, 0x7C, 0x08, 0x04, 0x04, 0x08}, // r

{0x00, 0x48, 0x54, 0x54, 0x54, 0x20}, // s

{0x00, 0x04, 0x3F, 0x44, 0x40, 0x20}, // t

{0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C}, // u

{0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C}, // v

{0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C}, // w

{0x00, 0x44, 0x28, 0x10, 0x28, 0x44}, // x

{0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C}, // y

{0x00, 0x44, 0x64, 0x54, 0x4C, 0x44}, // z

{0x00, 0x00, 0x08, 0x77, 0x41, 0x00}, // {

{0x00, 0x00, 0x00, 0x63, 0x00, 0x00}, // ¦

{0x00, 0x00, 0x41, 0x77, 0x08, 0x00}, // }

{0x00, 0x08, 0x04, 0x08, 0x08, 0x04}, // ~

/* end of normal char-set */

/* put your own signs/chars here, edit special_char too */

/* be sure that your first special char stand here */

{0x00, 0x3A, 0x40, 0x40, 0x20, 0x7A}, // ü, !!! Important: this must be special_char[0] !!!

{0x00, 0x3D, 0x40, 0x40, 0x40, 0x3D}, // Ü

{0x00, 0x21, 0x54, 0x54, 0x54, 0x79}, // ä

{0x00, 0x7D, 0x12, 0x11, 0x12, 0x7D}, // Ä

{0x00, 0x39, 0x44, 0x44, 0x44, 0x39}, // ö

{0x00, 0x3D, 0x42, 0x42, 0x42, 0x3D}, // Ö

{0x00, 0x02, 0x05, 0x02, 0x00, 0x00}, // °

{0x00, 0x7E, 0x01, 0x49, 0x55, 0x73}, // ß

{0x00, 0x7C, 0x10, 0x10, 0x08, 0x1C}, // µ

{0x00, 0x30, 0x48, 0x20, 0x48, 0x30}, // ω

{0x00, 0x5C, 0x62, 0x02, 0x62, 0x5C} // Ω

};


// 顯示字符的功能

void oled_display_char(uint8_t c) {

    i2c_start();

    i2c_write_byte(OLED_ADDRESS << 1);  // 發送地址

    i2c_write_byte(0x40);               // 控制位元 (0x40 表示後面是數據)

    

    // 發送 5x7 字符數據

    c = c - ' ';

    for (uint8_t i = 0; i < 6; i++) {

      i2c_write_byte(font5x7[c][i]);

    }

  

    // 6th byte is space between characters

    //i2c_write_byte(0x00);

  

    i2c_stop();

  

}


// 顯示字符串

void oled_display_string(uint8_t x, uint8_t y, const char* str) {

  oled_command(0xB0 + y);  // 設置頁地址

  oled_command(0x00);         // 設置低列地址

  oled_command(0x10 + x);         // 設置高列地址

    

  while (*str) {

    oled_display_char(*str);

    /*

    if (*str == 'H') oled_display_char(0);

    if (*str == 'E') oled_display_char(1);

    if (*str == 'L') oled_display_char(2);

    if (*str == 'O') oled_display_char(3);

    if (*str == '#') oled_display_char(4);

    */

    str++;

  }

}


void setup() {

  Serial.begin(9600);

  delay(100);


  //setup2();


  pinMode(OLED_SDA, OUTPUT);

  pinMode(OLED_SCL, OUTPUT);

  

  // 初始化 OLED

  oled_init();

  

  // 測試顯示,打開所有像素

  //oled_command(0xA5);  // 這個指令讓所有像素點亮


  // 清空顯示屏

  oled_clear();


  // 顯示 "HELLO"

  oled_display_string(0, 0, "12345678901234567890");

  oled_display_string(0, 1, "ABCDEFGHIJKLMNOPQRST");

  oled_display_string(0, 2, "abcdefghijklmnopqrst");

  oled_display_string(0, 3, "!@#$%^&*()_+-=,./;'?");

  oled_display_string(0, 7, "H####");

}


void loop() {

  // 空的 loop

}


/*

#include <Wire.h>


void setup2() {

  Wire.begin();

  Serial.begin(9600);

  Serial.println("\nI2C Scanner");

  for (uint8_t address = 1; address < 127; address++) {

    Wire.beginTransmission(address);

    if (Wire.endTransmission() == 0) {

      Serial.print("I2C device found at address 0x");

      if (address < 16) {

        Serial.print("0");

      }

      Serial.println(address, HEX);

    }

  }

  Serial.println("Done");

}

*/

沒有留言: