Руководства · 15 мин чтения

Arduino постоянно перезагружается? Решаем проблемы с сервоприводом, реле и зависаниями

Arduino постоянно перезагружается или зависает? Разбираем по шагам: ток сервопривода и реле, просадки напряжения, общая земля GND, конденсаторы 470 µF, переполнение RAM и сторожевой таймер.

Если Arduino постоянно перезагружается или зависает через какое-то время работы, плата почти никогда не бывает неисправной. Чаще всего причина в питании: когда сервопривод начинает двигаться, мотор раскручивается или реле срабатывает, резкий скачок потребляемого тока на мгновение обрушивает линию 5 V, и защита процессора от пониженного напряжения (brown-out) перезагружает плату. В остальных случаях виноваты электрические помехи от реле и моторов, длинные провода, переполненная RAM, забытый сторожевой таймер (watchdog) или USB-порт компьютера, которому не хватает тока.

В этом руководстве сначала разберёмся, как отличить настоящую перезагрузку от простого зависания. Затем объясним, как работает каждая причина, на реальных значениях тока и напряжения, и покажем решения с кодом: отдельное питание и общая земля (GND), конденсаторы 100–470 µF, обратные диоды (flyback), фиксированные буферы вместо String и сторожевой таймер. Здесь же есть диагностический скетч, который измеряет собственное напряжение питания Arduino и свободную RAM, пошаговая таблица диагностики от симптома к решению и примеры, которые читают причину сброса на ESP32 и Raspberry Pi Pico.

Плата Arduino Uno R3
Arduino Uno R3: 5 V от USB проходят через самовосстанавливающийся предохранитель на 500 mA. При сбросе программа запускается заново с setup(); кнопка RESET и пин RESET делают то же самое.

Перезагрузка или зависание? Сначала определи симптом

Перезагружающаяся Arduino выполняет программу с самого начала, как будто USB-кабель вынули и снова вставили: setup() выполняется снова, сервопривод возвращается в начальное положение, на LCD снова появляется стартовый текст, а в мониторе порта опять видно стартовое сообщение. Зависшая Arduino, наоборот, ни на что не реагирует: светодиоды остаются в последнем состоянии, вывод в порт прекращается, и плата так и ждёт, пока не нажмёшь кнопку сброса. Причины и решения у этих двух случаев разные, поэтому начни с того, чтобы понять, какой из них у тебя. Проще всего добавить в setup() строку Serial.println("STARTED") и оставить монитор порта открытым.

СимптомПерезагрузкаЗависание
setup() выполняется снова?Да, стартовое сообщение появляется сноваНет
Вывод в портПрекращается, затем начинается заново со стартового сообщенияПрекращается и больше не возобновляется
Выходы и светодиодыНенадолго гаснут, затем возвращаются в начальное состояниеЗастревают в последнем состоянии
Самая частая причинаПросадка напряжения, помехи, сторожевой таймерБесконечный цикл, зависшая шина I2C, повреждённая RAM
Что проверить первымПитание, GND и проводаКод, расход памяти и провода датчиков

Почему Arduino перезагружается сама? Источники сброса

Перезапустить процессор ATmega328P на Arduino Uno и Nano могут лишь несколько источников, и у каждого свой повод для срабатывания. Когда напряжение питания падает ниже определённого порога, включается детектор просадки питания (BOD, brown-out); на Uno и Nano fuse-биты (биты конфигурации) задают этот порог на уровне 2,7 V. Плату перезапускает и всё, что тянет пин RESET в LOW: кнопка сброса, сигнал DTR от компьютера или помехи, которые ловит длинный провод, подключённый к этому пину. Есть и случай, который выглядит как сброс, но им не является: из-за повреждённой памяти программа переходит на адрес 0 и код начинается заново, но поскольку аппаратная периферия не сбрасывается, плата начинает вести себя странно.

Источник сбросаЧто его вызывает?Типичный симптом
Включение питания (POR)Подключение кабеля, полное пропадание питанияОбычный запуск
Внешний сброс (пин RESET)Кнопка сброса, открытие монитора порта (DTR), помехи на пине RESETПерезапуск при открытии порта или касании провода
Просадка питания (BOD, 2,7 V)Пусковой ток сервопривода, мотора, реле или светодиодной ленты, слабая батарейкаСброс в тот момент, когда нагрузка начинает двигаться
Сторожевой таймер (watchdog)wdt_reset() не вызывается вовремяСбросы через равные промежутки (например, ровно каждые 2 секунды)
Программный сбойВыход за границы массива, переполнение RAM, неверный указательСлучайный сброс или зависание через минуты или часы

Ток сервопривода, мотора и реле: как просадка напряжения вызывает сброс

Сервопривод SG90 во время движения потребляет 100–250 mA, но при старте и под нагрузкой на качалке ток подскакивает выше 0,5 A. Порт USB 2.0 компьютера даёт не более 500 mA, и предохранитель на линии USB у Uno работает на том же пределе. Когда сервопривод, собственные 50 mA платы и несколько модулей вместе превышают этот предел, порт или предохранитель ограничивает ток, линия 5 V на мгновение проседает, и если напряжение опускается ниже 2,7 V, BOD перезагружает плату. Коварнее случай, когда напряжение остаётся между 2,7 V и примерно 3,8 V: по даташиту ATmega328P для надёжной работы на 16 MHz микросхеме нужно около 3,8 V. В этой серой зоне BOD не срабатывает, но процессор работает за пределами допустимой частоты, поэтому плата может не перезагрузиться, а зависнуть или выдавать мусорные значения, а I2C-дисплеи и датчики могут заблокироваться изнутри.

НагрузкаОбычный токПиковый токПитание от пина 5V на Uno?
Микросервопривод SG90100–250 mA0,5 A и больше (старт, нагрузка)Только один сервопривод с лёгкой нагрузкой
Сервопривод MG996R0,5–0,9 AДо 2,5 AНет, обязательно отдельный источник 5–6 V
Мотор-редуктор TT (DC)70–250 mA~1 A (старт, заклинивание)Нет, драйвер мотора и отдельный источник
Модуль реле 5 V (одноканальный)70–90 mAКороткий импульс при включении катушки1–2 канала можно, 4 и больше — от отдельного источника
Светодиод WS2812B (один)~20 mA (один цвет на полной яркости)60 mA (полный белый)Нет; 30 светодиодам на полном белом нужно 1,8 A

Провода тоже важны. Тонкие провода-перемычки в проектах на макетной плате обычно имеют сечение 26–28 AWG, а у медного провода 28 AWG сопротивление около 0,21 Ω на метр. Если питать сервопривод через два провода по 20 см (0,4 м туда и обратно) и макетную плату, провода добавят около 0,085 Ω, а четыре контакта макетной платы вместе — около 0,2 Ω. По закону Ома (V = I × R) импульс сервопривода в 1 A теряет на этих 0,29 Ω около 0,3 V. Тонкий длинный USB-кабель, предохранитель и защитные элементы на плате добавляют ещё примерно пол-ома; во время того же импульса линия 5 V у Arduino проседает ниже 4,5 V, а если порт компьютера начинает ограничивать ток, просадка становится гораздо глубже. Просадку в своей схеме можно посчитать с помощью калькулятора закона Ома.

От пина 5V на Uno питай не больше одного сервопривода SG90, и то с лёгкой нагрузкой. Никогда не подключай большие сервоприводы вроде MG996R, DC-моторы или светодиодные ленты к пину 5V или 3.3V Arduino: плата будет перезагружаться, а со временем могут пострадать предохранитель USB, стабилизатор и даже USB-порт компьютера.

Решение 1: отдельное питание и общая земля (GND)

  1. Выбери отдельный источник для сервоприводов и моторов: для сервоприводов подойдёт адаптер 5–6 V, который даёт не меньше 1 A на каждый сервопривод (2–3 A для MG996R), блок из 4×AA NiMH или понижающий модуль LM2596, настроенный на 5–6 V.
  2. Плюс источника подключай только к красным проводам сервоприводов или к силовому входу драйвера мотора; к пину 5V Arduino эту линию не подключай.
  3. Минус источника (GND) подключи и к нагрузке, и к пину GND Arduino. Без этой общей земли (GND) у напряжения на сигнальном пине нет точки отсчёта: сервопривод дёргается или вообще не двигается.
  4. Соедини все GND в одной точке рядом с источником (заземление звездой). Ток мотора не должен возвращаться через Arduino и её дорожки GND, иначе уровень GND у Arduino будет смещаться при каждом импульсе мотора.
  5. Питай Arduino через её собственный вход: USB, гнездо питания DC (7–12 V) или стабилизированные 5 V. Тогда процессор не пострадает, даже если питание сервоприводов просядет.
  6. В конце измерь напряжение между пинами 5V и GND Arduino во время движения сервопривода или запусти диагностический скетч ниже: напряжение не должно опускаться ниже 4,75 V.
Понижающий преобразователь напряжения LM2596
Понижающий модуль LM2596: подстроечным резистором можно понизить более высокое напряжение, например от адаптера 12 V или сборки 2S Li-ion, до 5–6 V. Это самый практичный способ сделать линию питания сервоприводов, независимую от Arduino. Настрой выход по мультиметру до подключения нагрузки.
Почему общая земля обязательна и как работает заземление звездой, мы объясняем в статье Что такое GND?, а как выбрать батареи и адаптеры — в руководстве по питанию Arduino от батарей. Правило простое: сигнальные провода идут от Arduino, силовые — от источника, а все GND соединяются.

Решение 2: конденсаторы (100–470 µF) и диоды

Электролитический конденсатор работает как небольшой накопитель энергии рядом с нагрузкой: когда сервопривод требует резкого тока, конденсатор отдаёт этот ток сам, пока провода и источник питания не успеют среагировать. Насколько он помогает, показывает формула ΔV = I × Δt / C. Конденсатор 470 µF при импульсе 1 A длительностью 100 µs даёт напряжению просесть всего на 0,21 V; если тот же импульс длится 1 мс, просадка составит 2,1 V. То есть конденсатор поглощает короткие импульсы и помехи от щёток мотора, но не заменяет слабый источник. Поставь 470–1000 µF на линию сервоприводов и 100 µF между 5V и GND Arduino, а рядом с каждым добавь керамический конденсатор 100 nF с маркировкой 104 против высокочастотных помех. Маркировку поможет прочитать утилита кодов конденсаторов, а общую ёмкость параллельно соединённых конденсаторов покажет калькулятор последовательного и параллельного соединения конденсаторов; чем отличаются типы, рассказано в статье Что такое конденсатор?.

Где?НоминалЗачем?
Линия питания сервопривода, рядом с ним470–1000 µF / 10–16 V, электролитический + 100 nFСмягчает пусковой импульс
Между двумя выводами DC-мотора100 nF, керамическийФильтрует помехи от искрения щёток
Между 5V и GND Arduino100 µF, электролитический + 100 nFЗащищает линию питания процессора от коротких просадок
Вход ленты WS2812B1000 µF / 10 VПринимает пусковой ток и импульсы при смене цвета
Пины питания датчиков и модулей100 nF, керамическийФильтрует помехи, которые приносят длинные провода
Электролитические конденсаторы разных номиналов
Электролитические конденсаторы: номинал вроде 470 µF / 16 V идеально подходит для линии сервоприводов 5 V. Полоса на корпусе отмечает отрицательную (−) ножку; номинальное напряжение должно быть хотя бы вдвое выше напряжения линии.

Катушки реле, моторы и соленоиды — всё это индуктивности. Когда ток через них резко прерывается, катушка сопротивляется изменению и создаёт короткий выброс напряжения в десятки и даже сотни вольт, намного выше напряжения питания. Этот выброс расходится по линии и перезагружает Arduino, а ещё может вывести из строя транзистор драйвера или пин. Решение — обратный диод (flyback), включённый параллельно катушке в обратном направлении: катод 1N4007, отмеченный полосой, идёт к плюсу, другой вывод — к стороне, которая ведёт к транзистору. В готовых модулях реле такой диод уже есть; если используется отдельное реле без модуля, соленоид или мотор, которым управляет транзистор или MOSFET, диод нужно добавить самостоятельно. Для моторов с регулировкой скорости через ШИМ (PWM) лучше подходит более быстрый диод Шоттки 1N5819. Подробности — в статьях Что такое диод? и MOSFET с Arduino.

Выпрямительный диод 1N4007
Диод 1N4007: серая полоса на корпусе обозначает катод (−). Включённый в обратном направлении параллельно катушке, он замыкает накоротко и гасит выброс напряжения, который возникает при разрыве тока.

Помехи, контакты реле и длинные провода

Если плата перезагружается ровно в момент отключения реле, проблема не в питании, а в помехах. Когда реле отключает водяной насос, вентилятор, люминесцентную лампу или контактор, между контактами возникает небольшая дуга, и она излучает широкополосные электромагнитные помехи. Помехи наводятся на соседние провода датчиков, линию RESET и линии I2C, перезагружая процессор или блокируя модуль. Чтобы этого избежать, используй модуль реле с оптопарой, сними перемычку JD-VCC и питай катушки реле от отдельного источника 5 V: так ток катушек и помехи держатся подальше от линии питания Arduino. При индуктивных сетевых нагрузках RC-снаббер (100 Ω + 100 nF, класс X2) или варистор параллельно контактам или нагрузке сильно подавляет дугу. Подробности подключения — в статье Что такое модуль реле?, а идея развязки — в статье Что такое оптопара?.

  • I2C покороче: шина I2C создавалась для коротких расстояний в пределах одной платы. Держи провода SDA и SCL короче 50 см; на более длинных линиях уменьши подтягивающие резисторы с 4,7 kΩ до 2,2 kΩ и оставь скорость 100 kHz.
  • Используй витые провода: скрути каждый сигнальный провод вместе с проводом GND; витые пары из сетевого кабеля идеально для этого подходят.
  • Раздели питание и сигнал: не прокладывай провода датчиков параллельно проводам моторов, реле или сетевым проводам; если им нужно пересечься, пусть пересекаются под прямым углом.
  • Не трогай пин RESET: длинный провод на пине RESET работает как антенна и перезагружает плату при касании или когда рядом работает мотор. Если нужна внешняя кнопка сброса, делай её провод коротким.
  • Ферриты и корпус: ферритовые кольца на проводах моторов и металлический корпус уменьшают высокочастотные помехи.
  • Добавь таймаут: если помехи блокируют шину I2C, библиотека Wire по умолчанию ждёт бесконечно, и плата зависает. Код ниже предотвращает такое зависание с помощью таймаута.
C++ (Arduino IDE)
1#include <Wire.h>
2
3const uint8_t ADDR = 0x27;   // örnek: I2C LCD adresi / example: I2C LCD address
4
5void setup() {
6  Serial.begin(9600);
7  Wire.begin();
8  Wire.setWireTimeout(25000, true);   // 25 ms; takılırsa I2C birimini sıfırla / reset the I2C unit on timeout
9}
10
11void loop() {
12  Wire.beginTransmission(ADDR);
13  byte err = Wire.endTransmission();  // 0 = cihaz cevap verdi / 0 = device answered
14
15  if (Wire.getWireTimeoutFlag()) {    // hat kilitlendi ama program donmadı / bus hung, sketch did not freeze
16    Serial.println(F("I2C zaman asimi / I2C timeout"));
17    Wire.clearWireTimeoutFlag();
18  } else if (err != 0) {
19    Serial.print(F("I2C hatasi / I2C error: "));
20    Serial.println(err);              // 2 = cihaz yok, 5 = zaman aşımı / 2 = no device, 5 = timeout
21  }
22  delay(1000);
23}

Переполнение RAM и использование String

У Arduino Uno всего 2 КБ SRAM, и это небольшое пространство делят глобальные переменные, динамическая память (куча, heap) и стек (stack), который используют вызовы функций. Если в конце компиляции появляется предупреждение Low memory available, stability problems may occur. (мало свободной памяти, возможны проблемы со стабильностью), плата, скорее всего, через некоторое время начнёт сбоить. Самая коварная причина — класс String: каждая конкатенация выделяет в куче новый кусок, старый освобождается, и со временем память становится дырявой. Однажды стек сталкивается с кучей, и программа перезагружается или зависает в случайный момент. Поскольку это обычно проявляется через минуты или часы, такую проблему легко отличить от проблем с питанием. Храни постоянный текст во флеш-памяти с помощью макроса F(), вместо String используй массивы char фиксированного размера и snprintf() и не объявляй большие локальные массивы внутри функций. Код ниже каждую секунду выводит объём свободной RAM; если значение постоянно уменьшается, значит, есть утечка памяти. Подробно эта тема разобрана в статье Arduino: не хватает памяти.

C++ (Arduino IDE)
1extern int __heap_start, *__brkval;
2
3// Heap ile stack arasındaki boş RAM / free RAM between heap and stack
4int freeRam() {
5  int v;
6  return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int)__brkval);
7}
8
9char line[32];             // sabit tampon, bir kez ayrılır / fixed buffer, allocated once
10unsigned long counter = 0;
11
12void setup() {
13  Serial.begin(9600);
14}
15
16void loop() {
17  counter++;
18  // Kaçın / avoid: String s = "Sayac: " + String(counter) + " sn";
19  snprintf(line, sizeof(line), "Sayac: %lu sn", counter);  // heap kullanmaz / no heap use
20  Serial.println(line);
21
22  Serial.print(F("Bos RAM / free RAM: "));  // F(): metin flaşta kalır / text stays in flash
23  Serial.println(freeRam());                // sürekli azalıyorsa sızıntı var / steady drop = leak
24  delay(1000);
25}

Сторожевой таймер: ремень безопасности против зависаний

Сторожевой таймер (watchdog) — это счётчик внутри процессора, который работает независимо, от собственного генератора 128 kHz. Программа должна регулярно «кормить» его вызовом wdt_reset(); если за заданное время (от 15 мс до 8 секунд) этого не случится, сторожевой таймер перезагрузит плату. Так зависшая шина I2C, функция, застрявшая в бесконечном цикле, или показание датчика, испорченное помехами, не смогут навсегда заморозить плату: она придёт в себя за несколько секунд. Помни, что сторожевой таймер — это ремень безопасности, а не ремонт: он не решает проблемы с питанием или памятью, а лишь позволяет проекту, работающему в полевых условиях, восстановиться без вмешательства. Выбирай таймаут заметно длиннее самой долгой операции в коде; в коде с delay(3000) сторожевой таймер на 2 секунды будет перезагружать плату снова и снова.

C++ (Arduino IDE)
1#include <avr/wdt.h>
2
3const int LED_PIN = 13;
4
5void setup() {
6  MCUSR = 0;          // reset bayraklarını temizle / clear reset flags
7  wdt_disable();      // açılışta watchdog kapalı / watchdog off during startup
8  Serial.begin(9600);
9  pinMode(LED_PIN, OUTPUT);
10  Serial.println(F("Basladi / started"));
11  delay(500);
12  wdt_enable(WDTO_2S);  // 2 sn içinde beslenmezse reset / reset if not fed within 2 s
13}
14
15void loop() {
16  digitalWrite(LED_PIN, !digitalRead(LED_PIN));
17  delay(250);
18
19  // Seri Monitör'den 'x' gönder: takılmayı taklit eder / send 'x' to simulate a hang
20  if (Serial.available() && Serial.read() == 'x') {
21    Serial.println(F("Sonsuz donguye girildi / stuck in a loop"));
22    while (true) {}     // wdt_reset() yok: 2 sn sonra reset / no wdt_reset(): reset after 2 s
23  }
24
25  wdt_reset();          // her turda besle / feed it every loop
26}
На клонах Nano со старым загрузчиком сторожевой таймер опасен. Такой загрузчик не отключает таймер после сброса по watchdog; таймер продолжает работать с самым коротким периодом (около 16 мс), и загрузчик не успевает закончить свою работу за это время. В результате возникает бесконечный цикл перезагрузок, в котором твой код так и не запускается; плата выходит из него, только если отключить и снова подключить USB-кабель, а при первом же срабатывании сторожевого таймера цикл начинается снова. Если для твоей платы нужно выбирать ATmega328P (Old Bootloader) в меню «Инструменты › Процессор» (Tools › Processor), перед использованием сторожевого таймера запиши в неё загрузчик Optiboot; как это сделать, рассказано в статье Ошибки загрузки кода в Arduino. У загрузчика Optiboot на Uno этой проблемы нет.

Диагностический скетч: пусть Arduino сама измерит своё напряжение и RAM

Мультиметр слишком медленный, чтобы заметить миллисекундные просадки напряжения. Вместо него можно использовать саму Arduino как простой измерительный прибор: код ниже с помощью АЦП (ADC) измеряет внутреннее опорное напряжение микросхемы 1,1 V, по нему вычисляет напряжение питания примерно 9000 раз в секунду и выводит минимальное значение за каждую секунду. Кроме того, при каждом запуске он увеличивает счётчик в EEPROM, так что даже если открыть монитор порта позже, видно, сколько раз плата перезапускалась. В качестве тестовой нагрузки он каждые 2 секунды поворачивает сервопривод на D9 между 0 и 180 градусами; если есть свой проект, измерительную часть можно добавить в его код. Открой монитор порта на скорости 115200 бод.

C++ (Arduino IDE)
1// Reset teşhis kodu (Uno, Nano) / reset diagnostic sketch (Uno, Nano)
2#include <EEPROM.h>
3#include <Servo.h>
4
5Servo servo;
6extern int __heap_start, *__brkval;
7
8int freeRam() {
9  int v;
10  return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int)__brkval);
11}
12
13// Besleme gerilimini dahili 1,1 V referansla ölç / measure supply voltage against the internal 1.1 V reference
14long readVcc() {
15  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
16  ADCSRA |= _BV(ADSC);                  // ölçümü başlat / start a conversion
17  while (bit_is_set(ADCSRA, ADSC)) {}   // bitmesini bekle / wait until it is done
18  return 1125300L / ADC;                // 1100 mV × 1023 / okuma → mV / reading → mV
19}
20
21long minVcc = 9999;
22unsigned long lastPrint = 0, lastMove = 0;
23bool sideA = false;
24
25void setup() {
26  Serial.begin(115200);
27  uint16_t boots;
28  EEPROM.get(0, boots);                 // açılış sayacı / boot counter
29  if (boots == 0xFFFF) boots = 0;       // boş EEPROM / blank EEPROM
30  EEPROM.put(0, ++boots);
31  Serial.print(F("BASLADI / STARTED  acilis no / boot #"));
32  Serial.println(boots);
33
34  servo.attach(9);                      // test yükü: servo D9'da / test load: servo on D9
35  readVcc();                            // ilk ölçümü at / discard the first reading
36  delay(5);
37}
38
39void loop() {
40  long v = readVcc();                   // saniyede ~9000 ölçüm / ~9000 samples per second
41  if (v < minVcc) minVcc = v;
42
43  if (millis() - lastMove >= 2000) {    // 2 sn'de bir servoyu oynat / move the servo every 2 s
44    lastMove = millis();
45    sideA = !sideA;
46    servo.write(sideA ? 180 : 0);
47  }
48
49  if (millis() - lastPrint >= 1000) {
50    lastPrint = millis();
51    Serial.print(F("sn/s: "));
52    Serial.print(millis() / 1000);
53    Serial.print(F("  min Vcc (mV): "));
54    Serial.print(minVcc);
55    Serial.print(F("  bos RAM / free RAM: "));
56    Serial.println(freeRam());
57    minVcc = 9999;                      // her saniye sıfırla / reset every second
58  }
59}

Читай результаты так: у исправной Uno с питанием от USB минимальное значение держится между 4,6 и 5,1 V. Если при каждом движении сервопривода значение падает ниже 4,5 V и сбросы совпадают с этими моментами, проблема в питании. Если номер запуска растёт, а напряжение остаётся стабильным, ищи помехи или программную причину; если при этом свободная RAM постоянно уменьшается, значит, есть утечка памяти. Внутреннее опорное напряжение 1,1 V может отличаться от микросхемы к микросхеме примерно на 10%, поэтому один раз сверь показания с мультиметром: если мультиметр показывает 4,95 V, а код выводит 5,10 V, замени константу 1125300 на 1125300 × 4.95 / 5.10 ≈ 1092200. Когда диагностика закончена, убери счётчик EEPROM из кода: ячейки EEPROM рассчитаны примерно на 100 000 циклов записи.

Пошаговая таблица диагностики: симптом, причина, решение

Читай таблицу сверху вниз: первые строки — самые частые причины. Меняй только одну вещь за раз и снова запускай диагностический скетч. Если поменять сразу три вещи, будет непонятно, какая из них решила проблему, и та же неисправность вернётся в следующем проекте.

СимптомВероятная причинаКак проверитьРешение
Сброс при движении сервопривода или мотораПусковой ток обрушивает линию 5 VМинимальное напряжение в диагностическом скетче падает ниже 4,5 VОтдельный источник 5–6 V, общая GND, 470–1000 µF
Сброс, когда реле отпускает, а не когда срабатываетДуга на контактах и выброс от катушки (помехи)Проблема исчезает, если отключить нагрузку релеОтдельное питание через JD-VCC, снаббер или варистор, обратный диод
Всё начинается заново при открытии монитора портаАвтосброс по DTR (нормальное поведение)STARTED появляется при каждом открытии портаЭто не неисправность; при необходимости 10 µF между RESET и GND
Сброс только от компьютера, от адаптера всё в порядкеUSB-порт или хаб не даёт достаточно токаПомогают другой порт и короткий толстый кабельИспользуй задний порт или хаб с внешним питанием, питай нагрузки отдельно
Сброс при движении, когда питание идёт от батарейки-«кроны» на 9 VВысокое внутреннее сопротивление, напряжение проседаетVin во время движения падает ниже 7 V6×AA или сборка 2S из 18650
Сброс или зависание через минуты или часыПереполнение RAM, фрагментация из-за StringСвободная RAM постоянно уменьшаетсяF(), массивы char, snprintf, небольшие локальные массивы
Сброс через строго равные промежуткиСторожевой таймер не сбрасывается вовремяИнтервал сбросов равен таймауту сторожевого таймераДобавь wdt_reset() или увеличь таймаут, избегай длинных delay()
На Nano после сброса по watchdog код так и не запускаетсяОшибка старого загрузчика со сторожевым таймеромКод в плату загружается только с опцией Old BootloaderЗапиши загрузчик Optiboot
Случайные зависания при подключении длинного кабеля датчикаШина I2C блокируется из-за помехУстановлен флаг таймаута WireКороткие витые провода, подтяжка 2,2 kΩ, setWireTimeout, сторожевой таймер
Сброс, когда подносишь руку или касаешьсяДлинный провод на пине RESET, статическое электричествоПроходит, если убрать проводДержи линию RESET короткой, помести схему в корпус
Стабилизатор сильно греется, затем сбросБольшой ток при 12 V на гнезде питания, срабатывает тепловая защита стабилизатораСтабилизатор такой горячий, что не дотронутьсяАдаптер 7–9 V или понижающий модуль на 5 V
Плата не включается или пропадает портКороткое замыкание, сработал предохранитель USBБез модулей плата включаетсяНайди короткое замыкание, проверь, цела ли плата

USB-порту не хватает тока, и сброс при открытии монитора порта

Порт USB 2.0 компьютера даёт 500 mA, а порт USB 3.0 — 900 mA; но поскольку предохранитель USB на Uno ограничивает ток на уровне 500 mA, порт USB 3.0 дополнительного тока не даёт. USB-хаб без внешнего питания делит ток одного порта между всеми устройствами, порты на передней панели теряют напряжение из-за тонких внутренних кабелей, а ноутбуки, работающие от батареи, в режиме энергосбережения могут слабо питать порты. Подключай плату напрямую к заднему порту коротким качественным кабелем. Бывает и сброс, который не является неисправностью: Uno и Nano перезагружаются через сигнал DTR, когда монитор порта или программа на Python открывает порт, и именно эта функция делает возможной загрузку кода. Если обмен данными идёт из Python, после открытия порта подожди 2 секунды (обмен данными между Arduino и Python по последовательному порту). Если нужно полностью отключить сброс, поставь конденсатор 10 µF между RESET и GND и убирай его на время загрузки кода. Подробности о последовательном порте — в статье Монитор порта Arduino.

ESP32 постоянно перезагружается: читаем причину сброса

ESP32 ещё чувствительнее к тем же проблемам, потому что работает от 3,3 V и во время передачи по Wi-Fi потребляет около 240 mA, а в коротких пиках и больше; Espressif рекомендует источник, способный дать не менее 500 mA. Хорошая новость: ESP32 сама сообщает причину перезапуска. Сообщение Brownout detector was triggered в мониторе порта означает просадку напряжения, а строки rst:0xf (RTCWDT_BROWN_OUT_RESET) или Guru Meditation Error при запуске показывают причину сброса. Код ниже читает ту же информацию через esp_reset_reason() и превращает её в понятный текст. На ESP32 кнопка EN полностью выключает и включает микросхему, поэтому сброс этой кнопкой тоже выглядит как включение питания. Все сообщения и способы их устранения — в статье Ошибки brownout и Guru Meditation на ESP32.

C++ (Arduino IDE)
1#include <esp_system.h>
2
3// Reset sebebini yazıya çevir / turn the reset reason into text
4const char* reasonText(esp_reset_reason_t r) {
5  switch (r) {
6    case ESP_RST_POWERON:   return "Guc acilisi ya da EN tusu / power-on or EN button";
7    case ESP_RST_SW:        return "Yazilimla (ESP.restart) / software restart";
8    case ESP_RST_PANIC:     return "Cokme (Guru Meditation) / panic";
9    case ESP_RST_INT_WDT:   return "Kesme watchdog'u / interrupt watchdog";
10    case ESP_RST_TASK_WDT:  return "Gorev watchdog'u / task watchdog";
11    case ESP_RST_WDT:       return "Diger watchdog / other watchdog";
12    case ESP_RST_DEEPSLEEP: return "Derin uykudan uyanma / deep sleep wake-up";
13    case ESP_RST_BROWNOUT:  return "Gerilim dusmesi (brownout) / brownout";
14    default:                return "Bilinmeyen / unknown";
15  }
16}
17
18void setup() {
19  Serial.begin(115200);
20  delay(500);
21  esp_reset_reason_t r = esp_reset_reason();
22  Serial.print("Reset nedeni / reset reason: ");
23  Serial.println(reasonText(r));
24}
25
26void loop() {
27  Serial.print("Calisma suresi / uptime (s): ");
28  Serial.println(millis() / 1000);
29  delay(5000);
30}

Raspberry Pi Pico: причина сброса и сторожевой таймер (MicroPython)

Благодаря понижающе-повышающему преобразователю Raspberry Pi Pico работает при любом напряжении от 1,8 до 5,5 V на пине VSYS, поэтому переносит просадки напряжения лучше, чем Arduino. И всё же если подключить сервопривод к пину VBUS, на который приходят 5 V от USB, ток берётся прямо из порта компьютера, и если порт проседает, Pico тоже отключается; кроме того, от пина 3V3 не стоит брать в сумме больше 300 mA. Пин сброса Pico, RUN, подтянут к питанию встроенным в микросхему резистором примерно 50 kΩ; длинный провод на нём открывает дорогу помехам, как и пин RESET у Arduino. В MicroPython на Pico machine.reset_cause() возвращает только два значения: PWRON_RESET при включении питания или сбросе через пин RUN и WDT_RESET при срабатывании сторожевого таймера или вызове machine.reset(). Сторожевой таймер можно настроить максимум на 8388 мс, и после запуска его нельзя остановить: он продолжает перезагружать плату, даже если остановить программу в Thonny. Поэтому в начале кода стоит поставить паузу в 3 секунды.

MicroPython
1import machine, time
2from machine import Pin
3
4time.sleep(3)   # Thonny durdurabilsin diye bekle / wait so Thonny can stop the script
5
6neden = machine.reset_cause()
7if neden == machine.WDT_RESET:
8    print("Watchdog ya da machine.reset() / watchdog or machine.reset()")
9else:
10    print("Guc acilisi ya da RUN pini / power-on or RUN pin")
11
12led = Pin("LED", Pin.OUT)          # Pico ve Pico W dahili LED / onboard LED
13wdt = machine.WDT(timeout=5000)    # 5 sn; RP2040'ta en fazla 8388 ms / max 8388 ms on RP2040
14
15sayac = 0
16while True:
17    led.toggle()
18    sayac += 1
19    print("Calisiyor / running", sayac)
20    wdt.feed()                     # her turda besle / feed it every loop
21    time.sleep(1)

Правильная схема питания для твоего проекта

  • Машинка-робот: питай моторы от сборки 2S из 18650 через L298N или L9110S и поставь конденсатор 100 nF на выводы мотора; как её собрать, рассказано в статье Машинка-робот на Arduino своими руками.
  • Робот-манипулятор на сервоприводах: для четырёх и более сервоприводов используй источник 5–6 V, который даёт не меньше 3–5 A, и добавь 1000 µF на линию сервоприводов; о выборе деталей — в статьях Сервопривод MG996R и Робот-манипулятор на Arduino.
  • Система полива с насосом и реле: питай насос от отдельного источника, изолируй реле с помощью JD-VCC и держи длинные провода датчиков подальше от кабеля насоса (датчик влажности почвы).
  • Светодиодные ленты и NeoPixel: закладывай около 2 A на каждые 30 светодиодов, поставь 1000 µF на вход ленты и резистор 300–500 Ω на линию данных (WS2812B NeoPixel).
  • Управление DC-моторами: не забывай про обратный диод на каждом моторе, которым управляешь через транзистор или MOSFET; о готовых платах драйверов — в статье Управление DC-мотором с L298N.
  • Станция датчиков в полевых условиях: включи сторожевой таймер, настрой таймаут I2C и бери питание от эффективного источника, например от понижающего преобразователя LM2596.

Arduino, которая сама перезагружается, раздражает, но почти всегда у этого есть измеримая и устранимая причина: сначала определи симптом, затем измерь напряжение и RAM диагностическим скетчем, потом раздели питание, соедини GND, добавь конденсатор и диод и при необходимости подстрахуй проект сторожевым таймером. Когда такая схема питания настроена, проекты с сервоприводами, моторами и реле работают днями без проблем. В приложении BlueGrays есть проекты «Работа с сервоприводом», «Машинка на L298N с управлением по Bluetooth», «Робот, объезжающий препятствия», «Включение лампы 220V кнопкой (вкл/выкл)» и «Умная станция полива» со схемами, на которых показано правильное подключение питания, и с пошаговым кодом.

Частые вопросы

Почему Arduino постоянно перезагружается?

Самая частая причина в том, что резкий ток сервопривода, мотора или реле на мгновение просаживает линию 5 V, и защита процессора от пониженного напряжения (2,7 V) перезагружает плату. Сбросы вызывают также помехи от контактов реле, переполнение RAM, сторожевой таймер, который не сбрасывается вовремя, и USB-порт, которому не хватает тока. Питание сервоприводов и моторов от отдельного источника и соединение GND решают большинство случаев.

Почему Arduino перезагружается, когда двигается сервопривод?

Даже маленький сервопривод SG90 при старте потребляет больше 0,5 A и вместе с другими нагрузками платы превышает предел USB-порта и предохранителя Uno на 500 mA. Когда напряжение проседает, плата перезагружается. Питай сервопривод от отдельного источника 5–6 V, соедини GND этого источника с GND Arduino и добавь конденсатор 470–1000 µF на линию сервопривода.

Почему Arduino перезагружается при переключении реле?

Катушка реле при включении потребляет резкий ток, а при отпускании катушка и контакты создают помехи. Дуга, которая возникает при отключении индуктивных нагрузок вроде насосов, вентиляторов или люминесцентных ламп, может перезагрузить Arduino. На модуле с оптопарой сними перемычку JD-VCC и питай реле от отдельного источника, добавь снаббер или варистор параллельно нагрузке и держи провода датчиков подальше от проводов нагрузки.

Почему Arduino зависает через некоторое время?

Зависания, которые появляются через минуты или часы, чаще всего вызваны заполнением RAM и фрагментацией памяти из-за конкатенации String. Плату также может заморозить шина I2C, зависшая из-за помех, или код, который ждёт в бесконечном цикле. Измерь свободную RAM, используй массивы char вместо String, задай таймаут через Wire.setWireTimeout() и включи сторожевой таймер для подстраховки.

Какой конденсатор добавить в схему с Arduino?

Хорошо работают 470–1000 µF на линии питания сервоприводов и моторов и электролитический конденсатор 100 µF между 5V и GND Arduino. Если рядом с каждым добавить керамический конденсатор 100 nF (104), он отфильтрует ещё и высокочастотные помехи. Номинальное напряжение электролитического конденсатора должно быть хотя бы вдвое выше напряжения линии, а его отрицательная ножка, отмеченная полосой, подключается к GND.

Почему Arduino перезагружается при открытии монитора порта?

Uno и Nano перезагружаются через сигнал DTR при открытии последовательного порта; это не неисправность, а функция автосброса, благодаря которой возможна загрузка кода. Если обмен данными идёт из программы, например на Python, после открытия порта подожди 2 секунды. Чтобы отключить сброс, поставь конденсатор 10 µF между RESET и GND и убери его перед загрузкой кода.

Все проекты
Работа с сервоприводом
#35Новичок
Premium

Работа с сервоприводом

Рычаг маленького сервопривода по очереди поворачивается в три положения: до упора в начало, ровно на середину и до упора в конец, задерживаясь на каждой остановке на две секунды. Arduino сообщает мото

4.7(48)
67
Включение лампы 220V кнопкой (удержание)
#19Продвинутый
Premium

Включение лампы 220V кнопкой (удержание)

Пока ты держишь кнопку, горит настоящая лампа на 220 вольт, а как только отпустишь — гаснет. Слабый сигнал Arduino не может зажечь лампу напрямую, поэтому между ними стоит реле — выключатель с электри

4.4(30)
38
Машинка на L298N с управлением по Bluetooth
#80Продвинутый
Premium

Машинка на L298N с управлением по Bluetooth

Преврати телефон в пульт и управляй своей машинкой-роботом. Arduino получает команды из приложения-пульта на телефоне через Bluetooth-модуль и вращает колёса через драйвер моторов; машинка едет вперёд

5.0(38)
65
Робот, объезжающий препятствия
#81Продвинутый
Premium

Робот, объезжающий препятствия

Как насчёт того, чтобы собрать умную машину, которая сама находит дорогу? Робот, объезжающий препятствия, постоянно осматривает всё вокруг благодаря ультразвуковому датчику спереди. Встретив препятств

5.0(38)
49
Умная станция полива
#83Продвинутый
Premium

Умная станция полива

Садовник, который сам поливает растения, чтобы они не засохли, пока ты в отпуске. Датчик влажности почвы измеряет, насколько влажная земля; когда она сохнет, Arduino на несколько секунд включает водян

5.0(42)
57
Хореография сервоприводов по кругу — анимации на 32 сервоприводах
#102Продвинутый
Premium

Хореография сервоприводов по кругу — анимации на 32 сервоприводах

Визуальный анимационный проект на Arduino Mega с 32 сервоприводами, расставленными по кругу. Сервоприводы собраны в один массив и подключены к пинам 22–53 Mega; они показывают четыре движения: хаотичное дрожание на случайных углах, синхронный взмах всех сразу, плавную волну по кругу и, наконец, стрелку компаса, качающуюся влево и вправо. Эффект бегущей волны создаётся поворотом каждого сервопривода в зависимости от его расстояния до активного.

4.5(40)
62
Сервопривод на ESP32 (управление потенциометром)
#118Средний
Premium

Сервопривод на ESP32 (управление потенциометром)

В этом проекте сервопривод SG90 управляется потенциометром. Угол сервопривода задаётся сопоставлением аналогового значения потенциометра с диапазоном 0–180 градусов. Библиотека ESP32Servo формирует сигналы сервопривода на подходящих выходных пинах GPIO у ESP32; этот проект использует GPIO 18. Это базовый способ управления для роборук, подвесов камер и механизмов автоматических дверей.

4.3(29)
42