Автоматическая перезагрузка Arduino при подключении терминала

Начав работать с последовательным портом Arduino, я столкнулся с особенностями, которых я не ожидал, в силу своего незнания. Разобравшись с работой отдельных компонентов, имеющихся в моем распоряжении, я начал разрабатывать программную часть (названную artesh) будущей системы автоматизации, для которой планируется использовать последовательный интерфейс Arduino. Внешний интерфейс нужен для контроля состояния и изменения настроек во время выполнения программы. Идея была в том, что микроконтроллер может работать автономно, но, по мере надобности, к нему будет подключаться терминал, чтобы вручную проверить показания датчиков, изменить состояния реле и т.д. Однако, при каждом подключении терминала я обнаруживал, что все переменные инициализированы начальными значениями. Перепроверив все несколько раз, осталось сделать вывод, что микроконтроллер перезагружается каждый раз, когда я подключаюсь к нему терминалом через последовательный порт. Тогда уже осталось прибегнуть к методу RTFM и убедиться, что это - стандартное поведение Arduino с USB-serial контроллером.

Именно USB-serial контроллер Arduino перезагружает МК каждый раз, когда терминальная программа (в т.ч. Serial monitor, встроенный в ПО Arduino IDE) устанавливает соединение. Реализовано это следующим образом: у USB-serial контроллера вывод DTR (Data Terminal Ready) связан с выводом RESET. Если программа, работающая с виртуальным последовательным портом, использует DTR, то при установке соединения МК перезагружается.

Само по себе это обеспечивает беспроблемную загрузку скетча из Arduino IDE - МК перезагружается перед загрузкой кода. В старых моделях было необходимо нажимать RESET вручную перед каждой загрузкой кода. В этом смысле автоматическая перезагрузка облегчает жизнь. Кроме того, перезагрузка при подключении терминала тоже может оказаться удобной, т.к. довольно много скетчей выводят какую-то полезную информацию через последовательный порт, при этом скетч выполняется сразу после загрузки в МК, когда терминал еще не подключен (т.к. недавно порт был занят), так что увидеть вывод скетча в первые секунды его работы было бы нельзя. Перезагрузка в момент подключения терминала позволяет получить весь вывод, начиная с момента загрузки МК. Т.е. функцию автоматической перезагрузки оправдывает удобство работы в Arduino IDE. Но для моих прикладных целей это нежелательно.

Простой способ избежать автоматической перезагрузки - не использовать USB-serial интерфейс вовсе, а подключаться напрямую к последовательному порту МК, используя выводы D0 (RX), D1 (TX). Но для этого необходим ТТЛ-совместимый последовательный интерфейс со стороны терминала, которого может не оказаться. Последовательный порт стандарта RS232 (COM порт) напрямую к выводам МК подключать нельзя!  Хотя можно сделать ТТЛ-совместимый адаптер из USB-RS232 адаптера.

Возможно избежать автоматической перезагрузки продолжая использовать USB-serial контроллер. Способов достигнуть этого оказалось несколько, как аппаратных, так и программных.

Аппаратные решения сводятся к тому, чтобы не дать сигналу DTR запустить перезагрузку, а именно:

  • У Arduino Uno R3 есть специальное место на плате, обозначенное как RESET EN, где можно перерезать дорожку, соединяющую DTR и RESET, а при необходимости спаять обратно без особых проблем (см.фото)
  • Соединить вывод RESET и 5V резистором 120 Ом (для моделей с FTDI USB-serial чипом, напр. Diecimila) [источник]
  • Соединить вывод RESET и GND конденсатором 10 мкФ (для моделей с USB-serial контроллером на ATmega8U/ATmega16U, напр. Uno) [источник]
  • Удалить конденсатор, соединяющий вывод DTR USB-serial контроллера и RESET МК (самый жестокий способ) [источник]

Программные решения избегают подачи сигнала DTR:

  • Модификация кода терминальной программы и/или драйвера последовательного порта с целью исключить использование DTR [источник]
  • Перепрошивка USB-serial контроллера (для моделей с USB-serial контроллером ATmega8U/ATmega16U) с целью игнорировать сигнал DTR от терминала [источник]

А здесь описывается обратное - как реализовать автоматическую перезагрузку на старых моделях, где ее нет.

Пока я остановился на использовании последовательного порта напрямую, минуя USB-serial контроллер. Для этого понадобился USB-TTL serial адаптер. Но для конечного, "промышленного" варианта все же планирую отключить эту функцию аппаратно.