در قسمت بیست و هفتم از آموزش Arduino به بررسی خواندن keyboard (صفحهکلید)، خواندن مقادیر آنالوگ و تغییر دامنه مقادیر پرداختیم. در این قسمت قصد داریم درباره خواندن بیش از شش ورودی آنالوگ و همچنین اندازهگیری ولتاژها تا 5 ولت صحبت کنیم.
خواندن بیش از شش ورودی آنالوگ
فرض کنید تعداد ورودیهای آنالوگ شما بیشتر از تعداد پینهای آنالوگ موجود در بردتان باشد. یک برد استاندارد Arduino (بر پایه ATmega328) دارای شش ورودی آنالوگ است (در حالی که Arduino Mega دارای 16 ورودی آنالوگ است). اگر تعداد ورودیهای مورد نیاز شما بیشتر از این مقدار باشد، میتوانید از یک Multiplexer استفاده کنید.
Multiplexer یک سوئیچ آنالوگ است که بهصورت دیجیتالی کنترل میشود. با استفاده از چیپ 4051 میتوان هشت ورودی آنالوگ را به یک پین آنالوگ متصل کرد و از طریق سه پین Selector (S0، S1 و S2) آنها را انتخاب کرد. در این روش، هر ورودی به نوبت خوانده میشود. در ادامه کد نمونهای آورده شده است:
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 | /* * multiplexer sketch * read 1 of 8 analog values into single analog input pin with 4051 multiplexer */ // array of pins used to select 1 of 8 inputs on multiplexer const int select[] = {2,3,4}; // pins connected to the 4051 input select lines const int analogPin = A0; // the analog pin connected to multiplexer output // this function returns the analog value for the given channel int getValue(int channel) { // set the selector pins HIGH and LOW to match the binary value of channel for(int bit = 0; bit < 3; bit++) { int pin = select[bit]; // the pin wired to the multiplexer select bit int isBitSet = bitRead(channel, bit); // true if given bit set in channel digitalWrite(pin, isBitSet); } return analogRead(analogPin); } void setup() { for(int bit = 0; bit < 3; bit++) { pinMode(select[bit], OUTPUT); // set the three select pins to output } Serial.begin(9600); } void loop () { // print the values for each channel once per second for(int channel = 0; channel < 8; channel++) { int value = getValue(channel); Serial.print("Channel "); Serial.print(channel); Serial.print(" = "); Serial.println(value); } delay (1000); } |

شکل 1: مالتپلکسر 4051 متصل به آردوینو
Analog Multiplexers سوئیچهای آنالوگی هستند که بهصورت دیجیتالی کنترل میشوند. Chip 4051 یکی از هشت ورودی را از طریق Three-Pin Selector (S0, S1, S2) انتخاب میکند. برای این Selector Pins، هشت ترکیب مختلف از مقادیر وجود دارد و Sketch بهصورت متوالی هر یک از این Bit Patterns را انتخاب میکند. به Table 1 نگاه کنید.
شما باید Ground (GND) دستگاههایی را که اندازهگیری میکنید، به GND ماژول 4051 و Arduino متصل کنید. برای اینکه بتوانید مقادیر را بهدرستی بخوانید، همه آنها باید یک Common GND داشته باشند. اگر قصد دارید تمام دستگاهها را از طریق پین 5V یا 3.3V روی برد خود تغذیه کنید، مطمئن شوید که میزان Power Consumption شما از حداکثر توان Power Supply یا بیشترین توانی که پین قادر به تأمین آن است (هرکدام که کمتر باشد) بیشتر نشود.
بهعنوانمثال، پین 5V در Arduino Uno میتواند تا 900mA جریان را بهصورت ایمن تأمین کند، البته در صورتی که از یک External Power Supply استفاده شود. در حالت تغذیه از طریق USB Power، حداکثر جریان 400mA است. (اما اگر از یک 500mA Power Source استفاده میکنید، حداکثر جریانی که میتوانید دریافت کنید کمتر از 500mA خواهد بود، زیرا Microcontroller، LEDs و سایر اجزا نیز از این توان استفاده میکنند). این مقدار یک مقدار تئوری است، بنابراین بهتر است همیشه کمی پایینتر از این حد بمانید.
همچنین، ممکن است لازم باشد به Board Documentation ،Microcontroller Datasheet و Voltage Regulator Datasheet مراجعه کنید تا از Current Limitations مطلع شوید.
علاوه بر این، برای دستگاههایی که متصل میکنید، اگر مجموع Current Consumption شما به حداکثر مقدار نزدیک شود، باید از یک External Power Supply استفاده کنید.

جدول 1: جدول مالتیپلکسر 4051
شما ممکن است الگوی موجود در Table 1 را بهعنوان نمایش Binary Representation مقادیر Decimal از 0 تا 7 تشخیص دهید.
در Solution Sketch، تابع getValue()
مسئول تنظیم Selector Bits برای کانال مشخص با استفاده از دستور digitalWrite(pin, isBitSet)
است. سپس مقدار Analog را از ورودی انتخابشده 4051 با استفاده از دستور analogRead(analogPin)
میخواند. همچنین، برای تولید Bit Patterns از تابع داخلی bitRead()
استفاده میشود.
به خاطر داشته باشید که این روش بهصورت Sequential هشت ورودی را انتخاب و نظارت میکند. بنابراین، برای خواندنهای ورودیهای مختلف، نسبت به زمانی که از analogRead()
بهصورت Direct استفاده میشود، زمان بیشتری نیاز است. برای مثال، اگر شما هشت ورودی را میخوانید، زمان لازم برای خواندن هر ورودی هشت برابر بیشتر خواهد بود. بهطورکلی، این مسئله ممکن است باعث شود این روش برای ورودیهایی که Rapidly Changing هستند، مناسب نباشد.
اندازهگیری ولتاژها تا 5 ولت
برای اندازهگیری ولتاژ در محدوده 0 تا 5 ولت از تابع analogRead() استفاده میشود. مقدار خواندهشده از این تابع را میتوان با استفاده از ولتاژ مرجع (Reference Voltage) به مقدار واقعی ولتاژ تبدیل کرد:

شکل 2: اندازهگیری ولتاژها تا 5 ولت با استفاده از برد 5 ولتی
اندازهگیری ولتاژهای آنالوگ بر روی بردهای ESP8266
اگر از بردی مبتنی بر ESP8266 استفاده میکنید، ممکن است محدود به ولتاژهایی در بازه 0 تا 1V باشید. برخی از بردهای مبتنی بر ESP8266 دارای Internal Voltage Dividers هستند که به شما این امکان را میدهند که تا 3.3V (چون ESP8266 روی 3.3 V کار میکند) را بخوانید، بنابراین حتماً Documentation برد خود را بررسی کنید. بدون Voltage Divider، Analog Input Pins در ESP8266 حداکثر تا 1V میتوانند ورودی داشته باشند.
سادهترین راهحل، استفاده از یک Floating-Point Calculation برای چاپ ولتاژ است. این راهحل نمونه، مقدار ولتاژ را بهصورت Ratio Calculation محاسبه کرده و نمایش میدهد:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /* * Display5vOrless sketch * prints the voltage on analog pin to the serial port * Warning - do not connect more than 5 volts directly to an Arduino pin. */ const float referenceVolts = 5.0; // the default reference on a 5-volt board const int batteryPin = A0; // battery is connected to analog pin 0 void setup() { Serial.begin(9600); } void loop() { int val = analogRead(batteryPin); // read the value from the sensor float volts = (val / 1023.0) * referenceVolts; // calculate the ratio Serial.println(volts); // print the value in volts } |
فرمول
ولتاژ = (مقدار دیجیتال خواندهشده از پین آنالوگ / analog steps) × ولتاژ مرجع
- analog steps: به تعداد تقسیماتی اشاره دارد که یک مبدل آنالوگ به دیجیتال (ADC) میتواند ولتاژ ورودی آنالوگ را به آنها تبدیل کند. در یک ADC 10 بیتی، این مراحل 2 به توان 10 یعنی 1024 مرحله است که از 0 تا 1023 شمارهگذاری میشود. به این معنی که ADC میتواند ولتاژ ورودی را به 1024 مقدار دیجیتال تقسیم کند.
- ولتاژ مرجع: ولتاژی که بهعنوان مرجع استفاده میشود (مثلاً 5 ولت یا 3.3 ولت بستگی به برد دارد).
این فرمول برای تبدیل مقدار دیجیتال خواندهشده به معادل ولتاژ آن استفاده میشود.
زمانی که یک مقدار Floating-Point را با استفاده از دستور Serial.println()
به Serial Port چاپ میکنید، بهصورت پیشفرض این مقدار با دو رقم اعشار نمایش داده میشود.
اگر از بردی استفاده میکنید که دارای 3.3V Logic است، این تغییر را اعمال کنید:
| const float referenceVolts = 3.3; |
اعداد شناور (Floating-Point) حافظه زیادی مصرف میکنند، بنابراین اگر در بخشهای دیگری از کدتان نیازی به آنها ندارید، بهتر است از مقادیر صحیح (Integer) استفاده کنید تا کارایی افزایش یابد.
کد زیر شاید در ابتدا کمی عجیب به نظر برسد، اما از آنجایی که analogRead()
برای 5V مقدار 1023 را برمیگرداند، هر تغییر در مقدار معادل 5 ÷ 1023 است.
در واحد میلیولت، این مقدار برابر است با: 5000 ÷ 1023.
کد زیر مقدار را برحسب میلیولت (mV) چاپ میکند:
| const int batteryPin = A0; void setup() { Serial.begin(9600); } void loop() { long val = analogRead(batteryPin); // read the value from the sensor - // note val is a long int Serial.println( (val * (500000/1023L)) / 100); // the value in millivolts } |
✅نکته
اگر از بردی با ولتاژ 3.3V استفاده میکنید، مقدار 500000/1023L
را به 330000/1023L
تغییر دهید.
کد زیر مقدار را با استفاده از اعداد اعشاری (Floating-Point) چاپ میکند. اگر ولتاژ 1.5V باشد، مقدار 1.5 را نمایش میدهد.
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 | const int batteryPin = A0; void setup() { Serial.begin(9600); } void loop() { int val = analogRead(batteryPin); // read the value from the sensor long mv = (val * (500000/1023L)) / 100; // calculate the value in millivolts Serial.print(mv/1000); // print the integer portion of the voltage Serial.print('.'); int fraction = (mv % 1000); // calculate the fraction if (fraction == 0) { Serial.print("000"); // add three zeros } else if (fraction < 10) // if fractional < 10 the 0 is ignored giving a wrong // time, so add the zeros { Serial.print("00"); // add two zeros } else if (fraction < 100) { Serial.print("0"); } Serial.println(fraction); // print the fraction } |
تابع analogRead()
مقداری را برمیگرداند که متناسب با نسبت ولتاژ اندازهگیریشده به ولتاژ مرجع (Reference Voltage) است. در Arduino Uno، مقدار ولتاژ مرجع 5V میباشد.
برای جلوگیری از استفاده از اعداد اعشاری (Floating-Point) و افزایش دقت، کد بهجای ولت (V) با میلیولت (mV) کار میکند (چون هر 1V معادل 1000mV است). ازآنجاییکه 1023 معادل 5000mV است، هر واحد برابر است با:
50001023≈4.89mV\frac{5000}{1023} \approx 4.89mV10235000≈4.89mV
✅نکته
شما ممکن است برای تبدیل مقادیر analogRead()
به میلیولت، هم از 1023
و هم از 1024
استفاده کنید.
- مهندسان معمولاً از
1024
استفاده میکنند زیرا 1024 مقدار ممکن بین 0 تا 1023 وجود دارد. - عدد
1023
برای برخی منطقیتر است چون بیشترین مقدار ممکن برابر با 1023 است. - در عمل، اختلاف بین این دو مقدار کمتر از دقت سختافزار است، بنابراین میتوانید هرکدام را که راحتترید استفاده کنید.
روش حذف اعشار برای بهینهسازی حافظه
برای حذف اعشار، مقادیر در 100 ضرب میشوند:
5000×1001023\frac{5000 \times 100}{1023}10235000×100
این مقدار تعداد میلیولتها را 100 برابر میکند. سپس با تقسیم بر 100، مقدار نهایی به میلیولت (mV) تبدیل میشود.
اگر ضرب کردن اعداد اعشاری در 100 برای شما پیچیده است، میتوانید از روش memory-hungry با اعداد شناور (Floating-Point) استفاده کنید. اما این روش زمانبرتر و پرهزینهتر از نظر پردازشی خواهد بود.
⚠ توجه
این راهحل فرض میکند که شما از Arduino Uno یا یک برد مشابه 8 بیتی با لاجیک 5V استفاده میکنید.
📌 اگر از بردی با ولتاژ 3.3V استفاده میکنید، حداکثر ولتاژی که میتوانید اندازهگیری کنید 3.3V خواهد بود، مگر اینکه از تقسیمکننده ولتاژ (Voltage Divider) استفاده کنید.
نویسنده شو !
سیسوگ با افتخار فضایی برای اشتراک گذاری دانش شماست. برای ما مقاله بنویسید.