آیا تا به حال در مورد تابع ()millis درآردوینو شنیدهاید؟ آیا میدانستید که این تابع با کمک تایمر در آردوینو، امکان مانیتور کردن زمان را بر حسب میلی ثانیه برای شما فراهم میکند؟ در این آموزش قصد داریم بیشتر با عملکرد و نحوه استفاده از این تابع آشنا شویم.
کلاک سختافزاری چیست؟
پیش از بیان نحوه عملکرد تابع ()millis درآردوینو، لازم است مروری بر یک سری مطالب پیشنیاز داشته باشیم . برای مثال، بیایید بررسی کنیم یک “کلاک سختافزاری” و یک “تایمر” چیست؟
کلاک سختافزاری، یک مدار الکتریکی است که یک سیگنال الکتریکی (مانند پالس ساعت) در یک فرکانس ثابت تولید میکند.
مدارهای زیادی هستند که میتوان با آنها سیگنالهای الکتریکی با فرکانس ثابت و مشخص تولید کرد. برخی از آنها مانند کریستالها و اسیلاتورها از پیشساخته و بسیار دقیق هستند، برخی را میتوانید خودتان بر روی بردبورد بسازید، و برخی دیگر ماژولهایی هستند که میتوانیم آنها را به آردوینو خود متصل کنیم.
کلاک سختافزاری در آردوینو
مدار یکپارچهای که در آردوینو به کار رفته، شامل یک کلاک سختافزاری است. درواقع، اکثر بردهای آردوینو از یک رزوناتور سرامیکی برای پیمایش زمان استفاده میکنند. کریستال اسیلاتور نیز معمولاً در مواردی از جمله ارتباط سریال به منظور کنترل بادریت، موردنیاز است.
بنابراین، اصطلاح “منبع کلاک” را در این متن به معنی “تولیدکنندهی یک سیگنال ثابت” آموزش میبینیم. ما میتوانیم این سیگنال را “تیک” بنامیم، مانند “تیک تاک” ساعتهای دیواری!
نقش تایمر در دستور ()millis چیست؟
اگر ما تعداد تیکهایی که در طی اجرای برنامه رخ داده را بشماریم، میتوانیم بفهمیم چه مدت زمان از لحظهی روشن شدن دستگاه گذشتهاست. خوشبختانه، آردوینو دارای تایمر یا شمارنده داخلی است که میتواند به کمک آن تعداد این “تیکها” را برای ما بشمارد.
بخش تایمر در آردوینو کارهای زیادی میتواند انجام دهد، اما درباره موضوع مورد بحث ما بیایید ببینیم چگونه کارهای زیر را انجام دهد:
- شمارش “تیکهای ساعت” از کریستال اسیلاتور
- ادامه دادن به شمارش مداوم “تیکهای ساعت”
تایمر به محض روشن شدن آردوینو شروع به شمردن “تیکهای ساعت” خواهد کرد. نیازی نیست شما به آن فرمان دهید، خودش به طور خودکار این کار را انجام میدهد و تا زمانی که آردوینو خاموش نشود، متوقف نخواهد شد.
تایمر به شمردن ادامه خواهد داد تا اینکه به حداکثر مقدار خودش برسد (49 روز)، در این زمان شمارش را از صفر شروع میکند.
وقتی تایمر به حداکثر تعداد قابل شمارش میرسد و پس از آن شمارش را از نو شروع میکند، اصطلاحاً میگوییم تایمر “سرریز” شده است.
دستور ()millis در آردوینو !
هماکنون که با نحوه عملکرد یک شمارنده در آردوینو آشنا شدید نوبت به بررسی و استفاده از یکی از توابع مهم در آردوینو رسیده یعنی دستور ()millis . به بیان ساده، این تابع امکان دسترسی به شمارشهای مداومی که توسط تایمر انجام شده را فراهم میکند. زمانی که آن را فراخوانی میکنید، این دستور مانند توابعی مانند ()delay، مدت زمانی که تاکنون تایمر به دست آورده را بر حسب “میلی ثانیه” به شما برمیگرداند. به بیان دیگر، مقداری که توسط تابع ()millis بازگردانده میشود، مدت زمانی است که از موقع روشن شدن برد آردوینو گذشته است.
تفاوت توابع ()delay یا ()delayMicroseconds با این دستور در این است که درواقع دستور millis در آردوینو به روند اجرای همزمان دو برنامه یا مولتی تسکینگ، کمک کرده و توقفی متوجه آن برنامهها نمیشود در صورتی که توابع گفته شده در حین کار باعث متوقف شدن عملکرد آردوینو میشوند و این باعث کند شدن اجرای کل دستورات میشود.
چگونه داده را از تابع ()millis دریافت کنیم؟
شاید تاکنون با اصطلاحات تخصصی توابع پایهای آردوینو برخورده و نام آنها را شنیده باشید، ماننده دو واژه “call” و “return”. زمانی که شما نام تابعی را تایپ میکنید، یعنی میخواهید از آن در کد خود استفاده کنید، میگوییم شما آن تابع را “فراخوانی (calling)” کردهاید. برای مثال، زمانی که ترکیب ()millis را در کد خود تایپ میکنیم، در واقع این تابع را فراخوانی میکنیم. زمانی که این تابع محاسباتی را برای شما انجام میدهد و دادهای را به شما میدهد، میگوییم تابع یک مقداری را “برمیگرداند (return)”.
unsigned long previousTime =0;
void setup() {
}
void loop() {
previousTime = millis();
}
دراینجا، ما تابع ()millis را “فراخوانی(calling)” میکنیم و آن هم زمانی که تاکنون آردوینو اجرا شدهاست را بر حسب میلی ثانیه “برمیگرداند(return)”.
چگونه دادهی حاصل از تابع ()millis را ذخیره کنیم؟
ممکن است با این سوال روبهرو شده باشید که “چگونه ما به مقدار زمان شمارنده دسترسی پیدا کنیم یا چگونه از آن استفاده کنیم؟”. انجام این کار بسیار ساده است و ما کافی است مقدار دادهی بازگردانده شده را به یک متغیر اختصاص دهیم. یعنی در این زمان متغیری تحت عنوان “previousTime” میسازیم و آن را برابر مقدار خروجی تابع ()millis در آردوینو قرار میدهیم. بنابراین هر زمان که حلقه loop اجرا میشود، مقدار این متغیر با آخرین زمان شمارش شده برحسب میلی ثانیه بهروزرسانی خواهد شد.
با چاپ متغیر روی سریال مانیتور میتوانیم مقدار خروجی این تابع را دنبال کنیم. یک دقیقه پس از روشن شدن آردوینو، مقدار این متغیر برابر (60 ثانیه x 1000 میلی ثانیه) 60000 خواهد شد.
چنانچه به مدت 7 روز صبر کنیم، مقدار بازگردانده شده توسط تابع ()millis برابر (7 روز x 24 ساعت x 60 دقیقه x 60 ثانیه x 1000 میلی ثانیه) 604800000 خواهد بود.
همچنین بهتر است از دستور ()millis در قسمت شرط “حلقههای شرطی” مانند توابع if استفاده کرد. زمانی که شرط ارزیابی میشود، این دستور، مقدار تایمر یا شمارنده را چک میکند و زمان فعلی را برحسب میلی ثانیه برمیگرداند. به این ترتیب، هر زمان که شرط چک شود، مقدار تابع به طور خودکار به روزرسانی خواهد شد.
اگر تا اینجا درک عملکرد این تابع برای شما کمی دشوار بوده است، راهحل آسان این است که دستور ()millis را مانند یک عدد در حال افزایش درنظر بگیرید.
معرفی انواع داده در کدنویسی آردوینو
شاید تاکنون متوجه شده باشید که مقدار دادهای که تابع ()millis در آردوینو برمیگرداند، میتواند عددی بسیار بزرگ باشد. بزرگترین مقداری که این تابع میتواند برگرداند، حدود 4 میلیارد (4294967295) است. بنابراین برای ذخیره این مقدار در یک متغیر، باید مطمئن شویم نوع متغیری که انتخاب میکنیم برای ذخیره این عدد بسیار بزرگ مناسب باشد. بیایید مرور سریعی داشته باشیم براینکه یک متغیر چیست و انواع متغیرها چه تفاوتهایی با یکدیگر دارند.
یک متغیر را به چشم یک قفسه قفلدار در مدرسه نگاه کنید. با این تفاوت که به جای نگهداری کتاب یا ساندویچ، از آن برای نگهداری دادهها استفاده میکنیم. قفسههایی با اندازههای مختلف در مدرسه وجود دارد، هرچه وسایل موردنظر شما بزرگتر باشد، به قفسه بزرگتری نیز نیاز خواهید داشت. همین امر برای داده ما نیز صدق میکند. اگر دادهی بزرگی داشته باشیم و متغیر ما (یا همان قفسه) اندازه کوچکی داشته باشد، اتفاق بدی رخ میدهد.
متغیرها در انواع و اندازههای مختلف میتواند در برنامه تعریف شوند. برای مثال در جدول زیر مجموعه ای از اتواع متغیرها برای آردوینو Uno آورده شده است.
bytes، دادههای بسیار کوچک از 0 تا 255 را ذخیره میکنند.
integers، اعداد صحیح از 32768- تا 32768 را ذخیره می کنند، اما این هم اعداد کوچکی را شامل میشود. ظرف چند ثانیه تابع ()millis میتواند این متغیر را کاملاً پر کند.
میتوانیم ازنوع float که قادر است دادهی بزرگتری را برای ما ذخیره کند، استفاده کنیم. اما این نوع داده برای اعداد اعشاری مورد استفاده قرار میگیرد.
یک متغیر long میتواند 32 بیت داده را از حدود 2- میلیارد تا 2 میلیارد ذخیره کند.
ازآنجایی که تابع ()millis در آردوینو هرگز یک عدد منفی را برنمیگرداند، بهترین نوع متغیر برای ذخیره این داده unsigned long است. این نوع متغیر فقط مقادیر مثبت از صفر تا 4 میلیارد را میتواند به خود اختصاص دهد. به علاوه، در مرجع توابع آردوینو در سایت آردوینو نیز بهترین نوع متغیر برای دستور ()millis را unsigned long معرفی کرده است.
2 نکته کلیدی برای استفاده از unsigned long:
چنانچه قصد دارید با یک متغیر unsigned long محاسبات ریاضی انجام دهید، به موارد زیر توجه داشته باشید:
- اولاً، هر متغیر دیگری را که قصد دارید برای تغییر آن متغیر استفاده کنید، باید از نوع unsigned long باشد. فرض کنید متغیری به نام previousTime دارید و میخواهید مقداری را از آن کم کنید که در متغیر دیگری مانند currentTime ذخیره کردهاید. باید اطمینان حاصل کنید که متغیر currentTime نیز از نوع unsigned long تعریف شده باشد.
if(currentTime - previousTime > 10000UL ){
//Do this thing...
- ثانیاً، اگر میخواهید از یک عدد خام برای انجام محاسباتی بر روی متغیر unsigned long استفاده کنید، اطمینان یابید که در انتهای حداقل یکی از اعدادی که در این محاسبه استفاده میشود، از تبدیل کننده فرمت “UL” استفاده شود.
برای مثال، اگر میخواهید previousTime که یک متغیر از نوع unsigned long است را بر عددی مانند 100 یا 1000 تقسیم کنید، مطمئن شوید که این اعداد به عنوان مقسوم علیه به صورت 100UL یا 1000UL نوشته شوند.
اعداد خامی مانند اینها، “ثابتهای عدد صحیح” نامیده میشوند و اگر در انتهای آنها تبدیلکننده UL را قرار ندهید، محاسبات نتایج غیرمنتظرهای را به همراه خواهند داشت. تبدیل کننده فرمت UL در پایان این اعداد خام به آردوینو میگوید که با این اعداد باید مانند یک unsigned long رفتار کند.
هشدار
لطفا توجه داشته باشید که مقدار بازگشتی تابع ()millis دادهای از نوع unsigned long است.اگر برنامه نویس بخواهد محاسبات ریاضی با داده کوچکی مانند یک عدد صحیح انجام دهد، ممکن است خطاهای منطقی رخ دهد. حتی داده signed long نیز ممکن است با خطا روبه رو شود، چون حداکثر مقدار آن نصف مقدار بدون علامت خود است.
(برگرفته از مراجع آموزشی آردوینو)
تبدیل کنندههای فرمت U و L:
به طور پیشفرض، با یک عدد صحیح ثابت مانند یک داده از نوع int، با محدودیتهایی در مقادیر آنها رفتار میشود. برای تبدیل یک عدد صحیح ثابت به دادهای از نوع دیگر، موارد زیر را حتماً دنبال کنید:
- ‘u’ یا ‘U’ برای تبدیل یک عدد ثابت به فرمت یک داده بدون علامت (unsigned)، مانند 33u استفاده میشود.
- ‘l’ یا ‘L’ برای تبدیل یک عدد ثابت به فرمت یک داده نوع long ، مانند 100000Lاستفاده میشود.
- ‘ul’ یا ‘UL’ برای تبدیل یک عدد ثابت به یک عدد ثابت نوع unsigned long، مانند 32767ul استفاده میشود.
خلاصه
در این آموزش اشاره کردیم که یک کلاک سختافزاری یک مدار الکتریکی است یک سیگنال الکتریکی با فرکانس ثابت تولید می کند.
همچنین در مورد تایمر در آردوینو صحبت کردیم و توضیح دادیم که آردوینو یک شمارنده داخلی دارد که تعداد تیکهایی ساعت را شمرده و سپس تیکهایی که به طور مداوم شمرده شدهاند را ذخیره میکند.
در مورد اینکه چطور تابع ()millis در آردوینو میتواند شمارشهای مداوم رو برای ما انجام دهد و اینکه چطور مقادیر را در یک متغیر ذخیره میکند، صحبت کردیم. این قسمت به فراخوانی ()millis و برگرداندن مقدار تابع درون یک شرط منتهی شد.
در پایان، استفاده از دادهی نوع unsigned long برای ذخیرهسازی مقدار خروجی بازگردانده شده توسط تابع ()millis بیان شد و به اقدامات احتیاطی که هنگام انجام محاسبات ریاضی با متغیرهای نوع unsigned long باید رعایت شود، اشاره شد.
امیدواریم این آموزش برای شما مفید بوده باشد.