در قسمت چهاردهم از آموزش آردوینو به بررسی عملیات های محاسباتی از جمله جمع، تفریق، ضرب و تقسیم و همچنین، افزایش و کاهش مقادیر متغیرها، یافتن باقیمانده حاصل از تقسیم دو مقدار، تعیین قدرمطلق یک عدد و یافتن حداقل یا حداکثر مقادیر، پرداختیم. در این قسمت قصد داریم درباره گرد کردن اعداد ممیزی، چگونگی استفاده از توابع مثلثاتی و تولید اعداد تصادفی صحبت کنیم.
گرد کردن اعداد ممیزی
تابع floor(x) بزرگترین عدد صحیح را که بزرگتر از مقدار x نیست و تابع ceil(x) کوچکترین عدد صحیح را که کوچکتر از مقدار x نیست، محاسبه میکند.
این توابع برای گرد کردن اعداد ممیزی استفاده میشوند.
در اینجا چند مثال از تابع floor آورده شده است:
1 2 3 4 5 6 | Serial.println( floor(1) ); // this prints 1.00 Serial.println( floor(1.1) ); // this prints 1.00 Serial.println( floor(0) ); // this prints 0.00 Serial.println( floor(.1) ); // this prints 0.00 Serial.println( floor(-1) ); // this prints -1.00 Serial.println( floor(-1.1) ); // this prints -2.00 |
همچنین، در اینجا چند مثال از تابع ceil آورده شده است:
1 2 3 4 5 6 | Serial.println( ceil(1) ); // this prints 1.00 Serial.println( ceil(1.1) ); // this prints 2.00 Serial.println( ceil(0) ); // this prints 0.00 Serial.println( ceil(.1) ); // this prints 1.00 Serial.println( ceil(-1) ); // this prints -1.00 Serial.println( ceil(-1.1) ); // this prints -1.00 |
با استفاده از تابع round() میتوانید یک عدد ممیزی را به نزدیکترین عدد صحیح ممکن، گرد کنید:
1 | int result = round(1.1); |
✅نکته
استفاده از توابع مثلثاتی
در ادامه توضیح خواهیم داد که چگونه شما میتوانید سینوس، کسینوس یا تانژانت را بهصورت رادیان یا درجه به دست آورید.
بهطورکلی، تابع sin(x) سینوس زاویه x، تابع cos(x) کسینوس زاویه x و تابع tan(x) تانژانت x را محاسبه میکند. زاویهها بر حسب رادیان هستند و نتیجه یک مقدار ممیزی است. مثال زیر توابع مثلثاتی را نشان میدهد:
1 2 3 4 5 | float deg = 30; // angle in degrees float rad = deg * PI / 180; // convert to radians Serial.println(rad); // print the radians Serial.println(sin(rad), 5); // print the sine Serial.println(cos(rad), 5); // print the cosine |
این کد، زاویه را به رادیان تبدیل میکند و سینوس و کسینوس را پرینت میکند.
همچنین، در کد زیر خروجی با توضیحات اضافه شده است:
1 2 3 | 0.52 30 degrees is 0.5235988 radians, println only shows two decimal places 0.50000 sine of 30 degrees is .5000000, displayed here to 5 decimal places 0.86603 cosine is .8660254, which rounds up to 0.86603 at 5 decimal places |
اسکچ این مقادیر را با دقت بالا بهصورت مقادیر ممیزی محاسبه میکند و توابع Serial.print و Serial.println مقادیر ممیزی را به صورت پیشفرض تا دو رقم اعشار نمایش میدهند، اما شما میتوانید دقت نمایش اعداد اعشاری Serial.print و Serial.println را بهعنوان آرگومان دوم تعیین کنید.
تبدیل از رادیان به درجه و بالعکس، مباحث معمولی در مثلثات است. عدد ثابت (π)PI نمایانگر مقدار (3.14159265…) میباشد. همچنین، 180 یک مقدار ثابت است. آردوینو نیز برخی از ثابتها را بصورت define را فراهم کرده است که شما میتوانید از آنها برای انجام تبدیل درجه به رادیان و بالعکس استفاده کنید:
1 2 | rad = deg * DEG_TO_RAD; // a way to convert degrees to radians deg = rad * RAD_TO_DEG; // a way to convert radians to degrees |
به نظر میرسد استفاده از DEG_TO_RAD کارایی بیشتری نسبت به deg * PI / 180 دارد، اما در عمل، کامپایلر آردوینو هوشمند است و میتواند تشخیص دهد که PI / 180 یک مقدار ثابت است (مقدار آن هرگز تغییر نخواهد کرد)؛ بنابراین نتیجه تقسیم PI بر 180 را جایگزین میکند که به صورت اتفاقی مقدار آن با ثابت DEG_TO_RAD (0.017453292519…) یکسان است. شما می توانید از هر روشی که می خواهید استفاده کنید.
برای کسب اطلاعات بیشتر درباره مباحث sin، cos و tan در آردوینو به لینک های زیر مراجعه کنید:
تولید اعداد تصادفی
در ادامه توضیح خواهیم داد که چگونه میتوان در آردوینو یک عدد تصادفی تولید کرد.
بهطورکلی، در آردوینو از دستور random میتوان برای تولید عدد تصادفی استفاده کرد. فراخوانی تابع random با یک پارامتر واحد، کران بالایی (upper bound) را تعیین میکند. اعداد تصادفی حاصل از این روش، بین صفر تا مقدار یکی کمتر از کران بالایی هستند.
1 2 3 | int minr = 50; int maxr = 100; long randnum = random(maxr); // random number between 0 and maxr -1 |
فراخوانی تابع random با دو پارامتر، کرانهای پایینی و بالایی را تعیین میکند. مقادیر حاصله بین مقدار کران پایین تا یک واحد کمتر از کران بالا، متغیر است.
1 | long randnum = random(minr, maxr); // random number between minr and maxr -1 |
درست است که اعداد تصادفی که توسط تابع ()random به دست میآیند، یک الگوی مشخص ندارند؛ اما این اعداد به طور کاملاً تصادفی هم تولید نمیشوند. این موضوع در بسیاری از برنامهها، مهم نیست. اما اگر نیاز دارید که هر بار که برنامهتان اجرا میشود، دنبالهای متفاوت از اعداد تصادفی را دریافت کنید، میتوانید از تابع randomSeed(seed) با مقادیر مختلف برای seed استفاده کنید. (اگر شما از یک مقدار seed یکسان استفاده کنید، دنبالهی مشابهی از اعداد تصادفی دریافت خواهید کرد).
بهطورکلی، این تابع، تولید اعداد تصادفی را از یک نقطهی تصادفی مبتنی بر مقدار seed مشخص شده آغاز میکند:
1 | randomSeed(1234); // change the starting sequence of random numbers |
در اینجا یک مثال آورده شده است که از شکلهای مختلف تولید اعداد تصادفی موجود در آردوینو استفاده میکند: }
این نتایج میتوانند بسته به معماری مختلف آردوینو و شرایط محیطی متفاوت باشند:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | // Random // demonstrates generating random numbers int randNumber; void setup() { Serial.begin(9600); while(!Serial); // Print random numbers with no seed value Serial.println("Print 20 random numbers between 0 and 9"); for(int i=0; i < 20; i++) { randNumber = random(10); Serial.print(randNumber); Serial.print(" "); } Serial.println(); Serial.println("Print 20 random numbers between 2 and 9"); for(int i=0; i < 20; i++) { randNumber = random(2,10); Serial.print(randNumber); Serial.print(" "); } // Print random numbers with the same seed value each time randomSeed(1234); Serial.println(); Serial.println("Print 20 random numbers between 0 and 9 after constant seed "); for(int i=0; i < 20; i++) { randNumber = random(10); Serial.print(randNumber); Serial.print(" "); } // Print random numbers with a different seed value each time randomSeed(analogRead(0)); // read from an analog port with nothing connected Serial.println(); Serial.println("Print 20 random numbers between 0 and 9 after floating seed "); for(int i=0; i < 20; i++) { randNumber = random(10); Serial.print(randNumber); Serial.print(" "); } Serial.println(); Serial.println(); } void loop() { } |
در اینجا خروجی این کد بهعنوانمثال در برد آردوینو Uno آورده شده است (ممکن است شما در ساختارها یا معماریهای مختلف نتایج متفاوتی دریافت کنید):
1 2 3 4 5 6 7 8 | Print 20 random numbers between 0 and 9 7 9 3 8 0 2 4 8 3 9 0 5 2 2 7 3 7 9 0 2 Print 20 random numbers between 2 and 9 9 3 7 7 2 7 5 8 2 9 3 4 2 5 4 3 5 7 5 7 Print 20 random numbers between 0 and 9 after constant seed 8 2 8 7 1 8 0 3 6 5 9 0 3 4 3 1 2 3 9 4 Print 20 random numbers between 0 and 9 after floating seed 0 9 7 4 4 7 7 4 4 9 1 6 0 2 3 1 5 9 1 1 |
وقتی دکمهی ریست (Reset) را روی آردوینو فشار دهید تا برنامه (اسکچ) خود را مجدداً اجرا کنید، سه خط اول اعداد تصادفی تغییر نخواهند کرد. (ممکن است پس از فشار دادن دکمهی ریست، لازم باشد سریال مانیتور را ببندید و دوباره باز کنید.) هر بار که برنامه (اسکچ) شما اجرا میشود، فقط خط آخر کد تغییر میکند؛ این موضوع به دلیل تنظیم مقدار اولیه برای تولید اعداد تصادفی با استفاده از یک مقدار متفاوت به عنوان نقطهی شروع (seed) اتفاق میافتد. این مقدار از یک پورت ورودی آنالوگ که به هیچ چیزی متصل نیست، خوانده میشود. اگر از پورت آنالوگ 0 برای مورد دیگری استفاده میکنید، میتوانید آرگومان تابع analogRead را به یک پورت آنالوگ استفادهنشده تغییر دهید.
در کل، مثال فوق تنها یکی از گزینههای موجود برای تولید اعداد تصادفی در آردوینو بدون استفاده از سختافزار خارجی میباشد. ممکن است به نظر برسد که یک پورت ورودی آنالوگ که به هیچ چیزی متصل نیست، روش خوب یا حداقل قابلقبولی برای تولید اعداد تصادفی باشد، اما تبدیل آنالوگ به دیجیتال در بیشتر بردهای آردوینو حداکثر مقدار ۱۰ بیتی را برمیگرداند که تنها میتواند ۱۰۲۴ مقدار مختلف را نگه دارد. این محدودهی مقادیر، بسیار کوچکتر از آن است که بتواند مولد اعداد تصادفی را برای تولید اعداد تصادفی قوی تنظیم کند.
در واقعیت، تولید اعداد تصادفی در آردوینو دشوار خواهد بود، اما مانند بسیاری از کامپیوترها، شما میتوانید اعداد شبهتصادفی (pseudorandom) رمزنگاری یا اعداد تصادفی که برای استفاده در برنامههای رمزنگاری مناسب هستند، تولید کنید. برخی از بردهای آردوینو مانند Arduino WiFi Rev2،MKR Vidor 4000 و MKR WiFi 1000/1010 شامل تراشه رمزنگاری Atmel ECC508 یا ECC608 میباشند که دارای پشتیبانی سختافزاری برای عملکردهای رمزنگاری، از جمله یک مولد اعداد تصادفی قوی هستند که شما میتوانید با نصب کتابخانه ArduinoECCX08 با استفاده از بخش منیجر (مدیریت) کتابخانه آردوینو به این چیپ دسترسی داشته باشید.
✅نکته
برای کسب اطلاعات بیشتر درباره مباحث اعداد تصادفی (random) و randomSeed به سایتهای زیر مراجعه کنید: