آردوینو آموزش آردوینو

آموزش آردوینو بخش پانزدهم – استفاده از I2C در Arduino

arduino-basic-tutorial-part-fifteen-i2c-protocol-digispark
نوشته شده توسط پریسا پوربلورچیان

پروتکل ارتباطی I2C به ارتباط دو سیمه در مدارات الکترونیکی گفته می‌شود. حتی بدون دانش الکترونیک شاید بارها از این پروتکل و ماژول هایی که از آن پشتیبانی می‌کنند، استفاده کرده باشید اما دلیل استفاده و روش کار با آن را نمیدانستید. در این آموزش پروتکل ارتباطی I2C زا یاد خواهیم گرفت. در ادامه آموزش استفاده از I2C در Arduino با مرجع تخصصی آردوینو به زبان فارسی، دیجی اسپارک همراه باشید.

 


پروتکل ارتباطی I2C


پروتکل ارتباطی I2C در آردوینو یک ارتباط دو سیمه برای اتصال سنسورهایی که از پروتکل I2C برای ارتباط با میکروکنترلرها استفاده می‌کنند، طراحی شده است. سرعت تبادل دیتا در پروتکل ارتباطی I2C بین ۱۰۰Kbits/s، ۴۰۰Kbits/s, 1M است. پروتکل I2C در دو مد کاری Master , Slave عمل می‌کند.Master , Slave میتوانند دیتا را ارسال کرده و همچنین دریافت کنند. این ارسال و دریافت دیتا وابسته به Master است و تا زمانی که درخواست توسط Master ارسال نشود، Slave دیتا به Master ارسال نمی‌کند. برای برقراری ارتباط در پروتکل I2C وجود دارد.

  • I2C = Serial Data  که جهت انتقال دیتا استفاده می‌شود.
  • SCL = Serial Clock که سیگنال کلاک را انتقال میدهد.

هر دو سیگنال SDA , SCL دو طرفه هستند که توسط یک مقاومت پول آپ به تغذیه متصل شده اند. به این معنی که زمانی که باس آزاد است، هر دو سیگنال HIGH هستند.تمامی دیوایس هایی که بر روی باس قرار میگیرند بایستی پایه های اوپن کلکتور و اوپن درین داشته باشند. فعال شدن لاین به این معنی است که پایه پول دان شده و به GND وصل شده اند. تعداد دیوایس های قرار گرفته شده بر روی یک باس نامحدود است و میتوانید دیوایس هایی با سطح ولتاژ متفاوت را بر روی یک باس وصل کرده و با یک مقاومت پول آپ به کمترین ولتاژ میکروکنترلر اتصال دهید. I2C از آدرس ۷ بیتی برای تعریف دیوایس ها استفاده می‌کند که هر کدام میتوانند هویت منحصر به فرد داشته باشند و درخواست به Slave صحیح ارسال کنند.

پروتکل ارتباطی I2C در برد رزبری پای پیکو - دیجی اسپارک

 

دو اصطلاح مهم در پروتکل ارتباطی I2C استفاده می‌شود. MASTET , SLAVE یک مستر داریم و چندین SLAVE که هر دو تامین کننده کلاک و مستر هستند. هر دو میتوانند دیتا را دریافت و ارسال کنند. اما برای انجام اینکار MASTER بایستی از SLAVE درخواست دیتا کند تا SLAVE بتواند دیتا را به MASTER ارسال کند. سیگنال کلاک توسط MASTER ایجاد می‌شود و در این بین SLAVE میتواند کلاک CLOCK را LOW کند. سیگنال I2C به صورت OPEN DRAIN طراحی شده است و قابلیت LOW کردن سیگنال ها را دارد. اما در مقابل قابلیت HIGH کردن سیگنال را ندارد. برای رفع این مشکل باید هر دو پایه را پول آپ کرد. مقدار مقاومت PULLUP وابسته به تعداد دستگاه های روی BUS و طول آن دارد. برای شروع بهترین انتخاب مقاومت ۴٫۷ کیلو اهم است که در صورت نیاز کاهش میدهیم. با توجه به اینکه پروتکل ارتباطی I2C قابلیت HIGH کردن سیگنال ورودی را ندارد میتوانیم دستگاه ها با سطح ولتاژ متفاوت را روی یک BUS یه یکدیگر وصل کنیم و با استفاده از مقاومت پول آپ به کمترین ولتاژ متصل کنیم. سرعت تبادل دیتا I2C به صورت  ۱۰۰Kbits/s, 400Kbits/s , 1Mbits/s است.

پروتکل ارتباطی از ماهیت Acknowledge استفاده می‌کند بدین معنی که هر بایت ارسالی توسط گیرنده دریافت می‌شود. انتخاب سطح ولتاژ یکسان بین پایه های SDA , SCL مهم است در صورتیکه از تراشه های اتمگا استفاده می‌کند سطح ولتاژ در حدود ۵ ولت است و بایستی سطح ولتاژ این پایه ها را یه ۵ ولت یرسانید. پروتکل ارتباطی I2C بدین صورت عمل می‌کند که پیام ها ارسال می‌شوند سپس همان پیام ها تفکیک می‌شوند. مهم ترین بخش آدرس پیام است که یک آدرس باینری است که برای هر پیام منحصر به فرد است. این آدرس همان آدرس SLAVE است. علاوه بر آدرس SLAVE بیت های خواندن و نوشتن READ AND WRITE و بیت های ACKNOWLEDGE یعنی ACK , NACK دسته بندی می‌شود. با توجه به اینکه این ارتباط به صورت دو سیمه است بایستی شروع و پایان مشخص شده باشد. SLAVE ها برای اینکه متوجه شوند چه دیتایی برای آن ها ارسال شده است از همان آدرش مشخص استفاده می‌کنند. لذا اولین بخش در پروتکل مشخص شدن آدرس است.

این آدرس توسط MASTRER ارسال شده و سپس هر SLAVE آدرس ارسالی توسط MASTER را با آدرس خود تطبیق میدهد. در صورت برابری آدرس یک بیت سطح LOW ACK برای MASTER ارسال شده و در صورتیکه آدرس برابری نداشته باشد SDA در همان وضعیت HIGH باقی میماند. طول هر آدرس باینری بین ۷ یا ۱۰ بیت است. برای اینکه SLAVE متوجه شود که MASTER برای خواندن دیتا و یا ارسال دیتا است بایستی از بیت READ AND WRITE استفاده کند. اگر MASTER دیتا را ارسال کند بیت در وضیعت LOW قرار میگیرد و اگر MASTER دیتا را بخواند بیت در وضعیت HIGH قرار میگیرد. اگر تا این مرحله تمامی جزییات رعایت شده باشد اگر آدرس به درستی ارسال و دریافت شده باشد یک بیت ACK از دستگاه دریافت کننده دیتا به فرستنده ارسال می‌شود که همان ماهیت Acknowledge اجرا می‌شود و سپس اولین دیتا ارسال می‌شود. بخش دیتا ۸ بیتی است و اولویت با بیت های ارزش بالاتر است که پس از تشخیص داده ی ارسالی صحیح،بیت ACK توسط MASTER , SLAVE دریافت شده که این مورد وابسته به این است که کدام یک دیتا را ارسال کرده باشد.

 


رابط I2C در ARDUINO


پایه های I2C در Arduino در هر برد آردوینو مطابق با جدول زیر است.

رابط I2C در ARDUINO - دیجی اسپارک

 

پایه های I2C در برد آردوینو مدل UNO به صورت زیر است.

شناخت پایه های I2C در ARDUINO - دیجی اسپارک

 

پروتکل I2C SCL SDA - دیجی اسپارک

  

توابع I2C برای آردوینو

از این تابع برای رایت دیتا در دستگاه MASTER , SLAVE استفاده می‌شود. دیتا میتواند به صورت یک بایت تکی، رشته و یا آرایه باشد.

Wire.write (data)

 

در این تابع توسط MASTER یا SLAVE وضیعت دیتا که در دسترس است یا خیر بررسی می‌شود. اگر بایتی در دسترس نباشد، پیغام NO را برمیگرداند.

Wire.available()

 

از این دستور برای خواندن دیتای درخواست شده توسط MASTER از SLAVE استفاده می‌شود. یا برای خواندن دیتای ارسال شده از MASTER به SLAVE

Wire.read()

 

توابع مورد نیاز برای I2C MASTER

هر دستگاه SLAVE I2C دارای یک آدرس منحصر به فرد است که این آدرس باید توسط MASTER استفاده شود. آردوینو دارای کتابخانه WIRE است که امکان برقراری ارتباط با پروتکل I2C را فراهم می‌کند.

Wire.begin ()

 

توسط این تابع کتابخانه آغاز به کار کرده و به عنوان MASTER در BUS شروع به کار می‌کند.

Wire.beginTransmission (slave address)

 

توسط این تابع ارسال دیتا توسط دستگاه SLAVE آغاز شده که دارای آدرس منحصر به فردی است که این آدرس ۷ بیتی است.

Wire.endTransmission()

توسط این تابع ارسال دیتا به دیوایس SLAVE را متوقف می‌کند که توسط تابع beginTransmission() آغاز شده بود.

 

توابع مورد نیاز برای I2C SLAVE

Wire.begin (address)

توسط این تابع کتابخانه WIRE آغاز به کار کرده و به باس تحت عنوان SLAVE ملحق می‌شود.

 

Wire.onReceive(handler)

توسط این تابع زمانیکه دیتا از دستگاه SLAVE به MASTER ارسال می‌شود را کنترل می‌کند.

 


کد I2C SCANNER آردوینو


برای اتصال دیوایس هایی که از رابط I2C بهره برده اند به میکروکنترلرها نیاز به استفاده از آدرس I2C آن ها هستیم که در بخش قبل به آن اشاره شد. برای یافتن کد I2C هر دستگاه یک روش بسیار ساده با برنامه نویسی وجود دارد. تنها چیزی که نیاز دارید استفاده از ARDUINO IDE است. یک کد برای یافتن و خواندن هر تعداد دستگاه I2C متصل به میکروکنترلر نوشته شده است. در ابتدا تمامی دستگاه ها را به برد آردوینو متصل می‌کنید. سپس آردوینو را به سیستم وصل کرده و کد زیر را بر روی برد آردوینو آپلود می‌کنید. کد I2C هفت بیتی هر دستگاه به صورت مجزا نمایش داده می‌شود.

#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
}

 


اتصال چندین دستگاه I2C


سوال مهمی که از بسیاری از کاربران مطرح می‌شود این است که فقط دو پایه برای برقراری ارتباط I2C در Arduino در دسترس است و در صورت استفاده از چندین دستگاه راه حل چیست؟! اگر بخش اول آموزش را کامل مطالعه کرده باشید، در یک باس I2C میتوانیم یک MASTER و چندین دستگاه SLAVE داشته باشیم و همگی فقط با یک ارتباط دو سیمه کار می‌کنند. به این معنی که در بخش سخت افزاری تمامی دیوایس ها را با یکدیگر سری کنید و اشتراک بگیرید و همه به یک پایه وصل شوند. مطابق با تصویر زیر:

  •  پایه های SDA با یکدیگر اشتراک داشته باشند.
  • پایه های SCL با یکدیگر اتصال داشته باشند.

در خصوص تغذیه همانطور که در یخش اول نوشته شد نیاز به استفاده از مقاومت پول آپ برای هر دستگاه داریم تا به کمترین ولتاژ برسیم.

اتصال چندین دستگاه I2C به آردوینو - دیجی اسپارک

 مستر MASTER میتواند آردوینو باشد و به ترتیب SLAVE ها هر کدام یک دستگاه I2C باشند. از جمله سنسورها و قطعاتی که از رابط I2C برخوردار هستند.

 


تست کد I2C


برای دریافت کد I2C یک یا چندین دستگاه مطابق با بخش قبل کافیست همه ی دستگاه ها را با دو سیم به پایه SDA SCL برد آردوینو متصل کنید. از SDA دستگاه اول به SDA دستگاه دوم از SDA دستگاه دوم به SDA دستگاه سوم و برای پایه SCL هم به ترتیب است. از SCL دستگاه اول به SCL دستگاه دوم و از SCL دستگاه دوم به سوم و … ادامه دار خواهد بود. در نهایت تمامی دستگاه ها فقط با دو سیم به پایه SDA , SCL برد آردوینو متصل می‌شوند. در این بخش یک و دو دستگاه I2C به برد آردوینو وصل شده است و سپس توسط کد I2C SCANNER کد شناسایی شده و بر روی سریال مانتیتور نمایش داده می‌شود.

تست کد I2C با آردوینو - دیجی اسپارک

 

 


جمع بندی لیدی پای


اگر بخواهیم پروژه دماسنج غیرتماسی را با آردوینو پیاده سازی کنید و همزمان از نمایشگر OLED استفاده کنید. متوجه خواهید شد که پروتکل ارتباطی هر دو دستگاه مورد استفاده I2C است. اما فقط دو پایه SDA , SCL برای برد آردوینو تعبیه شده است. چاره چیست؟ چاره؟ خیر کاملا اشتباه است. ماهیت پروتکل ارتباطی I2C به همین صورت است. یک ارتباط دو سیمه که میتواند همزمان به چندین SLAVE دیتا ارسال و دریافت کند. به همین سادگی! از تمامی پایه های دیوایس ها اشتراک گرفته و سپس به پایه های SDA , SCL متصل می‌کنیم. در متن آموزش چرایی این مورد کاملا آموزش داده شده است. مطالعه کنید.

 


وسایل مورد نیاز


آردوینو 

همین!

 

چنانچه در مراحل راه اندازی و انجام این پروژه با مشکل مواجه شدید، بدون هیچ نگرانی در انتهای همین پست، به صورت ثبت نظر سوالتان را مطرح کنید. من در سریع‌ترین زمان ممکن پاسخ رفع مشکل شما را خواهم داد. همچنین اگر ایرادی در کدها و یا مراحل اجرایی وجود دارند می‌توانید از همین طریق اطلاع رسانی کنید.

 

درباره نویسنده

پریسا پوربلورچیان

تولید کننده محتوا / کارشناس IOT

زندگی یعنی پژوهش و فهمیدن چیزی جدید

تلاشم بر این است تجربیاتم در زمینه IOT‌ را به بهترین شکل با شما در میان بگذارم.

تبادل نظر و رفع عیب با ثبت دیدگاه

۳۲ دیدگاه

    • با سلام
      کافی است بین پایه ها اشتراک بگیرید و در کدنویسی برای آن ها کد i2c مجزا تعریف کنید.

    • با سلام
      در متن آموزش کامل توضیح داده شده است. کافیست کد i2c مجزا برای هر oled در کد لحاظ کنید.

  • سلام من برای یک پروژه نیاز به اتصال به دو oled دارم که هر oled یک متن رو پخش کند. لطفا راهنمایی کنید.

    • با سلام
      تنها نکته ای که بایستی به آن توجه کنید، استفاده از دو oled با دو کد i2c متفاوت است و دقیقا مشابه اموزش و استفاده از آموزش oled میتوانید در کد برنامه دو oled را نمایش دهید و براساس کد i2c تابع جداگانه به آن نسبت دهید.

    • با سلام
      این کد مرجع است و برای دستگاه هایی که از رابط i2c استفاده می‌کنند، قابل استفاده است.

    • با سلام
      بله امکان پذیر است. کافی است کد i2c هر دستگاه را مجزا در کد برنامه مشخص کنید.

  • آیا برای برد Esp8266 هم مشابه آردوینو میتوان چندین دستگاه برای i2c به کد برنامه معرفی و استفاده کرد؟

    • با سلام
      بله روش کار پروتکل ارتباطی در صورت پشتیبانی تراشه از رابط i2c در تمامی بردها یکسان است.

  • سلام و خسته نباشید
    بابت انتشار این آموزش
    بنده قصد دارم سه عدد سنسور با رابط i2c را در آردوینو استفاده کنم
    لطفا راهنمایی کنید.

    • با سلام
      کاربر گرامی در این خصوص بایستی کد I2C هر دستگاه را مجزا از طریق I2C Scanner دریافت و سپس در کد برنامه تعریف کنید.

  • با سلام و خسته نباشید مهندس
    آیا آموزشی برای oled با اردونیو دارید؟ برای i2c و فرمانش ایراداتی دارم
    ممنون میشم راهنمایی کنید.

  • با تشکر از اطلاعاتی که به اشتراک گذاشتید،
    در مورد کد i2c مجزا که فرمودین باید تعریف کنیم اگه میشه کد آموزشی بزارین.
    مشکلی که هست مثلا در دو تا oled که با ارتباط i2c کار میکنن و کد همشون ۰x3C هست و در یک پروژه به صورت همزمان استفاده میشن نمی توان ازشون مجزا استفاده کرد.
    در آموزشی که برای oled قرار دادین ارتباط SPI هست یعنی یک ماژول با ارتباط SPI کار میکنه و ماژول دیگه با i2c و در این حالت ما مشکلی نداریم، مشکل زمانی بوجود میاد که ماژول ها فقط با ارتباط i2c کار میکنن.
    مثلا در یک پروژه یک oled i2c و یک سنسور AHT10 i2c داریم، آدرس i2c هر کدام به ترتیب ۰x3C و ۰x38 هست ولی هر دو با هم در برنامه کار نمی کنن!

    • با سلام
      در این خصوص بایستی پشت برد oled را بررسی کنید. در پشت برد کد I2C هک شده است و حتما باید کد I2C هر دستگاه متفاوت باشد.

  • سلام
    من میخوام یه ال سی دی رو با درایورش روشن کنم . اگه پایه های SDA & SCL رو به دوتا پایه سمت راستی وصل کنم با این که به A4 & A5 وصل کنم فرق داره ؟

  • سلام
    در پروژه ای نیاز به استفاده از چندین سنسورsht20 با آدرس i2c یکسان دارم. درمورد کد لازم برای تغییر آدرس i2c این سنسورها رو میشه راهنمایی کنید؟

    • با سلام
      هر سنسور کد I2C منحصر به فردی دارد که میتوانید در کد برنامه به صورت مجزا تعریف کنید.

  • با سلام وقت بخیر مهندس. بنده نیاز دارم که داده های دریافتی از یک روتاری انکودر رو با رابط I2C به آردوینوی دوم انتقال بدم و روی LCD گرافیکی نمایش بدم . چطور داده را با رابط I2C انتقال بدم ممنون میشم کمکم کنید .