🎛️ analogRead در ESP32: خواندن پتانسیومتر با ADC دوازده‌بیتی و تبدیل به ولتاژ

✍️ تیم ووکوی فارسی ·

در آردوینو اونو analogRead عددی بین ۰ تا ۱۰۲۳ برمی‌گرداند و تقریباً همیشه همان‌طور که انتظار داری کار می‌کند. در ESP32 همان دستور را می‌نویسی، ولی سه چیز فرق دارد: بازه‌ی عدد بزرگ‌تر است، ولتاژ مرجع ۳٫۳ ولت است و نیمی از پایه‌های آنالوگ با روشن شدن وای‌فای از کار می‌افتند. در این آموزش analogRead در ESP32 را با یک پتانسیومتر یاد می‌گیریم: عدد خام را می‌خوانیم، نویزش را کم می‌کنیم، به میلی‌ولت و درصد تبدیلش می‌کنیم و با آن یک LED را با «هیسترزیس» روشن و خاموش می‌کنیم تا در مرز چشمک نزند. همه‌چیز را در شبیه‌ساز ESP32، به همان سبکی که در ووکوی (Wokwi) کار می‌کنی، امتحان می‌کنیم.

ADC ۱۲ بیتی یعنی چه؟

ADC یا مبدل آنالوگ به دیجیتال، ولتاژ یک پایه را به یک عدد تبدیل می‌کند. «۱۲ بیتی» یعنی این عدد می‌تواند ۲ به توان ۱۲، یعنی ۴۰۹۶ مقدار مختلف داشته باشد: از ۰ تا ۴۰۹۵. صفر یعنی صفر ولت و ۴۰۹۵ یعنی تقریباً ۳٫۳ ولت. پس هر واحد حدود ۰٫۸ میلی‌ولت است؛ چهار برابر دقیق‌تر از اونو. البته این دقت روی کاغذ است. ADC در ESP32 کمی نویز دارد و در دو سر بازه خطی نیست: زیر حدود ۰٫۱ ولت معمولاً صفر می‌خواند و بالای حدود ۳٫۱ ولت به ۴۰۹۵ می‌چسبد. بهترین دقت در بازه‌ی میانی است.

قطعه‌ها و سیم‌کشی

پایه‌ی پتانسیومتربه ESP32توضیح
پایه‌ی کناری اول3V3نه VIN! بیشتر از ۳٫۳ ولت به پایه‌ی آنالوگ نرسان
پایه‌ی وسط (سرِ متحرک)GPIO34روی ADC1 است و با وای‌فای هم کار می‌کند
پایه‌ی کناری دومGNDزمین مشترک

چرا GPIO34؟ چون روی ADC1 است، فقط ورودی است و هیچ نقشی در بوت برد ندارد. فهرست کامل پایه‌های آنالوگ و دلیل هر انتخاب را در پین اوت ESP32 نوشته‌ایم.

کد کامل

// ESP32: read a potentiometer with the 12-bit ADC.
const int POT = 34;        // ADC1 pin, input-only: keeps working with Wi-Fi on
const int LED = 2;         // built-in blue LED
const int SAMPLES = 16;    // average a few readings to calm the noise

bool ledOn = false;

int readSmooth(int pin) {
  long sum = 0;
  for (int i = 0; i < SAMPLES; i++) {
    sum += analogRead(pin);
    delayMicroseconds(200);
  }
  return sum / SAMPLES;
}

void setup() {
  Serial.begin(115200);
  pinMode(LED, OUTPUT);
  analogReadResolution(12);         // 0..4095 (the ESP32 default)
  analogSetAttenuation(ADC_11db);   // full range, roughly 0..3.3 V
}

void loop() {
  int raw = readSmooth(POT);
  int mV = raw * 3300.0 / 4095;     // simple conversion to millivolts
  int percent = map(raw, 0, 4095, 0, 100);

  // hysteresis: ON above 55 %, OFF below 45 %, so the LED never flickers at the edge
  if (!ledOn && percent > 55) ledOn = true;
  if (ledOn && percent < 45) ledOn = false;
  digitalWrite(LED, ledOn ? HIGH : LOW);

  // "name:value" pairs, ready for the serial plotter
  Serial.print("raw:");
  Serial.print(raw);
  Serial.print(",mV:");
  Serial.println(mV);
  delay(100);
}

توضیح خط به خط

analogReadMilliVolts: ولتاژ دقیق‌تر روی برد واقعی

فرمول بالا فرض می‌کند ADC کاملاً خطی است، ولی نیست. هر تراشه‌ی ESP32 در کارخانه کالیبره می‌شود و اطلاعات کالیبراسیونش داخل خود تراشه ذخیره است. هسته‌ی آردوینوی ESP32 دستوری دارد که از همین اطلاعات استفاده می‌کند و مستقیم میلی‌ولت برمی‌گرداند: int mV = analogReadMilliVolts(34);. روی برد واقعی این عدد معمولاً چند ده میلی‌ولت به ولت‌متر نزدیک‌تر از فرمول ساده است. این دستور را روی برد واقعی امتحان کن و در شبیه‌ساز از همان فرمول ساده استفاده کن.

💡 برای اندازه گرفتن ولتاژ بیشتر از ۳٫۳ ولت، مثلاً ولتاژ باتری لیتیومی ۴٫۲ ولتی یا یک سنسور ۵ ولتی، هرگز مستقیم وصلش نکن. با دو مقاومت یک مقسم ولتاژ بساز تا ولتاژ پایین بیاید و در کد دوباره ضربش کن. ماشین‌حساب مقسم ولتاژ مقدار مقاومت‌ها را حساب می‌کند.

ADC2 و وای‌فای: مهم‌ترین تله

ESP32 دو ADC دارد. ADC1 روی پایه‌های 32 تا 39 است و ADC2 روی 0، 2، 4، 12 تا 15 و 25 تا 27. مشکل این است که رادیوی وای‌فای از ADC2 استفاده می‌کند. اگر پتانسیومتر را به GPIO4 یا GPIO25 وصل کنی، تا وقتی وای‌فای خاموش است همه‌چیز درست کار می‌کند؛ ولی به محض WiFi.begin، analogRead روی آن پایه عدد بی‌معنی یا خطا برمی‌گرداند. خیلی‌ها ساعت‌ها دنبال باگ در کد وب‌سرورشان می‌گردند در حالی که مشکل فقط شماره‌ی پایه است. قانون ساده: در هر پروژه‌ای که وای‌فای دارد، سنسور آنالوگ روی ADC1.

اجرا در شبیه‌ساز

در تینکرکد فارسی برد ESP32 و پتانسیومتر را بگذار، سیم‌کشی جدول را انجام بده و کد را اجرا کن. با چرخاندن ولوم، عدد در سریال مانیتور از صفر تا ۴۰۹۵ تغییر می‌کند و LED آبی در ۵۵ درصد روشن و در ۴۵ درصد خاموش می‌شود. تب نمودار را باز کن تا دو منحنی را زنده ببینی. خواندن مثال‌ها رایگان است و اجرای ESP32 به اشتراک Plus نیاز دارد. یک مثال آماده‌ی جذاب‌تر هم هست: نمایش زنده‌ی پتانسیومتر در صفحه‌ی وب با ESP32؛ همین پتانسیومتر روی GPIO34، با وای‌فای روشن. اگر اصل analogRead را هنوز روی اونو یاد نگرفته‌ای، درس analogRead و پتانسیومتر رایگان است و معنی analogRead را هم در واژه‌نامه ببین.

اشکال‌های رایج

حالا که عدد ولوم را داری، با آن چیزی را حرکت بده: کنترل سروو با ESP32 و پتانسیومتر، یا نور را با آن کم و زیاد کن: PWM با ledc. اگر پیکو داری، همین آموزش با میکروپایتون در ADC پیکو آمده است. همه‌ی آموزش‌ها در صفحه‌ی ESP32.

پتانسیومتر و ESP32 را در شبیه‌ساز امتحان کن 🎛️

سؤال‌های رایج

analogRead در ESP32 چه بازه‌ای برمی‌گرداند؟

به‌صورت پیش‌فرض عددی بین ۰ تا ۴۰۹۵، چون ADC در ESP32 دوازده‌بیتی است. با analogReadResolution می‌توانی آن را مثلاً به ۱۰ بیت (۰ تا ۱۰۲۳) تغییر دهی.

چرا عدد analogRead در ESP32 مدام بالا و پایین می‌رود؟

ADC در ESP32 نویز دارد. چند نمونه پشت سر هم بخوان و میانگین بگیر، یک خازن ۱۰۰ نانوفاراد بین پایه و GND بگذار و از تغییرات یکی دو واحدی چشم‌پوشی کن.

کدام پایه‌ی ESP32 برای پتانسیومتر بهتر است؟

پایه‌های ADC1 یعنی 32، 33، 34، 35، 36 و 39. این‌ها با روشن بودن وای‌فای هم کار می‌کنند. GPIO34 انتخاب محبوبی است چون فقط ورودی است و نقشی در بوت ندارد.

مقاله‌های مرتبط

👆

پین لمسی ESP32: ساخت کلید لمسی بدون هیچ قطعه‌ای با touchRead

🦾

راه‌اندازی سروو موتور با ESP32: کتابخانه‌ی ESP32Servo، روش ledc ۵۰ هرتز و تغذیه‌ی درست

📡

ESP32 در حالت Access Point: وب‌سرور بدون مودم با WiFi.softAP

⚙️

برنامه‌نویسی رزبری پای پیکو با زبان آردوینو (C++ و هسته‌ی arduino-pico)

همه‌ی آموزش‌های ESP32 و اینترنت اشیا ← · همه‌ی مقاله‌ها