چگونه ارتباطI2C کار میکند و چگونه از آن با آردینو استفاده کنیم
ما در این آموزش چگونگی راه اندازی i2c با آردوینو را یاد خواهیم گرفت که چگونه پروتکل ارتباطیI2C کار میکند و همچنین یک نمونه عملی از آن را با برد آردوینو و یک حسگر که از این پروتکل استفاده میکند، خواهیم ساخت.
مرور کلی راه اندازی i2c با آردوینو
باس ارتباطی I2C بسیار محبوب است و به طور گسترده توسط بسیاری از دستگاههای الکترونیکی مورد استفاده قرار میگیرد، زیرا میتواند به راحتی در بسیاری از طرحهای الکترونیکی که نیاز به ارتباط بین دستگاههای master و multiple salve و یا حتی دستگاههای multiple master دارند، پیادهسازی شود. پیادهسازی آسان با این حقیقت همراه است که تنها دو سیم برای ارتباط بین تقریبا ۱۲۸ (112) دستگاه در هنگام استفاده از ۷ بیت آدرس دهی و تقریباً ۱۰۲۴ (1008) دستگاه در هنگام استفاده از ۱۰ بیت آدرس دهی مورد نیاز است.
ارتباط بین این همه دستگاه فقط با سیم چگونه ممکن است؟ خب هر دستگاه یک ID از پیش تعیینشده یا یک آدرس دستگاه منحصر به فرد دارد بنابراین master میتواند انتخاب کند که با کدام دستگاهها ارتباط برقرار خواهد کرد.
این دو سیم، یا خطوط ساعت سریال (یا SCL) و دادههای سریال (یا SDA) نامیده میشوند. خط SCL سیگنال ساعت است که انتقال داده ها بین دستگاههای روی باس I2C را همزمان میکند و توسط دستگاه master تولید میشود. خط دیگر خط SDA است که دادهها را حمل میکند.
این دو خط “open – drain” هستند که به این معنی است که مقاومت باید به آنها متصل شود به طوری که خطوط بالا باشند زیرا دستگاهها روی باس I2C پایین فعال هستند. مقادیر معمول مورد استفاده برای مقاومتها از ۲ K برای سرعتهای بالاتر در حدود ۴۰۰ kbps تا ۱۰ K برای سرعت پایینتر در حدود ۱۰۰ kbps است. در آینده در پروژه های آموزش رباتیک و اینترنت اشیا خواهیم توانست از آموزش راه اندازی i2c با آردوینو استفاده کنیم.
پروتکل I2C
سیگنال داده ها در دنباله های ۸ بیتی منتقل میشود. بنابراین پس از اینکه یک شرایط شروع خاص رخ میدهد، دنباله ۸ بیتی اول میآید که آدرس slave را نشان میدهد که داده ها به آن ارسال میشود. بعد از هر دنباله ۸ بیتی، یک بیت به نام Acknowledge دنبال میشود. بعد از اولین بیت Acknowledge در بیشتر موارد یک دنباله آدرس دهی دیگر اما این بار برای ثبت کننده های داخلی دستگاه slave می آید. درست بعد از دنباله های آدرس دهی، دنباله های داده ها تا زمانی که داده ها به طور کامل ارسال شوند و با یک شرط توقف خاص به پایان برسند، دنبال میشوند.
بیایید نگاهی دقیقتر به این رویدادها بیندازیم. شرط شروع زمانی رخ میدهد که خط داده ها پایین بیاید در حالی که خط ساعت هنوز بالا است. بعد از این، ساعت شروع میشود و هر بیت داده ها در طول هر پالس ساعت منتقل میشود.
دستگاه آدرس دهی squence stars با باارزش ترین بیت (MSB) اول شروع و با کمارزشترین بیت (LSB) پایان مییابد و در واقع از ۷ بیت تشکیل شدهاست زیرا بیت هشتم برای نشان دادن اینکه آیا master به slave (منطق پایین) مینویسد یا از آن (منطق بالا) خوانده میشود، استفاده میشود.
بیت بعدی AKC / NACK توسط دستگاه slave استفاده میشود تا نشان دهد که آیا با موفقیت دنباله قبلی بیتها را دریافت کردهاست یا خیر. بنابراین در این زمان دستگاه master کنترل خط SDA را به دستگاه slave واگذار میکند و اگر دستگاه slave با موفقیت دنباله قبلی را دریافت کرده باشد، خط SDA را به شرایطی که Acknowledge نامیده میشود، پایین میکشد. اگر slave خط SDA را پایین نکشد، شرط Acknowledge نامیده نمی شود، و به این معنی است که آن دنباله قبلی را که میتواند به چند دلیل ایجاد شود، با موفقیت دریافت نکرده است. به عنوان مثال، ممکن است slave مشغول باشد، ممکن است دادههای دریافتی یا دستور را درک نکند، نمیتواند هیچ داده دیگری را دریافت کند و امثال اینها. در چنین مواردی دستگاه master تصمیم میگیرد که چگونه پیش برود.
بعدی آدرس دهی ثبت کننده های داخلی است. ثبت کننده های داخلی مکانهایی در حافظه slave هستند که حاوی اطلاعات یا داده های مختلف هستند. به عنوان مثال، شتابسنج ADX345 یک آدرس دستگاه منحصر به فرد و آدرسهای ثبت کننده های داخلی اضافی برای محور X، Y و Z دارد. بنابراین اگر بخواهیم دادههای محور X را بخوانیم، ابتدا باید آدرس دستگاه و سپس آدرس ثبت کننده های داخلی خاص را برای محور X ارسال کنیم. پس از آدرسدهی، ترتیب انتقال دادهها بسته به حالت انتخابی در بیت R / W از master یا slave آغاز میشود. پس از ارسال کامل دادهها، انتقال با یک شرط توقف پایان مییابد که زمانی اتفاق میافتد که خط SDA از پایین به بالا میرود در حالی که خط SCL بالا است.
مثال I2C آردوینو
به عنوان مثال، من از برد breakout GY-80 که شامل ۵ حسگر مختلف و برد breakout GY-521 که شامل ۳ حسگر مختلف است، استفاده خواهم کرد. بنابراین ما میتوانیم دادهها را از ۸ حسگر مختلف با تنها دو سیم با باس I2C بگیریم.
این روشی است که ما بردها را به هم متصل خواهیم کرد. پین ساعت سریال برد آردینو به پین های ساعت سریال دو برد breakout متصل میشود، همین کار برای پین داده های سریال انجام میشود و ما آن را با پین Gnd و ۵ ولت از برد آردینو به قدرت میرسانیم. توجه داشته باشید که در اینجا ما از مقاومتهای کششی استفاده نمیکنیم زیرا بردهای breakout در حال حاضر مقاومت کششی دارند.
حالا برای برقراری ارتباط با این تراشهها یا حسگرها باید آدرسهای منحصر به فرد آنها را بدانیم. ما میتوانیم آنها را از مجموعه دادههای حسگرها پیدا کنیم. برای برد breakout GY-80 ما ۴ آدرس زیر را داریم: یک هگزادسیمال 0x53 برای حسگر ۳ محوری اکسلومتر، یک هگزادسیمال 0x69 برای ۳ محوری Gyro، یک هگزادسیمال 0x1E برای ۳ محوری ماگنومتر و یک هگزادسیمال 0x77 برای حسگر بارومتر و ترمومتر.
برای برد breakout GY – 521 تنها یک آدرس داریم و آن یک هگزادسیمال 0x68 است. ما همچنین میتوانیم با استفاده از طرح اسکنر I2C آردوینو که از وب سایت رسمی آردوینو یافت میشود، آدرسها را بگیریم یا چک کنیم. بنابراین در اینجا اگر ما آن طرح را آپلود و اجرا کنیم، ما آدرسهای دستگاههای متصل شده را در باس I2C دریافت خواهیم کرد.
پس از آنکه ما آدرسهای دستگاهها را پیدا کردیم، باید آدرسهای ثبت کننده های داخلی آنها را نیز پیدا کنیم تا دادهها را از آنها بخوانیم. برای مثال اگر بخواهیم دادهها را برای محور X از حسگر ۳ محوری شتابسنج برد GY-80 بخوانیم، باید آدرس ثبت کننده داخلی را پیدا کنیم که در آن دادههای محور X ذخیره شدهاست. از مجموعه دادههای حسگر، میتوانیم ببینیم که دادهها برای محور X در واقع در دو ثبت کننده داخلی، DATAX0 با یک آدرس هگزادسیمال 0x32 و DATAX1 با یک آدرس هگزادسیمال 0x33 ذخیره شدهاند.
کد راه اندازی i2c با آردوینو
حال اجازه دهید کدی را ایجاد کنیم که دادهها را برای محور X بدست خواهد آورد. بنابراین ما از کتابخانه Arduino Wire استفاده میکنیم که باید در این طرح گنجانده شود. در اینجا ابتدا باید آدرس حسگر و دو آدرس ثبت کننده داخلی که قبلاً پیدا کردیم را تعریف کنیم. تابع ()Wire.begin کتابخانه Wire آغاز خواهد کرد و همچنین ما باید ارتباط سریال را آغاز کنیم زیرا ما از نمایشگر سریال برای نشان دادن دادهها از حسگر استفاده خواهیم کرد.
در ()loop ما کار را با تابع ()Wire.beginTransmission شروع میکنیم که انتقال به حسگر خاص را آغاز خواهد کرد، که در مورد انجام شده ما، شتابسنج ۳ محوری است. سپس با تابع ()Wire.write دادههای خاص از دو ثبت کننده محور X را درخواست خواهیم کرد. ()Wire.endTransmission به انتقال و انتقال دادن دادهها از ثبت کننده ها پایان خواهد داد. حال با تابع ()Wire.requestFrom ما داده های منتقلشده یا دو بایت از دو ثبت کننده را درخواست خواهیم کرد.
تابع ()Wire.available تعداد بایتهای موجود برای بازیابی را باز میگرداند و اگر آن عدد با بایتهای درخواستشده ما، در 2 بایت مورد انجام شده ما مطابقت داشته باشد، با استفاده از تابع ()Wire.read ما بایتهای دو ثبت کننده محور X را خواهیم خواند. در پایان ما دادهها را در نمایشگر سریال چاپ خواهیم کرد. این دادهها هستند اما به یاد داشته باشید که این دادهها خام هستند و به منظور به دست آوردن مقادیر صحیح از محور X، به مقداری ریاضی نیاز است.
/* * How I2C Communication Protocol Works - Arduino I2C Tutorial * * by Dejan, www.HowToMechatronics.com * */ #include <Wire.h> int ADXLAddress = 0x53; // Device address in which is also included the 8th bit for selecting the mode, read in this case. #define X_Axis_Register_DATAX0 0x32 // Hexadecima address for the DATAX0 internal register. #define X_Axis_Register_DATAX1 0x33 // Hexadecima address for the DATAX1 internal register. #define Power_Register 0x2D // Power Control Register int X0,X1,X_out; void setup() { Wire.begin(); // Initiate the Wire library Serial.begin(9600); delay(100); // Enable measurement Wire.beginTransmission(ADXLAddress); Wire.write(Power_Register); // Bit D3 High for measuring enable (0000 1000) Wire.write(8); Wire.endTransmission(); } void loop() { Wire.beginTransmission(ADXLAddress); // Begin transmission to the Sensor //Ask the particular registers for data Wire.write(X_Axis_Register_DATAX0); Wire.write(X_Axis_Register_DATAX1); Wire.endTransmission(); // Ends the transmission and transmits the data from the two registers Wire.requestFrom(ADXLAddress,2); // Request the transmitted two bytes from the two registers if(Wire.available()<=2) { // X0 = Wire.read(); // Reads the data from the register X1 = Wire.read(); } Serial.print("X0= "); Serial.print(X0); Serial.print(" X1= "); Serial.println(X1);