← До всіх проєктів
Основи Середній

ESP32 чи Arduino Uno: що ламається, коли переносиш скетч з однієї плати на іншу

Той самий `setup()` і `loop()`, але int різного розміру, АЦП на 1023 проти 4095, 5 В проти 3.3 В і немає printf. Дванадцять відмінностей, через які скетч з інтернету не компілюється або тихо працює неправильно, — і як їх виправити.

Складність
Середній
Час
30 min
Категорія
Основи
Оновлено

Навіщо це знати

Більшість прикладів в інтернеті написані для Arduino Uno, а проєкти все частіше збирають на ESP32 — і навпаки: хтось бере готовий скетч для ESP32 і прошиває в Nano. Мова одна, функції схожі, але плати дуже різні. Нижче — відмінності, які найчастіше ламають скетч, від помилок компіляції до тихих багів.

Коротке порівняння

Arduino Uno (ATmega328P) ESP32
Ядро 8 біт, 16 МГц 32 біти, 2 × 240 МГц
RAM 2 КБ 320 КБ (+ PSRAM)
Логіка 5 В 3.3 В
АЦП 10 біт, 0–1023, лінійний 12 біт, 0–4095, нелінійний
ШІМ analogWrite() лише на пінах ~ LEDC на будь-якому виході
Переривання лише D2, D3 будь-який GPIO
Wi-Fi / Bluetooth немає є

Мова: int, double і printf

  1. int — 16 біт на AVR. int x = 30000; x += 5000; на Uno дає −30536, на ESP32 — 35000. Для міліс, лічильників і добутків беріть long / unsigned long або int32_t. Особливо підступне 60 * 1000 — на Uno це вже переповнення: пишіть 60000UL.
  2. double = float на AVR. Точність лише 6–7 знаків. На ESP32 double справжній, 64-бітний.
  3. Немає Serial.printf() на AVR. Скетчі для ESP32 з printf на Uno не компілюються. Замініть на ланцюжок Serial.print(), або використайте snprintf() у буфер.
  4. %f не працює в sprintf на AVR — замість числа друкується ?. Для дробових чисел — dtostrf(value, width, digits, buf).

Залізо: напруги й виводи

  1. 5 В на вході ESP32 шкодить. Датчик, що живиться від 5 В і видає 5 В на виході (HC-SR04 ECHO, деякі модулі реле), потрібно підключати через дільник або перетворювач рівнів.
  2. 3.3 В з ESP32 може не вистачити. Модулі на 5 В (реле, HC-SR501, LCD 1602 без підсвітки) від 3.3 В працюють нестабільно, а логічна «одиниця» 3.3 В інколи не сприймається 5-вольтовою логікою.
  3. АЦП: 1023 проти 4095. map(analogRead(A0), 0, 1023, …) на ESP32 дасть учетверо більше. І навпаки. Крім того, АЦП ESP32 нелінійний біля країв — для точності є analogReadMilliVolts(), якої на AVR немає.
  4. ШІМ. На ESP32 3.x теж є analogWrite(), але для частоти й розрядності — ledcAttach(pin, freq, bits) і ledcWrite(pin, duty). На Uno ШІМ є лише на 3, 5, 6, 9, 10, 11, частота фіксована: 490 Гц (5 і 6 — 980 Гц). analogWrite() на піні без ~ просто вмикає або вимикає вихід.
  5. Переривання. На Uno attachInterrupt() працює лише для D2 і D3, і першим аргументом іде номер переривання — тому пишіть digitalPinToInterrupt(pin), а не просто pin. На ESP32 обробник позначають IRAM_ATTR; на AVR цього слова немає.
  6. Номери виводів. LED_BUILTIN — це 13 на Uno і 2 на ESP32 DevKit. I2C на Uno — A4/A5, на ESP32 — 21/22; SPI — 13/12/11/10 проти 18/19/23/5.

Пам'ять і бібліотеки

  1. 2 КБ RAM. Буфер OLED 128×64 — це вже 1 КБ, половина пам'яті Uno. Великі String, масиви й бібліотеки, що «легко» працюють на ESP32, на Uno переповнюють стек без жодного повідомлення — плата просто перезавантажується. Рядкові константи тримайте у флеші: Serial.println(F("текст")).
  2. Бібліотеки лише для однієї платформи. WiFi.h, Preferences.h, ESP32Servo.h, TFT_eSPI на AVR немає. На Uno замість Preferences — EEPROM.h, замість ESP32Servo — Servo.h. І навпаки: бібліотеки, що працюють з регістрами AVR (TimerOne, SoftwareSerial у старих версіях), на ESP32 не компілюються; там HardwareSerial Serial2 і апаратні таймери.

Спробуйте в симуляторі

У симуляторі всі ці відмінності відтворені. Оберіть плату в списку поруч із прикладами, і приклад відкриється, вже адаптований під неї. Порівняйте, наприклад, потенціометр і ШІМ на ESP32 з тим самим прикладом на Uno: ledcWrite став analogWrite, 4095 став 1023, а printf — ланцюжком print. Спробуйте самі написати Serial.printf() для Uno — компілятор підкаже, чим замінити.