[TH] I2C Bus/Wire.h

บทความนี้เป็นการอธิบายเมธอดต่าง ๆ ของ Wire.h ซึ่งเป็นคลาสสำหรับสื่อสารกับอุปกรณ์ผ่านบัสประเภท I2C ที่ใช้สายสัญญาณ 2 เส้นเรียกว่า SDA และ SCL สำหรับรับส่งข้อมูลระหว่างกัน ศึ่งพวกเรามีบทความเกี่ยวกับการสื่อสารประเภทนี้ค่อนข้างเยอะ และใช้เป็นบัสหลักในการพัฒนาอุปกรณ์ขึ้นมาเองแล้วเรียกใช้งานผ่านบัส เข่น บทความการใช้ esp8266 เชื่อมต่อกัย Arduino Uno หรือ การใช้ esp8266 กับ stm32f030f4p6 เป็นต้น

ขาสำหรับ I2C

ในหัวข้อนี้ขอกล่าวถึงขาที่เป็นขาทำหน้าที่ SCL และ SDA ที่ฮาร์ดแวร์ไมโครคอนโทรลเลอร์รองรับการทำงาน ซึ่งทำให้การทำงานของการสื่อสารนั้นรวดเร็วกว่าการใช้ซอฟต์แวร์เขียนจำลองการทำงาน

STM32F030F4P6

ขาสำหรับทำหน้าที่ SCL และ SDA เป็นดังภาพที่ 1 จะภพบว่ามี I2C เพียงชุดเดียว ใช้ PA10 เป็นขา SDA และ PA9 เป็น SCL

ภาพที่ 1 ขา I2C ของ STM32F030F4P6

STM32F103C8

สำหรับ STM32F103C8 วึ่งเป็น Cortex-M3 รองรับ I2C จำนวน 2 ชุด คือ I2C1 และ I2C2 ดังภาพที่ 2 โดยขา SCL ของแต่ละชุด คือ PB6 และ PB10 ส่วนขา SDA คือ PB7 และ PB11

ภาพที่ 2 ขาของ I2C ชิพ STM32F103C8

STM32F401CC

สำหรับ STM32F401CC รองรับ I2C จำนวน 3 ชุด โดยการเลือกให้ชุดที่ 2 ทำงานจะทำให้ SPI3 ไม้สามารถใช้งานได้เนื่องจากใช้ขาร่วมกัน และการเปิดการทำงาน I2C ชุดที่ 3 จะกระทบกับการใช้ USART1 โดยขา SCL ของแต่ละชุดได้แก่ PB6, PB10 และ PA8 สำหรับ SDA ใช้ขาดังนี้ PB7, PB3 และ PB4 ดังภาพที่ 3

ภาพที่ 3 ขาบัส I2C ของ STM32F301CC

ESP8266

สำหรับ ESP8266 ไม่มีขาที่สนับสนุนโดยฮาร์ดแวร์ แต่สามารถใช้ขาทุกขาที่ใช้ได้เป็นตัวทำงานแบบซอฟต์แวร์

ESP32

ชิพ ESP32 รองรับฮาร์ดแวร์ I2C จำนวน 2 ชุดดังนี้ ซึ่งขาในชุดที่ 2 นั้นใช้ร่วมกับการทำ DAC

  1. I2C id=0
    1. SCL เป็นขา GPIO18
    2. SDA เป็นขา GPIO19
  2. I2C id=1
    1. SCL เป็นขา 25
    2. SDA เป็นขา 26

การใช้งาน

การใช้บัส I2C ของ Arduino ต้องเรียกผ่าน Wire.h โดยเมธอดสำหรับใช้งานมีดังนี้

คำสั่งสำหรับเริ่มต้นให้บัสทำงานเป็นดังนี้

Wire.begin()

คำสั่งสำหรับขอเข้าถึงอุปกรณ์ ณ ตำแหน่งที่กำหนดเป็นดังนี้

Wire.beginTransmission( ตำแหน่งของอุปกรณ์ )

การยกเลิกการเข้าถึงอุปกรณ์ที่ขอเข้าถึงไว้มีรูปแบบดังนี้ โดยเมธอดคืนค่า 0 ถ้าการเข้าถึงถูกยกเลิก

Wire.endTransmission()

กรณีที่ต้องการส่งข้อมูลไปยังอุปกรณ์ผ่านบัสสามารถทำได้ 3 วิธี คือ ส่งไบต์ข้อมูล ส่งสตริงและส่งก้อนข้อมูลพร้อมระบุจำนวนข้อมูลดังนี้

Wire.write( ไบต์ข้อมูล )
Wire.write( สตริง )
Wire.write( ก้อนข้อมูล, จำนวนไบต์ของข้อมูล )

เมื่อมีการร้อขอข้อมูล่านบัส ระบบจะนำข้อมูลที่ได้มาเก็บในบัฟเฟอร์ ซึ่งคำสั่งที่ทำหน้าที่ตรวจสอบจำนวนข้อมูลในบัฟเฟอร์มีรูปแบบดังนี้

จำนวนข้อมูลในบัฟเฟอร์ = Wire.available()

วิธีการนำข้อมูลจำนวน 1 ไบต์ออกจากบัฟเฟอร์ใช้คำสั่งดังนี้

byteData = Wire.read()

ตำสั่งร้องขออ่านข้อมูลจากอุปกรณ์เพื่อนำมาเก็บในบัฟเฟอร์ต้องระบุตำแหน่งของอุปกรณ์และจำนวนไบต์ที่ต้องการอ่านดังนี้

Wire.requestFrom( ตำแหน่งอุปกรณ์, จำนวนไบต์ที่ต้องการอ่าน )

การปรับความเร็วในการสื่อสารของบัส I2C ใช้คำสั่งกำหนดค่าดังนี้

Wire.SetClock( ความถี่ในการสื่อสาร )

คำสั่งสำหรับกำหนดฟังก์ชันตอบสนองเมื่อได้รับข้อมูลจากอุปกรณ์ภายนอก

Wire.onReceive( ชื่อฟังก์ชัน )

กำหนดฟังก์ชันตอบสนองเมื่อมีการร้องขอ

Wire.onRequest( ชื่อฟังก์ชัน )

ตัวอย่างการใช้งาน

ตัวอย่างการตรวจสอบอุปกรณ์

ตัวอย่างการตรวจสอบว่ามีอุปกรณ์ I2C_DEVICE หรือไม่เขียนได้ดังนี้

      Wire.beginTransmission( I2C_DEVICE );
      if (Wire.endTransmission() == 0) {
        // พบอุปกรณ์
      } else {
        // ไม่พบอุปกรณ์
      } 

ตัวอย่างการเขียนข้อมูลไปยังอุปกรณ์

การเขียนข้อมูลไปยังอุปกรณ์มีขั้นตอน คือ เชื่อมต่อ ส่งข้อมูลลำดับไบต์ และปิดการเชื่อมต่อ ดังโค้ดต่อไปนี้

  Wire.beginTransmission( I2C_DEVICE ); // (1)
  Wire.write( ไบตข้อมูล1 );             // (2) ถ้ามีหลายไบต์ให้เขียนคำสั่งเรียงกันไป
  Wire.endTransmission();     // (3)

ตัวอย่างการอ่านข้อมูลจากอุปกรณ์

การอ่านข้อมูลจากอุปกรณ์ประกอบไปด้วย 3 ขั้นตอนหลัก คือ ขอเข้าถึงตำแหน่งข้อมูลของอุปกรณ์ การอ่านมาเก็บในบัฟเฟอร์ และการเข้าถึงบัฟเฟอร์เพื่อนำข้อมูลออก ดังนี้

ขั้นตอน 1
  Wire.beginTransmission( I2C_DEVICE );  
  Wire.write( ตำแหน่งของข้อมูล );   
  Wire.endTransmission(); 
ขั้นตอน 2
  Wire.requestFrom( I2C_DEVICE, จำนวนไบต์ที่ต้องการอ่าน );  
ขั้นตอน 3
  while (Wire.available( ) ) {
     ข้อมูล = Wire.read( );
  }

สรุป

จากบทความนี้จะพบว่า หลักการเขียนโปรแกรมเพื่อใช้งานอุปกรณ์ I2C ผ่านคลาส Wire นั้นต้องอาศัยความเข้าใจโปรโทคอล (Protocol) หรือรูปแบบการสื่อสารกับอุปกรณ์เป็นสำคัญ เนื่องจาก คำสั่งช่วยเหลือเพียงส่งข้อมูลไบต์ไปยังอุปกรณ์ และอ่านข้อมูลปริมาณหนึ่งจากอุปกรณ์เท่านั้น ทางทีมงานเราหวังว่าคงเป็นแนวทางสำหรับผู้สนใจเขียนโปรแกรมเพื่อสื่อสารกับอุปกรณ์บนบัส I2C หรือสร้างอุปกรณ์เพื่อใช้งานเองที่สื่อสารกับอุปกรณ์บนบัส สุดท้าย ขอให้สนุกกับการเขียนโปรแกรม

ท่านใดต้องการพูดคุยสามารถคอมเมนท์ไว้ได้เลยครับ

แหล่งอ้างอิง

  1. I2C
  2. Wire Library

(C) 2020-2021, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ
ปรับปรุงเมื่อ 2021-07-05, 2021-07-29, 2021-11-02