ESP32 чи Arduino Uno: що ламається, коли переносиш скетч з однієї плати на іншу
Той самий `setup()` і `loop()`, але int різного розміру, АЦП на 1023 проти 4095, 5 В проти 3.3 В і немає printf. Дванадцять відмінностей, через які скетч з інтернету не компілюється або тихо працює неправильно, — і як їх виправити.
Навіщо це знати
Більшість прикладів в інтернеті написані для 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
int— 16 біт на AVR.int x = 30000; x += 5000;на Uno дає −30536, на ESP32 — 35000. Для міліс, лічильників і добутків берітьlong/unsigned longабоint32_t. Особливо підступне60 * 1000— на Uno це вже переповнення: пишіть60000UL.double=floatна AVR. Точність лише 6–7 знаків. На ESP32doubleсправжній, 64-бітний.- Немає
Serial.printf()на AVR. Скетчі для ESP32 зprintfна Uno не компілюються. Замініть на ланцюжокSerial.print(), або використайтеsnprintf()у буфер. %fне працює вsprintfна AVR — замість числа друкується?. Для дробових чисел —dtostrf(value, width, digits, buf).
Залізо: напруги й виводи
- 5 В на вході ESP32 шкодить. Датчик, що живиться від 5 В і видає 5 В на виході (HC-SR04 ECHO, деякі модулі реле), потрібно підключати через дільник або перетворювач рівнів.
- 3.3 В з ESP32 може не вистачити. Модулі на 5 В (реле, HC-SR501, LCD 1602 без підсвітки) від 3.3 В працюють нестабільно, а логічна «одиниця» 3.3 В інколи не сприймається 5-вольтовою логікою.
- АЦП: 1023 проти 4095.
map(analogRead(A0), 0, 1023, …)на ESP32 дасть учетверо більше. І навпаки. Крім того, АЦП ESP32 нелінійний біля країв — для точності єanalogReadMilliVolts(), якої на AVR немає. - ШІМ. На ESP32 3.x теж є
analogWrite(), але для частоти й розрядності —ledcAttach(pin, freq, bits)іledcWrite(pin, duty). На Uno ШІМ є лише на 3, 5, 6, 9, 10, 11, частота фіксована: 490 Гц (5 і 6 — 980 Гц).analogWrite()на піні без~просто вмикає або вимикає вихід. - Переривання. На Uno
attachInterrupt()працює лише для D2 і D3, і першим аргументом іде номер переривання — тому пишітьdigitalPinToInterrupt(pin), а не простоpin. На ESP32 обробник позначаютьIRAM_ATTR; на AVR цього слова немає. - Номери виводів.
LED_BUILTIN— це 13 на Uno і 2 на ESP32 DevKit. I2C на Uno — A4/A5, на ESP32 — 21/22; SPI — 13/12/11/10 проти 18/19/23/5.
Пам'ять і бібліотеки
- 2 КБ RAM. Буфер OLED 128×64 — це вже 1 КБ, половина пам'яті Uno. Великі
String, масиви й бібліотеки, що «легко» працюють на ESP32, на Uno переповнюють стек без жодного повідомлення — плата просто перезавантажується. Рядкові константи тримайте у флеші:Serial.println(F("текст")). - Бібліотеки лише для однієї платформи.
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 — компілятор підкаже, чим замінити.