آموزش ارتباط دو برد آردوینو با پروتکل ارتباطی I2C

فهرست مطالب

مقدمه

گاهی اوقات در پروژه‌های الکترونیک لازم می‌شود از دو یا چند میکروکنترلر به طور همزمان در مدار خود استفاده کنید. قاعدتا این میکروکنترلرها با هم در ارتباط بوده و با یکدیگر انتقال دیتا انجام می‌دهند. برای انتقال دیتا بین دو یا چند میکروکنترلر می‌توانید از پروتکل‌های مختلفی مانند SPI ،UART ،CAN ،USB و …. استفاده کنید. یکی از این موارد پروتکل I2C می‌باشد.
توسط این پروتکل می‌توانید یک میکروکنترلر را Master و دیگری را Slave قرار دهید و بین این دو میکروکنترلر انتقال دیتا انجام دهید. شما از این طریق می‌توانید توسط هر میکروکنترلر، دیگری را کنترل و مانیتور نمائید. آن میکروکنترلری که Master می‌باشد، ارتباط را آغاز کرده و پالس کلاک خط SCL را تولید می‌کند.
 دو برد آردوینو نیز نقش دومیکروکنترلر AVR را دارند. بدین ترتیب می‌توان دو یا چند آردوینو را از طریق پروتکل I2C به یکدیگر متصل کرد. یکی را به عنوان Master در نظر گرفته و دیگری Slave می‌شود.

آنچه در این آموزش یاد می‌گیرید

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

توسط پتانسیومتر آردوینوی مستر LED آردوینوی Slave را کنترل کرده و بالعکس. یعنی از طریق ورودی Master، خروجی Slave را کنترل کرده و از طریق ورودی Slave، خروجی Master را کنترل می‌کنیم. مقادیر انتقال یافته از طریق باس I2C نیز از طریق Serial Monitor دو آردوینو نمایش می‌دهیم.

در نهایت مداری مانند زیر درست کرده و نتایج آموزش را به صورت عملی مشاهده می‌کنیم.

پروتکل I2C چیست و چگونه کار می کند؟

 Inter-Integrated Circuit یک پروتکل ارتباطی است که آنرا با نام‌های دیگری مانند IIC و I2C و… نیز نمایش می‌دهند. این پروتکل به طور گسترده در میکروکنترلرها کاربرد دارد. در این ارتباط Master ها و Slave ها (Master ها عموما تجهیزات اصلی مانند میکروکنترلر ها و Slave ها سنسورها و دیگر تجهیزات مدار هستند.) از طریق دو سیم با هم در ارتباط هستند:

  • SDA(Serial Data): خطی برای ارسال و دریافت دیتا و اطلاعات بین Master و Slave
  • SCL(Serial Clock): خطی برای ارسال کلاک
نکته

در آردوینو UNO پینSDA ،A4 و پین A5 نیز SCL می‌باشد.
برای بردهای دیگر و همچنین میکروکنترلرهای مختلف این پایه ها متفاوت می‌باشد. به راحتی می‌توانید از دیتاشیت، شماره پایه های I2C آنها را پیدا کنید.

از مهمترین ویژگی های پروتکل I2C عبارت است از:

  • خیلی سریع نمی‌باشد (اما برای استفاده از آن به اندازه کفایت سرعت دارد)
  • مناسب برای فواصل کوتاه (برای مثال فاصله مجاز در سرعت پایین 100 KHz حدود یک متر است)
  • این ارتباط سنکرون می‌باشد.
  • اطلاعات به صورت سریال ارسال می‌گردد.
  • ولتاژ آن 5 یا 3.3 ولت می‌باشد.

در پروتکل I2C دو نوع تجهیز برای اتصال به باس I2C وجود دارد: Master و Slave. در این ارتباط هم می‌توان چند Slave متفاوت را به یک عدد Master مانند یک میکروکنترلر متصل کرد و هم می‌توان یک Slave را از طریق چند Master مختلف کنترل و مانیتور نمود اما در هر لحظه فقط یک Master می‌تواند فعال باشد. هر Master می‌تواند انتخاب کند که با کدام یک از Slave ها میخواهد ارتباط برقرار کند. این انتخاب از طریق آدرس های 7 بیتی Slave ها (در بعضی موارد 10 بیت) مشخص می‌شود. پس تقریبا می‌توان حدود 128 عدد تجهیز Slave  را به باس I2C متصل کرد. بنابراین هر Slave آدرس مخصوص خود را  دارد و در ضمن آدرسی برای Master ها اختصاص داده نشده است.
دیتای ارسال شده بر روی باس I2C توسط پایه کلاک ، سنکرون می‌شود. عمل سنکرون‌سازی توسط پایه کلاک بر عهده Master می‌باشد.

نکته

2 پایه SDA و SCL در مدار بایستی Pull-Up شوند. در سرعت های بالا مانند 400kbps مقاومت 2KΩ کافی است و در سرعت های پایین‌تر مثل 100kbps مقاومت 10KΩ استفاده می‌شود.

کتابخانه Wire

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

  • ()begin: این تابع کار با کتابخانه را آغاز کرده و توسط آن می‌توان مشخص کرد که آردوینو Master باشد و یا Slave
  • ()requestFrom: توسط این تابع که در سمت Master به کاربرده می‌شود، می‌توان درخواست انتقال دیتا از سمت Slave را صادر نمود. تعداد بایت و همچنین آدرس Slave در این بخش وارد می‌گردد.
  • ()beginTransmiossion: این تابع که توسط Master به کار برده می‌شود، ارتباط با یک Slave مخصوص را با وارد کردن آدرس آن آغاز می‌کند.
  • ()endTransmiossion: ارتباطی که توسط تابع قبلی شروع شد، توسط این تابع خاتمه می‌یابد.
  • ()write: هم Master و هم Slave از این تابع برای ارسال اطلاعات به باس I2C استفاده میکنند.
  • ()available: هم Master و هم Slave از این تابع برای محاسبه تعداد بایت های دیتای دریافتی (توسط تابع ()read) استفاده می‌کنند.
  • ()read: تابعی برای خواندن یک بایت داده از باس I2C (هم برای Master و هم برای Slave)
  • ()setClock: از تابع برای تنظیم فرکانس کلاک بر روی یک میزان مشخص توسط Master استفاده می‌شود.
  • ()onReceive: این مورد به عنوان یک تابع در Slave تعریف شده و زمانی که دیتا از سمت Master دریافت شود، فراخوانی می‌شود.
  • ()onRequestاین مورد به عنوان یک تابع در Slave تعریف شده و زمانی که درخواست دیتا از سمت Master  باشد، فراخوانی می‌شود.

لوازمی که به آن احتیاج دارید

جهت ادامه آموزش و مشاهده نتایج، علاوه بر دو عدد برد آردوینو UNO به قطعات و لوازم زیر نیاز دارید:

سخت افزار های موردنیاز

برد آردوینو UNO R3 × 2
برد بورد 400 حفره ای × 2
ولوم 5 کیلو اهم × 2
ال ای دی 5 میلی متری قرمز × 1
مقاومت 330 اهم × 2
سیم جامپر نری به نری 10 سانتی متری × 1
سیم جامپر نری به نری 20 سانتی متری × 1

نرم افزارهای موردنیاز

آردوینو IDE

ارتباط دو آردوینو توسط I2C یکی به عنوان Master و دیگری به عنوان Slave

حال رسیدیم به بخش اصلی آموزش و می‌خواهیم بین دو آردوینو UNO، از طریق پروتکل I2C ارتباط برقرار کنیم. یکی از آردوینو ها به عنوان Master و دیگری به عنوان Slave انتخاب می‌شوند. ابتدا مدار عملی آن را آماده کرده و سپس برنامه آن توضیح داده و بعد از آپلود برنامه ها بر روی دو آردوینو، خروجی آن را مشاهده می‌کنیم.

گام اول: سیم‌بندی

قبل از هر کاری ابتدا باید مدار آن را آماده کنید. نحوه اتصالات دو آردوینو با دیگر قطعات به صورت زیر است:

همانطور که در شکل بالا مشاهده می‌کنید، ارتباط دو آردوینو فقط از طریق باس I2C می‌باشد. آردوینوی سمت چپ، Master و آردوینوی سمت راست، Slave می‌باشد. هر آردوینو دارای یک ورودی پتانسیومتر و یک خروجی LED می‌باشند. قرار است LED هر آردوینو را از طریق آردوینوی دیگر کنترل کنیم.

نکته

اگر هر دو آردوینو به یک کامپیوتر متصل باشند، نیازی نیست پایه های GND دو آردوینو را به هم متصل کنید.

اما اگر آردوینوها را به دو کامپیوتر مختلف وصل کرده باشید، بایستی پایه‌های GND دو آردوینو را به هم متصل کنید.

گام دوم: کد برنامه Master

پس از اینکه مدار آن را آماده کردید، بایستی برنامه های Master و Slave جدا جدا بر روی آردوینو ها آپلود نمایید. ابتدا برنامه Master را بر روی آردوینوی مورد نظر آپلود نمایید:

/*
  Made on 8 June 2021
  By Amirmohammad Shojaei
  https://electropeak.com/learn/
*/

#include <Wire.h>

int value = 0;

void setup() {
  Wire.begin(); // join i2c bus (address optional for master)
  Serial.begin(9600);

  pinMode(5, OUTPUT);
}

void loop() {
  int y = analogRead(A1);         //Read from A1 & Save to value
  value = map(y, 0, 1023, 0, 255);

  Wire.beginTransmission(8); // transmit to device #8
  Wire.write("Master value :  ");         // sends these bytes
  Wire.write(value);              // sends one byte
  Wire.endTransmission();    // stop transmitting

  Wire.requestFrom(8, 1);    // request 1 byte from slave device #8
  while (Wire.available()) { // slave may send less than requested
    int c = Wire.read(); // receive a byte as character
    
    analogWrite(5, c);
    Serial.print("Slave value : ");
    Serial.println(c);         // print the character
  }

  delay(100);
}

میخواهیم مقدار ورودی پتانسومتر Master را برای Slave ارسال کنیم و یک بیت دیتای پتانسیومتر را از طرف Slave دریافت کرده  و آن را بر روی Serial Monitor نمایش داده و روشنایی LED را با آن کنترل کنیم.
 نکات زیر در رابطه با برنامه بالا قابل توجه می‌باشند:

  • ابتدا کتابخانه Wire را پیوست می‌کنیم.
  • توسط تابع ()begin کار با کتابخانه را آغاز می‌کنیم.
  • ابتدا در حلقه‌ی اصلی، مقدار ورودی آنالوگ را بر روی متغیر value ذخیره، و مقدار آن را به بازه‌ی 0 تا 255 تبدیل می‌کنیم.
  • سپس توسط دستور beginTransmission(8) شماره آدرس Slave وارد شده و ارتباط I2C برای ارسال داده آغاز می‌شود.توسط تابع ()Write، ابتدا چند کاراکتر شامل تعدادی حرف و علامت ارسال کرده و سپس یک بایت داده اصلی ارسال می‌گردد. در آخر نیز با دستور ()endTransmission این انتقال خاتمه می‌یابد.
  • در گام بعدی Master درخواست دریافت 1 بایت دیتا از سمت Slave را با آدرس 8 می‌دهد. این عمل توسط دستور requestFrom(8,1) انجام می‌شود. سپس دیتای دریافتی از سمت Slave را ذخیره (این دیتا متغیر از 0 تا 255 می‌باشد) و توسط آن نور LED را کنترل کرده و همچنین بر روی Serial Monitor نمایش می‌دهیم.
نکته

در زمان آپلود دقت کنید که Port موردنظر را به درستی انتخاب کرده باشید.

گام سوم: کد برنامه Slave

اینک برنامه Slave را بر روی آردوینوی مورد نظر آپلود نمایید:

/*
  Made on 8 June 2021
  By Amirmohammad Shojaei
  https://electropeak.com/learn/
*/

#include <Wire.h>

int x;
int value=0; 

void setup() {
  Wire.begin(8);                // join i2c bus with address #8
  Wire.onRequest(requestEvent); // register event
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(9600);    // start serial for output

  pinMode(9,OUTPUT);
}

void loop() {
  delay(100);
  analogWrite(9,x);

  int t=analogRead(A0);          //Read from A0 & Save to value
  value=map(t,0,1023,0,255);
}

// function that executes whenever data is received from master
void receiveEvent() {
  while (1 < Wire.available()) { // loop through all but the last
    char c = Wire.read();       // receive byte as a character
    Serial.print(c);         // print the character
  }
   x = Wire.read();    // receive byte as an integer
   Serial.println(x);         // print the integer
}

// function that executes whenever data is requested by master
void requestEvent() {
  Wire.write(value); // respond with message of 1 byte
  // as expected by master
}

میخواهیم مقدار ورودی پتانسومتر Slave را برای Master ارسال کنیم و دیتایی را که از طرف Master ارسال شده را دریافت کنیم. و آن را بر روی Serial Monitor نمایش داده و روشنایی LED را با آن کنترل کنیم.
  نکات زیر در رابطه با برنامه بالا قابل توجه می‌باشند:

  • ابتدا کتابخانه Wire را پیوست می‌کنیم.
  • توسط تابع begin(8) کار با کتابخانه را آغاز می‌کنیم و توسط عدد آن، آدرس Slave را مشخص می‌کنیم.
  • توابع onRequest و onRecieve به ترتیب برای درخواست ارسال دیتا و همچنین دریافت اطلاعات استفاده می‌شوند. در ادامه درون هر تابع را نیز شرح می‌دهیم.
  • تابع ()receiveEvent: توسط این تابع، دیتای ارسالی از طرف Master دریافت می‌شود. در ابتدا توسط حلقه While همه ی بایت ها به غیر از بایت آخر دریافت می‌شود. این بایت ها همان کاراکترهای عبارت “:Master value” می‌باشند. سپس از حلقه While عبور کرده و بایت آخر را که همان دیتای پتانسیومتر Master است را دریافت کرده و  در متغیر x ذخیره می‌کند.
  • تابع ()requestEvent: زمانی که Master درخواست دیتا کند، Slave توسط این تابع و با دستور ()Write دیتای موردنظر را به سمت Master ارسال می‌کند.
  • حال در حلقه اصلی، مقدار x که از سمت Master ارسال شد، باعث کنترل نور LED می‌شود. یعنی با تغییر پتانسومتر Master، متغیر x از 0 تا 255 تغییر کرده و باعث تغییر نور LED می‌شود.

در ادامه حلقه اصلی نیز، مقدار ورودی پتانسیومتر را خوانده و به مقدار 0 تا 255 تبدیل کرده و آن را در متغیر value ذخیره کرده و آن را آماده ارسال به سمت Master می‌کنیم.

نکته

اگر از یک کامپیوتر برای اتصال به دو آردوینو استفاده می‌کنید، بایستی به انتخاب Port هر آردوینو دقت کنید.
برای آپلود برنامه Slave یک صفحه جدید باز کنید تا بتوانید بر روی هر دو Port، برنامه موردنظرشان را بدون مشکل آپلود کنید.

گام چهارم: مشاهده خروجی

پس از اینکه هر دو برنامه را به درستی بر روی دو آردوینو آپلود کردید، سریال مانیتور هر دو Port را باز کرده و مانند فیلم زیر تغییرات LED ها و همچنین سریال مانیتور را به ازای تغییر در پتانسیومترهای ورودی بررسی کنید و از عملکرد صحیح آن مطمئن شوید.

در فیلم بالا مشاهده می‌کنید که با ازای تغییر در پتانسیومتر Master می‌توانید LED سمت Slave را کنترل کنید. همچنین این مقدار بر روی Serial Monitor سمت Slave نیز قابل مشاهده است. دقیقا همین حالت برای سمت Master نیز برقرار است. یعنی با تغییر پتانسومتر ورودی Slave، نور LED در سمت Master و مقدار دیتا بر روی Serial Monitor آن تغییر می‌کند.

یک گام جلوتر

پس از انجام کامل این آموزش، موضوعات و طرح های زیر را می‌توانید به عنوان گام بعدی انجام دهید:

  • به کاربردن بردهای دیگر مانند رزبری و یا ESP در ارتباط با یکدیگر
  • از سنسورهای دیگر به عنوان Slave نیز بهره بگیرید.
  • سعی کنید دیتاهایی با تعداد بایت بالاتر را ارسال و دریافت کنید.
  • سراغ پروتکل های دیگر مانند SPI ،CAN و…. رفته و سعی کنید با آنها ارتباط بین دو آردوینو را برقرار کنید.
  • استفاده از دو Master و چند Slave در ارتباط با باس I2C

آموزش های مشابه

Comments (5)

  • .... Reply

    عالی??

    ژانویه 26, 2022 at 10:17 ق.ظ
    • مهران ملکی Reply

      ممنون از لطف شما.?

      ژانویه 29, 2022 at 10:54 ق.ظ
  • رضا Reply

    بسیار عالی
    و کاربردی

    نوامبر 25, 2022 at 6:50 ب.ظ
    • علی عبدالملکی Reply

      ممنون از شما

      نوامبر 30, 2022 at 2:50 ب.ظ
  • اسما Reply

    سلام. این کد برای من قسمت slave اش یک مشکل داشت که اینجوری درستش کردم:
    void receiveEvent( int y)

    اضافه کردن متغییر y. بخاطر اروری که تابع onRequest میداد

    دسامبر 14, 2022 at 8:28 ب.ظ

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

نشانی ایمیل شما منتشر نخواهد شد.