заливка скетча через блютуз соединение
- Войдите на сайт для отправки комментариев
Возникло желание не только дистанционно управлять мобильной платформой игрушки-робота через блютуз с пк, но и перезаливать скетчи на неё. Писать приложения-пульты для пк смог, а вот со скетчами вопрос...
Нашёл такую статью
http://robocraft.ru/blog/3089.html
В ней ссылка на исходник
https://forum.arduino.cc/index.php?topic=128115.0
А там нюанс - при перезагрузке ардуино соединение с блютуз модулем разрывается и надо редактировать файлы "ИДЕ" для преодоления проблемы. Вопрос кто так делал и каков конечный результат? Ещё вопрос зачем транзистор для сброса ардуино, почему нельзя LOW подавать на ресет с любого пина? Почему на HC-05 соединяют проводком 34 вывод с 12 если есть кнопка для входа в АТ режим?
hc-05 подключаем как беспроводной uart, предварительно на нём скорость 115200, на дуне optiboot с той же скоростью, в иде выбираем соответственно. При отправке скетча приходится нажимать ресет руками, когда по диоду визуально виден коннект, готово. Авторесет не победил, не напрягает
Ещё вопрос зачем транзистор для сброса ардуино, почему нельзя LOW подавать на ресет с любого пина?
Делал без блютуза, по TX/RX только, без нажатия кнопки.
В скетче резидент нужно держать для старта загрузчика.
Можно без транзистора.
Вот получилось как в статьях написано, напрямую ресет соединяю с А5 проводом. Но!, после загрузки светодиод начинает мигать как надо только после физического кратковременного разрыва связи между A5 и выводом res. Почему так?
//тест "блинк" для дистанционной загрузки скетчей в плату ардуино уно int uploadpin=A5; long Y=0; void setup() { Serial.begin(115200); // скорость 115200 для Arduino UNO, // может быть разная для разных моделей pinMode(uploadpin,OUTPUT); digitalWrite(uploadpin,HIGH); //////////// pinMode(13,OUTPUT); digitalWrite(13,LOW); } void loop() { if(millis()-Y>1000){Y=millis();digitalWrite(13,!digitalRead(13));}//мигаем светодиодом как угодно с паузой zagruzka();//запрашиваем функцию о загрузки нового скетча } ///////////////////////////////////////// //функция проверки на загрузку нового скетча void zagruzka() { if( Serial.peek()=='0' ) { for( int i=0; i<100; i++ ) // повторить проверку { if( Serial.read()=='0' && Serial.read()==' ') { Serial.write(0x14); // ответить avrdude.exe Serial.write(0x10); // для синхронизации digitalWrite(uploadpin,LOW); // подтянуть ресет к земле (если без транзистора то LOW иначе HIGH - как в статье) } delay(10); // небольшая задержка } } ///////////////////////////////////////// }8 с 9 поменять местами. В 24 переименовать в serialEvent.
19 удалить. До чего ж коряво вы пишете...
////////////////////////////////////////////////////// // int uploadpin=8; void setup() { Serial.begin(115200); // baudrate 115200 corresponds Arduino UNO, // it can be different for different boards pinMode(uploadpin,OUTPUT); } void loop() { // your codes here... ///////////////////////////////////////// // Upload checking if( Serial.peek()=='0' ) { for( int i=0; i<100; i++ ) // repeat the check for a short peroid { if( Serial.read()=='0' && Serial.read()==' ' ) { Serial.write(0x14); // reply two char to avrdude.exe Serial.write(0x10); // for synchronization digitalWrite(uploadpin,HIGH); // turn on the relay to ground the reset pin } delay(10); // cannot repeat too fast here } } ///////////////////////////////////////// } // //////////////////////////////////////////////////////Я лишь слегка исправил исходник и убрал транзистор между ресет и А5 (в исходнике вывод 8).
/тест "блинк" для дистанционной загрузки скетчей в плату ардуино уно int uploadpin=7; long Y=0; bool zagr=false; String inputString;// строки данных int n=2000; void setup() { Serial.begin(115200); // скорость 115200 для Arduino UNO, // может быть разная для разных моделей //////////// pinMode(13,OUTPUT); digitalWrite(13,LOW); } void loop() { if(millis()-Y>n){Y=millis();digitalWrite(13,!digitalRead(13));}//мигаем светодиодом как угодно с паузой if(zagr==true){EventSerial();}//запрашиваем функцию о загрузке нового скетча if(zagr==false){CheckSerial();}//ЖДЁМ ПОСТУПЛЕНИЯ КОМАНДЫ В РАМКАХ ТЕКУЩЕГО СКЕТЧА } ///////////////////////////////////////// //функция проверки на загрузку нового скетча void EventSerial() { ////////////////////////////////////////// if( Serial.peek()=='0' ) { for( int i=0; i<100; i++ ) // повторить проверку { if( Serial.read()=='0' && Serial.read()==' ') { Serial.write(0x14); // ответить avrdude.exe Serial.write(0x10); // для синхронизации pinMode(uploadpin,OUTPUT);//ЭТО ВЫЗОВЕТ РЕСЕТ } delay(10); // небольшая задержка } } ///////////////////////////////////////// } ///////////////////////////////////////////////////////////////////////////////////////////////// //ФУНКЦИИ ПРИЁМА И ОБРАБОТКИ КОМАНД-ДАННЫХ void CheckSerial() { ////////////////////////////////////////////////////////////////////////////// while (Serial.available())//считываем строку данных пока они поступают { char inChar = (char)Serial.read(); if (inChar == '\n'||inChar == ',') //если окончание строки { MakeCmd();//обрабатываем её данной функцией break; } else inputString += inChar;// иначе удлиняем строку на один символ } } ///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////// void MakeCmd() { int y = inputString.length(); // присваиваем переменной у число символов в строке if (y < 1 || y > 4){inputString = "";return;} //если их меньше 1 или больше 4, выходим из функции String cmd = inputString; // передаём строку другой переменной inputString = "";//"обнуляем переменную" if (cmd == "Z") { zagr=true;//ПЕРЕХОДИМ В РЕЖИМ ОЖИДАНИЯ ЗАГРУЗКИ СКЕТЧА } else { n=cmd.toInt();}// МЕНЯЕМ ДЛИТЕЛЬНОСТЬ ПАУЗ-СВЕЧЕНИЯ СВЕТОДИОДА ПО ДАННЫМ-КОМАНДАМ } ///////////////////////////////////////////////////////////////////////////////////////////////////////Чуть улучшил скетч. Оказывается для ресета ардуино надо просто писать pinMode(uploadpin,OUTPUT); - т.е. "антаматически" выставляется низкий уровень при объявлении (ясно зачем был нужен транзистор). Теперь через монитор порта можно управлять мобильной платформой и перезаливать управляющие скетчи в неё дистанционно. Но всё очень зыбко. Для перехода из одного режима в другой приходиться посылать в плату предварительно символ Z. Если забыл и нажал загрузку- IDE "ломается". Приходиться выключать-включать платформу, блютуз-модуль на ПК и закрывать-открывать скетч. Аналогично, если послал Z, а потом ещё какой нибудь символ.
Тренируюсь пока на блинке для 13 пина. Как сделать скетч устойчивым к ошибочным действиям оператора?
Ужас! Проще нужно быть).
#define RESET 8 //пины #define LED 13 #define BAUD 115200 //скорость загрузчика #define reboot() pinMode(RESET, OUTPUT) //аппаратный сброс #define CMD1 '0' //последовательность от загрузчика для рестарта #define CMD2 ' ' #define toggle_led() digitalWrite(LED, !digitalRead(LED)) void setup() { Serial.begin(BAUD); pinMode(LED, OUTPUT); } void loop() { toggle_led(); delay(100); } // резидент, ребутящий от загрузчика void serialEvent() { static char old_ch; while (Serial.available()) { register char ch = Serial.read(); if (ch == CMD2 && old_ch == CMD1) reboot(); old_ch = ch; } }Красиво написано. Я так не смогу.
Serial.write(0x14);// ответить avrdude.exeSerial.write(0x10);// для синхронизацииНу и смысл не только загружать дистанционно, но управлять одновременно. А изящно совместить не получается, ошибка и всё зависает.
Я о перезагрузке. Насколько помню, у меня перезагружало и так. Добавьте передачу 20 и 16, если это влияет.
Да, заливка по воздуху для упрямых... Нет,нет и срывается устойчивая работа. Чего то захотелось посмотреть аналоги в заводском исполнении. Гуглю Arduino BT - в ответ тишина, как она хоть выглядит?
Касательно загрузки. По красивому нужно иметь отдельный reboot.ino. Тогда в скетче может быть, типа:
#define LED 13 #define boot_init() Serial.begin(115200) //скорость загрузчика #define toggle(x) digitalWrite(x, !digitalRead(x)) void setup() { boot_init(); pinMode(LED, OUTPUT); } void loop() { toggle(LED); delay(500); }А в reboot.ino:
#define RESET 8 //пин на reset #define reboot() pinMode(RESET, OUTPUT) //аппаратный сброс #define CMD1 '0' //последовательность от загрузчика для рестарта #define CMD2 ' ' void serialEvent() { static char old_ch; while (Serial.available()) { char ch = Serial.read(); if (ch == CMD2 && old_ch == CMD1) { // Serial.write(0x14); // ответить avrdude.exe // Serial.write(0x10); // для синхронизации // delay(1); reboot(); } old_ch = ch; }Нет. Даже так ещё красивше):
#define LED 13 #define toggle(x) digitalWrite(x, !digitalRead(x)) void setup() { boot_init(); pinMode(LED, OUTPUT); } void loop() { toggle(LED); delay(500); }reboot.ino:
#define RESET 8 //пин на reset #define BOOT_BAUDRATE 115200 //скорость загрузчика #define reboot() pinMode(RESET, OUTPUT) //аппаратный сброс #define CMD1 '0' //последовательность от загрузчика для рестарта #define CMD2 ' ' void boot_init() { Serial.begin(BOOT_BAUDRATE); } // резидент, ребутящий от последовательности загрузчика void serialEvent() { static char old_ch; while (Serial.available()) { register char ch = Serial.read(); if (ch == CMD2 && old_ch == CMD1) { // Serial.write(0x14); // ответить avrdude.exe // Serial.write(0x10); // для синхронизации // delay(1); reboot(); } old_ch = ch; } }Красота в чём? Вы пишет скетч, в setup которого вставляете boot_init(), ну а в саму папку со скетчем копируете reboot.ino. И ни о чём не думаете.)
Здорово!, получается функции можно выносить в отдельный скетч и к ним обращаться из основного. А define с переменной может быть.
Конечно вид скетча становится совершенно иным.
Среда Ардуино удобна чем. Вы можете иметь несколько .ino в рабочей папке. Все они будут собраны и оттранслированы в алфавитном порядке после вашего главного скетча. Т.е., всё так, как если бы вы писали все .ino в своём одном главном скетче.
Ну такой практики я ещё не осуществлял). Плохо только что эта среда очень обидчива на ошибки). После перехода в режим ожидания загрузки скетча можно жать только загрузка скетча (, если послать любой символ по ошибке, потом нажать загрузить скетч - всё повиснет насмерть и иногда приходиться перезагружать комп, соединение-опознание с внешним блютуз модулем, снова открывать скетч, перевключать питание на конструкции (в общем опять как в первый раз))).
//тест "блинк" для дистанционной загрузки скетчей в плату ардуино уно int uploadpin=7;// вывод платы для осуществления аппаратной перезагрузки long Y=0; bool zagr=false; String inputString;// строки данных int n=2000; void setup() { Serial.begin(115200); // скорость 115200 для Arduino UNO, // может быть разная для разных моделей плат //////////// pinMode(13,OUTPUT); digitalWrite(13,LOW); } void loop() { if(millis()-Y>n){Y=millis();digitalWrite(13,!digitalRead(13));}//мигаем светодиодом как угодно с паузой if(zagr==true){EventSerial();}//запрашиваем функцию о загрузке нового скетча if(zagr==false){CheckSerial();}//ЖДЁМ ПОСТУПЛЕНИЯ КОМАНДЫ В РАМКАХ ТЕКУЩЕГО СКЕТЧА } ///////////////////////////////////////// //функция проверки на загрузку нового скетча void EventSerial() { static char old_ch; while (Serial.available()) { register char ch = Serial.read(); if(ch!=' '&&ch!='0'){zagr=false;} if (ch == ' ' && old_ch == '0') { Serial.write(0x14); // ответить avrdude.exe Serial.write(0x10); // для синхронизации delay(10); pinMode(uploadpin,OUTPUT);//ЭТО ВЫЗОВЕТ РЕСЕТ } old_ch = ch; } } ///////////////////////////////////////////////////////////////////////////////////////////////// //ФУНКЦИИ ПРИЁМА И ОБРАБОТКИ КОМАНД-ДАННЫХ void CheckSerial() { ////////////////////////////////////////////////////////////////////////////// while (Serial.available())//считываем строку данных пока они поступают { char inChar = (char)Serial.read(); if (inChar == '\n'||inChar == ',') //если окончание строки { MakeCmd();//обрабатываем её данной функцией break; } else inputString += inChar;// иначе удлиняем строку на один символ } } ///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////// void MakeCmd() { int y = inputString.length(); // присваиваем переменной у число символов в строке if (y < 1 || y > 4){inputString = "";return;} //если их меньше 1 или больше 4, выходим из функции String cmd = inputString; // передаём строку другой переменной inputString = "";//"обнуляем переменную" if (cmd == "Z") { zagr=true;//ПЕРЕХОДИМ В РЕЖИМ ОЖИДАНИЯ ЗАГРУЗКИ СКЕТЧА } if (cmd == "R") { pinMode(uploadpin,OUTPUT);//ЭТО ВЫЗОВЕТ РЕСЕТ } if (cmd != "R"&&cmd != "Z"){ n=cmd.toInt();}// МЕНЯЕМ ДЛИТЕЛЬНОСТЬ ПАУЗ-СВЕЧЕНИЯ СВЕТОДИОДА ПО ДАННЫМ-КОМАНДАМ } ///////////////////////////////////////////////////////////////////////////////////////////////////////Вставил предложенный фрагмент в свой дремучий код - избавился от Serial.peek(), работать стало стабильнее. Посмотрел и понял что надо придумывать общую функцию обработки входящих данных, которая будет понимать и команды управления и команды на перезаливку скетча, а не использовать две с переключением по флагу.
Расколол скетч на два, сделал одну функцию обработки входящих данных, попробовал на про мини 168 - работает стабильно.
//тест "блинк" для дистанционной загрузки скетчей в плату ардуино pro mini (168) long Y=0;//пременная хранения моментов времени int t=1000;// переменная хранения длительностей пауз между переключениями светодиода void setup() { Serial.begin(19200); // скорость 19200 для Arduino pro mini , // может быть разная для разных моделей плат //////////// pinMode(13,OUTPUT); digitalWrite(13,LOW); } void loop() { if(millis()-Y>t){Y=millis();digitalWrite(13,!digitalRead(13));}//мигаем светодиодом как угодно с паузой t=CheckSerial();//по поступившей команде выставляем паузу }и вторая часть
// int uploadpin=A0;// вывод платы для осуществления аппаратной перезагрузки, соединён с RES String inputString;// строки данных int n=1000;//переменная хранения команды-числа ///////////////////////////////////////////////////////////////////////////////////////////////// //ФУНКЦИИ ПРИЁМА И ОБРАБОТКИ КОМАНД-ДАННЫХ int CheckSerial() { ////////////////////////////////////////////////////////////////////////////// while (Serial.available())//считываем строку данных пока они поступают { char inChar = (char)Serial.read(); if (inChar == '\n'||inChar == ' ') //если окончание строки или запрос на загрузку { MakeCmd();//обрабатываем её данной функцией break; } else inputString += inChar;// иначе удлиняем строку на один символ } return n;// возвращаем значение переменной как значение всей функции } ///////////////////////////////////////////////////////////////////////////////// void MakeCmd() { int y = inputString.length(); // присваиваем переменной у число символов в строке if (y < 1 || y > 4){inputString = "";return;} //если их меньше 1 или больше 4, выходим из функции String cmd = inputString; // передаём строку другой переменной inputString = "";//"обнуляем переменную" ////// if (cmd == "0") { //если получили ноль Serial.write(0x14); // ответить avrdude.exe Serial.write(0x10); // для синхронизации delay(10); pinMode(uploadpin,OUTPUT); //ЭТО ВЫЗОВЕТ аппаратный РЕСЕТ } if (cmd != "0"){ n=cmd.toInt();} // преобразуем строку в номер команды-число ////// } ///////////////////////////////////////////////////////////////////////////////////////////////////////осталось красиво написать.
Сдуру купившись на
https://2150692.ru/faq/82-co2-mhz19
попробовал сделать программную перезагрузку - сэкономить провод и вывод ) - зря. Всё нафиг повисло, еле откачал ПК. Видимо программная перезагрузка не перезагрузка.
Ну так программный сброс (jmp 0) перезапускает пользовательскую программу, а не запускает загрузчик.
Но даже если вы напишите jmp на начало загрузчика, это ещё не значит что он будет выполнять загрузку.)
Ну так программный сброс (jmp 0) перезапускает пользовательскую программу, а не запускает загрузчик.
Но даже если вы напишите jmp на начало загрузчика, это ещё не значит что он будет выполнять загрузку.)
да, загрузчик надо научить выполнять загрузку, сейчас не вспомню у кого, но встречал, там правда загрузчик сделан под шилд W5100 и обновляет прошивку через TFTP,
Ясно, - овчинка выделки не стоит, раз и так хорошо работает.
Теперь захотелось решить вопрос с включением-выключением дистанционным всей конструкции опять же через блютуз модуль. У Дмитрия Осипова нашёл такой вариант снижения потребления модулем до 3-4 мА. Правда команда АТ, используемая им совсем не про энергосбережение.
https://www.youtube.com/watch?v=3-wqQu3AKh0
Подумал, что включать МК и периферию можно передавая любые символы и запуская низким уровнем с TX модуля RS триггер (на полевых транзисторах), перебрасывая из одного состояния в другое его. Может проще есть решение?
Пардон, ссылку не на тот урок дал.
https://www.youtube.com/watch?v=McDeejrLgT8