I2C เป็นวิธีการสื่อสารระหว่างอุปกรณ์พัฒนาโดย Philips [1] ที่สามารถนำมาใช้สื่อสารกันระหว่าง Raspberry Pi กับ Arduino ได้ ข้อดีของการใช้ I2C คือใช้การสื่อสารบน Bus ทำให้เราสามารถสร้างระบบสื่อสารระหว่างสื่อสารระหว่างอุปกรณ์ได้มากกว่า 1 คู่ที่ต่ออยู่บน Bus เดียวกัน โดยแต่ละอุปกรณ์จะแยกกันด้วย address เฉพาะ นึกถึงภาพว่าผู้โดยสารอยู่ในรถบัสคันเดียวกันก็สื่อสารกันได้ ในขณะที่การสื่อสารด้วย USB port หรือการใช้ Tx/Rx จะทำได้ที่ละคู่เท่านั้น
การสร้าง Bus
การสร้าง Bus ศัยเส้นทางสองเส้นทางคือ Serial Data (SDA) และ Serial Clock (SCL) ท่านต้องตรวจสอบว่าอุปกรณ์แต่ละชิ้นมี PIN ใดเป็น SDA และ SCL เอง เพราะแต่ละรุ่นแต่ละชิ้นจะแตกต่างกันออกไป การต่ออุปกรณ์แต่ละชิ้นก็ยึดหลักง่าย ๆ คือ- ให้เอา SDA ของแต่ละอุปกรณ์เชื่อมต่อกัน และ
- SCL ของแต่ละอุปกรณ์ก็เชื่อมต่อกัน
- อุปกรณ์ทุกชิ้นบน Bus ต้องต่อ Groud ร่วมกัน
- อุปกรณ์ทุกชิ้นต้องมีกระไฟฟ้าเลี้ยงที่เหมาะสมของแต่ละอุปกรณ์
ในกรณีของการต่อ Raspberry Pi ควรใช้อุปกรณ์เสริมคือ Bi-directional Logic Level Converter มาต่อคั่นเพราะ Raspberry Pi ถือว่าเป็นอุปกรณ์ที่รับไฟฟ้าความต่างศักย์ที่ 3.3 V ส่วน Arduino จะเป็น 5 V แต่ในเอกสารและ Tutorial หลายแห่งอ้างว่าไม่จำเป็นเนื่องจาก Raspberry Pi ได้มีการติดตั้งตัวต้านทานมาแล้ว แต่ก็เพื่อความสบายใจนะ ต่อไว้ก็ดี ท่านสามารถหาซื้อ Bi-directional Logic Level Converter ได้จากผู้จำหน่ายหลายรายในประเทศไทยครับ ในกรณีของผมจะเป็นดังภาพ
Master and Slaves
บทบาทของอุปกรณ์ใน I2C มีสองบทบาทคือ Master กับ Slave ครับ ทำหน้าที่ต่างกันนิดเดียวคือ
- Master จะเป็นคนสร้างสัญญาณนาฬิกา และจะเป็นคนเริ่มต้นการสื่อสาร
- Slave เป็นคนรับสัญญาณนาฬิกา และคอยตอบสนองต่อการติดต่อมาจาก Master
ในโครงงานนี้ผมตั้งให้ Raspberry Pi รับบทเป็น Master เพราะมี OS ทำงานในส่วนงานวิเคราะห์ได้ดี ส่วน Arduino รับบทเป็น Slave
อุปกรณ์และการต่อสายสัญญาณ
ในโครงงานนี้ผมใช้อุปกรณ์ดังนี้
- Raspberry Pi model B
- Bidirectional Logic Level converter
- Arduino Pro Micro
- Jumping Wires
ผังการต่อสายระหว่างอุปกรณ์
Raspberry Pi | Arduino Pro Micro |
pin 3 (SDA) --> | D2 (SDA) |
pin 5 (SCL) --> | D3 (SDA) |
pin 6 (GRD) --> | GRD |
หมายเหตุ
ในกรณีมีการต่อ Logic level converter คั่น ต้องตรวจสอบการต่อสายสัญญาณให้ถูกต้องตามคู่มือ หรือศึกษาการต่อโดยไม่มี Logic converter จาก [3]
ในกรณีมีการต่อ Logic level converter คั่น ต้องตรวจสอบการต่อสายสัญญาณให้ถูกต้องตามคู่มือ หรือศึกษาการต่อโดยไม่มี Logic converter จาก [3]
ขั้นตอนการเตรียม Raspberry Pi
1. เอารายการ blacklist ออก
sudo nano /etc/modprobe.d/raspi-blacklist.conf
ใส่ # ไว้ข้างหน้าสองบรรทัดนี้ (เดิมไม่มี # )
#blacklist spi-bcm2708 #balcklist i2c-bcm2708
แล้วบันทึก
sudo nano /etc/modules
แล้วเติมบรรทัดนี้เข้าไป
i2c-dev
แล้วบันทึก
3. ติดตั้ง I2C-tools
sudo apt-get install i2c-tools
** หากมีปัญหาในการติดตั้งอาจใช้คำสั่งนี้แล้วติดตั้งใหม่อีกครั้ง
sudo apt-get update --fix-missing
4. เพิ่ม user ให้กับ i2c
sudo adduser pi i2c
** ท่านอาจ user รายอื่นได้อีกนอกจาก pi (default user)
5. restart Raspberry Pi แล้ว login ด้วย user ที่ add ไว้ตามข้อ 4
6. ตรวจสอบ
ls /dev/i2c*
Raspberry Pi รุ่นใหม่ จะกำหนดให้ i2c ใช้ port เป็น 1 ซึ่งท่านควรจะเห็น
/etc/i2c-1
ขึ้นบนหน้าจอ ลองใช้คำสั่ง
sudo i2cdetect -y 1
จะได้ภาพที่คล้ายแบบนี้ ตัวเลขก็อาจแตกต่างกันไป
ปล.ถ้าไม่ขึ้นเลขใดๆ ให้ทำการรันโค้ดใน Arduino ก่อนนะครับ
หมายเหตุ ตอนทดสอบท่านต้องต่อสาย Bus และให้ไฟฟ้าเลี้ยง Arduino ไว้เลยนะครับ
การเตรียม Arduino
การเตรียม Arduino ก็คือการสร้าง Sketch ขึ้นมาเพื่อทำงานตามปรกติ เพียงแต่ต้องใช้ Wire.h และกำหนด Address ของตัวเองขึ้นมา ผมยกตัวอย่าง Sketch ที่เขียนขึ้นเพื่อรับ-ส่งตัวเลขจำนวนเต็มระหว่าง Raspberry Pi กับ Arduino ให้ดูพอเป็นแนวทางสร้างความเข้าใจนะครับเขียน Sketch เสร็จแล้ว compile แล้วก็ upload ไว้ใน Arduino ตอนที่ทำไม่จำเป็นต้องต่อ I2C Bus ก็ได้นะครับ
การเขียนโปรแกรมสื่อสารบน Raspberry Pi
เราสามารถใช้ภาษาใด ๆ ก็ได้ที่สนับสนุน I2C และทำงานบน Raspberry Pi ได้ เช่น Python, Java , C++ เป็นต้น ตัวอย่างของผมจะใช้ Python โดยเราต้องติดตั้ง python-smbus [2] ด้วยคำสั่ง
sudo apt-get install python-smbus
ตัวอย่าง Python Code
import smbus import time ard_addr = 0x04 #design in arduino sketch bus = smbus.SMBus(1) # 1 : i2c bus port you can see in /dev/i2c-1 def writeNumber(val): # to send a number to arduino bus.write_byte(ard_addr) return -1 def readNumber(): number = bus.read_byte(ard_addr) print number return number snd_num = 0 rcv_num = 0 stop_flag = False while not stop_flag : writeNumber(snd_num) print "Send %d to Arduino" % snd_num rcv_num = readNumber() print "Recieved %d from Arduino" % rcv_num time.sleep(0.5) if snd_num == 10 : stop_flag=True else : snd_num = snd_num + 1
ทดสอบการทำงาน
1. ต่อสายต่าง ๆ ให้เรียบร้อย2. ป้อนกระแสไฟเลี้ยง Arduino แล้ว start up Raspberry Pi
3. เรียกใช้ Python code บน Raspberry Pi ก็ได้ผลออกมาดังภาพ แสดงว่าเรารับ-ส่งข้อมูลระหว่าง Arduino กับ Raspberry Pi ผ่าน I2C Bus สำเร็จด้วยดี
---------------------------------------
เอกสารอ้างอิง
[1] http://en.wikipedia.org/wiki/I%C2%B2C
[2] http://www.acmesystems.it/i2c
[3] http://blog.oscarliang.net/raspberry-pi-and-arduino-connected-serial-gpio/
Cr. tosakunmeeting.blogspot.com
อยากขอสอบถามหน่อยครับทำไมในส่วนของโปรแกรมอาดูโน่ส่วนของการ receive ต้องพิจารณา number> 8 ถึงจะทำการตอบกลับแต่เห็นตอนรันโปรแกรมก็ตอบกลับตั้งแต่ number 0 นะครับ
ตอบลบ