در آموزشهای قبلی نحوهی استفاده از پروتکل SPI در بوردهای آردوینو را توضیح دادهایم. در این جلسه میخواهیم نوع دیگری از ارتباط سریال در این بوردها یعنی پروتکل ارتباطی Inter Integrated Circuits) I2C) را یاد بگیریم. اگر بخواهیم این دو پروتکل یعنی I2C و SPI را با هم مقایسه کنیم؛ I2C یک پروتکل (two wires) و SPI یک پروتکل (four wires) است. از طرفی I2C میتواند دارای چند Master و یک Slave باشد در حالیکه SPI برعکس است و میتواند دارای یک Master و چند Slave باشد. بنابراین در پروژههایی که چند میکروکنترلر در آنها استفاده شده است و لازم است که بیش از یکی از آنها Master باشند، باید از پروتکل I2C استفاده شود. از جمله کاربردهای متداول این پروتکل در ارتباط با ابزارهایی مانند ژیروسکوپ، سنسور شتابسنج، سنسور اندازهگیری فشار بارومتری، نمایشگرهای LCD و … است.
مقالات مرتبط مفید:
در این آموزش ما قصد داریم بین دو بورد آردوینو از طریق ارتباط I2C ارتباط برقرار کنیم و مقادیری از صفر تا ۱۲۷ را از هر طرف به طرف دیگر ارسال کنیم. این مقادیر را با استفاده از پتانسیومتر خواهیم ساخت. از طرفی به هر کدام از این دو بورد یک LCD نیز متصل میکنیم که اعداد دریافت شده آن بورد را همزمان بر روی LCD نیز نمایش دهیم. در این ارتباط، یکی از بوردها به عنوان Master و دیگری به عنوان Slave تلقی میشود. بحثمان را با مقدمهای در مورد ارتباط I2C شروع میکنیم.
پروتکل ارتباطی I2C
همانطور که در بخش مقدمه هم گفتیم، نام I2C یا IIC از عبارت Inter Integrated Circuits گرفته شده است. معمولا آن را با همین نام و یا نامهای دیگری مانند I مربع C، پروتکل ارتباطی TWI نیز میخوانند. این پروتکل یک پروتکل ارتباطی synchronous است به این معنا که طرفین ارتباط باید سیگنال زمانی (clock) یکسان و مشترکی داشته باشند. این پروتکل تنها دارای دو سیم است که یکی همان کلاک مشترک بین طرفین تبادل است و دیگری نیز به منظور مبادلهی داده استفاده میشود.
چگونگی عملکرد پروتکل I2C
این پروتکل نخستین بار توسط شرکت Phillips معرفی شد. دو سیم مورد استفاده در آن در بین دو طرف تبادل برقرار میشوند. به یکی از این دو طرف Master ارتباط سریال و به دیگری Slave ارتباط سریال گفته میشود. در هر ارتباط I2C الزاما هر دوی این دو طرف باید وجود داشته باشند، یعنی ارتباط بدون Master و یا بدون Serial امکانپذیر نیست. مزیت مهم این پروتکل این است که بیش از یک Slave را میتوان به یک Master مشترک متصل کرد.
همانطور که گفتیم ارتباط به واسطهای این دو سیم برقرار میشود، سیم کلاک (SCL) و سیم داده (SDA).
کلاک سریال (SCL): کلاکی که توسط Master تولید میشود را بین Slaveها نیز به اشتراک میگذارد.
داده سریال (SDA): برای تبادل داده بین Master و Slaveها. (چه از Master به Slaveها و چه برعکس)
یک قانون مهم در این پروتکل این است که همواره تنها Master است که میتواند ارتباط را آغاز کند و از آنجایی که گفتیم ممکن است بیش از یک Slave در آن سمت I2C Bus وجود داشته باشند، Master برای هر یک از این Slaveها یک آدرس مشخص میکند. بنابراین زمانی که Master آدرس یک Slave مشخص را در بستههای ارسالی خود قید میکند، تنها آن Slave قادر به پاسخگویی به Master خواهد بود و بقیه ساکت خواهند ماند.
سطح ولتاژ مورد استفاده در این پروتکل از پیش تعیین نشده است و از این لحاظ بسیار انعطافپذیر است یعنی مثلا ابزاری که ولتاژ ۵ ولت دارد، برای ارتباط I2C میتواند از همان ۵ ولت استفاده کند، و ابزاری هم که ولتاژ ۳.۳ ولت دارد میتواند از ولتاژ ۳ ولت برای ارتباط I2C استفاده کند. سوالی که احتمالا در اینجا میتوان مطرح کرد این است که اگر دو وسیله با ولتاژهای مختلف بخواهند با یکدیگر ارتباط I2C برقرار کنند چه اتفاقی میافتد؟ آیا امکانپذیر است؟ پاسخ این است که خیر؛ متاسفانه در این حد انعطافپذیری نداریم! در چنین مواردی باید از مبدلهای ولتاژ استفاده کرد و سطح ولتاژ طرفین را یکسان ساخت.
به صورت قراردادی برخی از حالتهای سیگنالها در پروتکل I2C معناهای بخصوصی در ارتباط این پروتکل دارند. مثلا لبهی پایین روندهی سیگنال SDA به معنای شروع ارتباط است (در نمودار شکل زیر همان وضعیت START). در این شرایط تا زمانی که SDA در همین وضعیت LOW باشد، سیگنال SCL را در وضعیت HIGH نگه میدارد.
همانطور که در نمودار فوق نشان داده شده است؛ لبهی پایین روندهی SDA، به نوعی تریگر سختافزاری برای وضعیت START محسوب میشود. در این وضعیت، تمام دیوایسهای متصل به باس منتظر شنیدن پیغام خواهند بود.
به همین ترتیب، لبهی بالاروندهی سیگنال SDAها به STOP تعبیر میشود (نمودار بالا را ببینید) در این شرایط نیز Master سیگنال SCL را HIGH نگه میدارد.
بیتهای R/W نشان دهندهی جهت ارتباط برای دادههایی هستند که قرار است در ادامه مبادله شوند. اگر مقدار این بیت یک باشد یعنی Slave قرار است دادهای را ارسال کند و اگر مقدار آن صفر باشد یعنی Master قرار است دادهای را ارسال کند.
هر یک بیت در یک سیکل کلاک مبادله میشود. بنابراین هر یک بایت برای جابهجایی به ۸ سیکل نیاز خواهد داشت. پس از هر ۸ سیکل، سیکل نهم به ارسال سیگنال ACK/NACK (تایید یا عدم تایید) اختصاص دارد. این سیگنال بر اساس موقعیت، توسط یکی از Master یا Serial تولید میشود. اگر قرار بر تایید باشد (ACK)، Master سیگنال SDA را در سیکل نهم صفر میکند. بنابراین اگر این سیگنال درسیکل کلاک نهم صفر باشد نشانهی تایید دریافت ۸ بیت قبلی و اگر یک باشد نشانهی عدم تایید است.
کاربردهای پروتکل ارتباطی I2C
پروتکل ارتباطی I2C تنها در مواردی کاربرد دارد که فاصلهی بین طرفین ارتباط کوتاه باشد. علت اینکه فاصله نمیتواند از حدی بالاتر باشد این است که این ارتباط به کلاک synchronous نیاز دارد. بنابراین عمدهی کاربرد آن در مواردی است که بذات به فاصلهی کمی نیاز دارند، مثلا سنسورهایی که در یک محیط معین قرار دارند و لازم است اطلاعاتی را برای یک پردازندهی مرکزی در همان محدوده ارسال کنند. یا مثلا در سیستمهایی که میکروکنترلر باید با دیوایسهای متعددی ارتباط داشته باشد و ترجیح میدهیم که از حداقل تعداد ممکن برای wireها استفاده شود. اگر به ارتباطهایی با برد بلندتر نیاز داشته باشید باید به سراغ پروتکل RS232 بروید و اگر به ارتباطهایی با قابلیت اطمینان بالاتر، پروتکل SPI انتخاب بهتری خواهد بود.
ارتباط I2C در بوردهای آردوینو
تصویر زیر پینهای I2C را در بورد Arduino UNO نشان میدهد.
قبل از ورود به بحث چگونگی برقراری ارتباط I2C بین دو بورد Arduino، لازم است که اول کتابخانههای مربوط به wire را در IDE بررسی کنیم.
کتابخانهی wire.h که در کد استفاده میکنیم، برای استفاده از توابعی است که در ادامه میآیند.
- (Wire.begin(address:
کاربرد: استفاده برای ایجاد ارتباط میان دیوایسهای درگیر در ارتباط I2C. به این ترتیب دیوایس مورد نظر که آدرس آن مشخص میشود، برای پیوستن به I2C Bus مقداردهی اولیه خواهد شد.
آرگومان این تابع یک آدرس ۷ بیتی است که همانطور که گفتیم مشخص کنندهی Slaveهاست. چنانچه در فیلد آدرس چیزی ننویسیم، دیوایس مربوط به عنوان Master به باس ارتباط سریال ملحق خواهد شد.
- ()Wire.read:
کاربرد: برای خواندن بایت دریافت شده از سوی Master یا یکی از Slaveها. اگر داده از سوی slave به master ارسال شده باشد، قبل از این دستور، تابع ()requestFrom وجود دارد.
- ()Wire.write:
کاربرد: برای نوشتن داده در Master و یا Slave؛
- اگر Slave بخواهد در Master چیزی بنویسد، تابع ()Wire.RequestFrom در Master فراخوانی شده است.
- اگر Master بخواهد در Slave چیزی بنویسد، ابتدا تابع ()Wire.beginTransmission فراخوانی میشود، سپس تابع ()Wire.write و پس از آن ()Wire.endTransmission.
خود تابع ()Wire.write میتواند به صورتهای زیر نوشته شود.
- (Wire.write(value: مقدار value همان بایتی است که قرار است نوشته شود.
- (Wire.write(string: رشتهای از بایتهای متوالی که ارسال و نوشته میشوند.
- (Wire.write(data, length: آرایهای از دادهها به صورت بایت به بایت و length تعداد این بایتها را مشخص میکند.
- (Wire.beginTransmission(address:
کاربرد: این تابع ارتباط I2C با Slaveای که آدرس آن مشخص شده است را آغاز خواهد کرد.
پس از آغاز ارتباط دیتایی که قرار است مبادله شود در صف ارسال قرار میگیرد و تابع ()write مورد استفاده قرار خواهد گرفت. در انتهای تبادل نیز تابع ()endTransmission فراخوانی خواهد شد. آدرس نیز همانطور که قبلتر هم گفتیم یک آدرس ۷ بیتی است.
- ()Wire.endTransmission:
کاربرد: همانطور که در مورد قبلی گفتیم، این تابع ارتباطی را که قبلتر توسط ()beginTransmission شروع شده است را خاتمه خواهد داد.
- ()Wire.onRequest:
کاربرد: کاربرد این تابع زمانی است که Master بخواهد از یکی از Slaveها با استفاده از تابع ()Wire.requestFrom درخواست داده کند. Slave مذکور با استفاده از تابع ()Wire.write داده را ارسال خواهد نمود.
- ()Wire.onReceive:
کاربرد: زمانی که Slave از Master داده دریافت کرده باشد، فراخوانی میشود. برای خواندن دادهی دریافتی نیز از تابع ()Wire.read استفاده میشود.
- (Wire.requestFrom(address,quantity:
این تابع در Master و برای گرفتن داده از یک Slave استفاده میشود. پس از دریافت دادهی مورد نظر با استفاده از تابع ()Wire.read خوانده خواهد شد.
آدرس همان آدرس ۷ بیتی Slave مورد خطاب است.
و quantity تعداد بایتهای مورد درخواست است.
تجهیزات مورد نیاز برای اجرای پروژه
- دو عدد بورد Arduino Uno
- دو عدد LCD 16×2
- چهار عدد پتانسیومتر 10K
- برد بورد
- سیم رابط
مدار مورد استفاده
توضیح عملکرد پروژه
برای فهم چگونگی عملکرد پروتکل I2C ما در اینجا یک پروژهی ساده تعریف میکنیم. دو بورد Arduino UNO را یکی به عنوان Master و دیگری به عنوان Slave در نظر میگیریم و به هر کدام یک LCD و یک پتانسیومتر نیز متصل میکنیم. پتانسیومتر برای ساختن مقادیر صفر تا ۱۲۷ و ارسال آن از هر طرف به طرف دیگر است.
در حقیقت پتانسیومتر یک ولتاژ آنالوگ بین صفر تا ۵ ولت را به ورودی آنالوگ A0 از بورد آردوینو میدهد. آردوینو با استفاده از مبدل آنالوگ به دیجیتالی که دارد مقدار دریافتی از پتانسیومتر را به عددی در بازهی صفر تا ۱۰۲۳ نظیر میکند. اما از آنجا که برای ارتباط I2C ما به مقادیر ۷ بیتی نیاز داریم، این مقادیر نیز با استفاده از نگاشت دیگری به عددی در بازهی صفر تا ۱۲۷ نظیر شده و سپس ارسال میشوند. به این ترتیب با چرخاندن پیچ پتانسیومتر متصل به Master، اعداد نشان داده شده در LCD متصل به Slave تغییر خواهند کرد و برعکس.
ارتباط I2C نیز از طریق پینهای A4 و A5 بوردها برقرار میشود.
پروگرم کردن بوردهای آردوینو به منظور ارتباط I2C
احتمالا میتوانید حدس بزنید که برای هر کدام از طرفیت Master و Slave ما باید دو نوع برنامه داشته داشته باشیم. کد کامل هر دو طرف و نیز ویدئویی از انجام پروژه را در انتهای جلسه در دسترستان قرار دادهایم.
پروگرم کردن بورد Master
- قبل از هر کار، کتابخانه h را اضافه میکنیم تا بتوانیم از توابع ارتباط I2C استفاده کنیم. به همین ترتیب کتابخانهی LCD را نیز به منظور استفاده از توابع ارتباط با LCD اضافه میکنیم. در مورد نحوهی ارتباط با LCD نیز در جلسهی جداگانهای به طور مفصل توضیح دادهایم که میتوانید مراجعه کنید.
#include<Wire.h> #include<LiquidCrystal.h> LiquidCrystal lcd(2, 7, 8, 9, 10, 11);
- در بخش ()void setup:
یک ارتباط سریال را با بادریت ۹۶۰۰ آغاز میکنیم.
Serial.begin(9600);
یک ارتباط I2C را بر روی پینهای A4 و A5 آغاز میکنیم.
Wire.begin(); //Begins I2C communication at pin (A4,A5)
LCD را روی مود 2×16 مقداردهی اولیه میکنیم. پیغام شروع به کار را برای چند لحظه نمایش داده و سپس پاک میکنیم.
lcd.begin(16,2); //Initilize LCD display lcd.setCursor(0,0); //Sets Cursor at first line of Display lcd.print("Circuit Digest"); //Prints CIRCUIT DIGEST in LCD lcd.setCursor(0,1); //Sets Cursor at second line of Display lcd.print("I2C 2 ARDUINO"); //Prints I2C ARDUINO in LCD delay(5000); //Delay for 5 seconds lcd.clear(); //Clears LCD display
- در بخش ()void loop:
با استفاده از تابع ()requestFrom داده را از Slaveای که در آدرس ۸ قرار دارد دریافت میکنیم. تعداد بایتهای دریافتی را نیز یک قرار میدهیم.
Wire.requestFrom(8,1);
دادهی دریافتی را سپس با استفاده از تابع ()Wire.read باید بخوانیم.
byte MasterReceive = Wire.read();
در مرحلهی بعدی Master باید مقدار آنالوگی که پتانسیومتر متصل به پایهی A0 تولید میکند را بخواند.
int potvalue = analogRead(A0);
سپس مقدار دریافت شده باید به فرمت یک بایت یعنی عددی بین صفر تا ۱۲۷ تبدیل شود.
byte MasterSend = map(potvalue,0,1023,0,127);
حال دادهی به دست آمده را برای Slave با آدرس ۸ ارسال میکنیم.
Wire.beginTransmission(8); Wire.write(MasterSend); Wire.endTransmission();
در نهایت مقادیر دریافتی از Slave را هم باید بر روی LCD نمایش دهیم. این مقادیر را به طور پیوسته و با تاخیرهای ۵۰۰ میلی ثانیهای نمایش میدهیم.
lcd.setCursor(0,0); //Sets Currsor at line one of LCD lcd.print(">> Master <<"); //Prints >> Master << at LCD lcd.setCursor(0,1); //Sets Cursor at line two of LCD lcd.print("SlaveVal:"); //Prints SlaveVal: in LCD lcd.print(MasterReceive); //Prints MasterReceive in LCD received from Slave Serial.println("Master Received From Slave"); //Prints in Serial Monitor Serial.println(MasterReceive); delay(500); lcd.clear();
پروگرم کردن بورد Slave
- دقیقا مانند Master، در اینجا نیز ابتدا کتابخانههای لازم برای ارتباط با LCD و ارتباط I2C را اضافه میکنیم.
#include<Wire.h> #include<LiquidCrystal.h> LiquidCrystal lcd(2, 7, 8, 9, 10, 11);
- در بخش ()void setup:
یک ارتباط سریال را با بادریت ۹۶۰۰ آغاز میکنیم.
Serial.begin(9600);
یک ارتباط I2C را بر روی پینهای A4 و A5 آغاز میکنیم و مهم است که آدرس Slave را نیز حتما وارد کنیم که ۸ است.
Wire.begin(8);
سپس توابعی را فراخوانی میکنیم که Slave به کمک آنها مقداری را از Master دریافت میکند و یا Master از آن تقاضای داده میکند.
Wire.onReceive(receiveEvent); Wire.onRequest(requestEvent);
LCD را روی مود 2×16 مقداردهی اولیه میکنیم. پیغام شروع به کار را برای چند لحظه نمایش داده و سپس پاک میکنیم.
lcd.begin(16,2); //Initilize LCD display lcd.setCursor(0,0); //Sets Cursor at first line of Display lcd.print("Circuit Digest"); //Prints CIRCUIT DIGEST in LCD lcd.setCursor(0,1); //Sets Cursor at second line of Display lcd.print("I2C 2 ARDUINO"); //Prints I2C ARDUINO in LCD delay(5000); //Delay for 5 seconds lcd.clear(); //Clears LCD display
- در ادامه دو اتفاق ممکن است رخ دهد؛ یا داده درخواست شود و یا داده دریافت شود.
- برای حالت درخواست داده:
زمانی که Master از Slave تقاضای داده کند تابع زیر باید فراخوانی و اجرا شود. این تابع در واقع مقدار آنالوگ دریافت شده از پتانسیومتر Slave را به یک بایت تبدیل کرده و سپس آن را برای Master ارسال میکند.
void requestEvent() { int potvalue = analogRead(A0); byte SlaveSend = map(potvalue,0,1023,0,127); Wire.write(SlaveSend); }
- برای حالت دریافت داده:
هر زمان که Master دادهای را برای Slave ارسال کند تابع زیر فراخوانی و اجرا خواهد شد. عملکرد تابع به این شکل است که مقدار دریافتی از Master را خوانده و در متغیری به نام byte ذخیره میکند.
void receiveEvent (int howMany { SlaveReceived = Wire.read(); }
- در بخش ()void loop:
مقادیر دریافتی از Master را به صورت پیوسته بر روی LCD نمایش میدهیم.
void loop(void) { lcd.setCursor(0,0); //Sets Currsor at line one of LCD lcd.print(">> Slave <<"); //Prints >> Slave << at LCD lcd.setCursor(0,1); //Sets Cursor at line two of LCD lcd.print("MasterVal:"); //Prints MasterVal: in LCD lcd.print(SlaveReceived); //Prints SlaveReceived value in LCD received from Master Serial.println("Slave Received From Master:"); //Prints in Serial Monitor Serial.println(SlaveReceived); delay(500); lcd.clear(); }
برای تست کردن مدار؛ اگر پیچ پتانسیومتر یکی از طرفین را بچرخانید، خواهید دید که مقادیر نمایش داده شده بر روی LCD طرف مقابل تغییر میکنند.
این تمام چیزی بود که در مورد ارتباط I2C بین دو دیوایس مختلف باید میدانستید. درست است که ما در اینجا از دو بورد آردوینو استفاده کردیم، اما کلیت ارتباط در سایر دیوایسها نیز همین است و اکنون شما قادر هستید با به کار گرفتن همین چهارچوب بین ابزارهای مختلف ارتباط I2C برقرار کنید.
در ادامه کد کامل هر دو بخش Master و Slave را به همراه ویدئویی از اجرای این پروژه میتوانید ببینید.
کد
Master Arduino Programming //I2C MASTER CODE //I2C Communication between Two Arduino //Circuit Digest //Pramoth.T #include<Wire.h> //Library for I2C Communication functions #include<LiquidCrystal.h> //Library for LCD display function LiquidCrystal lcd(2, 7, 8, 9, 10, 11); //Define LCD Module Pins (RS,EN,D4,D5,D6,D7) void setup() { lcd.begin(16,2); //Initilize LCD display lcd.setCursor(0,0); //Sets Cursor at first line of Display lcd.print("Circuit Digest"); //Prints CIRCUIT DIGEST in LCD lcd.setCursor(0,1); //Sets Cursor at second line of Display lcd.print("I2C 2 ARDUINO"); //Prints I2C ARDUINO in LCD delay(5000); //Delay for 5 seconds lcd.clear(); //Clears LCD display Serial.begin(9600); //Begins Serial Communication at 9600 baud rate Wire.begin(); //Begins I2C communication at pin (A4,A5) } void loop() { Wire.requestFrom(8,1); // request 1 byte from slave arduino (8) byte MasterReceive = Wire.read(); // receive a byte from the slave arduino and store in MasterReceive int potvalue = analogRead(A0); // Reads analog value from POT (0-5V) byte MasterSend = map(potvalue,0,1023,0,127); //Convert digital value (0 to 1023) to (0 to 127) Wire.beginTransmission(8); // start transmit to slave arduino (8) Wire.write(MasterSend); // sends one byte converted POT value to slave Wire.endTransmission(); // stop transmitting lcd.setCursor(0,0); //Sets Currsor at line one of LCD lcd.print(">> Master <<"); //Prints >> Master << at LCD lcd.setCursor(0,1); //Sets Cursor at line two of LCD lcd.print("SlaveVal:"); //Prints SlaveVal: in LCD lcd.print(MasterReceive); //Prints MasterReceive in LCD received from Slave Serial.println("Master Received From Slave"); //Prints in Serial Monitor Serial.println(MasterReceive); delay(500); lcd.clear(); } Slave Arduino Programming //I2C SLAVE CODE //I2C Communication between Two Arduino //CircuitDigest //Pramoth.T #include<Wire.h> //Library for I2C Communication functions #include<LiquidCrystal.h> //Library for LCD display function LiquidCrystal lcd(2, 7, 8, 9, 10, 11); //Define LCD Module Pins (RS,EN,D4,D5,D6,D7) byte SlaveReceived = 0; void setup() { lcd.begin(16,2); //Initilize LCD display lcd.setCursor(0,0); //Sets Cursor at first line of Display lcd.print("Circuit Digest"); //Prints CIRCUIT DIGEST in LCD lcd.setCursor(0,1); //Sets Cursor at second line of Display lcd.print("I2C 2 ARDUINO"); //Prints I2C ARDUINO in LCD delay(5000); //Delay for 5 seconds lcd.clear(); //Clears LCD display Serial.begin(9600); //Begins Serial Communication at 9600 baud rate Wire.begin(8); //Begins I2C communication with Slave Address as 8 at pin (A4,A5) Wire.onReceive(receiveEvent); //Function call when Slave receives value from master Wire.onRequest(requestEvent); //Function call when Master request value from Slave } void loop(void) { lcd.setCursor(0,0); //Sets Currsor at line one of LCD lcd.print(">> Slave <<"); //Prints >> Slave << at LCD lcd.setCursor(0,1); //Sets Cursor at line two of LCD lcd.print("MasterVal:"); //Prints MasterVal: in LCD lcd.print(SlaveReceived); //Prints SlaveReceived value in LCD received from Master Serial.println("Slave Received From Master:"); //Prints in Serial Monitor Serial.println(SlaveReceived); delay(500); lcd.clear(); } void receiveEvent (int howMany) //This Function is called when Slave receives value from master { SlaveReceived = Wire.read(); //Used to read value received from master and store in variable SlaveReceived } void requestEvent() //This Function is called when Master wants value from slave { int potvalue = analogRead(A0); // Reads analog value from POT (0-5V) byte SlaveSend = map(potvalue,0,1023,0,127); // Convert potvalue digital value (0 to 1023) to (0 to 127) Wire.write(SlaveSend); // sends one byte converted POT value to master }
ویدئو
- منبع: ترجمه از سایت circuitdigest.com
امیدواریم آموزش «برقراری ارتباط بین دو بورد آردوینو با استفاده از پروتکل I2C» براتون مفید واقع شده باشه. پیشنهاد میکنم دیگر آموزشهای آردوینو و پروژههای آردوینو را هم مطالعه کنید.
اگر این نوشته برایتان مفید بود لطفا کامنت بنویسید.