เรื่องที่เราจะคุยกันวันนี้เกี่ยวกับโปรโตคอลการสื่อสารระหว่างอุปกรณ์ 2 ตัว เรียกว่า I2C (Inter-Intergrated Circuit) กันครับ
I2C อ่านว่า ไอสแควร์ซี หรือ ไอทูซี ก็ได้ครับ บางคนอาจจะเจอคำว่า TWI (Two Wire Interface ก็คือ I2C นะครับ) เป็นวิธีการส่งข้อมูลกันระหว่างไอซี หรือ ไมโครคอลโทรเลอร์ (ทีละ) 2 ตัว ที่ผมใช้คำว่า "ทีละ" 2 ตัวก็เพราะว่ามันสามารถติดต่อกันได้หลายตัวครับ แต่คุยกันได้ทีละคู่ โดยมีตัวออกคำสั่งว่าจะคุยกับใคร คือ Master และ ตัวที่สั่งให้ต้องตอบคือ Slave ครับ
วิธีการสื่อสารระหว่างไอซีแบบนี้คิดค้นโดยบริษัท Phillips Semiconductor ซึ่งปัจจุบันคือบริษัท NXP Semiconductor โดยคิดค้นคั้งแต่ปี 1982 และได้มีการพัฒนามาเรื่อยๆ จนกลายเป็นโปรโตคอลมาตรฐานที่ใช่ในการติดต่อกันระหว่างอุปกรณ์ครับ
ถ้าลองดูภาพด้านบนจะเห็นว่าโปรโตคอล I2C จะสื่อสารโดยใช้สายเพียง 2 เส้นเท่านั้น คือ SDA (Serial Line Data) และ SCL (Serial Clock) ก็สามารถส่งข้อมูลหากันได้ โดยมีความเร็วตั้งแต่ 100 kHz ไปถึงเป็นระดับ 5 MHz ได้เลย
การสื่อสารแบบ I2C นี้เป็นมาตรฐานการติดต่อกันระหว่างไมโครคอนโทรลเลอร์กับไอซีทั้งหลาย ที่่ผมจะบอกก็คือ I2C นี้มีอยู่ในทุกเวอร์ชั่นของบอร์ด Arduino และ Raspberry Pi ครับ ส่วนอีกโปรโตคอลนึงที่จะไม่กล่าวถึงไม่ได้ก็คือ SPI (Serial Peripheral Interface) ซึ่งก็จะมีอยู่บนทุกเวอร์ชั่นของบอร์ด Arduino และ RPi เช่นเดียวกันครับ (วันนี้ไม่พูดถึง SPI ละกันนะครับ เดี๋ยวจะยาวเกินไป)
ข้อแตกต่างหลักๆ ของ I2C และ SPI คือ จำนวนสายที่ใช้ในการติดต่อ I2C ใช้ 2 เส้น ส่วน SPI ใช้ 3 - 4 เส้นครับ การใช้สายที่น้อยกว่าของ I2C ก็ทำให้ความเร็วในการส่งของ I2C ช้ากว่าแบบ SPI ครับ แต่ที่ว่าช้าก็เพียงพอสำหรับงานทั่วๆไปแล้ว เช่น การทำ D2A หรือ A2D (ประมาณ 100 ksps) การส่งข้อมูลไปที่จอ LCD การรับค่าจากเซนเซอร์ที่ไม่ต้องการความเร็วสูงๆ (พวกวัดค่าทางกายภาพต่างๆ เช่น แสง สี เสียง ความเร็ว ความเร่ง พวกนี้เหลือเฟือครับ)
ทีนี้มาดูขั้นตอนการส่งข้อมูลด้วยโปรโตคอล I2C กันครับ ว่ามันทำยังไง (ขั้นตอนที่ว่านี้ค่อนข้างจะเป็นทางวิศวกรรมอิเล็กทรอนิกส์หน่อยนะครับ ถ้าอ่านข้ามไปเลยก็ไม่ว่ากัน)
เริ่มต้นก็ต่อสายตามแบบที่แสดงในภาพแรกครับ คือ VCC GND SDA SCL โดยต่อ Pull up resistor ไว้ที่ขา SDA และ SCL ด้วยครับ ลำดับการทำงาน (Timing Diagram) ก็จะเริ่มต้นด้งนี้ครับ
1. ในสภาวะที่ยังไม่เริ่มทำงาน อุปกรณ์ทุกตัวจะมีแรงดันระดับสูง (H)
2. เมื่อเริ่มจะส่งข้อมูล SDA จะลดลงไปที่ระดับแรงดันศูนย์ (L) ในขณะที่ SCL ยังอยู่ที่ ็H จะเห็นในช่องที่แรงเงาสีเหลืองซ้ายสุด โดย SCL จะค้างที่ H นาน 0.6 ไมโครวินาที (tHDSTA: Hold Time to Start Condition) ผ่านช่วงเวลานี้ไปเป็นอันรู้กันว่า Master จะเริ่มสั่งการ (แต่ตอนนี้ยังไม่รู้นะครับว่าจะสั่ง Slave ตัวไหน เพราะอาจมีหลายตัวต่ออยู่บนบัส)
3. ตอนนี้ SCL จะลงไปที่ L จากนั้น ระหว่างที่รอสัญญาณขาขึ้นของ Clock แรกอีก 1.3 ไมโครวินาที SDA จะเริ่มกำหนดค่า Bit แรก โดย Master จะส่งค่าบิตแรกไปพร้อมกับสัญญาณ Clock และไอซีที่เป็น Slave บนบัสจะเริ่มอ่านค่าในจังหวะที่ SCL เป็น H
4. จากนั้นก็จะเป็นอย่างนี้ไปอีกเพื่อส่งค่า Address ของไอซีที่ต้องการจะติดต่อด้วยไปรวมทั้งสิ้น 7 บิตและตามด้วยบิตที่ 8 ซึ่งจะระบุว่าจะสั่งให้ Slave รอคำสั่ง (Write ระบุโดย SDA เป็น H) หรือจะรออ่านค่าที่ส่งมาจาก Slave (Read ระบุค่าโดย SDA เป็น L)
5. บิตที่ 9 จะเป็นการตอบรับจาก Slave ที่มี Address ตรงกับที่ Master ส่งไป ถ้ามี Slave ตอบรับ (Acknoledge) โดยการดึงสัญญาณ SDA ลง L ก็แปลได้ว่ามี Slave พร้อมจะสื่อสารด้วย แต่ถ้าไม่มี คือ SDA ค้างที่ H แปลว่า (Not Acknowledge) Master ไม่มีใครคุยด้วย
6. หลังจาก Acknowledge กันเรียบร้อย (สมมุติว่ามีสัญญาณตอบรับ) จะเป็นช่วงเวลาที่ SCL ถูกดึงลง L เป็นเวลาสั้นๆ และ SDA จะถูกปล่อยว่าง ก่อนที่ Slave ที่ติดต่อด้วยจะเริ่มส่งค่า Bit แรกมาที่ SDA
7. จากนั้นสัญญาณ SCL จาก Master จะปล่อยออกมาเพื่ออ่านค่าสัญญาณบนสาย SDA ในจังหวะที่ SCL เป็น H และรับค่าเช่นนี้ไปเรื่อยๆ จน Data ครบ 8 บิตแรก ตามจังหวะสัญญาณ SCL
8. เมื่อ Data ครบ 8 บิตแรกแล้ว Master จะให้สัญญาณ Acknowledge โดยดึงสัญญาณเป็น L เพื่อแสดงให้ Slave รู้ว่า Master จะรอ Data อีก 8 บิตต่อไป (ในกรณีที่ข้อมูลที่ Slave ต้องการส่งเป็นแบบ 16 บิต)
9. จะกลับเข้าการทำงานในข้อ 6 และอ่านข้อมูลไปจนครบบิตที่ 9 - 16
10. จากนั้นเมื่อถึงจังหวะการ Acknowledge ในบิตที่ 9 คราวนี้ Slave ไม่ต้องการส่งข้อมูลต่อแล้ว เพราะครบ 16 บิตแล้ว Slave จะ ไม่ตอบสนองแล้ว สาย SDA จะถูกปล่อยให้เป็น H
11. จากนั้น Master จะรู้แล้วว่าข้อมูลมาครบถ้วน 16 บิต Master ก็จะสั่งหยุดโดยการส่งสัญญาณ ขาขึ้นในสาย SDA พร้อมๆกับ SCL เป็น H ก็เป็นอันรู้กันว่าคือ Stop bit หมายถึงส่งข้อมูลครบ Byte แรก ซึ่งเป็น Address ของ Slave ตัวที่ Master ต้องการคุยด้วย
มันก็เข้าใจยากอยู่ครับ ลองอ่านดูช้าๆ และดูรูป timing diagram ด้านบนประกอบนะครับ
ทีนี้ถ้าต้องการอ่านคู่มือจริง ต้นตำหรับจาก NXP Semiconductor ก็ไปที่นี่เลยครับ
สังเกตอีกนิดจะเห็นว่า สัญญาณ Start และ Stop จะส่งโดย Master เท่านั้น โดย Start คือ ให้ SDA เปลี่ยนจาก H เป็น L ในจังหวะที่ SCL เป็น H ส่วนการ Stop ก็คิอให้ SDA เปลี่ยนจาก L เป็น H ในจังหวะที่ SCL เป็น H และที่ว่ามาทั้งหมด Master จะเป็นตัวปล่อยสัญญาณ SCL ครับ
อ่านแล้วคงจะรู้สึกยาก ก็ไม่ต้องกังวลครับ เพราะเราไม่ต้องเขียนโปรแกรมที่คุมสัญญาณแต่ละเส้นเอง Arduino เขาทำ Library ที่ชื่อว่า Wire มาให้แล้ว สบายครับ เราแค่เลือก Address ของอุปกรณ์ให้ถูก แล้วปล่อยให้ Wire.h จัดการส่ง รับค่าให้เราครับ
Library ที่ชื่อ wire.h ก็ไม่ต้องไปหา download ให้ยุ่งครับ มันมีอยู่แล้วใน Arduino IDE เรียกใช้กันได้เลย เพียงแค่ Add ชื่อไว้ตอนเริ่มต้น Sketch ที่จะใช้ก็เท่านั้น รายละเอียดวิธีใช้งาน Library wire.h ก็ดดูได้ที่นี่ครับ
Functions ต่างๆ ของ wire.h ก็ดูตามนี้เลยครับ
ทีนี้ I2C หรือ TWI บนบอร์ด Arduino นั้น ก็ต้องเรียกให้ถูกขาที่เขากำหนดนะครับ (ไม่สามารถ Assign เป็นขาอื่นๆ) ลองดูรายละเอียดตามนีครับ
Board | I2C / TWI pins |
Uno, Ethernet | A4 (SDA), A5 (SCL) |
Mega2560 | 20 (SDA), 21 (SCL) |
Leonardo | 2 (SDA), 3 (SCL) |
Due | 20 (SDA), 21 (SCL), SDA1, SCL1 |
คราวนี้เรามาลองใช้งาน I2C ในการรับส่งข้อมูลกับไอซีซักตัวกันครับ วันนี้ผมเลือกใช้ GY-30 ซึ่งเป็น โมดูลที่ใช้อ่านค่าความสว่างของแสงที่มองเห็นด้วยตากันครับ โมดูลนี้มีหัวใจหลักคือ BH1750FVI ซึ่งจะแปลงค่าความสว่างที่ตกลงบนไอซี แล้วแปลงเป็นสัญญาณทางไฟฟ้า และส่งต่อกับอุปกรณ์ภายนอกโดยใช้โปรโตคอล I2C
ผมสาธิตการใช้งานด้วย Arduino UNO R3 นะครับ ดังนั้นเราต้องใช้ A4 (SDA), A5 (SCL)
ทีนี้มาดูวิธีการต่อ Pin กันครับ จะเห็นว่าโมดูล GY-30 นี้มีอยู่ 5 ขาตามรูปด้านล่าง
ข้อดีของการใช้เป็นโมดูลก็คือ ผู้ผลิตเขาออกแบบมาให้ใช้ได้ทั้ง 3 และ 5 โวลต์แล้วครับ ดังนั้นก็ไม่ต้องกังวลเรื่องระดับแรงดัน แค่ต่อ VCC กับ GND ตามที่มีให้มาในบอร์ด จากนั้นต่อสาย SDA -> Pin A4 และ SCL -> Pin A5
คราวนี้มาดูขา ADDR กันครับ ก่อนอื่นต้องเข้าไปดูใน datasheet กันซักนิดจะเห็นว่าเราสามารถเลือกค่าความละเอียดในการวัดได้ 3 Mode ด้วยกัน โดยเลือกได้จากการต่อขา ADDR ไปที่ 5 V หรือ ต่อไปที่ GND ครับ
Measurement Mode | Measurement Time | Resolution | ADDR |
H-Resolution Mode2 | 120 ms | 0.5 lux | GND |
H-Resolution Mode2 | 120 ms | 1 lux | GND |
L-Resolution Mode2 | 16 ms | 1 lux | VCC |
ก็จะเห็นว่าความละเอียดในการวัดก็ต้องแลกมาด้วยเวลาที่ใช้ในการวัดครับ
ลองดู Sketch ตัวอย่างกันครับ
จะเห็นว่าตำแหน่งที่ highlight ไว้คือการระบุ Address ของไอซี BH1750FVI ครับ ทั้งนี้เพื่อให้ Wire.h สามารถเรียก Address ของอุปกรณ์ที่จะติดต่อได้ถูกต้อง และอย่าลืมเลือกขา ADDR บนโมดูล GY-30 ให้สอดคล้องกับ Address ที่เลือกด้วยนะครับ
เสร็จแล้วก็จะเห็นมันทำงานแบบนี้ครับ
อีกนิดสำหรับโมดูล GY-30 นะครับ ไอซีที่ใช้คือ BH1750FVI นั้นเป็นตัวเดียวกับที่ใชับนโทรศัพท์มือถือเพื่อใช้ในการปรับความสว่างของจอ LCD ครับ ออกแบบมาเพื่อให้ตอบสนองกับช่วงความถี่ของแสงที่ตามองเห็น จึงเหมาะกับการใช้ในการอ่านค่าความสว่าง เปิดปิด หรือ หรีไฟแสงสว่างครับ
หลักการทำงานของโปรโตคอล I2C ก็ว่ากันจบไปแล้ว Library wire.h นี้ก็สามารถใช้งานได้กับอุปกรณ์ที่สื่อสารโดยใช้ I2C แบบอื่นๆ เช่น โมดูลอื่นในตระกูล GY นะครับ เพียงแต่ต้องไปเปลี่ยน Address ให้ตรงกับอุปกรณ์ที่ใช้เท่านั้น
วันนี้พอแค่นี้ครับ ถ้ามีข้อสงสัย เสนอแนะ หรือ คำถามก็ยินดีนะครับ
โดย Mountain A
หน้านี้เป็นสารบัญของบทความที่ปรากฏในเว็บของ Arduitronics.com นะครับ จะขอแบ่งออกเป็นหัวข้อตามกลุ่มของสินค้าในร้านดังต่อไปนี้
หน้าที่เข้าชม | 15,387,460 ครั้ง |
ผู้ชมทั้งหมด | 5,890,538 ครั้ง |
เปิดร้าน | 21 พ.ค. 2556 |
ร้านค้าอัพเดท | 13 ก.ย. 2568 |