顯示具有 I2C 標籤的文章。 顯示所有文章
顯示具有 I2C 標籤的文章。 顯示所有文章

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");

}

*/

2022年8月23日 星期二

NodeMCU I2C 與 Arduino IDE

介紹

I2C(Inter-Integrated Circuit)是一種串行總線接口連接協議。它也被稱為 TWI(雙線接口),因為它只使用兩條線進行通信。這兩條線是 SDA(串行數據)和 SCL(串行時鐘)。

I2C 是一種基於確認的通信協議,即發送器在發送數據後檢查接收器的確認,以了解接收器是否成功接收數據。

I2C以兩種模式工作,即,

  • 主模式
  • 從機模式

SDA(串行數據)線用於主從設備之間的數據交換。SCL(串行時鐘)用於主從設備之間的同步時鐘。

主設備發起與從設備的通信。主設備需要從設備地址來發起與從設備的對話。當從設備被主設備尋址時,從設備響應主設備。

NodeMCU 在其 GPIO 引腳上支持 I2C 功能。由於 ESP-12E 的內部功能,我們不能將其所有 GPIO 用於 I2C 功能。因此,在將任何 GPIO 用於 I2C 應用之前進行測試。

 

例子

讓我們為作為 I2C 主設備的 NodeMCU 編寫一個 Arduino 草圖,為作為 I2C 從設備的 Arduino Uno 編寫一個 Arduino 草圖。主設備向從設備發送一個​​問候字符串,從設備將發送一個問候字符串以響應主設備。

在這裡,我們使用

主設備: NodeMCU

從設備: Arduino Uno

從設備地址: 8

接口圖如下圖所示

NodeMCU Arduino I2C 接口

NodeMCU Arduino I2C 接口

 

用於 NodeMCU(主 I2C 設備)的 Arduino 草圖

#include <Wire.h>

void setup() {
 Serial.begin(9600); /* begin serial for debug */
 Wire.begin(D1, D2); /* join i2c bus with SDA=D1 and SCL=D2 of NodeMCU */
}

void loop() {
 Wire.beginTransmission(8); /* begin with device address 8 */
 Wire.write("Hello Arduino");  /* sends hello string */
 Wire.endTransmission();    /* stop transmitting */

 Wire.requestFrom(8, 13); /* request & read data of size 13 from slave */
 while(Wire.available()){
    char c = Wire.read();
  Serial.print(c);
 }
 Serial.println();
 delay(1000);
}

Arduino Uno(從 I2C 設備)的 Arduino Sketch

#include <Wire.h>

void setup() {
 Wire.begin(8);                /* join i2c bus with address 8 */
 Wire.onReceive(receiveEvent); /* register receive event */
 Wire.onRequest(requestEvent); /* register request event */
 Serial.begin(9600);           /* start serial for debug */
}

void loop() {
 delay(100);
}

// function that executes whenever data is received from master
void receiveEvent(int howMany) {
 while (0 <Wire.available()) {
    char c = Wire.read();      /* receive byte as a character */
    Serial.print(c);           /* print the character */
  }
 Serial.println();             /* to newline */
}

// function that executes whenever data is requested from master
void requestEvent() {
 Wire.write("Hello NodeMCU");  /*send string on request */
}

輸出窗口

從設備上串行監視器的輸出窗口(Arduino Uno)

Arduino Slave 輸出窗口

主設備(NodeMCU)上串行監視器的輸出窗口

NodeMCU I2C主控的Arduino輸出窗口

  

資料來源:https://www.electronicwings.com/nodemcu/nodemcu-i2c-with-arduino-ide

I2C遠距離通訊注意事項

I2C通訊質量主要與主電路設計形式、通訊速度、電阻選擇、通訊線路長度、通訊線路結構形式有關。其中,通訊線路結構影響最為明顯:

根線結構形式:I2需要4根線,VCC,GND,SCL,SDA。在遠距離時,SCL和SDA兩根長距離並排走線附近沒有GND線時,且由於通訊通訊本身與C為了降低問題距離傳輸時的干擾,可以採用以下幾種優化方式:

1.採用SCLSDA避免中間排線,用GND和VCC隔開,接線CL,GND,VCC,這樣可以在一定程度上為SDA走線和抗干擾SDA;


2.採用單線跟貼用時,SCL,SDA應與,VCC緊著走線,可分離,4根線可以絞成麻花狀繞線,可以將其捆綁線管將其套掉;


3.採用帶外皮的電纜,有比較好的改善效果,則帶接地層的屏蔽效果更好;


4 採用雙絞線時,例如寬帶電纜,可以將SCL,SCL,VCC分別與一組地線形成雙絞線,此時抗干擾效果

主控控制器的主控端抗干擾性能會設計好,通訊會得到保障。繞線,不要有交叉線,不要與高頻線並走線,芯片上的I2C路口靠近IO口;

通訊低也震盪(≤100Hz)有:距離更遠的數據傳輸,而高頻率(10~400KHz)頻率低通訊,同時更容易產生干擾

上拉電阻多少決定了值的通訊速度,同時對通訊距離有,適當降低上拉電阻的影響有距離:上拉距離通訊,參考2K~4.7K;

通訊線路長度:線路短,干擾強,適合高頻率抗通訊,通訊質量更好



資料來源:https://www.kodorobot.com/wp-content/uploads/2019/06/小MU視覺傳感器I2C遠距離通訊事項.pdf