Можно ли изменить программу Arduino на лету?
У меня есть Arduino, который запрограммирован на что-то. Возможно ли, чтобы я мог изменить его поведение, меняя программу «на лету» без необходимости перепрограммирования Arduino через компьютер?
Мне нужно отправить сообщение через MQTT, которое получит Arduino, и изменить его поведение. Мне удалось изменить частоту публикации сообщений или добавить новые данные, но что, если я захочу изменить способ принятия решений? Что, если я захочу изменить код Arduino, добавить какое-либо if или другое состояние, можно ли это сделать на лету?
Обновление: изменение поведения устройства на лету или после перезагрузки допускается. Я не строг с использованием Arduino, есть и опция Nodemcu. Мне просто нужен способ добавить новые функции к устройству, если мне понадобится.
@emir, 👍0
Обсуждение6 ответов
- Код, который записывает данные во флэш-память, должен находиться в разделе загрузчика. Единственный известный мне способ выполнить код в разделе загрузчика — это после сброса. Однако даже если бы вы могли перенести выполнение в раздел загрузчика и заставить что-то работать, это бы приходится мириться с тем фактом, что флэш-память имеет ограниченные циклы записи и сократит срок службы устройства. Возможно, до такой степени, что бесполезно для практического применения.
- Выполнение кода из оперативной памяти. Самоочевидно, изменяйте код как хотите. Существует примечание к применению для AVR, в котором обсуждается этот вопрос.
- Напишите переводчика для своих нужд. Фу!
EDIT: Есть пример кода GCC здесь.
Вы должны иметь возможность переходить к местам в разделе загрузчика, при условии, что вы знаете предположения кода, который вы там разместили. Вы также можете сделать мягкий сброс. Но да, выносливость флэш-памяти является проблемой., @Chris Stratton
Я не знал об ограничении количества перепрошивок. Вы имеете в виду прошивку прошивки или обновление устройства с кодом с помощью IDE или через OTA?, @emir
Циклы записи/стирания: 10 000 Flash/100 000 EEPROM, @atland
Утверждение о "выполнении кода из ОЗУ" ошибочно. Это не поддерживается на AVR, ваша ссылка ведет на документ для процессора ARM серии Atmel SAM, а не на AVR., @Chris Stratton
Извините. Неправильная заметка по применению. Мне было интересно, почему я написал AVR. Это взято из этой заметки по применению для [AVR32825: Выполнение кода из внешнего SDRAM](http://www.atmel.com/Images/doc32160.pdf) Специально для серий AVR 32 UC3A и UC3C., @atland
Вы можете изменить поведение Arduino «на лету», но перепрограммировать его не обязательно, просто разработайте свой код так, чтобы он изменял поведение с помощью некоторых переменных, которые вы получаете извне, например, с сервера, но эти новые изменения должны быть определены заранее в вашем коде.
Если у вас есть список состояний и вы хотите добавить больше, используйте динамический массив или массив с достаточным пространством, а затем отправьте сообщение MQTT, которое Arduino проанализирует, добавив новое состояние или даже удалив состояние.
Мне нужно посмотреть, как можно обновить устройство, добавив в него новые функции, которые ранее не планировалось., @emir
Замена или изменение существующего кода во время выполнения потребует некоторой формы загрузки и перезаписи старого кода. Это намеренно не сделано простым или легким для этих типов микроконтроллеров.
Но вы можете изменить стратегию программы на лету, если предвидите потенциальные изменения и включите код для каждой из возможностей.
Например, напишите набор функций, каждая из которых реализует один из различных способов работы, и во время выполнения выберите, какую функцию должна использовать программа. Вы можете изменить выбор, установив значение с клавиатуры, или программа может обнаружить некий внешний триггер, например нажатие кнопки или показания температуры, и отреагировать, изменив выбор — возможно, значение типа int. Оператор switch
может использовать это значение для вызова соответствующей функции в соответствующее время:
uint8_t strategy = 0; // инициализация стратегии по умолчанию
switch( selector ){
case(1): // произошло ли событие 1?
func1();
break;
case(2): // произошло ли событие 2?
func2();
break;
case(3): // произошло ли событие 3?
func3();
break;
default: // ничего из вышеперечисленного или неопределенное значение селектора
funcDefault();
break;
}
Это означает, что весь код для возможных рабочих стратегий должен быть включен во время загрузки и совместно использовать пространство памяти программы, но если ваша работа не очень сложная, даже Uno должен быть достаточно мощным.
Обновление:
Мне нужно иметь возможность обновить устройство, добавив в него новые функции.
Есть еще один подход, который может подойти или не подойти для Uno, но будет осуществим с Mega 2560 или другой машиной с большим объемом оперативной памяти: интерпретируемый код.
Определите набор операций, который включает все, что вам понадобится для работы вашего внешнего устройства(-ий): необходимые операции ввода-вывода для считывания показаний датчиков и управления оборудованием; для выполнения логических и/или арифметических тестов и условного перехода или вызова функции на основе результата теста; для прослушивания пользовательского сигнала с терминала (например) и возврата в программу arduino. Это будет «язык», на котором вы напишете свою программу управления.
Определите краткую схему кодирования для указания каждой операции и любых данных, которые ей нужны, например, считывание показаний датчика температуры и сохранение результата в именованном месте. Если ваши программы управления не будут слишком сложными, вы можете обойтись предопределением A, B, ..., Z как регистров данных некоторого подходящего типа.
Напишите интерпретатор на языке C++ для этого нового языка. Его программа будет состоять из кодов, которые вы только что определили. Но этот код будет рассматриваться интерпретатором как данные. Это ключ — этот псевдокод будет находиться в оперативной памяти, где ваш интерпретатор — набор функций C++ — может его прочитать и выполнить, а программа Arduino может загрузить новый, перезаписать старый и снова запустить интерпретатор.
Предостережение: подобно греческой мифической Гидре, эта работа может создавать новые проблемы по мере решения текущих, но она выполнима, если вы максимально упростите ее и включите только то, что вам действительно необходимо для ее выполнения.
Выполнение интерпретируемого во время выполнения кода может занять в 10–50 раз больше времени, чем выполнение нативно закодированного приложения, поэтому все, что может быть предварительно закодировано на C++, должно быть предварительно закодировано. Чем точнее и гибче ваши интерпретируемые инструкции, тем более выразительными вы можете быть при написании управляющей программы, но интерпретатор будет сложнее писать, медленнее выполняться и сложнее отлаживаться. Разрабатывайте свой язык так, чтобы он был настолько гибким, насколько это необходимо для того, чтобы вы могли писать новые алгоритмы управления.
Если вы попытаетесь изобрести целый псевдокомпьютер, полностью гибкий и способный программироваться для любых целей, вы сведете себя с ума. Целые предприятия сворачивались после того, как вкладывали деньги и время в изобретение нового и лучшего компьютера, и так увязали, что не могли оправиться. Не идите этим путем.
Начните с самых грубых, наименее гибких операций, с которыми вы можете жить, и заставьте их работать. Выявите их ограничения и устраняйте их, и только их, по одному за раз, пока у вас не будет достаточно гибкой системы, в которой вы сможете управлять своим устройством.
Я знаю об этом подходе, но это потребует заранее знать, что может делать устройство. Мне нужно иметь возможность обновить устройство некоторыми новыми функциями., @emir
Возможно ли, что я смогу позволить ему менять поведение, изменяя программу на лету, без необходимости перепрограммировать Arduino через компьютер?
Абсолютно да. По сути, именно так работает множество зашифрованных кодов.
как это можно сделать?, @emir
ознакомьтесь с техническим описанием программирования флэш-памяти. По сути, вы шифруете свой код и сохраняете зашифрованный код во флэш-памяти -> в текущем виде он не может быть выполнен. После прохождения аутентификации вы расшифровываете флэш-память и перезаписываете в нее расшифрованный код, а затем запускаете флэш-память., @dannyf
С этой точки зрения загрузчик можно рассматривать как нечто, выполняющее этапы прошивки и выполнения описанного выше процесса., @dannyf
Другими словами, вам нужен загрузчик + шифрование/дешифрование/аутентификация. Так что это может стать для вас отличной отправной точкой., @dannyf
@dannyf Этот ответ был отмечен как некачественный. Я считаю, что вы можете улучшить его, просто добавив эти комментарии к самому ответу. Спасибо., @sa_leinad
Возможно ли, что я мог бы позволить ему менять поведение, изменяя программу на лету, без необходимости перепрограммировать Arduino через компьютер.
(выделено мной).
Как было указано в некоторых ответах, вы можете изменить поведение, если вы позволите это заранее. Например, сохраните в EEPROM некоторые настройки (например, как часто что-то происходит) и предусмотрите метод изменения этих настроек.
Другой загрузчик
Однако, если вы хотите изменить поведение полностью, то вам необходимо загрузить новый код (независимо от того, находится ли код в оперативной памяти или в памяти программы, эта часть на самом деле не меняется).
Загрузчик, установленный в качестве стандарта на Arduinos, позволяет загружать код через протокол, который поступает на последовательный порт вскоре после сброса. Ничто не мешает вам написать свой собственный протокол (например, с использованием MQTT) и создать свой собственный загрузчик, который его использует — при условии, что он достаточно мал, чтобы поместиться в пространство загрузчика (максимальный размер загрузчика, который может хранить Atmega328P, составляет 4096 байт).
Автономный программатор
Поскольку вы спросили о загрузке нового кода без необходимости иметь компьютер, альтернативой является программирование его в полевых условиях с использованием автономного программатора. Существует множество программаторов, включая разработанный пользователем Crossroads с форума Arduino:
Я написал код для этого. Основной подход заключается в том, чтобы написать новый код с помощью IDE (что вам в любом случае придется сделать), а затем скопировать файл .hex на карту SD или micro-SD, которую затем вставляют в программатор, как вы можете видеть на фотографии. Затем программатор подключается к целевой плате через интерфейс ICSP с помощью 6-жильного кабеля, как показано на рисунке. Это перепрограммирует цель примерно за секунду. Это делает практичным перепрограммирование устройства «в полевых условиях», без необходимости возвращать его на базу или носить с собой ноутбук.
Вам нужен не «пони с одним трюком» (arduino), а настоящая «лошадь» — Raspberry Pi. У вас нет причин не делать этого, например:
- Цена — RPi Zero — 10 долларов США.
- Размер — примерно как у Nano.
Функциональность::
Пи. . . . . . . . . . . . . . . . Ардуино
Wi-Fi. . . . . . . . . . . . . . . . нет (wifly /Zigbee теперь вы нарушаете пункт 2)
блютуз. . . . . . . . . . . . . . . . нет
веб-сервер. . . . . . . . . . . . . . . . нет
База данных MySQL. . . . . . . . . . . .. нет
любой многопоточный Linux Программы. . . . . . . .. . . . . . . . . . . . . нет
и т. д. и т. п.
Я что-то пропустил? Работа технологического архитектора начинается с знания того, какое аппаратное и программное обеспечение следует применять в той или иной ситуации. IE избегает использования квадратных колышков в круглых отверстиях.
Вы забыли упомянуть, что RPi Zero не будет работать без качественной карты Micro SD объемом от 4 до 8 ГБ для хранения (ОС, библиотек и пользовательских программ). Вам также понадобится «кабель USB OTG», блок питания на 1 А с разъемом Micro USB, и если вы хотите подключить его через HDMI, для этого также потребуется адаптер. Это обойдется мне в 51,46 канадских долларов плюс от 5 до 10 долларов за доставку, просто чтобы начать работу с RPi Zero., @VE7JRO
Еще один момент, который следует учитывать: нужен ли вашему проекту Wi-Fi, Bluetooth, веб-сервер и MySQL. Зачем платить за всю эту «лошадиную силу», если вы не собираетесь ее использовать. RPi Zero — это компьютер, и к нему следует относиться соответственно. Если на Arduino пропадет питание, вы не получите поврежденную операционную систему или другие программные ошибки: он просто начнет выполнять код при повторном подключении. Для Raspberry Pi вы должны выключить его в операционной системе, например любой другой компьютер, иначе возникнет риск повреждения и проблем с программным обеспечением., @VE7JRO
- Печать string and integer LCD
- Почему мои часы реального времени показывают неверное время с моего ПК?
- Arduino uno + cnc Shield v3 + драйвер шагового двигателя A4988 + AccelStepper?
- Отправьте несколько значений int из Python в Arduino, используя pySerial
- Глобальные переменные занимают много места в динамической памяти.
- (Код ультразвукового датчика: такого файла или каталога нет)
- rfid_default_keys проверить с помощью RC522
- Команда strtok() с Serial связью
Но это с использованием Arduino IDE, не так ли? Можно ли изменить какой-то код без необходимости его перепрограммирования?, @emir
Ваш код хранится во флэш-памяти. Ваш код не может изменить содержимое флэш-памяти. Вы должны понимать, что Arduino — это НЕ компьютер. На компьютере (архитектура фон Неймана) мы храним код и данные в оперативной памяти и можем изменять содержимое оперативной памяти. Таким образом, код может изменяться на лету. Arduino имеет гарвардскую архитектуру: код находится в одной памяти, данные — в другой. Код не может выполнить «самомодификацию». С другой стороны, у вас может быть код, использующий «скрипт», и вы можете обновить этот скрипт (в ОЗУ или EEPROM)., @Peter
@Питер, ты ошибаешься. Машины Гарвардской архитектуры также во многом являются «компьютерами». Ардуино определенно является «компьютером». Кроме того, хотя это ни в коем случае не является обязательным требованием для того, чтобы быть «компьютером», Arduino *может* изменять свою собственную флэш-память, хотя этот процесс немного сложен, и не следует разрабатывать схему, позволяющую делать это неоднократно и на постоянной основе. или вспышка выйдет из строя., @Chris Stratton
@Peter предложил: «_вы можете использовать код, используя «скрипт»_». Я поддерживаю это предложение. См. [Интерпретируемые языки](https://playground.arduino.cc/CommonTopics/InterpretedLanguages) на игровой площадке Arduino., @Edgar Bonet
@Chris Stratton Сам факт разговора о Гарварде имел основной целью дать лучшее представление о проблеме. Я много играл с ASM и самомодифицирующимся кодом (в 80-х годах) и вижу, что многие люди на базовом уровне борются с проблемой памяти на Arduino, потому что они думают о нем как о «маленьком компьютере», хотя на самом деле принцип другой. Я согласен, что у нас может быть компьютер Гарварда или фон Неймана, конечно :) Приветствую., @Peter
@Питер, тот факт, что существует загрузчик, способный перепрограммировать Arduino без внешнего программатора, может сказать вам, что AVR действительно способен записывать на собственную флэш-память;), @frarugi87
@emir, не могли бы вы просто уточнить, нужно ли вам, чтобы Arduino перепрограммировал его «во время выполнения», без перезагрузки, или так же, как если бы вы подключились к порту USB (но через сеть)? Если первое, то предложение состоит в том, чтобы изменить логику алгоритма, как предлагает Дж.Роберт в своем ответе; если последнее, то можно модифицировать загрузчик, чтобы он принимал данные из сетевого подключения, тогда, когда захотите прошить, придется сбросить плату и потом подключиться к загрузчику (не так просто, но выполнимо), @frarugi87
@ Frarugi87 перезагрузка устройства не проблема. Это сработает в любом случае, @emir
@emir, тогда это возможно, даже если это довольно сложно. Вам придется изменить загрузчик, чтобы он куда-то загружал программу (например, через прямое TCP-соединение). Обратите внимание, что загрузчик имеет очень ограниченное пространство. Потом из приложения при поступлении MQTT-запроса сохраняешь флаг в eeprom и потом сбрасываешь плату; в загрузчике, если флаг присутствует, скачайте прошивку и запишите ее во флеш, затем снимите флаг и перезагрузитесь. Если флаг отсутствует, запустите приложение. Даже если... Опять же, если вы сможете сделать то, что предлагает Джей Роберт, это НАМНОГО лучше., @frarugi87
@ Farugi87. Все возможно. Но я думаю, что мы должны прояснить один момент: некоторые советы и рекомендации возможны и могут быть использованы при написании кода. Но использовать их в реальном приложении – это совсем другая история. ;), @Peter