I2C เป็นรูปแบบการเชื่อมต่อ (interface) ที่นิยมใช้กันมากในฝั่งเทคโนโลยีสมองกลฝังตัว (Embedded System) และระบบ IoT โดยเซ็นเซอร์ต่าง ๆ เช่น เซ็นเซอร์อุณหภูมิและความชื้น เซ็นเซอร์แสง เซ็นเซอร์วัดฝุ่น และเซ็นเซอร์อื่น ๆ ล้วนใช้ I2C ในการเชื่อมต่อกับไมโครคอนโทรลเลอร์ ในบทความนี้จะแนะนำให้รู้จัก I2C, หลักการทำงาน และการเขียนโปรแกรมอ่านค่าอุณหภูมิและความชื้นผ่าน I2C เบื้องต้น โดยใช้อุปกรณ์ตัวอย่าง SHT40
ข้อมูลเบื้องต้นเกี่ยวกับ I2C
I2C (อ่านว่า ไอสแควซี หรือ ไอทูซี) หรือ IIC ถูกพัฒนาโดยบริษัท ฯ Philips Semiconductors หรือ NXP ในปัจจุบัน เป็นทั้งรูปแบบการเชื่อมต่อสาย และรูปแบบการสื่อสาร (Protocal) ทำงานแบบซิงโครไนซ์ (Synchrony) เชื่อมต่อแบบอนุกรม นิยมใช้กันมากในไอซีที่เป็นอุปกรณ์ต่อร่วมกับไมโครคอนโทรลเลอร์ เช่น ไอซี ADC, DAC, เซ็นเซอร์ต่าง ๆ, Digital Potentiometer ในเชิง Physical (การเชื่อมต่อสาย) ประกอบด้วยสายสัญญาณ 2 เส้น คือ SCL (Serial Clock) และ SDA (Serial Data) ทั้งฝั่งไมโครคอนโทรลเลอร์ และฝั่งอุปกรณ์ I2C โดยการเชื่อมต่อจะต้องเชื่อมต่อสายให้ชื่อตรงกัน คือ SCL เชื่อมต่อกับ SCL, SDA เชื่อมต่อกับ SDA โดยมีตัวต้านทานค่าตั้งแต่ 10k โอห์ม ถึง 1k โอห์ม ต่อ Pull-up ทั้ง SDA และ SCL ไว้ ตัวอย่างการเชื่อมต่อบอร์ด Arduino Uno เข้ากับเซ็นเซอร์ SHT40 แสดงดังรูปที่ 1
I2C สามารถเชื่อมต่อหลาย ๆ อุปกรณ์เข้าด้วยกันได้ด้วยชุด SCL, SDA ชุดเดียวกัน จากรูปที่ 1 เพิ่มการเชื่อมต่อจอ OLED และไอซีขยายขา PCF8574 ได้วงจรใหม่ดังรูปที่ 2
* อุปกรณ์ I2C ที่จะเชื่อมต่อบน SCL, SDA ชุดเดียวกันได้ ต้องมีหมายเลข (Address) ไม่ซ้ำกัน อ่านรายละเอียดได้ในหัวข้อต่อไป
หลักการทำงานของ I2C
I2C ทำงานแบบถาม-ตอบ โดยคนถามจะเป็นฝั่ง Master (ไมโครคอนโทรลเลอร์) เสมอ ฝั่งอุปกรณ์ / Slave ที่มีหมายเลขประจำตัวตรงกับที่ Master ถามจะเป็นผู้ตอบ
การเริ่ม-หยุดรับ-ส่งข้อมูล จะกำหนดโดยฝั่ง Master โดยปกติหากไม่มีการสื่อสารภายในบัส I2C ทั้งขา SCL และ SDA จะมีลอจิกเป็น 1 อยู่เสมอ เมื่อฝั่ง Master ต้องการเริ่มส่งข้อมูล จะส่งสัญญาณ Start Condition ออกไป โดยดึงสัญญาณขา SDA ลงเป็นลอจิก 0 ในขณะที่ขา SCL ยังเป็นลอจิก 1 อยู่
หลังจากรับ-ส่งข้อมูลเรียบร้อยแล้ว เพื่อเป็นการบอกฝั่ง Slave ว่าต้องการหยุดรับ-ส่งข้อมูล จะส่งสัญญาณ Stop Condition ออกไป โดยปล่อยสัญญาณขา SCL เป็นลอจิก 1 ก่อน แล้วจึงปล่อยขา SDA เป็นลอจิก 1 ตาม
* โดยปกติขา SDA จะไม่สามารถเปลี่ยนลอจิกในขณะที่ SCL ยังเป็นลอจิก 1 แต่สำหรับสัญญาณ START, STOP ถือเป็นข้อยกเว้น
ข้อมูลเริ่มจากการส่ง Control Byte ประกอบด้วย Address ของ Slave ที่ต้องการส่ง (Write) หรือรับ (Read) จำนวน 7 ไบต์แรก ไบต์สุดท้ายคือ R/W ใช้บอกว่าจะ Write หรือ Read
หากต้องการ Write บิตนี้จะเป็น 1
หากต้องการ Read บิตนี้จะเป็น 0
ฝั่ง Slave เมื่อได้รับข้อมูล และตรวจสอบแล้วว่า Address ตรงกับตนเอง จะส่งสัญญาณ ACK (Acknowledge) กลับไป โดยดึงสัญญาณ SDA เป็นลอจิก 0 ที่ฝั่ง Master เมื่อได้รับสัญญาณ ACK กลับมา จะดำเนินการรับ-ส่งข้อมูลต่อไป (หากไม่ได้รับ ACK จะยกเลิกการ Read / Write ในรอบนั้นไป)
หากเป็นการ Write ฝั่ง Master จะส่งข้อมูลออกไปทันทีผ่านขา SDA แล้วรอสัญญาณ ACK ตอบกลับมา หากมี ACK ตอบกลับมาจึงจะส่งข้อมูลไบต์ถัดไป หากไม่มี จะส่งสัญญาณ Stop ออกไปทันที (ยกเลิกการส่งข้อมูลรอบนั้น)
หากเป็นการ Read ฝั่ง Master จะปล่อยให้ Slave เข้ามาควบคุม SDA แทน โดยฝั่ง Master จะควบคุมจังหวะการรับข้อมูลผ่าน SCL เมื่อรับข้อมูลครบ 1 ไบต์ ฝั่ง Master ต้องส่ง ACK กลับไปบอก Slave ว่าได้รับข้อมูลครบถ้วนแล้ว หากไม่ส่ง ACK กลับ ฝั่ง Slave จะถือว่าการส่งข้อมูลล้มเหลว และไม่ตอบสนองอะไรอีกจนกว่าจะเริ่มการรับ-ส่งข้อมูลรอบใหม่
หลังจาก Read / Write จนครบแล้ว ฝั่ง Master จะส่งสัญญาณ Stop ออกไปเพื่อบอกฝั่ง Slave ว่าจบการรับ-ส่งข้อมูลในรอบนั้น ๆ แล้ว
ขอบคุณรูปภาพที่ 5 และ 6 จาก I2C Primer: What is I2C? (Part 1) | Analog Devices
การหาและเลือกหมายเลขอุปกรณ์ (Address)
หมายเลขอุปกรณ์จะถูกกำหนดมาเป็นค่าคงที่ โดยแต่ละเบอร์ของไอซีหรือเซ็นเซอร์จะไม่เหมือนกันในแต่ละผู้ผลิต ในแต่ละเบอร์ บางเซ็นเซอร์หรือไอซีบางตัวสามารถเปลี่ยนหมายเลข Address ได้โดยกำหนดลอจิกให้ขาบางขาบนไอซี เช่น PCF8574 มีขา A0 ถึง A2 ที่เมื่อเปลี่ยนรูปแบบการป้อนลอจิก จะทำให้หมายเลขของ Address เปลี่ยนไปด้วย ตำแหน่งขา A0 ถึง A1 แสดงดังรูปที่ 7
เซ็นเซอร์บางรุ่นไม่สามารถเปลี่ยนหมายเลข Address ได้ โดยจะมีค่าคงที่เป็นค่า ๆ หนึ่งเสนอ ค่าดังกล่าวจำเป็นต้องตรวจสอบใน Datasheet (อย่างละเอียด) ตัวอย่างเซ็นเซอร์วัดอุณหภูมิและความชื้นไม่มีขาให้เปลี่ยนหมายเลข Address โดยหมายเลขจะถูกกำหนดเป็น 0x44 ตามข้อมูลในเอกสาร Datasheet_SHT4x-1917879.pdf หน้าที่ 3
หากไม่ทราบหมายเลขของอุปกรณ์ หรือต้องการทดสอบว่าอุปกรณ์ทำงานได้หรือไม่ หรือต่อวงจรถูกหรือไม่ สามารถใช้โปรแกรม I2C Scanner ในการค้นหาหมายเลขอุปกรณ์ I2C ทั้งหมดได้ ดังโค้ดโปรแกรมด้านล่างนี้
// --------------------------------------
// i2c_scanner
//
// Version 1
// This program (or code that looks like it)
// can be found in many places.
// For example on the Arduino.cc forum.
// The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
// Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26 2013
// V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
// by Arduino.cc user Krodal.
// Changes by louarnold removed.
// Scanning addresses changed from 0...127 to 1...119,
// according to the i2c scanner by Nick Gammon
// https://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
// As version 4, but address scans now to 127.
// A sensor seems to use address 120.
// Version 6, November 27, 2015.
// Added waiting for the Leonardo serial communication.
//
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//
#include <Wire.h>
void setup()
{
Wire.begin();
Serial.begin(9600);
while (!Serial); // Leonardo: wait for serial monitor
Serial.println("\nI2C Scanner");
}
void loop()
{
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 1; address < 127; address++ )
{
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0)
{
Serial.print("I2C device found at address 0x");
if (address<16)
Serial.print("0");
Serial.print(address,HEX);
Serial.println(" !");
nDevices++;
}
else if (error==4)
{
Serial.print("Unknown error at address 0x");
if (address<16)
Serial.print("0");
Serial.println(address,HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");
delay(5000); // wait 5 seconds for next scan
}
ที่มาโค้ดโปรแกรมทดสอบ Arduino Playground - I2cScanner
หลังจากอัพโหลดโปรแกรม เปิด Serial Monitor ขึ้นมา จะแสดงหมายเลข I2C ทั้งหมดที่ค้นหาเจอ (ตัวอย่างรูปด้านล่าง ค้นเจอ 0x44 คือ SHT40)
หลักการทำงานของโปรแกรม I2C Scanner คือการส่ง Control Byte ออกไป ส่วนของฟิลด์ Address เป็นหมายเลขที่ใช้ทดสอบว่ามีอยู่หรือไม่ จากนั้นรอดูสัญญาณ ACK หากมีสัญญาณ ACK แสดงว่าหมายเลขอุปกรณ์ที่ส่งไปมีอยู่บัส หากไม่มี ACK ตอบกลับมา แสดงว่าอาจจะต่อสายผิด หรือไม่ได้ต่ออุปกรณ์หมายเลยนั้น ๆ บนบัส หรืออุปกรณ์ไม่สามารถใช้งานได้
การเขียนโปรแกรมรับ-ส่งข้อมูลผ่าน I2C ด้วยแพลตฟอร์ม Arduino
แพลตฟอร์ม Arduino ใช้ไลบารี่ Wire.h ในการเขียนโปรแกรมรับ-ส่งข้อมูล โดยก่อนเริ่มรับ-ส่งข้อมูล จะต้องเรียกใช้คำสั่ง Wire.begin() ก่อน โดยปกติจะอยู่ใน void setup()
Wire.begin()
จากนั้นหากต้องการเขียนข้อมูล จะต้องเริ่มต้นด้วย Wire.beginTransmission() แล้วใช้คำสั่ง Wire.write() เขียนข้อมูลลงไปให้ครบตามจำนวนไบต์ (เรียกใช้คำสั่งนี้ได้หลายครั้งหากมีข้อมูลหลายไบต์) แล้วจบด้วย Wire.endTransmission()
ตัวอย่างการเขียนข้อมูล 0xF1 ไปยังอุปกรณ์ I2C หมายเลข 0x3F แสดงดังโค้ดโปรแกรมด้านล่าง
#include <Wire.h>
void setup() {
Wire.begin();
}
void loop() {
Wire.beginTransmission(0x3F); // เริ่มส่งข้อมูลไปที่อุปกรณ์ 0x3F
Wire.write(0xF1); // ส่งข้อมูล 0xF1
Wire.endTransmission(); // จบการส่งข้อมูล
delay(2000);
}
การอ่านข้อมูลใช้คำสั่ง Wire.requestFrom() โดยกำหนดหมายเลข I2C และจำนวนข้อมูลที่ต้องการอ่าน โดยคำสั่งนี้จะคืนค่าจำนวนไบต์ที่อ่านได้ออกมา จากนั้นใช้คำสั่ง Wire.read() อ่านข้อมูลทีละไบต์ออกมาได้เลย ตัวอย่างการอ่านข้อมูล 1 ไบต์ จากอุปกรณ์หมายเลข 0x3F แสดงดังโค้ดด้านล่าง
#include <Wire.h>
void setup() {
Wire.begin();
}
void loop() {
int n = Wire.requestFrom(0x3F, 1); // อ่านข้อมูล 1 ไบต์ จากอุปกรณ์ 0x3F
if (n == 1) { // ตรวจสอบว่าได้รับข้อมูล 1 ไบต์ หรือไม่
Serial.print("Data: ");
Serial.println((byte)Wire.read(), HEX); // แสดงผลข้อมูลไบต์แรกที่อ่านจาก I2C บน Serial Monitor
} else { // ถ้าไม่ใช่ แสดงว่ารับ-ส่งข้อมูลผิดพลาด
Serial.println("Read error"); // แสดงข้อความ Read error
}
delay(2000);
}
ตัวอย่างเขียนโปรแกรมอ่าน-เขียนข้อมูลอุปกรณ์ I2C
อุปกรณ์ I2C แต่ละตัวมีรูปแบบการเขียนรับ-ส่งข้อมูลไม่เหมือนกัน โดยส่วนใหญ่แบ่งได้ 3 รูปแบบดังนี้
1) แบบอ่าน-เขียนได้ตรง ๆ - PCF8574
PCF8574 เป็นไอซีขยสายขา ประกอบด้วยขา P0 ถึง P7 ที่สามารถสั่งให้เป็นลอจิก 0 หรือ 1 ได้อิสระ โดยสั่งผ่าน I2C มีขา A0 ถึง A3 ที่ใช้กำหนดหมายเลขอุปกรณ์ มีขา SCL, SDA สำหรับต่อกับไมโครคอนโทรลเลอร์ และขา VCC, GND สำหรับต่อไฟเลี้ยง ตำแหน่งขาของ PCF8574 แสดงดังรูปที่ 9
การสั่งงานผ่าน I2C สามารถสั่งอ่าน-เขียนได้ตรง ๆ โดยหากเขียน (Write) ข้อมูลลงไป สัญญาณลอจิกที่ขา P0 ถึง P7 จะเปลี่ยนไปตามข้อมูลที่ Write ลงไป หากอ่าน (Read) ข้อมูลที่จะได้จะเป็นลอจิกที่ขา P0 ถึง P7 ข้อมูลจาก Datasheet ของ PCF8574 แสดงขั้นตอนการอ่าน-เขียนไว้ในเอกสาร PCF8574 Datasheet หน้าที่ 13 ดังรูปที่ 10 แสดงขั้นตอนการเขียนข้อมูล (หาก Write หลายไบต์ ตัวไอซี PCF8574 จะเลือกไบต์สุดท้ายมากำหนดลอจิก P0 ถึง P7) และรูปที่ 11 แสดงขั้นตอนการอ่านข้อมูลจาก P0 ถึง P7
ตัวอย่างการเขียนโปรแกรมสั่งงาน PCF8574 ให้ขา P0 ถึง P7 เป็นลอจิก 0 และ 1 สลับกันทุก ๆ 1 วินาที แสดงดังโค้ดด้านล่าง
#include <Wire.h>
void setup() {
Wire.begin();
}
void loop() {
Wire.beginTransmission(0x3F); // เริ่มส่งข้อมูลไปที่อุปกรณ์ 0x3F
Wire.write(0xFF); // ส่งข้อมูล 0xFF สั่งให้ P0 ถึง P7 เป็นลอจิก 1
Wire.endTransmission(); // จบการส่งข้อมูล
delay(1000);
Wire.beginTransmission(0x3F); // เริ่มส่งข้อมูลไปที่อุปกรณ์ 0x3F
Wire.write(0x00); // ส่งข้อมูล 0x00 สั่งให้ P0 ถึง P7 เป็นลอจิก 0
Wire.endTransmission(); // จบการส่งข้อมูล
delay(1000);
}
2) แบบอ่าน-เขียนรีจิสเตอร์ - DS1307
รีจิสเตอร์เปรียบเสมือนที่เก็บข้อมูลที่สามารถเขียน-อ่านได้ โดยมีหมายเลขของรีจิสเตอร์เป็นตัวกำกับ อุปกรณ์ I2C ส่วนใหญ่ใช้วิธีนี้ในการใช้งาน ตัวอย่างเลือกใช้ไอซีฐานเวลา (RTC : Real Time Clock) เบอร์ DS1307 เนื่องจากเข้าใจได้ง่าย
DS1307 มีขา 8 ขา ประกอบด้วยขา SCL, SDA สำหรับต่อเข้ากับไมโครคอนโทรลเลอร์ ขา XTAL จำนวน 2 ขา สำหรับต่อคริสตัล 32.768 kHz ขาต่อแบตเตอรี่สำรองไฟ และขาต่อไฟเลี้ยง VCC และ GND ตำแหน่งขาของ DS1307 แสดงดังรูปที่ 12
จากข้อมูลเอกสาร DS1307 Datasheet หน้า 8 ดังรูปที่ 13 จะเห็นได้ว่ารีจีสเตอร์สำหรับเก็บเวลาวินาทีอยู่ที่รีจีสเตอร์ตำแหน่ง 0x00 ส่วนนาทีอยู่ตำแหน่ง 0x01 รีจีสเตอร์ของชั่วโมง, Week day, วัน, เดือน, ปี ตามลำดับ
การเขียนข้อมูลลงรีจีสเตอร์ ตามเอกสาร Datasheet หน้าที่ 12 แสดงตามรูปที่ 14 เริ่มต้นด้วยการส่ง Control Byte แล้วตามด้วยหมายเลขรีจีสเตอร์เริ่มต้น (Word Address) ที่ต้องการเขียน จากนั้นตามด้วยข้อมูลที่ต้องการเขียน (Data(n)) หากข้อมูลที่เขียนมีมากกว่า 1 ไบต์ ข้อมูลที่เขียนลงไปจะไปลงใน Address ถัดไป เช่น ที่ Word Address กำหนดเป็น 0x00 ข้อมูลไบต์แรกจะลงในรีจีสเตอร์ 0x00 ไบต์ที่ 2 ลงใน 0x01 ไบต์ที่ 3 ลงใน 0x02 เป็นต้น
* ไอซีหรือเซ็นเซอร์บางตัวไม่สามารถเขียนข้อมูลลงรีจีสเตอร์แบบต่อเนื่องได้ จำเป็นต้องตรวจสอบข้อมูลใน Datasheet ก่อน
การอ่านข้อมูลจากรีจีสเตอร์ ตามเอกสาร Datasheet หน้าที่ 12 แสดงตามรูปที่ 15 เริ่มต้นด้วยการส่ง Control Byte แล้วตามด้วยหมายเลขรีจีสเตอร์เริ่มต้น (Word Address) ที่ต้องการอ่านข้อมูลออกมา จากนั้นส่งสัญญาณ Restart (ถ้า Start โดยไม่ส่ง Stop ก่อน จะเรียกว่า Restart) ส่ง Control Byte จากนั้นอ่านข้อมูลออกมาได้ตามจำนวนที่ต้องการได้เลย โดยข้อมูลไบต์แรกจะเป็นของรีจีสเตอร์ Word Address ไบต์ต่อไปเป็นของรีจีสเตอร์ตัวถัดไป ตัวอย่างกำหนด Word Address เป็น 0x05 อ่านไบต์แรกจะเป็นข้อมูลของ 0x05 ไบต์ที่ 2 เป็นของรีจีสเตอร์ 0x06 เป็นแบบนี้ไปเรื่อย ๆ
* ไอซีหรือเซ็นเซอร์บางตัวไม่สามารถอ่านข้อมูลจากรีจีสเตอร์แบบต่อเนื่องได้ จำเป็นต้องตรวจสอบข้อมูลใน Datasheet ก่อน
ตัวอย่างการเขียนโปรแกรมตั้งเวลาลง DS1307 และอ่านค่าเวลาจาก DS1307 แสดงดังโค้ดด้านล้าง
#include <Wire.h>
void setup() {
Serial.begin(9600);
Wire.begin();
// ตั้งเวลาเป็น 8:12:45
Wire.beginTransmission(0x68); // เริ่มส่งข้อมูลไปที่อุปกรณ์ DS1307 (Address: 0x68)
Wire.write(0x00); // เริ่มเขียนข้อมูลไปที่รีจีสเตอร์ 0x00 (Word Address: 0x00)
Wire.write(0x45); // รีจีสเตอร์ 0x00 (Seconds) กำหนดเป็น 46 (ในรหัส BCD)
Wire.write(0x12); // รีจีสเตอร์ 0x01 (Minutes) กำหนดเป็น 12 (ในรหัส BCD)
Wire.write(0x08); // รีจีสเตอร์ 0x02 (Hours) กำหนดเป็น 8 (ในรหัส BCD)
Wire.endTransmission(); // จบการส่งข้อมูล
}
void loop() {
Wire.beginTransmission(0x68); // เริ่มส่งข้อมูลไปที่อุปกรณ์ 0x3F
Wire.write(0x00); // เริ่มเขียนข้อมูลไปที่รีจีสเตอร์ 0x00 (Word Address: 0x00)
Wire.endTransmission(false); // จบการส่งข้อมูล (ไม่ส่ง Stop)
int n = Wire.requestFrom(0x68, 3); // อ่านข้อมูล 1 ไบต์ จากอุปกรณ์ 0x3F
if (n == 3) { // ถ้าอ่านข้อมูลได้ครบ 3 ไบต์ ให้
byte sec = Wire.read(); // อ่านข้อมูลไบต์แรก เก็บลงตัวแปร sec
byte min = Wire.read(); // อ่านข้อมูลไบต์ 2 เก็บลงตัวแปร min
byte hour = Wire.read(); // อ่านข้อมูลไบต์ 3 เก็บลงตัวแปร hour
Serial.print(hour, HEX);
Serial.print(":");
Serial.print(min, HEX);
Serial.print(":");
Serial.print(sec, HEX);
} else {
Serial.println("Read data fail");
}
delay(1000);
}
3) แบบใช้ Command - SHT40
SHT40 เป็นเซ็นเซอร์วัดอุณหภูมิและความชื้นที่ประกอบด้วยขาต่อใช้งาน 4 ขา คือ SDA, SCL สำหรับต่อเข้ากับไมโครคอนโทรลเลอร์ ขา VCC และ GND สำหรับต่อไฟเลี้ยง
ลำดับการอ่านค่าจากเซ็นเซอร์ตามเอกสาร SHT40 Datasheet หน้าที่ 8 แสดงดังรูปที่ 17 จะเห็นว่าจำเป็นจะต้องส่ง Control Byte แล้วตามด้วย Command จากนั้นจึงจะอ่านข้อมูลออกมาได้
การร้องขอข้อมูลที่วัดได้จะทำผ่าน I2C ด้วยการ Write Command จากนั้นจึง Read ข้อมูลออกมา ตามเอกสาร SHT40 Datasheet หน้า 8 ได้ระบุรายการ Command ไว้ตามรูปที่ 18 โดยจะเห็นได้ว่าหากต้องการอ่านค่าอุณหภูมิและความชื้นสามารถเลือกใช้ได้ทั้ง 0xFD (high repeatability), 0xF6 (medium repeatability) หรือ 0xE0 (low repeatability)
ตัวอย่างการเขียนโปรแกรมอ่านค่าจากเซ็นเซอร์ SHT40 ใน Datasheet ได้ให้ตัวอย่างโค้ดโปรแกรมแบบ Pseudo code ไว้ แสดงดังรูปที่ 19
จาก Pseudo code สามารถแปลงเป็นโค้ดโปรแกรมในแพลตฟอร์ม Arduino ได้ดังนี้
#include <Wire.h>
void setup() {
Serial.begin(9600);
Wire.begin();
}
void loop() {
Wire.beginTransmission(0x44); // เริ่มส่งข้อมูลไปที่อุปกรณ์ 0x44 (SHT40)
Wire.write(0xFD); // ส่ง Command: 0xFD
Wire.endTransmission(); // จบการส่งข้อมูล
delay(20); // หน่วงเวลา 20 mS
int n = Wire.requestFrom(0x44, 6); // อ่านข้อมูล 6 ไบต์ จากอุปกรณ์ 0x44
if (n == 6) { // ถ้าอ่านข้อมูลได้ครบ 6 ไบต์ ให้
uint8_t rx_bytes[6]; // สร้างตัวแปรอาร์เรย์ 6 ชุด
Wire.readBytes(rx_bytes, 6); // อ่านข้อมูล 6 ไบต์ เก็บลงตัวแปร rx_bytes
uint16_t t_ticks = rx_bytes[0] * 256 + rx_bytes[1];
uint16_t rh_ticks = rx_bytes[3] * 256 + rx_bytes[4];
float t_degC = -45 + 175 * t_ticks / 65535.0;
float rh_pRH = -6 + 125 * rh_ticks / 65535.0;
Serial.println("t: " + String(t_degC) + " *C\th: " + String(rh_pRH) + " %RH"); // แสดงผลค่าอุณหภูมิและความชื้นที่อ่านได้บน Serial Monitor
} else {
Serial.println("Read data fail");
}
delay(1000);
}
สรุป
I2C อ่านว่า ไอสแควซี หรือ ไอทูซี เป็นรูปแบบการเชื่อมต่อสายและการสื่อสารผ่านสาย 2 เส้น คือ SCL, SDA อุปกรณ์ที่มีหมายเลข (Address) ไม่ซ้ำกัน สามารถต่อ SDA, SCL ร่วมกันได้ การเขียนโปรแกรมอ่านค่าและสั่งงานอุปกรณ์ I2C จำเป็นต้องทำความเข้าใจข้อมูลใน Datasheet จึงจะเขียนโปรแกรมสั่งงานได้
Comments