تروشین ع.ن.، آروتیونیان م.گ. برقراری ارتباط و تبادل داده از طریق بلوتوث بین برنامه آردوینو و iOS. پارامترهای پروتکل برای ارتباط بین آردوینو و ارتباط آردوینو ESP8266

دانلود مثال استاندارد«Physical Pixel» از طریق منوی File\Examples\4.Communication\PhysicalPixel. این برنامه منتظر داده ها از کامپیوتر است. با دریافت کاراکتر "H"، نشانگر تست روشن می شود، با دریافت کاراکتر "L" خاموش می شود. بیایید کد منبع آن را تجزیه و تحلیل کنیم:

int outputPin = 13 ; // در اینجا شماره تماس را ذخیره می کنیم
مقدار int; // کاراکتر دریافتی در اینجا ذخیره می شود

تنظیم خالی ()
{
Serial.begin(9600) ; // پورت را روی 9600 bps تنظیم کنید
pinMode (outputPin، OUTPUT) ; // پایه 13 را روی حالت خروجی قرار دهید
}

حلقه خالی()
{
if(Serial.available())( //اگر یک کاراکتر پذیرفته شده وجود داشته باشد،
val = Serial.read(); // سپس آن را بخوانید و در val ذخیره کنید
اگر (val == "H") ( // اگر کاراکتر "H" پذیرفته شود...
digitalWrite (outputPin، HIGH) ; // سپس LED را روشن کنید
}
اگر (val == "L") ( // اگر کاراکتر "L" پذیرفته شود،
digitalWrite (outputPin، LOW) ; // سپس LED را خاموش کنید
}
}
}

به شرایط تو در تو و ترتیب باز و بسته شدن بریس های فرفری توجه کنید. برای راحتی خواندن کد برنامه، هر سطح بعدی از تودرتو به سمت راست منتقل می شود. علاوه بر این، ویرایشگر به خواندن کد کمک می کند - اگر مکان نما را در سمت راست براکت قرار دهید، جفت براکت مربوطه را برجسته می کند.

چگونه می توان عملکرد این برنامه را پس از دانلود در میکروکنترلر بررسی کرد؟ باید راهی برای ارسال کاراکترها به پورت COM کامپیوتر پیدا کنیم تا میکروکنترلر آنها را دریافت و پردازش کند. گزینه های زیادی برای حل این مشکل وجود دارد.

ما از مانیتور داخلی پورت COM در محیط توسعه آردوینو استفاده می کنیم

این ساده ترین و قابل درک ترین روش برای مبتدیان است.

مانیتور پورت COM از طریق منوی Tools\Serial Monitor یا از طریق نوار ابزار راه اندازی می شود. در نسخه های قدیمی نرم افزار، مانیتور فقط از طریق نوار ابزار در دسترس بود: . هنگام فراخوانی مانیتور، مطمئن شوید که همان نرخ باود مانند برنامه میکروکنترلر انتخاب شده است. اکنون می توانید هر کاراکتری را در قسمت ورودی سمت راست وارد کنید و دکمه "ارسال" را فشار دهید - کاراکترهای وارد شده به پورت ارسال می شوند و برنامه شما آنها را در آنجا می پذیرد. حرف لاتین "H" را در آنجا وارد کنید، "ارسال" را فشار دهید - LED تست روشن می شود. اگر "L" را ارسال کنید - خاموش می شود. ضمناً تمام داده هایی که برنامه شما به پورت COM ارسال می کند در پنجره زیر نمایش داده می شود.

با استفاده از برنامه شبیه سازی ترمینال HyperTerminal

این یک گزینه تبادل کمی پیچیده تر برای پیاده سازی است.

ویندوز معمولا شامل یک برنامه شبیه سازی ترمینال به نام HyperTerminal است. در ویندوز XP، می توان آن را در Start\All Programs\Programs\Accessories\Communications\HyperTerminal پیدا کرد. هنگام راه اندازی، باید از ایجاد اتصال خودداری کنید، منوی File \ Properties را انتخاب کنید. در گفتگوی ظاهر شده، پورت COM خود را انتخاب کنید، روی "Configure" کلیک کنید و تنظیمات ارتباطی را مطابق شکل پیکربندی کنید:

می توانید از شبیه ساز ترمینال دیگری استفاده کنید - همه آنها معمولاً عملکردهای مشابه و تنظیمات مشابهی دارند.

در هر دو پنجره روی "OK" کلیک کنید، و یک بار در پنجره اصلی برنامه، هر کلید روی صفحه کلید - HyperTerminal به پورت COM متصل می شود. حالا تمام کاراکترهای تایپ شده روی کیبورد از طریق پورت COM به میکروکنترلر می روند و هر چیزی که میکروکنترلر ارسال می کند به صفحه نمایش می رود. کلیدهای "H" و "L" را فشار دهید (به زبان و حروف انتخاب شده دقت کنید) - LED تست باید روشن شود و خاموش شود.

بیایید برنامه کامپیوتر شخصی خودمان را بنویسیم!

این گزینه برای علاقه مندان واقعی است که می خواهند نه تنها Freeduino، بلکه رایانه شخصی را نیز برنامه نویسی کنند. چرا که نه؟ ما نیازی به یادگیری جزئیات برنامه نویسی نداریم درگاه سریالتحت ویندوز، یا چیزهای پیچیده دیگر. مخصوصاً برای حل چنین کارهای ساده ای، زبان Processing (http://processing.org) وجود دارد که از نظر نحو و حتی محیط توسعه بسیار شبیه به نرم افزار آردوینو است.

Processing را نصب و اجرا کنید - یک محیط توسعه مانند آردوینو خواهید دید.

کد منبع برای زبان پردازش در نظرات زیر متن اصلی مثال Physical Pixel است. در اینجا با حداقل تغییرات است - ما درب پورت را تعمیر کردیم تا بتوانید به راحتی شماره آن را جایگزین کنید:

واردات پردازش.سریال.* ;
درگاه سریال؛
تنظیم خالی ()
{
سایز (200 , 200 ) ;
noStroke() ;
نرخ فریم (10) ;
پورت = سریال جدید (این، "COM5"، 9600); //!!! پورت COM خود را اینجا وارد کنید!
}
ماوس بولین OverRect() //در صورتی که مکان نما داخل مربع باشد، مقدار true را برمی گرداند
{
بازگشت ((mouseX >= 50 ) && (mouseX<= 150 ) && (mouseY >= 50) و (موسY<= 150 ) ) ;
}
void draw()
{
پس زمینه(#222222) ;
if (MoseOverRect()) // اگر مکان نما داخل مربع باشد ....
{
fill(#BBBBB0) ; // رنگ را به روشن تر تغییر دهید
port.write("H"); // ارسال "H" به میکروکنترلر
) دیگر ( // اگر داخل نیست...
fill(#666660)؛ // رنگ را به تیره تر تغییر دهید
port.write("L"); // "L" را به میکروکنترلر ارسال کنید
}
rect(50، 50، 100، 100); // یک مربع رسم کنید
}

برنامه را اجرا کنید (از طریق منوی Sketch \ Run) - یک پنجره با مربع ظاهر می شود، هنگامی که مکان نما ماوس را در آن قرار می دهید، LED Freeduino روشن می شود.

توضیح زبان Processing و قابلیت‌های آن خارج از حوصله این روایت ساده است، اما بسیاری از نمونه‌های آردوینو در نظرات زیر بدنه برنامه، پردازش کد رایانه شخصی را نشان می‌دهند که با Freeduino در تعامل است.

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

اما بیایید دست به کار شویم. تبادل داده با آردوینو چندان سخت نیست، اما نکته مهم این است که داده ها کاراکتر به کاراکتر منتقل می شوند که بسیار بد است. در جستجوی این مشکل، مجبور شدم زمان زیادی را صرف کنم، تا اینکه به یک کتابخانه شگفت انگیز در Habrahabr برخوردم. نویسنده تابع پذیرش اعداد را در آن پیاده سازی کرده است. می توانید بیش از یک رقم را به کنترلر ارسال کنید و به درستی کار خواهد کرد. کتابخانه (لینک) را دانلود کنید، آن را در کتابخانه های سخت افزاری باز کنید، و بیایید به تمرین ادامه دهیم.

اول از همه، ما یک طرح می نویسیم و آن را در آردوینو (Freeduino) آپلود می کنیم.

#include void setup() (

Serial.begin(9600); // سرعت پورت را تنظیم کنید

PinMode (9، OUTPUT)؛ // پایه 9 را به عنوان خروجی بلندگو تنظیم کنید

) void loop()

Long intNumber; Serial.print("شماره را وارد کنید:");

Number = SerialInput.InputNumber(); // یک عدد وارد کنید Serial.print("نتیجه =");

Serial.println(Number * Number, DEC);

بیپ (500)؛

} بوق خالی (تاخیرهای کاراکتر بدون علامت)(

analogWrite(9, 20); مقدار // باید بین 0 تا 255 باشد

// برای لحن خوب آزمایش کنید

analogWrite(9, 0); // 0 - پیزو را خاموش کنید

تاخیر (تاخیر)؛ // مکث تاخیر ms

همه اینها به چه معناست. من سعی کردم کد را با نظرات دقیق ارائه کنم، به نظر می رسد همه چیز واضح است. این طرح از شما می خواهد که هر عددی را وارد کنید، پس از آن مربع خود را نشان می دهد و یک سیگنال صوتی را از طریق یک بلندگوی پیزو متصل به پایه 9 پخش می کند.

و اکنون، جالب ترین چیز - وقت آن است که تلاش کنید. برای تعویض با کنترلر، توصیه می کنم از یک برنامه رایگان استفاده کنید بتونه. در تنظیمات نوع اتصال، سریال را انتخاب کنید و به جای COM1 شماره پورت صحیح را وارد کنید (می‌توانید در محیط برنامه‌نویسی آردوینو در منوی Tools->Serial Port نگاهی بیاندازید). Open را فشار می دهیم و کتیبه Enter number را در کنسول می بینیم، هر عددی را وارد می کنیم (در حد منطق)، Enter را فشار می دهیم و نتیجه را می بینیم.

همه چیز، شما می توانید شادی کنید و از شادی بپرید. طبیعتاً همه اینها قابل بهبود هستند، به عنوان مثال ابتدا یک منو برای ارسال از کنترلر به کنسول نمایش دهید که در آن دستورات به طور کامل شرح داده شود. به عنوان مثال، عدد 0 را وارد کنید - روشن می شود لامپ های ال ای دی، 1 را فشار دهید - خاموش می شود. بنابراین، می توانید حداقل 100500 دستور را فشار دهید، اگر فقط حافظه میکروکنترلر کافی (که بسیار کوچک است) وجود داشته باشد. و دفعه بعد در مورد نحوه افزایش حافظه موجود صحبت خواهیم کرد.

UPD: بخشی از کد توسط تجزیه کننده موتور بریده شده است، بنابراین منبع آن است

مانند بسیاری دیگر از DIYers، من به طور مرتب از میکروکنترلرهای AVR برای انواع کاردستی های آماتوری مختلف استفاده می کنم. و به لطف مفهوم "Arduino"، این صنایع دستی اکنون ظاهری ظریف به خود می گیرند. در واقع، برای حدود 300-400 روبل، ما یک برد چند لایه مینیاتوری با ماسک، چاپ روی صفحه ابریشم و با لوازم جانبی برای میکروکنترلر به طور کامل روی آن (و در نسخه SMD!) دریافت می کنیم. من در مورد انواع پلاگین های همان سری "Arduino" صحبت نمی کنم: سنسورها، کنترلرها، نمایشگرها و مجموعه کاملی از تجهیزات جانبی اضافی که ما بسیار به آنها نیاز داریم. و دوباره، همه چیز نیز ارزان و در عملکرد عالی است. عملاً نیازی به رقیق کردن و لحیم کردن چیزی روی "زانو" نیست.

اما همه این صنایع مختلف آماتور به طور طبیعی نیاز دارند، پیش برنامه ریزیو در آینده، با پیشرفت های مختلف، این صنایع دستی دائماً مجبور هستند reflash. واضح است که انجام این کار از راه دور راحت تر از کشیدن مداوم آنها به یک برنامه نویس معمولی است. به طور کلی، به لطف همان پلتفرم آردوینو، گزینه های زیادی در اینجا وجود دارد: بلوتوث، ZigBee، یک کانال رادیویی با پروتکل شخصی شما، IR و حتی Wi-Fi. همه آنها به شما امکان می دهند با میکروکنترلر خود ارتباط بی سیم برقرار کنید. اما ما روی گزینه آخر تمرکز خواهیم کرد. در اینجا چهار دلیل اصلی وجود دارد:

1: مدرن، اینترنت اشیا!

2: روتر بیسیمموجود در هر آپارتمان، ثبت نام در شبکه خانگیدستگاه های شما و voila!

3: صنایع دستی شما یک جهش انقلابی در توسعه خود ایجاد می کند. آنها نه تنها می توانند از راه دور برنامه ریزی شوند، بلکه اکنون می توانند با دنیای اطراف خود نیز ارتباط برقرار کنند: ساعت دیجیتالبه طور مستقل بگیرند زمان دقیقاز سرورهای ساعت NTP، دستگاه های اجرایی از طرف دیگر شهر یا کشور کنترل می شوند، دستگاه های ثبت کننده داده های انباشته شده را در فضای ابری ذخیره می کنند و غیره. و غیره.

4: یک سری تراشه های فوق العاده ESP8266 وجود دارد که پیاده سازی همه اینها روی آنها خیلی آسان نیست.

علاوه بر این، در این مقاله، با استفاده از مثال بازوی مکانیکی روی سرووها، برنامه نویسی از راه دور و تبادل داده از رایانه شخصی (یا هر چیز دیگری) با دستگاه های مبتنی بر میکروکنترلرهای AVR. من می خواهم فوراً توجه داشته باشم که همه برنامه های ارائه شده در زیر صرفاً نمایشی هستند و ارزش تجاری ندارند. بنابراین، ادعاهایی مانند اینکه چرا برنامه نویس تا این حد خنثی شده و خیلی کاربردی نیست یا اینکه چرا هیچ سرویس اضافی که همه جا وجود دارد وجود ندارد، پذیرفته نمی شود. از آنجایی که کدها باز هستند، هر کسی می تواند به صلاحدید خود آنها را تکمیل کند، اما برای من، هنوز به اندازه کافی برای کار وجود دارد.

فرض بر این است که خواننده قبلاً با ماژول‌های آردوینو (شیلدها) و اتصال و سیستم عامل ESP8266 آشنا است. در واقع، حجم عظیمی از مطالب در وب منتشر شده است که اصول کار با این دستگاه ها را توضیح می دهد، و من نمی خواهم در اینجا خودم را تکرار کنم. برای مبتدیان، لیستی در انتهای مقاله وجود دارد. لینک های مفیددر مورد این مسائل، جایی که می توانید اطلاعات زیادی را پیدا کنید که چرا همه چیز برای شما کار نمی کند. با توجه به تجربه‌ای که به‌عنوان یک مهندس الکترونیک سابق داشتم، می‌توانم مسئولانه بگویم که 99 درصد مشکلات به موارد زیر برمی‌گردد:

1. مخاطبین بد. از آنجایی که سپرهای "Arduino" به معنای جابجایی با یکدیگر از طریق سیم های نوع "پدر-مادر" است و نه از طریق لحیم کاری، اغلب چیزی، در جایی، اما برگ. بررسی. و به طور کلی همانطور که می گویند الکترونیک علم تماس است.

2. مشکلات تغذیه ای. در جاهایی که 3.3 مورد نیاز است، 5 ولت برق مصرف نکنید. گاهی اوقات دود از ESP8266 خارج می شود. اگرچه از طرف دیگر سیگنال های منطقی دستگاه های پنج ولتی را بدون مشکل هضم می کند.

3. مشکلات منبع تغذیه کافی. ESP8266 ماهیت متوسطی دارد و گاهی اوقات می تواند تقریباً سیصد میلی آمپر را بکشد، اگرچه قبل از آن می توانست با سی آمپر راضی باشد. بر این اساس، تثبیت کننده ضعیف 3.3 ولتی برد آردوینو که بدون هیچ تردیدی آن را به آن متصل کرده اید، بلافاصله در مقادیر میکروسکوپی فرو می رود. و نمی توانید بفهمید که چرا کار می کند یا نمی کند.

4. سردرگمی با نتیجه گیری. همیشه بررسی کنید که کدام سیگنال به کجا می رود. گیرنده RXD باید به فرستنده TXD و همچنین TXD به RXD متصل باشد، اما MOSI باید به MOSI، MISO به MISO و غیره وصل شود.

5. به مقاومت های کششی داخل مدار ESP8266 تکیه نکنید، همیشه پین ​​ها را از طریق مقاومت های خارجی 5 تا 10 کیلو اهم، نه فقط یک جامپر، به صفر یا قدرت بکشید. در غیر این صورت، در بهترین حالت، می توانید مصرف فعلی بی سابقه ای داشته باشید و سپس بوی نامطبوع پلاستیک سوخته را استشمام کنید.

6. علف های هرز نرم افزار. از آنجایی که نرم‌افزار برای کاربران فردی توسط علاقه‌مندان یکسان نوشته می‌شود، هنگام به‌روزرسانی نسخه‌های میان‌افزار، ایراداتی در خود سیستم‌افزار و باگ‌ها ظاهر می‌شوند. با خزیدن در تالارهای گفتگوی مناسب، حتی گاهی به زبان انگلیسی، درمان می شود. حتی برخی از رفقا ادعا کردند که خود تراشه ESP به اندازه هوای سن پترزبورگ مرطوب است، اما از طرف دیگر، این نظر نیز وجود دارد که از سال 2014 (سال انتشار اولین آن) وضعیت به طور چشمگیری بهبود یافته است (برخلاف آب و هوا).

7. اشکالات مرموز. این یک اتفاق نادر اما اعصاب گیر است. به عنوان مثال، من یک دستگاه "Arduino" از راه دور دوخته نشده بودم. بلکه دوخته شده بود اما با خطا. اما اگر کابلی از پروگرامر به آن آویزان بود (اما بدون خود برنامه نویس) بدون خطا دوخته می شد. با خودم گفتم: «YAH» و یک خازن 15 pF را بین پایه انتقال و پایه ساعت لحیم کردم. همه چیز کار کرد. اما روز را کشت.

پس بیایید با ساده ترین شروع کنیم. ما یک اندام مکانیکی MechArm داریم (اما نه آن چیزی که Howard Wolowits ساخته است) ساخت چین و کامپیوتر شخصیبا ویندوز وظیفه این است که برنامه را از راه دور فلش کنید و آن را از طریق رایانه مدیریت کنید.


برای کنترلر، یک روسری مینیاتوری زیبا بردارید آردوینو نانوبا سنگ ATmega328P. این تخته کاملاً داخل بازوی مکانیکی قرار می گیرد.


حالا بیایید تصمیم بگیریم که چگونه آن را برنامه ریزی کنیم. سه روش اصلی برای سیستم عامل راه دور وجود دارد: از طریق رابط SPI، از طریق بوت لودر داخلی، از طریق پورت JTAG.

ساده ترین گزینه البته بوت لودر داخلی (بوت لودر) است. این یک حافظه از پیش نوشته شده در FLASH است، برنامه ای که یک کد را با استفاده از یک پروتکل خاص (مثلاً با استفاده از ساده ترین UART) دریافت می کند و آن را با دستورات خاصی در محل برنامه دانلود شده می نویسد. به عنوان مثال، خود بوت لودر ARDUINO IDE اینگونه کار می کند. پس از ریست یا شروع، لودر مدتی منتظر دریافت اطلاعات می ماند و اگر منتظر نماند، از آدرس صفر شروع به اجرای برنامه می کند. اگر داده وارد شود، آن را در قسمت برنامه می نویسد. پس از ریست بعدی، برنامه بارگذاری شده شروع به اجرا می کند. در جزئیات، شاید من نادرست توصیف کرده ام، اما ماهیت دقیقاً همین است. در نتیجه برای برنامه نویسی فقط به سه پایه نیاز داریم: گیرنده RTD، RESET و GND. به طور کلی، یک فرستنده TRD نیز برای تأیید برنامه ضبط شده استفاده می شود، اما برای کاربردهای ساده نمایشی (نه برای یک نیروگاه هسته ای)، تأیید را می توان حذف کرد.

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

گزینه دوم برنامه نویسی است رابط سریال SPI. در اینجا بوت لودر داخلی وجود ندارد، اما ما با ارسال دستورات خاص و سپس داده ها از طریق رابط فوق برنامه ریزی می کنیم. در اینجا ما یک بوت لودر خارجی داریم، اما هنوز باید آن را بنویسیم. در طول انتقال، علاوه بر RESET و GND، از چهار خروجی اضافی MOSI، MISO - داده، همگام سازی SLK، CS - انتخاب کریستال استفاده می شود. اما به طور کلی می توانید MISO و CS را هم حذف کنید. داده‌ها فقط دریافت می‌شوند (سپس هیچ تأییدی از برنامه وجود نخواهد داشت)، و به هر حال فقط یک کریستال داریم.

هر رویکردی مزایا و معایب خود را دارد (و من به هیچ وجه JTAG را در نظر نگرفتم، زیرا عمر انسان کوتاه است). اما در نهایت به SPI متمایل شدم زیرا برای نوشتن در اسمبلر تنبلی داشتم و لودرهای آماده باز پیدا نکردم (فقط خوب نگاه نکردم).

برای ساخت کانال بیسیمهمانطور که قبلا ذکر شد، تراشه ESP8266 در حال حاضر بسیار شناخته شده را انتخاب کردم - یک میکروکنترلر یا به عبارتی یک SoC کامل (System-on-Chip) از سازنده چینی Espressif با رابط Wi-Fi. علاوه بر Wi-Fi، با توانایی اجرای برنامه ها از حافظه فلش خارجی متمایز می شود. و به طور خاص برای پروژه من، ESP8266-07 را با 512 کیلوبایت حافظه در برد گرفتم.


به طور کلی، هر ESP8266 مناسب است، جایی که پایه های اضافی برای اجرای SPI وجود دارد. بنابراین، ساده ترین ESP8266-01 برای ما مناسب نیست، زیرا دارای پایه های بسیار کمی برای پورت های I / O است. اما از طرف دیگر، تفاوت قیمت برای آنها کمتر از صد روبل است و آنها به همان اندازه در دسترس هستند. خوب، تابلوهای اشکال زدایی بزرگ با ESP، که در آن دسته ای از لوازم جانبی برای راحتی جدا شده اند، نیز برای ما مناسب نیستند، زیرا در جایی که می خواهیم آنها را در دست مکانیکی خود قرار دهیم، مناسب نیستند.

جوهر جهانی این ایده به طور کلی به شرح زیر بود. از کامپیوتر به ESP، بدنه برنامه بارگذاری شده در میکروکنترلر به صورت بی سیم از طریق WI-FI (در شبکه خانگی شما) منتقل می شود. و ESP قبلاً با سیم با استفاده از رابط SPI این برنامه را مستقیماً روی حافظه FLASH میکروکنترلر می‌نویسد. سپس به طور طبیعی آن را ریست می کند و اجازه می دهد برنامه بارگذاری شده اجرا شود. علاوه بر این، ESP باید یک واحد مستقل داشته باشد که تبادل داده با میکروکنترلر را نیز مدیریت کند، زیرا ما می‌خواهیم نه تنها برنامه‌نویسی کنیم، بلکه داده‌ها را نیز با آن تبادل کنیم. به خصوص برای پروژه MechArm، پس از ضبط برنامه، سیگنال های کنترل سروو را نیز ارسال می کنیم تا این بازو به حرکت درآید. بنابراین، در خود ESP، برای ما مطلوب است که بالا ببریم سرور TCPبرای انتقال برنامه و سرور UDP برای کنترل MechArm. بر این اساس، این سرورها به شبکه خانگی می‌پیوندند و با دقت گوش می‌دهند تا ببینند آیا کسی می‌خواهد کد جدیدی را در MechaArm آپلود کند یا آن را برای کسی موج بزند.

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

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

برای کامپیوتر، من همه چیز را در JAVA، محیط IntelliJ IDEA نوشتم. اما در اصل، شما می توانید از هر چیزی استفاده کنید، نکته اصلی برای ما این است که یک مشتری بنویسیم که برنامه ای را برای آن ارسال کند سیستم عامل AVRدر ESP8266.

من برنامه های AVR را در ATMEL STUDIO، به زبان C، به ندرت در اسمبلر می نویسم. من اصولاً از طرح‌های آردوینو استفاده نمی‌کنم، تقریباً هر کتابخانه لازم در یک ساعت دیگر و با درک کامل از کار آن نوشته می‌شود. من اسکچ ها را امتحان کردم، اما تاکنون آن را روی AVR ندارید سیستم عامل، اسکچ ها همچنان لوازم جانبی را از یک دوست می گیرند و مرتباً خراب می شوند. بله، خود آردوینو IDE، در مقایسه با ATMEL STUDIO، البته، یک چیز بسیار ابتدایی است. اما در اینجا، البته، این سؤال قابل بحث است، برای علوم انسانی و دانش آموزان مدرسه، احتمالاً با طرح ها سرگرم کننده تر و آسان تر خواهد بود.

برای برنامه نویسی ESP8266 از فریمور NodeMCU استفاده کردم و برنامه ها را با Lua نوشتم. نه، من دوست دارم به زبان جاوا و سی بنویسم، اما هیچ کدام در ESP وجود ندارد. استفاده از زبان Lua برای کار ما دشوار نیست، تسلط بر آن چند چیز کوچک است. و در واقع، برای دانلود برنامه ها و اشکال زدایی آنها در ESP، IDE ESPlorer را گرفتم. داخلی محصول رایگان(اما می توانید به نویسنده کمک مالی کنید) که البته با محیط های ذکر شده در بالا قابل مقایسه نیست، اما همانطور که می گویند به یک اسب هدیه ... اما برای استفاده از ESPlorer و نوشتن در LUA ابتدا باید سیستم عامل اصلی (تهیه شده از سازنده) در تراشه ESP8266 را به یک جدید تغییر دهید. در این شرکت، برنامه NODE MCU PyFlasher به ما کمک خواهد کرد. به یک معنا، به تجدید آن کمک خواهد کرد. و ما خود سفت‌افزار را می‌سازیم و در وب‌سایت سازندگان NodeMCU در دستان خود قرار می‌دهیم و می‌توانید در مورد این فرآیند بیشتر بخوانید.

همه چیز بسیار در دسترس و قابل درک است. ما پشتیبانی SPI و عملیات بیت را به کتابخانه های پایه اضافه می کنیم (در LUA، در مورد ما، عملیات بیت بیش از حد بارگذاری می شود و کاربرد کمی دارند). شما نباید کتابخانه های زیادی را داخل فریمور فرو کنید، زیرا به دلیل وجود انواع نرم افزارها، حافظه بسیار کمی روی ESP8266 باقی می ماند، مقداری 20 کیلوبایتی بد.

البته، شما فقط می توانید سیستم عامل آماده را بردارید، که در حال حاضر تعداد زیادی از آنها در اینترنت آویزان است، اما من آن را توصیه نمی کنم. فقط به این دلیل که برخی از عملیات بیت را پشتیبانی نمی کنند (و ما به آنها نیاز داریم) و هیچ تنظیمی در مورد نرخ انتقال داده از طریق SPI وجود ندارد.
بر این اساس، آنها به طور پیش فرض با سرعت 40 مگاهرتز تقسیم بر مقداری ضریب کوچک منتقل می شوند و بنابراین AVR زمان هضم آنها را ندارد.

اگر برای ایجاد سفت‌افزار تنبل هستید، می‌توانید نسخه من را از ابر دانلود کنید.

اکنون ما سیستم عامل را داریم و باید آن را به جای نسخه پایه در ESP8266 بارگذاری کنیم. برای این کار به یک آداپتور USB-UART ساده نیاز داریم.


ما پایه های TXD را به RXD و RXD را به TXD وصل می کنیم، یک زمین مشترک ایجاد می کنیم، اما همانطور که به نظر می رسید از یک خروجی برق 3.3 ولت مناسب روی آداپتور استفاده نمی کنیم. در بیشتر موارد، ESP8266 آن را کاملاً هدر می دهد. بنابراین، ما آن را به طور جداگانه درخواست می کنیم. سپس ESP را در حالت برنامه نویسی قرار می دهیم (GP0 به زمین، اگر کسی فراموش کرد) و NODE MCU PyFlasher را اجرا می کنیم.

مهمتر از همه، فراموش نکنید که فلش مموری را پاک کنید (بله، تمام داده ها را پاک می کند)، در غیر این صورت، بسته به نسخه سیستم عامل، ممکن است پس از برنامه ریزی در حافظه باقی بماند. زباله های غیر ضروری، که به نوبه خود زباله ها را در طول کار بعدی به کنسول می ریزد. قبل از آن، من از نرم افزاری استفاده می کردم که در آن هیچ گزینه ای برای پاک کردن حافظه از قبل وجود نداشت، به شدت رنج می بردم، زیرا هیچ چیز کار نمی کرد. و تابوت تازه باز شد، فقط حقیقت در انجمن انگلیسی زبان سازندگان NODE MCU است.

زائیمف سیستم عامل مورد نظراکنون می‌توانیم برنامه‌ها را به زبان LUA بنویسیم و اشکال‌زدایی کنیم (MicroPython هم وجود دارد، اما من از آن استفاده نکردم) با استفاده از APIهای بسیار راحت از NODE MCU. ما ESPlorer را که قبلا ذکر شد راه اندازی می کنیم.

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

اکنون ما در حال نوشتن یک برنامه در LUA هستیم که سپس آن را در ESP8266 آپلود می کنیم:

بوت لودر Lua برای AVR که روی ESP8266 نوشته شده است

تابع InstrProgrammingEnable () -- دستورالعمل MC "فعال کردن برنامه نویسی" p=0 در حالی که p<31 do p=p+1 pin=8 gpio.write(pin, gpio.LOW) spi.send(1, 0xAC,0x53) read = spi.recv(1, 8) spi.send(1,0,0) gpio.write(pin, gpio.HIGH) if (string.byte(read)== 83) then print("connection established") p=33 if(p==31) then print("no connection") end end end end functionProgrammingDisable() pin=2--انتهاي ESET FOR MK gpio.mode(pin, gpio.INPUT) pin=8 gpio.mode(pin, gpio.INPUT) pin=5--CLK MASTER for SPI gpio.mode(pin, gpio. INPUT) پین=6--MISO MASTER برای SPI gpio.mode(پین، gpio.INPUT) پین=7--MOSI MASTER برای SPI gpio.mode(پین، gpio.INPUT) پایان تابع ProgrammingEnable() pin=2-- RESET FOR MK gpio.mode(pin,gpio.OUTPUT) gpio.write(pin,gpio.LOW) pin=2--POZITIV FOR 4MSEC RESET FOR MK gpio.mode(pin,gpio.OUTPUT) gpio .write(pin,gpio.HIGH) tmr.delay(4) gpio.mode(pin,gpio.OUTPUT) gpio.write(pin,gpio.LOW) tmr.delay(25000) پایان تابع InstrFlashErase() pin=8 gpio.write(pin,gpio.LOW) spi.send(1,0xAC,0x80,0,0) gpio.write(pin,gpio.HIGH) tmr.delay(15000) pin=2--RESET FOR MK gpio.mode(pin, gpio.OUTPUT) gpio.write(pin, gpio.HIGH) tmr.delay(20000) gpio.write(pin, gpio.LOW) print("FLASH پاک شد") InstrProgrammingEnable () end تابع InstrStorePAGE (H، آدرس، داده) pin=8 gpio.write(pin,gpio.LOW) spi.send(1,H,0,address,data) gpio.write(pin,gpio.HIGH) tmr.delay(500) end تابع InstrWriteFLASH(page_address_low,page_address_high) pin=8 gpio.write(pin,gpio.LOW) spi.send(1,0x4C,page_address_high,page_address_low,0) gpio.write(pin,gpio.HIGH) tmr.delay(5000)-- گاهی اوقات فلش نوشته نمی شود زمانی که تاخیرهای کوتاه به پایان می رسد برنامه نویسی تابع (بارگذاری بار) pin=8--CS MASTER برای SPI gpio.mode(pin, gpio.OUTPUT, gpio.PULLUP) pin=4--LED LIGHT ON LOW gpio.mode(pin, gpio.OUTPUT) gpio.write(pin, gpio. LOW) print(string.len(payload)) page_count = 7 -- نوشتن 1 کیلوبایت برای k = 0 ,page_count ,1 do -- تعداد صفحات برای i=0 , 127, 2 do -- -1 آدرس = i/ 2 data=payload:byte(i+1+128*k) اگر داده == صفر، داده = 0xff end InstrStorePAGE(0x40،آدرس،داده) -- tmr.delay(100)-- در غیر این صورت به موقع داده نمی نویسد = payload:byte(i+1+1+128*k) اگر داده == صفر، داده = 0xff end InstrStorePAGE(0x48,address,data) -- tmr.delay(100) end page_address_low=bit.band(k ,3 )*64 -- 3 باینری 11 page_address_high=k/4+frame1024*2 tmr.delay(1000) InstrWriteFLASH(page_address_low,page_address_high) tmr.wdclr() end pin=4--LED gpio.mode.(pin,gpio OUTPUT) gpio.write(pin, gpio.HIGH) end -- بلوک اصلی wifi.setmode(wifi.STATION) --wifi.sta.config("نام شبکه"،"رمز عبور") -- SSID و رمز عبور نقطه دسترسی خود را تنظیم کنید station_cfg=() tmr.delay(30000) station_cfg.ssid=" نام شبکه" tmr.delay(30000) station_cfg.pwd="رمز عبور" tmr.delay(30000) wifi.sta.config(station_cfg) tmr.delay(30000) wifi.sta.connect() tmr.delay(1000000) چاپ (wifi.sta.status()) print(wifi.sta.getip()) در حالی که (wifi.sta.status()~=1) if(wifi.sta.status()==5) را انجام دهید سپس پایان پایان را قطع کنید sv=net.createServer(net.TCP,30) tmr.delay(100) print("SERVER READY") sv:listen(4000,function(c) c:on("دریافت"، تابع(c، محموله) چاپ (payload) if (payload =="program\r\n") سپس c:send("ready\r\n") print("ready for program\r\n") spi.setup(1, spi.MASTER , spi.CPOL_LOW, spi.CPHA_LOW, spi.DATABITS_8,320,spi.FULLDUPLEX) ProgrammingEnable () tmr.delay(100) InstrProgrammingEnable () tmr.delay(100) InstrFlashErase() tmr.0-1(124=1 فریم -تعداد فریم های ارسال شده st=net.createServer(net.TCP,30) st:listen(4001,function(c) c:on("receive" , function(c, payload) tmr.wdclr() برنامه نویسی (payload) frame1024=frame1024+1 end) end) end if (payload =="data\r\n") سپس c:send("ready\r\n" ") print("ready for data\r\n") srv=net.createServer(net.UDP) tmr.delay(1000) pin=10 gpio.write(pin, gpio.HIGH) uart.setup(0.9600 ,8 ,0,1,0) srv:listen(5000) srv:on("receive", function(srv, pl) pl=pl*1 --print(pl) uart.write(0,pl) tmr. wdclr( ) end) end if (payload =="stop\r\n") سپس if(st~=nil) سپس st:close() frame1024=0 ProgrammingDisable () print("stop program") end if(srv ~= صفر) سپس srv:close() print("stop data") end end end) end) end)


جایی که توابع مربوطه موارد زیر را انجام می دهند:

تابع InstrProgrammingEnable()- میکروکنترلر را با دستور خاصی که از طریق SPI ارسال می شود در حالت برنامه نویسی قرار می دهد.

تابع ProgrammingEnable()- فقط قبل از برنامه نویسی AVR را برای 25 میلی ثانیه تنظیم مجدد کنید

functionProgrammingDisable()- پس از برنامه نویسی، پین های SPI را در ESP8266 به حالت غیرفعال منتقل می کنیم تا هنگام اجرای کد روی میکروکنترلر با ما تداخل نداشته باشند (ناگهان در آنجا استفاده می شوند)

تابع InstrFlashErase()- قبل از شروع برنامه نویسی، فلش مموری را روی میکروکنترلر بازنویسی کنید. چرا این نیاز به توضیح دارد ضروری نیست.

تابع InstrStorePAGE (H، آدرس، داده)- با این دستور یک بایت برنامه در بافر داخلی میکروکنترلر نوشته می شود. اما این خود رکورد فلش نیست، زیرا فلش در اینجا 128 بایت نوشته شده است.

تابع InstrWriteFLASH(page_address_low,page_address_high)- اما این یک ضبط فلش ​​است و زمان می برد، به تاخیر زمانی 5000 میکرو ثانیه توجه کنید.

برنامه نویسی تابع (بارگذاری بار)- بزرگترین و مهمترین تابع با استفاده از توابع بالا. برنامه انتقال داده شده را در قطعات 1024 بایتی می گیرد، آنها را به بایت ها تقسیم می کند و آدرس هایی را برای آنها تشکیل می دهد و سپس آنها را به میکروکنترلر در بافر داخلی می فرستد و هر 128 بایت نوشتن فلش را مقدار دهی اولیه می کند. سپس کیلوبایت کد بعدی را می گیرد و عمل را تکرار می کند، طبیعتاً با یک افست در آدرس ها، تا بیشتر بنویسد و آنچه نوشته شده را بازنویسی نکند. در ابتدا سعی کردم کل برنامه ها را ارسال کنم، اما اگر ESP8266 از 6 کیلوبایت بیشتر شود، حافظه موجود به سادگی تمام می شود و از کار می افتد. یک کیلوبایت راحت ترین واحد است، زیرا به طور منظم به قطعات تقسیم می شود و به راحتی از طریق TCP منتقل می شود (ما هنوز باید آن را از رایانه دریافت کنیم). اندازه بزرگتر نیز مورد نیاز نیست، TCP، می دانید، در نسخه فعلی بسته ارسالی را به 1500 بایت یا چیزی محدود می کند (اما به دلایلی من 1440 را منتقل کردم).

مهم نیست چقدر سخت است، اما باید بر چند دام غلبه کرد.

ما در یک شبکه بی سیم ثبت نام می کنیم.

ابتدا یک سرور TCP ایجاد می کنیم که به سه دستور گوش می دهد:

1. "برنامه" (ما برنامه ریزی خواهیم کرد)،

2. "داده" (ما داده ها را مبادله خواهیم کرد)،

3. "ایست" (ما همه چیز را متوقف می کنیم).

اگر در حال برنامه نویسی هستیم، ابتدا SPI را مقداردهی اولیه می کنیم و سرور TCP دیگری ایجاد می کنیم که داده ها (کد برنامه فلش شده) را در هر کیلوبایت می گیرد و توابع برنامه نویسی میکروکنترلر را برای آنها فراخوانی می کند. می‌دانم که ایجاد سرور دوم احمقانه به نظر می‌رسد، اما این یک ضرورت است، زیرا API محلی از ایجاد تنها یک سوکت پشتیبانی می‌کند و ما باید دستورات «برنامه» و «داده» را با خود داده‌های ارسالی جدا کنیم. چون از نظر چشمی تفاوتی با هم ندارند، در اینجا بایت ها و بایت ها وجود دارد.

اگر می‌خواهیم نه برنامه‌نویسی، بلکه تبادل داده‌ها، ارسال آنها به میکروکنترلر، ابتدا رشته «داده» را از طریق TCP ارسال می‌کنیم. در پاسخ به این، یک سرور UDP از قبل ایجاد خواهد شد (به شما یادآوری می کنم که ما به صورت پویا با یک دست مکانیکی کنترل می کنیم و نیازی به تاخیر در تشکیل بسته های TCP نداریم و در واقع یک بایت را به عنوان یک کل فریم TCP با رفتارهای بد ارسال می کنیم. ). و دیتاگرام های UDP کوچک خواهند بود و به سرعت تشکیل می شوند.

پس از آن UART مقدار دهی اولیه می شود و هر بایت دریافتی به صورت بی سیم از طریق سیم TXD به میکروکنترلر ارسال می شود که در صورت فلش شدن برنامه مربوطه در آنجا موظف به پذیرش آن است. همچنین سازماندهی تبادل داده در جهت دیگر دشوار نیست، اما من هنوز آن را اجرا نکرده ام.

خوب، در دستور توقف، سرورهای فوق (به جز همان اولی) اتصالات را می بندند و مهم ترین سرور دوباره به حالت انتظار برای دستورات "برنامه" و "داده" می رود.

از آنجایی که رابط SPI به صورت برنامه‌ریزی در ESP8266 شبیه‌سازی می‌شود، می‌توانید از هر پورت ورودی/خروجی برای سیگنال‌های CS، CLK، MISO، MOSI، RESET (برای AVR) موجود استفاده کنید، و نه آن‌هایی که در بوت‌لودر من نشان داده شده‌اند. علاوه بر این، معلوم شد که CS و MISO، در اصل، در این مورد نیز می توانند قطع شوند، بدون آنها کار خواهد کرد. خوب، روی LED تعبیه شده در برد ESP8266 از یک خروجی استفاده می شود که گاهی چشمک می زند و نشان می دهد که برنامه هنوز زنده است.

هیچ بررسی برای خطاهای نوشتن وجود ندارد (به جز اولین درخواست به AVR، اما این اطلاعات به سادگی روی کنسول نمایش داده می شود)، EEPROM برنامه ریزی نشده است، بیش از 32 کیلوبایت دوخته نشده است - به طور خلاصه، هنوز چیزی برای کار وجود دارد. بر. نرخ تبادل از طریق SPI تقریباً 115 کیلوبیت بر ثانیه است، همه چیز در چند ثانیه فلش می شود، تقریباً مانند یک برنامه نویس سریال معمولی مانند ISP500).

کد را بردارید، شبکه ها و رمزهای عبور خود را وارد کنید، در ESplorer کامپایل کنید، آن را "init" صدا کنید (برای اجرا در راه اندازی مجدد) و آن را به ESP8266 ارسال کنید. باید کار کند. حداقل به معنای کار به عنوان یک برنامه نویس بی سیم.

اکنون به سمت کنترل - یک رایانه شخصی می پردازیم.

در واقع باید فایل HEX را که برنامه های نوشته شده شما در محیط ATMEL STUDIO به آن تبدیل می شوند، برداریم و از طریق WI-FI به پورت سوکتی که می شناسیم (در این مورد 4000) ارسال کنیم. نکته کوچک این است که ما به یک فایل BIN باینری برای ارسال نیاز داریم و ATMEL STUDIO فقط ما را با HEX خوشحال می کند. در اینجا دو خروجی وجود دارد. یا با یک برنامه مبدل مخصوص مانند WinHex آن را به فرمت BIN تبدیل کنید یا خودتان در برنامه خود این کار را انجام دهید. من هنوز این کار را نکردم، اما به نظر می رسد سخت نیست، باید عنوان را قطع کنید و کار دیگری انجام دهید.

در نتیجه، من برنامه لودر را در JAVA نوشتم (عمدتاً به این دلیل که کار دیگری را نمی دانم) و در محیط ساده و رایگان IntelliJ IDEA کار کردم. این یک سرویس گیرنده TCP ایجاد می کند که به دنبال سروری است که روی ESP8266 اجرا می شود. اگر آن را پیدا کرد، با آن تماس می گیرد و فایلی را که در فلان آدرس قرار دارد برای آن ارسال می کند. کد زیر

آپلود کننده فایل JAVA که در سمت رایانه شخصی اجرا می شود

واردات java.io.*؛ واردات java.net.*; وارد کردن java.util.ArrayList; وارد کردن java.util.List. شبکه عمومی کلاس ( public static void main (String args) (Http_client جدید (4000)؛ )) کلاس Http_client Thread را گسترش می دهد ( پورت int; String s؛ String Greetings_from_S؛ Http_client(int port)( this.port = port; start(); ) public void run() (//192.168.1.113 آدرس ESP8266 در شبکه من است اما به طور کلی، از ارتباط با روتر یاد می شود // بهتر است آن را ثابت کنید، روترها می توانند این کار را انجام دهند (Socket socket = new Socket("192.168.1.113", port)) ( PrintWriter pw = new PrintWriter( New OutputStreamWriter(socket.getOutputStream()),true)؛ pw.println("برنامه");// سلام با SERVER System.out.println("برنامه")؛ BufferedReader br = BufferedReader جدید (InputStreamReader(سوکت جدید .getInputStream()))؛ Greetings_from_S = br.readLine(); System.out.println(Greetings_from_S); if(Greetings_from_S.equals("ready")) ( (پرونده فایل = فایل جدید ("d:BlinkOUT.bin) را امتحان کنید ");// آدرس فایل برای آپلود BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))؛ داده بایت = بایت جدید؛ bis.read(داده؛ بایت data_buffer = بایت جدید؛ فریم های int = data.length/1024 ؛ سیستم m.out.println(قاب); int residence = data.length%1024; برای (int i = 0; i< frames;i++) { for (int k = 0; k< (1024); k++) { data_buffer[k] = data; } sendingChunk(data_buffer); } byte data_buffer2= new byte; for (int i = 0; i < residy;i++) { data_buffer2[i] = data; } sendingChunk(data_buffer2); pw.println("stop");// System.out.println("stop program"); } catch (Exception e) { System.out.println(e); } } } catch (Exception e) { System.out.println(e); } } public void sendingChunk (byte data_buffer){ try (Socket socket = new Socket("192.168.1.113", 4001)){ BufferedOutputStream bos = new BufferedOutputStream((socket.getOutputStream())); bos.write(data_buffer); bos.flush(); System.out.println(data_buffer.length); } catch (Exception e) { System.out.println(e); } } }


در اینجا ، البته ، چیزهای اضافی از بین می روند ، در اصل به همه انواع آماده نیازی نیست. اگر یک اتصال TCP ایجاد شود، آنگاه برقرار است. تنها مشکل این بود که فایل نمی خواست حتی در تکه های 1024 بایتی ارسال شود، همانطور که من واقعاً نیاز داشتم، اگرچه من به صراحت اندازه آن را ذکر کردم. ظاهرا یک بافر نهایی غیرقابل دسترسی از JAVA وجود دارد و بسته هایی را در اندازه ای که می خواهد ارسال می کند که برای طرف گیرنده کاملاً غیرقابل قبول است. ابتدا سعی کردم یک تاخیر ایجاد کنم تا بافر از انتظار برای قطعات بعدی خسته شود و آن را همانطور که هست ارسال کرد. اما تاخیر زمانی شروع به کار کرد که به 10 ثانیه رسید، که به نوعی به نظر من برای یک کیلوبایت ارسالی کمی بیش از حد به نظر می رسید.

اما بعد متوجه شدم که به دلایلی اولین قطعه همیشه دقیقاً مطابق سفارش پیش می رود و یک باکانالیای غیرقابل پیش بینی از قطعه دوم شروع می شود. بنابراین، من آن را طوری ساختم که مشتری یک اتصال را باز کرد، بخشی از کد را در 1024 بایت ارسال کرد و اتصال را بسته بود. و به همین ترتیب تا زمانی که کل فایل ارسال شود. همه چیز با موفقیت کار کرد.

تنها نکته این است که برای اجرای آن باید محیط اجرا JAVA را بر روی کامپیوتر خود نصب کنید. اما من معمولاً بلافاصله از IntelliJ IDEA شروع می کنم زیرا همیشه می توانید آنچه را که در کنسول اتفاق می افتد مشاهده کنید (اما در اینجا محیط JAVA نیز مورد نیاز است). اگرچه، البته، به روشی هوشمندانه باید یک رابط کاربری گرافیکی ایجاد کنید. یعنی پنجره ای که مسیر فایل از بین می رود، امکان تغییر شماره پورت در همان پنجره و خوب و موارد ضروری دیگر. و همه اینها را در قالب یک فایل اجرایی جمع آوری کنید.

و تاپریچا، همانطور که کوروویف می گفت، بیایید شهروندان را در واقع به اندام مکانیکی MechArm که در همان ابتدا ذکر شد برگردانیم. ما اکنون توانایی برنامه ریزی از راه دور و سپس کنترل آن را داریم. بیایید به برنامه کنترل در کنار میکروکنترلر برویم.

در این حالت باید چهار سروو را کنترل کنیم. اینها هستند.


چنین درایوی توسط پالس های مستطیلی، دوره 20 میلی ثانیه (50 هرتز) با چرخه کاری 2 تا 4 درصد کنترل می شود. یعنی 2% چرخش کامل در یک جهت است، 4% در جهت دیگر. وظیفه فقط برای PWM داخلی در AVR است.

یک سروو برای حرکت راست به چپ استفاده می شود. دوم روی خودتان - از خودتان؛ سوم بالا به پایین؛ چهارم خود پنجه است که باید فشرده و باز شود. همه چیز به زبان C نوشته شده و در یک فایل HEX در ATMEL STUDIO کامپایل شده است. ظاهر کمی عجیب این برنامه به این دلیل است که در ابتدا عقربه از صفحه کلیدی که توسط سیم به میکروکنترلر بسته شده بود کنترل می شد. اما سیم ها دیروز هستند، ما باید بیشتر تکامل پیدا کنیم.

البته می توانید از طرح هایی برای سرووهای "ARDUINO" استفاده کنید، اما من آنها را دوست نداشتم. نوشتن به تنهایی سرگرم کننده تر است. علاوه بر این، زمانی که PWM به نوبت به هر سروو سوئیچ می شود، هر چهار سروو باید به طور همزمان کار کنند و نه در حالت مالتی پلکس. زیرا هیچ کس گرانش را لغو نکرده است و اگر تکانه های کنترلی از دریافت تکانه های کنترلی به سرووی مربوطه خودداری کنند، اندام بلند شده فوراً سقوط می کند. من مطمئن نیستم که طرح "ARDUINO" عملکرد همزمان برای چهار سروو را فراهم می کند یا خیر. اما ما خودمان می توانیم برنامه ای بنویسیم که شرایط لازم را برآورده کند. و به طور کلی، در غیاب سیستم عاملی که گوسفندان را از بزها جدا می کند، استفاده از طرح هایی که برای تجهیزات جانبی میکروکنترلر رقابت می کنند (و ما حتی از قبل نمی دانیم کدام یک) بیش از حد باگ تولید می کند.

در اینجا کد واقعی است که با استفاده از ESP8266-07 به آردوینو نانو می نویسیم.

برنامه کنترل MechArm برای میکروکنترلر AVRmega328P

#تعریف F_CPU 16000000 #شامل #عبارتند از // اعداد صحیح استاندارد #include #عبارتند از // ریاضی #شامل //ورودی/خروجی استاندارد #شامل #عبارتند از #عبارتند از //ویژگی‌های استاندارد #define UART_BAUD_RATE 115200 // شمارنده T1 فاصله زمانی 20 میلی‌ثانیه را تنظیم می‌کند #define COUNTER1_OFF TCCR1B=0b00000000 // CS02 CS01 CS00 - 000 - غیرفعال. 001 بدون تقسیم کننده؛ 010 با مقسوم علیه 8; 011-64; 100 -256; 101 -1024 #define COUNTER1_ON TCCR1B=0b00000011 // شمارنده T0 پهنای پالس کنترل را برای سرووهای PB0 و PB1 تنظیم می کند #define COUNTER0_OFF TCCR0B=0b00000000 // CS02 -CS0 CS00 disable; 001 بدون تقسیم کننده؛ 010 با مقسوم علیه 8; 011-64; 100 -256; 101 -1024 #define COUNTER0_ON TCCR0B=0b00000100 // شمارنده T2 پهنای پالس کنترل را برای سرووهای РB2(PD6) و РВ3(PD7) تنظیم می کند #define COUNTER2_OFF TCCR2B=0b00000000-CS0/CS00000 001 بدون تقسیم کننده؛ 010 با مقسوم علیه 8; 011-64; 100 -256; 101 -1024 #define COUNTER2_ON TCCR2B=0b00000110 volatile uint16_t period_20ms; فرار uint8_t State_of_keyboard; فرار uint8_t start_position ; فرار int8_t number_servo; ISR(USART_RX_vect)// وقفه برای UART ( State_of_keyboard=UDR0; return; ) ISR(TIMER0_COMPA_vect)// سروو PB0 عرض پالس کنترل (PORTB &=~(1<<0); TIMSK0&=~(1<
اصل برنامه از متن و نظرات مشخص است. ما از شمارنده T1 برای یک دوره مرجع 20 میلی‌ثانیه و شمارنده‌های T0، T2 برای صدور سیگنال‌های PWM به چهار خط پورت I/O استفاده می‌کنیم، زیرا هر یک از این دو شمارنده می‌توانند برای دو دستگاه کار کنند.
این برنامه با بارگذاری رجیسترهای شمارش OCR0A، OCR0B، OCR2A، OCR2B، موقعیت های اولیه سرووها را تنظیم می کند. ثابت های محدود کننده نیز معرفی شده اند، زیرا ما همیشه به یک دهانه 180 درجه نیاز نداریم. خوب، در ادامه، با وقفه از UART، برنامه شماره ارسال شده توسط ESP8266 (از 1 تا 8) را می گیرد و آن را به دستوری برای سرووی مربوطه ترجمه می کند. چهار درایو وجود دارد که هر کدام در دو جهت کار می کنند، بنابراین اعداد صحیح از یک تا هشت کافی است. پس از انتخاب یک عدد، محتویات رجیسترهای شمارنده فوق الذکر افزایش یا کاهش می یابد، به ترتیب چرخه وظیفه پالس کنترل و زاویه چرخش سروو انتخاب شده تغییر می کند. درایوهایی که ما انتخاب نکردیم مقدار قدیمی زاویه چرخش را حفظ می کنند (زیرا محتویات رجیسترهای مربوطه، اگرچه به روز شده اند، اما تغییر نکرده اند) و بازوی مکانیکی را در همان موقعیت نگه می دارند.

اکنون فقط باید یک برنامه کنترل بنویسیم، با عرض پوزش برای توتولوژی، تا بازوی مکانیکی را مستقیماً از رایانه از طریق WI-FI کنترل کند.
کد نیز به زبان JAVA نوشته شده است، اما کمی ابداع شده است. یک رابط کاربری گرافیکی و امکان ویرایش شماره پورت و آدرس شبکه ESP8266 وجود داشت.

آنچه در آنجا اتفاق می افتد از پنجره مشخص است. من متن برنامه را در اینجا ارائه نمی دهم (در اینجا موجود است

من یک دستگاه ساخته شده با آردوینو uno دارم:

    نرم افزار آردوینو روی آردوینو uno نصب شده است

    می توان با دستورات سریال کنترل کرد

    با دکمه های فیزیکی و سنسورها قابل کنترل است

    وقتی هر دکمه/سنسوری تغییر می کند، وضعیت فعلی را در سریال می نویسد

    اگر در عرض 5 ثانیه هیچ پیامی ارسال نشده باشد، یک پیام سریال بدون تغییر ارسال می کند

چه چیزی نیاز دارید:

    از ESP8266 برای ایجاد پلی بین نرم افزار فعلی آردوینو و MQTT/web استفاده کنید

    من می‌توانم ESP8266 را به‌عنوان یک وب سرور، کلاینت MQTT و غیره با استفاده از Arduino IDE یا Lua برنامه‌ریزی کنم (اما Arduino IDE را ترجیح می‌دهم زیرا می‌توانم از بخش‌هایی از کد برای تولید/تفسیر ارتباطات مجدد استفاده کنم).

    ESP8266 تمام موارد مورد نیاز برای wifi/web/MQTT را انجام خواهد داد. بدون ماژول MQTT، بخش آردوینو به طور مستقل کار می کند، تنها کنترل از راه دور وجود ندارد.

    من می خواهم حداقل تغییرات را در کد آردوینو ایجاد کنم (یا در صورت امکان هیچ کدام). هر گونه تغییری نیاز به آزمایش مجدد گسترده ای دارد که سعی می کنم از آن اجتناب کنم.

    ESP8266 ممکن است در برخی از نصب ها در دسترس نباشد.

چه گزینه هایی پیدا کردم:

    <�Литий>استوار

ESP8266 می تواند خروجی سریال را بخواند و پلی بین شبکه/MQTT و سریال باشد، وضعیت فعلی را در حافظه ذخیره می کند تا در صورت درخواست ارسال شود تا از نظرسنجی دستگاه در هر بار جلوگیری شود.

یکی از مزایا عدم نیاز به تغییر کد/تست برای قسمت آردوینو است.

آردوینو را به I2C Master و ESP8266 Slave (یا برعکس) تبدیل کنید و ارتباطات دو جهته را پیاده سازی کنید. با خواندن این موضوع به این ایده رسیدم.

اطلاعات دیگر در مورد دستورات سریال:

یک بسته داده (توضیح دستور یا وضعیت) از 1 تا 20 کاراکتر با حداکثر حداکثر 20 بسته در 5 ثانیه و به طور متوسط ​​یک بسته در هر 3 ثانیه تشکیل شده است. در صورت نیاز، می توانم این را برای ارسال 5 عدد صحیح بدون علامت به جای کاراکترهای الفبایی دریافت کنم.

اگر بیش از پین های I2C/سریال مورد نیاز است، می توانم به آردوینو مگا ارتقا دهم (بنابراین تعداد پین های رایگان مشکلی ندارد).

آیا گزینه های دیگری برای این کار وجود دارد؟ (پروتکل ها، کتابخانه های خارج از قفسه برای ارتباط سریال و غیره). من سعی می کنم چرخ را دوباره اختراع نکنم.

ممنون بخاطر وقتی که گذاشتید!

3

1 پاسخ

اکثر آموزش‌های I2C هر آردوینو را به صورت Slave و Master می‌سازند، اما این بهتر است زیرا هر آردوینو یا Master است یا Slave (نه هر دو) و نیازی به تعویض نیست. این کار را آسان تر می کند.

I2C بهتر از سریال است زیرا می توانید آردوینوهای بیشتری را به همان باس اضافه کنید.

من I2C را بین دو آردوینو پیاده‌سازی کرده‌ام و سخت‌تر از خواندن/نوشتن در پورت سریال نیست (که قبلاً انجام دادید). و من مطمئن هستم که می توانید کد پورت سریال خود را برای کار با ارتباط سریال و I2C تعمیم دهید.

این مثال من است (فقط یک اثبات مفهوم). Slave Arduino برخی از پین ها، دما را کنترل می کند. سنسور و تایمر نگهبان به سفارش استاد آردوینو. اگر Slave بیتی را به موقع دریافت نکند، Arduino master را ریست می کند.

کد اصلی

#include #define CMD_SENSOR 1 #define CMD_PIN_ON 2 #define CMD_PIN_OFF 3 #define CMD_LUMEN 4 #define CMD_BEAT 5 const byte SLAVE_ADDRESS = 42; const byte LED = 13; charbuffer; void setup() (Serial.begin(9600)؛ Serial.println("Master")؛ Wire.begin(); pinMode(LED، OUTPUT)؛ digitalWrite(LED، HIGH)؛ Delay(1000) DigitalWrite(LED، LOW؛ Wire.beginTransmission (SLAVE_ADDRESS)؛ Serial.println ("ارسال LED روشن")؛ Wire.write (CMD_PIN_ON)؛ Wire.write(2); Wire.write(10)؛ Wire.endTransmission(); int x = Wire.requestFrom(SLAVE_ADDRESS, 1); Serial.print("status="); Serial.println(x); ) //پایان حلقه خالی تنظیم () ( Serial.println("."); Wire.beginTransmission (SLAVE_ADDRESS)؛ Wire.write(CMD_SENSOR)؛ Wire.endTransmission(); int x = Wire.requestFrom(SLAVE_ADDRESS, 1); Serial.print ("Disponibles = "); Serial.println(x)؛ دمای بین المللی = ( () ()<< 8 | Wire.read(); Serial.print("Light="); Serial.println(light); Wire.beginTransmission (SLAVE_ADDRESS); Wire.write (CMD_BEAT); Wire.endTransmission(); Wire.requestFrom(SLAVE_ADDRESS, 1); delay (5000); } //end of loop

کد هدایت شده

/* Esclavo I2C Recibe los siguientes comandos<- 1° byte -> <- 2° byte -> <- 3° byte ->CMD_SENSOR CMD_PIN_ON n° de pin duacion and segundos CMD_PIN_OFF n° de pin CMD_LUMEN CMD_BEAT Cada comando recibe una respuesta, ya sea el valor pedido o un status. */ #include #include typedef struct ( int pin; unsigned long off; ) PIN_PGMA; /* List de pines que se pueden activar از طریق CMD_PIN_ON. */ #define PIN_LUMEN A0 #define PIN_LED 2 #define PIN_RESET 3 PIN_PGMA pgma = ( (PIN_LED, 0), (PIN_RESET, 0) ); const int pgmaSize = sizeof(pgma)/sizeof(PIN_PGMA); #define CMD_SENSOR 1 #define CMD_PIN_ON 2 #define CMD_PIN_OFF 3 #define CMD_LUMEN 4 #define CMD_BEAT 5 #define ST_OK 0 #define ST_BAD_PIN 1 #define ST_TIME_PIN 1 #define ST_TIME_PIN 1 #define ST_TIME_FIN_OFF 3 #define ST_TIMEe_0 /BADYe Pasado // ese tiempo, se activa el PIN_RESET. // En milisegundos. #define BEAT_INTERVAL 10000 unsigned long lastBeat; // Largo del reset en milisegundos. #define RESET_LENGTH 250 بایت cmd = 0; وضعیت بایت = 0; int thermoDO = 11; int thermoCS = 12; int thermoCLK = 13; ترموکوپل MAX6675 (thermoCLK، thermoCS، thermoDO)؛ تنظیم void () (Serial.begin(9600)؛ pinMode(PIN_LUMEN, INPUT); analogRead(PIN_LUMEN)؛ برای (int i = 0؛ i< pgmaSize; i++) { pinMode(pgma[i].pin, OUTPUT); digitalWrite(pgma[i].pin, LOW); } lastBeat = millis(); Wire.begin (MY_ADDRESS); Wire.onReceive (receiveCommand); Wire.onRequest (sendAnswer); } void loop() { unsigned long now = millis(); // Baja la linea de RESET si no ha recibido un beat ultimamente. unsigned long diff = now - lastBeat; if (diff >BEAT_INTERVAL) ( resetPin(); ) // Recorre la lista de pines y apaga aquellos cuyo tiempo termino. برای (int i = 0; i< pgmaSize; i++) { if (pgma[i].off >0 && pgma[i].off<= now) { Serial.print("off pin="); Serial.println(pgma[i].pin); pgma[i].off = 0; digitalWrite(pgma[i].pin, LOW); } } } // called by interrupt service routine when outgoing data is requested void sendAnswer() { byte temp; int lightReading; switch (cmd) { case CMD_SENSOR: temp = thermocouple.readCelsius(); Wire.write(temp); break; case CMD_LUMEN: lightReading = analogRead(PIN_LUMEN); Wire.write(lightReading >> 8)؛ wire.write(lightReading % 0xFF); زنگ تفريح؛ مورد CMD_PIN_ON: مورد CMD_PIN_OFF: مورد CMD_BEAT: Wire.write(وضعیت); وضعیت = ST_OK; زنگ تفريح؛ ) cmd = 0; ) // با روال سرویس وقفه فراخوانی می شود هنگام دریافت داده های ورودی void receiveCommand (int howMany) (cmd = Wire.read (); status = ST_OK؛ سوئیچ (cmd) (مورد CMD_PIN_ON: cmdPinOn();؛ break؛ مورد CMD_PIN_OFF: cmdPinOff ()؛ شکست؛ مورد CMD_BEAT: lastBeat = millis(؛ break; ) ) //پایان دریافتEvent void cmdPinOff() ( if (Wire.available() != 1) ( status = ST_BAD_LEN; ) other ( int pin = Wire.read()؛ int i = searchPin(pin)؛ if (i< 0) { status = ST_BAD_PIN; } else { pgma[i].off = 0; digitalWrite(pin, LOW); } } } int searchPin(int pin) { int i = pgmaSize - 1; while (i >= 0 && pgma[i].pin != پین) (i--;) بازگشت i; ) /* * Programa el encendido y duracion del RESET. */ void resetPin() ( if (digitalRead(PIN_RESET) == LOW) ( بدون امضاء طولانی اکنون = millis(؛ int i = searchPin(PIN_RESET)؛ pgma[i].off = now + RESET_LENGTH؛ lastBeat = اکنون؛ digitalWrite (PIN_RESET، HIGH)؛ ) void cmdPinOn() (اگر (Wire.available() != 2) (وضعیت = ST_BAD_LEN؛ ) other (پین int = Wire.read(); int len ​​= Wire.read( );< 0) { status = ST_BAD_PIN; Serial.println("bad pin"); } else { if (len == 0) { status = ST_TIME_0; Serial.println("ban len"); } else { pgma[i].off = millis() + len * 1000; digitalWrite(pin, HIGH); Serial.println("ok"); } } } }

پورت COM اغلب برای اتصال میکروکنترلر به کامپیوتر استفاده می شود. در این مقاله نحوه ارسال دستورات کنترلی از رایانه و ارسال داده از کنترلر را نشان خواهیم داد.

آمادگی برای کار

اکثر میکروکنترلرها دارای چندین پورت I/O هستند. پروتکل UART مناسب ترین پروتکل برای ارتباط با کامپیوتر است. این یک پروتکل انتقال داده ناهمزمان سریال است. برای تبدیل آن به رابط USB، برد دارای مبدل USB-RS232 - FT232RL است.
برای اجرای نمونه های این مقاله فقط به یک برد سازگار با آردوینو نیاز دارید. ما استفاده می کنیم . مطمئن شوید که برد شما یک LED متصل به پین ​​13 و یک دکمه ریست دارد.

به عنوان مثال، بیایید یک کد را روی بردی آپلود کنیم که جدول ASCII را نمایش می دهد. ASCII یک رمزگذاری برای نمایش ارقام اعشاری، الفبای لاتین و ملی، علائم نگارشی و کاراکترهای کنترلی است.

نماد int = 33 ; void setup() (Serial. begin(9600) ; Serial. println(" ASCII Table ~ Character Map ") ;) void loop() (Serial. write(symbol) ; Serial. print(" , dec: " ) ; Serial .print(symbol) ; Serial.print(" , hex: " ) ; Serial.print(symbol, HEX) ; Serial.print(" , Oct: " ) ; Serial.print(symbol, OCT) ; Serial.print( " , bin: " ) ; Serial.println(symbol, BIN) ; if (symbol == 126 ) ( while (true) ( ​​Continue ; ) ) sign+ + ; )

متغیر نماد کد نماد را ذخیره می کند. جدول از 33 شروع می شود و به 126 ختم می شود، بنابراین نماد در ابتدا روی 33 تنظیم می شود.
برای شروع عملکرد پورت UART، از تابع استفاده کنید Serial.begin(). تنها پارامتر آن سرعت است. از آنجایی که پروتکل انتقال ناهمزمان است، سرعت باید از قبل در طرف گیرنده و فرستنده مذاکره شود. در این مثال سرعت 9600bps است.
برای نوشتن یک مقدار در پورت از سه تابع استفاده می شود:

  1. Serial.write()- داده ها را به صورت باینری در پورت می نویسد.
  2. Serial.print()می تواند مقادیر زیادی داشته باشد، اما همه آنها برای نمایش اطلاعات به شکلی انسان پسند عمل می کنند. به عنوان مثال، اگر اطلاعاتی که به عنوان یک پارامتر برای عبور مشخص شده است در گیومه قرار داده شود، برنامه ترمینال آن را بدون تغییر نمایش می دهد. اگر می خواهید هر مقداری را در یک سیستم عددی خاص نمایش دهید، باید یک کلمه خدماتی اضافه کنید: BIN-binary، OCT - octal، DEC - اعشاری، HEX - هگزا دسیمال. مثلا، Serial.print (25, HEX).
  3. Serial.println()همان کار را انجام می دهد Serial.print()، اما همچنان رشته را پس از نمایش اطلاعات ترجمه می کند.

برای بررسی عملکرد برنامه، لازم است رایانه دارای یک برنامه ترمینال باشد که داده ها را از پورت COM دریافت می کند. آردوینو IDE قبلاً یک مورد داخلی دارد. برای فراخوانی آن، Tools->Port Monitor را از منو انتخاب کنید. پنجره این ابزار بسیار ساده است:

حالا روی دکمه راه اندازی مجدد کلیک کنید. MK دوباره راه اندازی می شود و جدول ASCII را نمایش می دهد:

به این قسمت از کد توجه کنید:

اگر (نماد = = 126) (در حالی که (درست) (ادامه ؛ ))

اجرای برنامه را متوقف می کند. اگر آن را حذف کنید، جدول به طور نامحدود نمایش داده می شود.
برای تثبیت دانش به دست آمده، سعی کنید یک حلقه بی نهایت بنویسید که نام شما را هر ثانیه یک بار به پورت سریال ارسال می کند. اعداد مرحله را به خروجی اضافه کنید و فراموش نکنید که خط بعد از نام را ترجمه کنید.

ارسال دستورات از کامپیوتر

قبل از انجام این کار، باید ایده ای از نحوه عملکرد پورت COM داشته باشید.
اول از همه، تمام تبادلات از طریق بافر حافظه انجام می شود. یعنی وقتی چیزی را از رایانه شخصی به دستگاهی ارسال می کنید، داده ها در قسمت خاصی از حافظه قرار می گیرند. به محض آماده شدن دستگاه، داده ها را از بافر می خواند. این تابع به شما امکان می دهد وضعیت بافر را بررسی کنید serial.avaliable(). این تابع تعداد بایت های بافر را برمی گرداند. برای کم کردن این بایت ها، باید از تابع استفاده کنید Serial.read(). بیایید ببینیم این توابع با یک مثال چگونه کار می کنند:

int val = 0 ; void setup() (Serial. begin(9600) ;) void loop() ( if (Serial. available() > 0) (val = Serial. read() ; Serial. print(" I دریافت: " ) ؛ سریال. write(val) ; Serial.println() ;) )

پس از بارگذاری کد در حافظه میکروکنترلر، مانیتور پورت COM را باز کنید. یک کاراکتر را تایپ کرده و Enter را فشار دهید. در قسمت داده های دریافتی خواهید دید: "من دریافت کردم: X"، جایی که به جای ایکسشخصیتی خواهد بود که وارد کرده اید.
برنامه به طور نامحدود در حلقه اصلی می چرخد. در لحظه ای که یک بایت در پورت نوشته می شود، تابع ()Serial.available مقدار 1 را می گیرد، یعنی شرط انجام می شود. Serial.available() > 0. تابع بعدی Serial.read()این بایت را می خواند و در نتیجه بافر را پاک می کند. پس از آن، با استفاده از توابعی که قبلاً برای شما شناخته شده است، خروجی رخ می دهد.
استفاده از مانیتور داخلی پورت COM Arduino IDE دارای محدودیت هایی است. هنگام ارسال داده ها از برد به پورت COM، خروجی را می توان در قالب دلخواه سازماندهی کرد. و هنگام ارسال از رایانه شخصی به برد، انتقال کاراکترها مطابق با جدول ASCII انجام می شود. این بدان معناست که وقتی برای مثال کاراکتر "1" را وارد می کنید، باینری "00110001" (یعنی "49" به صورت اعشاری) از طریق پورت COM ارسال می شود.
بیایید کد را کمی تغییر دهیم و این عبارت را بررسی کنیم:

int val = 0 ; void setup() (Serial. begin(9600) ;) void loop() ( if (Serial. available() > 0) (val = Serial. read() ; Serial. print(" I دریافت: " ) ؛ سریال. println(val، BIN)؛ ))

پس از دانلود، در پورت مانیتور هنگام ارسال "1"، در پاسخ خواهید دید: "من دریافت کردم: 110001". می توانید فرمت خروجی را تغییر دهید و ببینید که برد با کاراکترهای دیگر چه چیزی را می پذیرد.

کنترل دستگاه از طریق پورت COM

بدیهی است که با دستورات رایانه شخصی، می توانید هر عملکرد میکروکنترلر را کنترل کنید. دانلود برنامه ای که عملکرد LED را کنترل می کند:

int val = 0 ; void setup() (Serial. begin(9600)؛ ) void loop() ( if (Serial. available() > 0) (val = Serial. read()؛ if (val= = "H") digitalWrite(13, HIGH) ؛ if (val= = "L") digitalWrite(13، LOW) ; ))

هنگامی که کاراکتر "H" به درگاه COM ارسال می شود، LED در خروجی سیزدهم روشن می شود و هنگامی که "L" ارسال می شود، LED خاموش می شود.
اگر بر اساس نتایج دریافت داده از پورت COM، می خواهید برنامه در حلقه اصلی اقدامات مختلفی را انجام دهد، می توانید شرایط موجود در حلقه اصلی را بررسی کنید. مثلا.