آردوینو آموزش آردوینو

آموزش و بررسی زمان سنجی با تابع millis در آردوینو Arduino

نوشته شده توسط معین صابری

پلتفرم آردویینو، یکی از پلتفرم های سخت افزاری/ نرم افزاری است که طی دو دهه اخیر، تحول شگرفی در زمینه الکترونیک و برنامه نویسی سیستم های سخت افزاری ایجاد کرده است. به کمک بردهای آردویینو و نرم افزار آن، روند توسعه و اجرای پروژه ها، افزایش می یابد. سهولت در کار، وجود منابع آموزشی فراوان و جامع کاربری گسترده سبب شده تمام افراد فعال در حوزه الکترونیک، چه با سطح حرفه ای و چه در سطح کار آموز، جزو مخاطبین این برد باشند. در این آموزش به بررسی یکی از توابع مهم و کاربردی آردویینو، ()millis می پردازیم. این تابع که برای کنترل زمانبندی فرایندهای مختلف به کار می رود، قادر است تا مدت زمان طی شده از زمان راه اندازی آردویینو تاکنون را اندازه گیری کرده و بر حسب میلی ثانیه، در خروجی تولید کند. اما کار با این تابع نیاز به رعایت الزامات و نکاتی است که در این آموزش به آن می پردازیم. در ادامه با مرجع تخصصی آردوینو به زبان فارسی، دیجی اسپارک همراه باشید.

 


اهمیت زمانبدی در برنامه نویسی


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

اهمیت زمانبدی فرایندها در برنامه نویسی - دیجی اسپارک

 

مطابق شکل فوق، ورودی به تابع اعمل می شود. تابع شروع به اجرای فرامین و پردازش داده ها می نماید. به موازات اجرای دستورات، تایمر millis زمان را کنترل می کند. چنانچه زمان از حد انتظار، مثلا از ۱۰ ثانیه بیشتر شده و اجرای تابع خاتمه نیافته باشد، اجرا تابع پایان گرفته و روال عادی برنامه، دنبال خواهد شد. در این شرایط، با توجه به خطای صورت گرفته، تصمیم لازم، اتخاذ خواهد شد.

یکی دیگر از کاربردهای تابع millis، اجرای یک فرایند، به صورت مکرر و در زمان های خاص است. به عنوان مثال، به کمک تابع millis می توان هر ۱۵ ثانیه یکبار، اقدام به خواندن ورودی آنالوگ، نمود. از آنجاییکه کار با تابع millis بسیار ساده بوده و در خروجی خود زمان سپری شده را اعلام می نماید، بنابراین با اندازه گیری زمان فعلی و مفابسه آن با زمان اندازه گیری شده در مرحله قبل، می توان زمان سپری شده بین این دو بازه را اندازه گیری کرده و در صورت لزوم، ورودی از آنالوگ خوانده شود.

 


تعریف تابع millis


یکی از قابلیت های بردهای آردویینو، به عنوان مثال برد آردویینو UNO، وجود تایمرهای داخلی است. به لطف وجود همین تایمر، تابع millis که جزو یکی از پایه ای ترین توابع آردویینو  به شمار می رود، می تواند مدت زمان سپری شده از لحظه شروع به کار برد تاکنون را محاسبه کند. خروجی این تابع از نوع unsigned long int بوده که در معماری بردهای آردویینو ۸ بیتی نظیر برد آردویینو UNO، به اندازه ۳۲ بیت خواهد بود. نحوه استفاده از این تابع، به شکل زیر است.

به عنوان مثالی دیگر، عبارت زیر، مدت زمان طی شده از لحظه راه اندازی برد آردویینو تاکنون را نشان می دهد.

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

تابع millis، تعریف و توضیح در آردوینو - دیجی اسپارک

 

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

 


اجرای یک نمونه کد با تابع millis


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

 مطابق برنامه فوق، هر ۱۰ ثانیه یکبار، تابع analogRead فراخوانی میشود. اما اندازه گیری زمان ۱۰ ثانیه، به کمک تابع millis صورت می گیرد. در ابتدا، در منغیر interval، عدد ۱۰۰۰۰(ده هزار) ذخیره می گردد. همچنین، مقدار اولیه متغیر t1، برابر با صفر، فرض می شود. بنابراین، در لحظه اول، حاصل جمع متغیر t1 و interval، ده هزار خواهد بود. در طرف دیگر، مقدار تابع millis(مدت زمان سپری شده از ابتدای راه اندازی برد آردویینو) با این حاصل جمع مقایسه شده و هرگاه از مقدار ۱۰ هزار بیشتر شود، وارد شرط شده و مقدار آنالوگ، خوانده می شود. در نظر داشته باشید که مقدار ۱۰ هزار، همان ۱۰ هزار میلی ثانیه و یا ۱۰ ثانیه است.

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

برای درک بهتر موضوع فوق، فرض کنید پس از اولین ورود به شرط، مقدار زمان فعلی به صورت عدد ۱۰۰۰۰(ده هزار) در متغیر t1 ذخیره می گردد. در این قسمت نیز، خروجی تابع millis در حال افزایش نسبت به عدد ۱۰ هزار است. چراکه با رسیدن به عدد ۱۰ هزار در ابتدای اجرای برنامه، شرط اجرا می شود. در این حالت، حاصل جمع مقدار ذخیره شده در متغیر t1 و عدد interval، مقدار ۲۰ هزار خواهد بود. در این حالت، تا زمانیکه مقدار خروجی تابع millis بیشتر از ۱۰ هزار نشود، شرط مجددا اجرا نخواهد شد. بدین ترتیب، هر ده ثانیه یکبار، شرط اجرا شده و با ذخیره زمان فعلی، ورودی آنالوگ خوانده خواهد شد.

 


Overflow در تابع millis و خطرات آن


در قسمت قبلی، به بررسی نحوه استفاده از تابع millis، خروجی آن و استفاده از این تابع در زمانبندی فرآیندها، استفاده کردیم. نکته مهم در به کارگیری این تابع، بحث بیشینه مقدار خروجی آن و سرریز(Oveflow) است. همانطورکه در بخش پیشین نیز گفته شد، این تابع مقدار خود را به صورت  unsigned long int تولید می کند. در بردهای آردویینو مبتنی بر تراشه AVR که معماری آن ها ۸ بیتی است، بیشنه مقدار برای نوع داده unsigned long int برابر با ۴۲۹۴۹۶۷۲۹۵ خواهد بود. تابع millis، پس از رسیدن به این مقدار، سر ریز کرده و روال شمارش خود را از ۰ آغاز خواهد کرد. به عبارتی دیگر، این تابع، پس از ۴۹ روز، سر ریز کرده و با پاک شدن مقادیر قبلی، شمارش از مقدار ۰ آغاز خواهد شد.

Overflow در تابع millis و خطرات آن - دیجی اسپارک

بدین ترتیب، با سر ریز شدن خروجی تابع millis، شمارش از صفر شروع خواهد شد. بدین ترتیب، اجرای فرایندها در زمان های مشخص، با این وجود، پس از ۵۰ روز غیرممکن خواهد بود. به عنوان مثال، در مورد خواندن هر ۱۰ ثانیه یکبار ورودی آنالوگ، این مقدار غیر ممکن خواهد بود. چراکه ممکن است در بعضی موارد، ۴۹ روز زمان نیاز باشد تا ورودی آنالوگ مجددا خوانده شود! اما غلبه بر این مشکل، راهکاری خلاقانه و البته ساده دارد که پیش از آن، می بایست به مطالعه برخی مباحث پایه در محاسبات کامپیوتری بپردازیم. پس از این مرحله، به ارائه و بررسی راهکار خواهیم پرداخت.

 


مکمل دو و نحوه اجرای عمل تفریق در کامپیوتر


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

در قطعه کد فوق، عدد a از عدد b کم شده و حاصل در c ذخیره می گردد. در سیستم های کامپیوتری، عملی به اسم تفریق وجود ندارد! در حقیقت عمل تفریق، با ساختن مکمل دو ساخته می شود. در مثال فوق، عدد a با مکمل ۲ عدد b جمع شده و حاصل در عدد c ذخیره می شود. ذکر این نکته ضروریست که در داده های علامت دار(signed)، آخرین بیت عدد، علامت آن را مشخص میکند. چنانچه این بیت یک شود، عدد مورد نظر منفی خواهد بود. به عنوان مثال، برنامه زیر را در نظر بگیرید.

با اجرای برنامه فوق، مشاهده خواهید کرد که حاصل تفریق، یک عدد منفی نبوده و در سریال مانیتور، عدد ۲ نمایش داده خواهد شد. همانطور که بیان شد، برای اجرای عمل تفریق، از مکمل دو عدد استفاده می شود. در مثال فوق، عدد a برابر با ۱ و عدد b برابر با ۴۲۹۴۹۶۷۲۹۵ و هر دو آن ها از نوع unsigned long int هستند. مطابق آنچه که که پیشتر گفته شد، در معماری بردهای آردویینو ۸ بیتی، نوع داده unsogned long int به میزان ۳۲ بیت است. برای اجرای عمل تفریق، ابتدا عدد b را به باینری تبدیل می کنیم. معادل باینری این عدد به صورت زیر است.

برای ساخت مکمل دو عددb، می بایست ابتدا بیت های آن را معکوس کنیم. بنابراین عدد فوق به صورت زیر تبدیل می شود.

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

در نهایت می بایست عدد a با مقدار ۱، با مکمل دو عدد b جمع کنیم. حاصل این جمع به صورت باینری، برابر با عدد زیر است.

معادل عدد فوق در مبنای ۱۰، عدد ۲ است! به عبارت دیگر، شما با تفریق یک عدد کوچکتر از یک عدد بزرگتر، نه تنها عدد منفی کسب نمی کنید، بلکه یک عدد مثبت بدست خواهید آورد. البته چنانچه که تعداد بیت های این دو عدد بیشتر می بود، مثلا ۶۴ بیت، عدد منفی به راحتی تولید می شد. از آنجاییکه سر ریز رخ داده و جایی برای بیت علامت وجود نداشت، بنابراین یک عدد مثبت حاصل شده است. از دیگر دلایل ایجاد عدد مثبت، بدون علامت بودن آن است. در حقیقت در سیستم اعداد بودن علامت، نتیجه محاسبات هیچ گاه منفی نخواهد شد. چراکه بیت علامت، همواره برابر با ۰ است. از این موضوع می توان در غلبه بر مشکل تابع millis، استفاده نمود. این موضوع در قسمت بعدی، مورد بحث و بررسی قرار می گیرد.

 


غلبه بر مشکل Overflow در تابع millis


در قسمت قبلی، در رابطه با بحث تفریق دو عدد علامت دار و تولید یک عدد مثبت، صحبت کردیم. در این قسمت، با توجه به مطالب گفته شده در قسمت قبلی، به جای اینکه مقدار t1 را با interval جمع کرده و خروجی تابع millis با آن مقایسه شود، از تفریق استفاده می کنیم. برای این منظور، کد زیر را در نظر بگیرید.

در کد فوق، تا پیش از سر ریز شدن تابع millis()، همه چیز عادی و مثل گذشته پیش می رود. اما زمانیکه تابع millis سرریز کرده و مقدار آن صفر می شود، کد فوق بر مشکل سر ریز، غلبه می کند. برای روشن تر شدن موضوع، فرض کنید که در روز چهل و نهم، مقدار ۴۲۹۴۹۶۷۲۹۵ در متغیر t1 ذخیره می شود. پس از این مرحله، تابع millis سر ریز کرده و شمارش خود را از صفر آغاز می نماید. همانطور که پیشتر گفتیم، برای تفریق از مکمل دو استفاده می شود. به عبارت دیگر، مکمل دو عدد ۴۲۹۴۹۶۷۲۹۵، برابر با یک خواهد بود. در طرف دیگر، تابع millis پس از سر ریز، مقدار خود را از ۴۲۹۴۹۶۷۲۹۵ یا همان یک کسر کرده و تا زمانیکه حاصل این تفریق بیشتر از ۱۰ هزار(۱۰ثانیه) نشود، وارد شرط نخواهد شد. بدین ترتیب با راهکاری ساده، بر مشکل سر ریز این تابع غلبه شده و دیگر نگرانی وجود نخواهد داشت.

 


جمع بندی


در این آموزش به بررسی تابع millis و نقش آن در کنترل فرایندها، پرداختیم. این تابع میتواند مدت زمان طی شده از ابتدای راه اندازی برد آردویینو را اندازه بگیرد. بدین ترتیب به کمک این تابع می توانیم اجرای برخی از قسمت های برنامه را زمانبندی کرده و در بازه های زمانی مشخص، آن ها را اجرا کنیم. در کنار این مزایا، تابع millis بعد از ۴۹ روز مداوم کاری، دچار سر ریز شده و مقدار آن از صفر شروع خواهد شد. این موضوع می تواند سبب ایجاد اختلال در برنامه و عدم عملکرد صحیح قسمت های زمان بندی شده باشد. در این نوشتار، به این مشکل و نحوه غلبه بر آن به طور مفصل صحبت شده است.

 

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

 

درباره نویسنده

معین صابری

کارشناسی ارشد رشته معماری سیستم های کامپیوتری

مالي که ز تو کس نستاند، علم است
حرزي که تو را به حق رساند، علم است
جز علم طلب مکن تو اندر عالم
چيزي که تو را ز غم رهاند، علم است
(شیخ بهایی)

تبادل نظر و رفع عیب با ثبت دیدگاه

۱۴ دیدگاه

  • درود، خسته نباشید، عالی بود جناب صابری عزیز.
    آیا میشه با همین تابع millis یک ساعت دیجیتال ۲۴ ساعته شش رقمی با سون سگمنت و آردوینو ساخت ؟
    من توی دیجی اسپارک آموزشی در موردش ندیدم. میشه لطفا بهم کمک کنید ؟

    • درود و سپاس از لطف شما
      بله می شود ساخت، اما کار بسیار سختی خواهد بود، چراکه تابع millis همانطور که در مطلب به آن اشاره شد، بعد از ۵۰ روز، سر ریز کرده و مجددا از صفر شروع به شمارش می کند. بهترین راه استفاده از آی سی های ساعت نظیر DS1307 است. آموزش زیر را مطالعه نمایید:
      لینک آموزش ساعت دیجیتال با سون سگمنت، کلیک کنید

      • بله درسته، اما همانطور که در جریان هستید، ساعت دیجیتالی هر ۲۴ ساعت یکبار صفر میشه، در حالی که گفتید تابع millis بعد از ۵۰ روز سر ریز میکنه. بنابراین اصلا کار به اونجاها نمیکشه و ما میتونیم هر یک روز یکبار اینو صفر کنیم. به نظرتون چجوری میشه اینکار رو انجام داد ؟؟
        در ضمن، آموزشی که لینکشو برام گذاشته بودید، ساعت دیجیتال ۴ رقمی بود، در صورتی که من میخواستم ۶ رقمی بسازم. برای ۶ رقمی آموشی هست توی دیجی اسپارک ؟

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

      • سوال دیگه که داشتم در مکمل ۲ وقتی به اون عدد ۳۲ بیتی ، عدد ۱ رو اضافه میکنی میشه ۳۳ بیت چه طوری همچین چیزی برای آردوینو ۳۲ بیتی ممکنه؟؟

        • خیر، زمانیکه عدد ۱ به یک عدد ۳۲ بیتی که تمام بیت های آن ۱ است اضافه می شود، نتیجه ۳۳ بیت خواهد شد که چون ۳۳ بیت در ۳۲ بیت جا نمی شود، سر ریز اتفاق خواهد افتاد.
          در رابطه با ۳۲ بیت در آردوینو، در حقیقت ۳۲ بیت با قراردادن ۴ حافظه(رجیستر) ۸ بیتی کنار هم، ساخته می شود.

  • عالی عالی
    درود بر شما که به پیشرفت علمی ایران کمک میکنید
    دمتون گرم کیف کردم از نحوه توضیح دادنتون

  • سلام خیلی آموزش کاربردی بود مچکرم
    سوالی که دارم:
    برای غلبه بر مشکل تابع بعد از ۴۹ روز ، خب صفر منهای اون عدد بزرگ که بعد ۴۹ روز به دست میاد عددش کمتر ۱۰ هزار هست پس وارد حلقه if نمیشه چه طور میشه که عدد منفی بیشتر از ۱۰ هزار میشه؟؟؟

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