در ساختار ماشینهای امروزی، معمولا از چیزی بین ۶۰ تا ۱۰۰ عدد سنسور مختلف برای تشخیص و تبادل دادهها استفاده میشود. این را هم اضافه کنید که تولیدکنندگان خودرو دائما در تلاش هستند که ماشینهای تولیدی خود را روز به روز هوشمندتر و پیشرفتهتر کنند. مثلا امکاناتی همچون سیستم ایربگ، رانندگی خودکار، سیستم سنجش فشار لاستیکها، سیستم کروز کنترل و … . به این ترتیب تعداد سنسورهای مورد استفاده روز به روز بیشتر و بیشتر هم خواهد شد. نکتهی مهم دیگری که وجود دارد این است که این سنسورها برخلاف سنسورهای معمولی دادههای بسیار حساس و تاثیرگذاری را دریافت و مخابره میکنند بنابراین لازم است در انتقال اطلاعات آنها و برقرار ارتباط میان آنها از پروتکلهای استاندارد و مخصوص استفاده شود. مثلا دادههای سیستم کروز کنترل را در نظر بگیرید، سرعت در هر لحظه، موقعیت دریچهی گاز در هر لحظه و … ، دادههای مهمی که به ECU یا واحد کنترل سیگنالهای الکترونیکی (Electronic Control Unit) ارسال میشوند و براساس آنها مواردی چون میزان شتاب خودرو تصمیمگیری میشوند. واضح است که کوچکترین اختلال یا خطا یا قطعی در انتقال این اطلاعات میتواند نتایج فاجعه باری به دنبال داشته باشد.
- مقاله مرتبط: انواع سنسورها
بنابراین برخلاف پروتکلهای ارتباطی متداولی چون UART ،SPI و I2C، طراحان و سازندگان خودروها ترجیح میدهند از پروتکلهای ارتباطی مخصوص اتوموبیلها مانند LIN ،CAN ،FlexRay و … استفاده کنند.
در این میان CAN از بقیهی پروتکلها محبوبتر و پرکاربردتر است. در این آموزش ابتدا مقدمات CAN را توضیح داده و مرور میکنیم و سپس با استفاده از این پروتکل، میان دو بورد آردوینو تبادل اطلاعات انجام میدهیم. به نظر جالب و هیجانانگیز میرسد، اینطور نیست؟ با ما همراه باشید.
مقدمهای بر پروتکل CAN
CAN یا اگر دقیقتر بگوییم Controller Area Network، یک باس ارتباط سریال است که برای کاربرد در صنایع و خودروها طراحی شده است. در حقیقت یک پروتکل مبتنی بر پیام (message-based) داریم که میتواند میان دستگاههای مختلفی ارتباط برقرار کند. زمانی که این دستگاههای مختلف مانند تصویر زیر به یکدیگر متصل میشوند، یک شبکه تشکیل میدهند که دقیقا مانند سیستم عصبی بدن انسان عمل میکند، هر کدام از ابزارها میتوانند در هر لحظه با هر کدام دیگر صحبت و مبادلهی پیغام کنند.
همانطور که در تصویر فوق میبینید، معماری ارتباطات این شبکه به صورت 2-wire یا دو سیمه است که مبادلات دو طرفهی پیغام را میسر میکند. یکی از این سیمها CAN High و دیگری CAN Low گفته میشود. معمولا سرعت تبادل اطلاعات در این شبکه بین 50Kbps تا 1Mbps است و فاصلهی مجاز بین دستگاهها در آن میتواند از ۴۰ متر (در حالت سرعت 1Mbps) تا ۱ کیلومتر (در حالت سرعت 50Kbps) باشد.
فرمت پیامها در CAN
پیامهایی که در این پروتکل مبادله میشوند، باید دارای فرمت مخصوصی باشند. این فرمت از بخشهای مختلفی تشکیل شده اما دو بخش اصلی و مهم آن یکی شناسه (identifier) و دیگری متن پیام (data) هستند. به کمک این دو بخش پیامهای مختلف ارسال و دریافت میشوند.
Identifeir یا CAN ID
به CAN ID اصطلاحا PGN یا Parameter Group Number نیز گفته میشود. با استفاده از این شناسه، دستگاههای مختلفی که در یک شبکهی CAN حضور دارند شناسایی و از هم متمایز میشوند. بر اساس نوع پروتکل CAN مورد استفاده، طول این شناسه میتواند از ۱۱ تا ۲۹ بیت باشد.
Standard CAN: 0-2047 (11-bit)
Extended CAN: 0-229-1 (29-bit)
DATA
این بخش به همان داده یا پیغامی اختصاص دارد که آن دستگاه میخواهد به دستگاه دیگر منتقل کند. این داده میتواند به عنوان مثال اطلاعات بدست آمده از یک سنسور یا … باشند. طول این داده میتواند از ۰ تا ۸ بایت باشد.
یکی از زیربخشهای این قسمت DLC یا Data Length Code است که مشخص میکند پیغام ارسال شده چند بایت است. بنابراین این کد میتواند مقادیر از ۰ تا ۸ را بپذیرد.
Wireهای استفاده شده در CAN
همانطور که گفتیم این پروتکل از دو سیم تشکیل میشود که آنها را به اختصار CAN_H و CAN_L مینامند. یکی از آنها مسئول ارسال و دیگری مسئول دریافت پیغامهاست. هر دوی این سیمها سیگنالها را به صورت اختلاف ولتاژ تفسیر میکنند. به این معنی که اگر اختلاف ولتاژ از مقدار معینی بیشتر باشد آن سیگنال را ۱ و اگر کمتر باشد آن سیگنال را ۰ تفسیر میکنند.
معمولا در پروتکل CAN از کابلهایی استفاده میکنند که به صورت یک جفت سیم در هم پیچیده است. یک مقاومت ۱۰۰ اهمی ساده هم در انتهای کابلها مانند آنچه که در تصویر قبلی دیدید، به آن اضافه میکنند. این مقاومت به بالانس شدن ولتاژ خط کمک میکند.
مقایسهی پروتکل CAN با SPI و I2C
ما در آموزشهای قبلی طریقهی استفاده از پروتکلهای SPI و I2C را در بوردهای آردوینو با هم یادگرفتهایم. همچنین مشخصات این دو پروتکل را نیز از قبل میدانیم. حالا بیایید که این دو را با پروتکل CAN مقایسه کنیم.
کاربردهای پروتکل CAN
- به علت قدرت و قابلیت اطمینانی که این پروتکل دارد، از آن در صنایعی مانند تولید خودرو، تولید ماشینآلات کشاورزی، تجهیزات پزشکی و غیره استفاده میکنند.
- از آنجایی که وایرینگ این پروتکل پیچیدگیهای بسیار کمی دارد، از آن در کاربردهای اتوماتسازی مثلا در خودروهای پیشرفته استفاده میکنند.
- سختافزارهای مورد نیاز برای پیادهسازی آن و نیز خود پیادهسازی آن قیمتهای بسیار مناسبی دارند پس در کاربردهایی که میزان قیمت تمام شده از اهمیت بالایی برخوردار است CAN پروتکل کارآمدی محسوب میشود.
- اضافه کردن آن به یک سیستم و یا برداشتن آن از آن سیستم، بسیار راحت است و خود این قابلیت متحرک بودن در کابردهایی حائز اهمیت است.
طریقهی استفاده از پروتکل CAN در بورد آردوینو
در ابتدا باید بگوییم که بوردهای آردوینو پورتی که مخصوص ارتباط CAN باشد را در درون سختافزار خود ندارند. بنابراین باید از یک ماژول جانبی برای این کار استفاده کنیم. این ماژول MCP2515 نام دارد. این ماژول خود با استفاده از پروتکل SPI با بورد آردوینو ارتباط برقرار میکند. قبل از شروع توضیحات چگونگی استفاده از CAN در آردوینو، بیایید نگاه دقیقتری به این ماژول داشته باشیم.
ماژول MCP2515
این ماژول دارای یک CAN controller است که در درون آن یک گیرندهی سرعت بالای ارتباطات CAN وجود دارد. ارتباط بین این ماژول با هر ماژول دیگری از طریق پروتکل SPI است بنابراین به راحتی با هر پردازنده یا میکروکنترلری که از SPI پشتبانی کند، قابل هماهنگ شدن است.
ضمنا این ماژول برای افراد مبتدی، که به تازگی قصد دارند کار با پروتکل CAN Bus را شروع کنند نیز پیشنهاد بسیار خوبی است.
به عبارتی میتوان گفت که این ماژول که به واسطهی پروتکل SPI با ماژولهای دیگر ارتباط برقرار کرده و امکان استفاده از پروتکل CAN را برای ما فراهم میکند، در کاربردهای اتوماسیون صنعتی، پروژههای اتوماسیون خانگی و آزمایشگاهی و غیره بسیار کاربردی است.
ویژگیها و مشخصات ماژول MCP2515
- استفاده از گیرندهی پرسرعت TJA1050 در ارتباط CAN
- ابعاد : ۴۰*۲۸ میلیمتر
- استفاده از SPI برای توسعهی اینترفیسهای پروتکل CAN Bus
- فرکانس کریستال اسیلاتور 8MHz
- مقاومت ترمینالها ۱۲۰ اهم
- دارای کلید، نشانگر LED و نشانگر Power به صورت جداگانه
- پشتیانی از مبادلهی اطلاعات با حداکثر سرعت (1Mb/s) در CAN
- مصرف توان پایین در زمان استندبای
- امکان متصل کردن تا ۱۱۲ نود در یک شبکهی CAN
پایههای ماژولMCP2515
بسیار خب، در ادامهی این آموزش، میخواهیم ببینیم چگونه میتوانیم اطلاعات دریافتی از سنسورهای سنجش رطوبت و سنجش دما (DHT11) را با استفاده از پروتکل CAN و با کمک گرفتن از ماژول MCP2515، از یک بورد Arduino Nano به یک بورد Arduino Uno ارسال کنیم.
تجهیزات مورد نیاز
- بورد Arduino UNO
- بورد Arduino NANO
- سنسور DHT11
- نمایشگر LCD با ابعاد ۲*۱۶
- دو عدد ماژول MCP2515
- پتانسیومتر 10k
- برد بورد
- سیمهای اتصال برد بوردی
دیاگرام کلی مدار
اتصالات مربوط به بخش CAN Transmitter
اتصالات مربوط به بخش CAN Receiver
اتصالات بین دو ماژول MCP2515
H – CAN High
L – CAN Low
زمانی که تمام این اتصالات را برقرار کردید، مداری مشابه تصویر زیر خواهید داشت.
نوشتن کد ارتباط CAN برای بوردهای آردوینو
ابتدا باید کتابخانه CAN را در Arduino IDE نصب کنیم. برقرای ارتباط بین ماژول MCP2515 و بورد آردوینو در صورت وجود این کتابخانه بسیار راحتتر خواهد بود.
- فایل زیپ Arduino CAN MCP2515 Library را دانلود کنید.
- در Arduino IDE مسیر Sketch -> Include Library -> Add .ZIP Library را بروید و کتابخانه را اضافه کنید.
در این آموزش ما کدنویسی را در دو بخش انجام دادهایم. یک بخش به عنوان CAN transmitter code که برای بورد Arduino Nano است و بخش دیگر به عنوان CAN Receiver code که برای بورد Arduino UNO است. در ادامه هر دوی این کدها را بخش به بخش توضیح میدهیم و کدهای کامل را نیز در انتهای آموزش قرار دادهایم.
پیش از شروع کدنویسی برای ارسال و دریافت داده، اطمینان داشته باشید که کتابخانهای که در بالا توضیح دادیم را به همان روشی که گفتیم در IDE اضافه کردهاید. در قدم بعدی باید مطابق مراحل زیر ماژول MCP2515 را مقداردهی اولیه (initialize) کنید.
Initialize کردن ماژول MCP2515
برای برقرار شدن ارتباط با این ماژول ۳ مرحلهی زیر را انجام دهید.
- شماره پینی که SPI CS به آن متصل است را وارد کنید (به صورت پیشفرض پین شماره ۱۰)
MCP2515 mcp2515(10);
- بادریت فرکانس اسیلاتور را وارد کنید.
mcp2515.setBitrate(CAN_125KBPS, MCP_8MHZ);
بادریتهای موجود:
CAN_5KBPS, CAN_10KBPS, CAN_20KBPS, CAN_31K25BPS, CAN_33KBPS, CAN_40KBPS, CAN_50KBPS, CAN_80KBPS, CAN_83K3BPS, CAN_95KBPS, CAN_100KBPS, CAN_125KBPS, CAN_200KBPS, CAN_250KBPS, CAN_500KBPS, CAN_1000KBPS.
Clock speed های موجود :
MCP_20MHZ, MCP_16MHZ, MCP_8MHZ
- مودها را تنظیم کنید.
mcp2515.setNormalMode(); mcp2515.setLoopbackMode(); mcp2515.setListenOnlyMode();
کد مربوط به بخش فرستنده (Arduino Nano)
بسیار خب، در بخش فرستنده بورد Arduino Nano که با ماژول MCP2515 ارتباط SPI دارد و دادههای مربوط به دما و رطوبت را از سنسور DHT11 دریافت کرده و میخواهد آنها را روی CAN Bus ارسال کند، را داریم.
ابتدا باید کتابخانههای مورد نیاز را include کنیم، کتابخانهی SPI برای برقراری ارتباط SPI، کتابخانهی MCP2515 برای برقراری ارتباط CAN و کتابخانهی DHT برای دریافت دادهها از سنسور DHT. (فرض میکنیم که اینترفیس DHT11 از قبل با بورد آردوینو برقرار شده است)
#include <SPI.h> #include <mcp2515.h> #include <DHT.h>
حال باید پین خروجی DHT11 که به پین A0 آردوینو Nano متصل است را مشخص کنیم.
#define DHTPIN A0
همچنین DHTType را هم که DHT11 است مشخص میکنیم.
#define DHTTYPE DHT11
تعریف یک متغیر از نوع struct برای ذخیره کردن پیامهای پروتکل CAN که در فرمت struct data هستند.
struct can_frame canMsg;
تنظیم شمارهی پینی که SPI CS متصل است (به صورت پیشفرض پین شماره ۱۰)
MCP2515 mcp2515(10);
همچنین یک object dht هم برای class DHT تعریف میکنیم که شامل پین ارتباطی آن با بورد Nano و نوع آن یعنی DHT11 است که از قبل مقداردهی شدهاند.
DHT dht(DHTPIN, DHTTYPE);
سپس وارد بخش ()void setup میشویم و با استفاده از دستور زیر ارتباط SPI را تعریف میکنیم.
SPI.begin();
و با استفاده از دستور زیر مقادیر دما و رطوبت را از سنسور DHT11 دریافت میکنیم.
dht.begin();
ماژول MCP2515 را با کمک دستور زیر ریست میکنیم.
mcp2515.reset();
و سپس سرعت و فرکانس کلاک ماژول را تعیین میکنیم.
mcp2515.setBitrate(CAN_500KBPS,MCP_8MHZ);
و آن را در مود نرمال قرار میدهیم.
mcp2515.setNormalMode();
وارد بخش ()void loop میشویم.
عبارت زیر مقادیر دما و رطوبت اندازهگیری شده را دریافت کرده و آنها را در متغیرهای t و h ذخیره میکند.
int h = dht.readHumidity(); int t = dht.readTemperature();
در بخش بعد CAN ID و DLC را به ترتیب روی ۰x۰۳۶ و ۸ قرار میدهیم. به متغیرهای h و t مقادیر data[0] و data[1] را میدهیم و تمام دادهها را با ۰ ریست میکنیم.
canMsg.can_id = 0x036; canMsg.can_dlc = 8; canMsg.data[0] = h; //Update humidity value in [0] canMsg.data[1] = t; //Update temperature value in [1] canMsg.data[2] = 0x00; //Rest all with 0 canMsg.data[3] = 0x00; canMsg.data[4] = 0x00; canMsg.data[5] = 0x00; canMsg.data[6] = 0x00; canMsg.data[7] = 0x00;
و در نهایت برای فرستادن دادهها روی CAN Bus از دستور زیر استفاده میکنیم.
mcp2515.sendMessage(&canMsg);
کاری که تا این لحظه انجام دادیم این است که مقادیر دما و رطوبت اندازهگیری شده را در قالب پیامهایی روی CAN Bus قرار دادهایم.
کد مربوط به بخش گیرنده (Arduino UNO)
در بخش گیرنده بورد UNO را داریم که با ماژول MCP2515 و یک نمایشگر LCD اینترفیس دارد. قرار است بورد UNO مقادیر قرار داده شده بر روی CAN Bus را با واسطهی ماژول MCP2515 دریافت کند و آنها را روی LCD نمایش دهد.
مانند بخش قبلی، در اینجا نیز ابتدا باید کتابخانههای موردنیاز را include کنیم، کتابخانهی SPI برای برقراری ارتباط SPI، کتابخانهی MCP2515 برای برقراری ارتباط CAN و کتابخانهی LiquidCrsytal برای برقراری ارتباط LCD با آردوینو.
#include <SPI.h #include <mcp2515.h> #include <LiquidCrystal.h>
پینهای LCD که قرار است به بورد متصل شوند را مشخص میکنیم.
const int rs = 3, en = 4, d4 = 5, d5 = 6, d6 = 7, d7 = 8; LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
در اینجا هم یک struct data تعریف میکنیم که بتوانیم پیغامهای دریافت شده از CAN Bus را در آن ذخیره کنیم.
struct can_frame canMsg;
شمارهی پینی که SPI CS به آن متصل است را وارد میکنیم (به صورت پیشفرض پین شماره ۱۰)
MCP2515 mcp2515(10);
وارد بخش ()void setup میشویم، LCD را روی مود ۲*۱۶ تنظیم میکنیم و پیام اولیهی آن پس از روشن شدن را نیز تنظیم میکنیم.
lcd.begin(16,2); lcd.setCursor(0,0); lcd.print("CIRCUIT DIGEST"); lcd.setCursor(0,1); lcd.print("CAN ARDUINO"); delay(3000); lcd.clear();
شروع ارتباط SPI با دستور زیر:
SPI.begin();
ماژول MCP2515 را ریست میکنیم.
mcp2515.reset();
سرعت و فرکانس کلاک آن را تعیین میکنیم.
mcp2515.setBitrate(CAN_500KBPS,MCP_8MHZ);
و آن را در مود نرمال قرار میدهیم.
mcp2515.setNormalMode();
در مرحله بعدی وارد ()void loop میشویم.
با استفاده از دستور زیر، پیامها را از روی CAN Bus میخوانیم. هر زمان پیام جدیدی وجود داشته باشد وارد دستور if میشود.
if (mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK)
در این عبارت شرطی، دادهها دریافت شده و در canMsg ذخیره میشوند. date[0] دادهی مربوط به مقدار رطوبت و data[1] دادهی مربوط به مقدار دما را دارند و به ترتیب در متغیرهای x و y ذخیره میشوند.
int x = canMsg.data[0]; int y = canMsg.data[1];
پس از دریافت دادهها، به کمک دستور زیر آنها را روی LCD نمایش میدهیم.
lcd.setCursor(0,0); lcd.print("Humidity : "); lcd.print(x); lcd.setCursor(0,1); lcd.print("Temp : "); lcd.print(y); delay(1000); lcd.clear();
عملکرد ارتباط CAN در بورد آردوینو
در صورتی که از مرحلهی قبلی سختافزارها و اتصالات را تکمیل کرده بودید، در این مرحله میتوانید کدهای مربوط به هرکدام از بوردها (فرستنده و گیرنده) را بر روی آنها آپلود کنید. در ادامه میتوانید به هر دوی این کدها به صورت کامل دسترسی داشته باشید.
پس از روشن کردن بوردها و ماژولها، باید ببینید که دما و رطوبتی که توسط سنسور اندازهگیری شدهاند، توسط بورد اول به بورد دوم ارسال شده و اکنون بر روی LCD متصل به بورد دوم نمایش داده میشوند. همانطور که در تصویر زیر میبینید. در اینجا ما دما را با یک دستگاه دیگر نیز اندازهگرفتهایم تا مطمئن شویم عدد نمایش داده شده بر روی LCD درست است.
تمام مراحل فوق را میتوانید یک بار دیگر در ویدئوی زیر نیز مرور کنید. اگر در حین انجام دادن این پروژه سوالی داشتید، آن را در بخش کامنتهای همین مطلب با ما در میان بگذارید.
کد
CAN Transmitter Code (Arduino Nano): #include <SPI.h> //Library for using SPI Communication #include <mcp2515.h> //Library for using CAN Communication #include <DHT.h> //Library for using DHT sensor #define DHTPIN A0 #define DHTTYPE DHT11 struct can_frame canMsg; MCP2515 mcp2515(10); DHT dht(DHTPIN, DHTTYPE); //initilize object dht for class DHT with DHT pin with STM32 and DHT type as DHT11 void setup() { while (!Serial); Serial.begin(9600); SPI.begin(); //Begins SPI communication dht.begin(); //Begins to read temperature & humidity sesnor value mcp2515.reset(); mcp2515.setBitrate(CAN_500KBPS,MCP_8MHZ); //Sets CAN at speed 500KBPS and Clock 8MHz mcp2515.setNormalMode(); } void loop() { int h = dht.readHumidity(); //Gets Humidity value int t = dht.readTemperature(); //Gets Temperature value canMsg.can_id = 0x036; //CAN id as 0x036 canMsg.can_dlc = 8; //CAN data length as 8 canMsg.data[0] = h; //Update humidity value in [0] canMsg.data[1] = t; //Update temperature value in [1] canMsg.data[2] = 0x00; //Rest all with 0 canMsg.data[3] = 0x00; canMsg.data[4] = 0x00; canMsg.data[5] = 0x00; canMsg.data[6] = 0x00; canMsg.data[7] = 0x00; mcp2515.sendMessage(&canMsg); //Sends the CAN message delay(1000); } CAN Receiver Code (Arduino UNO): #include <SPI.h> //Library for using SPI Communication #include <mcp2515.h> //Library for using CAN Communication #include <LiquidCrystal.h> //Library for using LCD display const int rs = 3, en = 4, d4 = 5, d5 = 6, d6 = 7, d7 = 8; LiquidCrystal lcd(rs, en, d4, d5, d6, d7); //Define LCD display pins RS,E,D4,D5,D6,D7 struct can_frame canMsg; MCP2515 mcp2515(10); // SPI CS Pin 10 void setup() { lcd.begin(16,2); //Sets LCD as 16x2 type lcd.setCursor(0,0); //Display Welcome Message lcd.print("CIRCUIT DIGEST"); lcd.setCursor(0,1); lcd.print("CAN ARDUINO"); delay(3000); lcd.clear(); SPI.begin(); //Begins SPI communication Serial.begin(9600); //Begins Serial Communication at 9600 baudrate mcp2515.reset(); mcp2515.setBitrate(CAN_500KBPS,MCP_8MHZ); //Sets CAN at speed 500KBPS and Clock 8MHz mcp2515.setNormalMode(); //Sets CAN at normal mode } void loop() { if (mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK) // To receive data (Poll Read) { int x = canMsg.data[0]; int y = canMsg.data[1]; lcd.setCursor(0,0); //Display Temp & Humidity value received at 16x2 LCD lcd.print("Humidity : "); lcd.print(x); lcd.setCursor(0,1); lcd.print("Temp : "); lcd.print(y); delay(1000); lcd.clear(); } }
ویدئو
- منبع: ترجمه از سایت circuitdigest.com
امیدوارم این آموزش براتون مفید واقع شده باشه. کامنت یادتون نره 🙂
اگر این نوشته برایتان مفید بود لطفا کامنت بنویسید.
سلام روزتون بخیر و سلامتی
من یه سوال دارم
چطور میتونم از طریق کابل کن ای سی یو خودرو، به یک رله برای قطع و وصل جریان برق 12 فرمان بگیرم؟
به عنوان مثال زمانی که دور موتور به 4000 دور رسید بتونم یه چراغ اعلام روشن کنم.
آیا ماژول و رله نیاز دارم؟
پیشاپیش سپاسگزارم.
عالی بود ، ممنون از وقتی که گذاشتید