заливка скетча через блютуз соединение

leks
Offline
Зарегистрирован: 22.10.2017

Возникло желание не только дистанционно управлять мобильной платформой игрушки-робота через блютуз с пк, но и перезаливать скетчи на неё. Писать приложения-пульты для пк смог, а вот со скетчами вопрос...

Нашёл такую статью

  http://robocraft.ru/blog/3089.html

В ней ссылка на исходник

 https://forum.arduino.cc/index.php?topic=128115.0

А там нюанс - при перезагрузке ардуино соединение с блютуз модулем разрывается и надо редактировать файлы "ИДЕ" для преодоления проблемы. Вопрос кто так делал и каков конечный  результат? Ещё вопрос зачем транзистор для сброса ардуино, почему нельзя LOW подавать на ресет с любого пина? Почему на HC-05 соединяют проводком 34 вывод с 12 если есть кнопка для входа в АТ режим?

Temik007
Offline
Зарегистрирован: 24.12.2017

hc-05 подключаем как беспроводной uart, предварительно на нём скорость 115200, на дуне optiboot с той же скоростью, в иде выбираем соответственно. При отправке скетча приходится нажимать ресет руками, когда по диоду визуально виден коннект, готово. Авторесет не победил, не напрягает

Green
Offline
Зарегистрирован: 01.10.2015

leks пишет:

Ещё вопрос зачем транзистор для сброса ардуино, почему нельзя LOW подавать на ресет с любого пина?


Делал без блютуза, по TX/RX только, без нажатия кнопки.
В скетче резидент нужно держать для старта загрузчика.
Можно без транзистора. 

leks
Offline
Зарегистрирован: 22.10.2017

Вот получилось как в статьях написано, напрямую ресет соединяю с А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);  // небольшая задержка
    }
    
  }
   /////////////////////////////////////////
}

 

Green
Offline
Зарегистрирован: 01.10.2015

8 с 9 поменять местами. В 24 переименовать в serialEvent.
19 удалить. До чего ж коряво вы пишете...

leks
Offline
Зарегистрирован: 22.10.2017
//////////////////////////////////////////////////////
//
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).

leks
Offline
Зарегистрирован: 22.10.2017
/тест "блинк" для дистанционной загрузки скетчей в плату ардуино уно
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 пина. Как сделать скетч устойчивым к ошибочным действиям оператора? 

Green
Offline
Зарегистрирован: 01.10.2015

Ужас! Проще нужно быть).

#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;
  }
}

 

leks
Offline
Зарегистрирован: 22.10.2017

Красиво написано. Я так не смогу.

 Только вот этих строк наверное не хватает, поэтому не перезаливает, а ломает работу.
     Serial.write(0x14);  // ответить avrdude.exe
   Serial.write(0x10);  //  для синхронизации

Ну и смысл не только загружать дистанционно, но управлять одновременно. А изящно совместить не получается, ошибка и всё зависает.

Green
Offline
Зарегистрирован: 01.10.2015

Я о перезагрузке. Насколько помню, у меня перезагружало и так. Добавьте передачу 20 и 16, если это влияет. 

leks
Offline
Зарегистрирован: 22.10.2017

Да, заливка по воздуху для упрямых... Нет,нет и срывается устойчивая работа. Чего то захотелось посмотреть аналоги в заводском исполнении. Гуглю Arduino BT - в ответ тишина, как она хоть выглядит?

Green
Offline
Зарегистрирован: 01.10.2015

Касательно загрузки. По красивому нужно иметь отдельный 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;
  }

 

Green
Offline
Зарегистрирован: 01.10.2015

Нет. Даже так ещё красивше):

#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;
  }
}

 

Green
Offline
Зарегистрирован: 01.10.2015

Красота в чём? Вы пишет скетч, в setup которого вставляете boot_init(), ну а в саму папку со скетчем копируете reboot.ino. И ни о чём не думаете.)

leks
Offline
Зарегистрирован: 22.10.2017

Здорово!, получается функции можно выносить в отдельный скетч и к ним обращаться из основного. А define с переменной может быть.

Конечно вид  скетча становится совершенно иным.  

Green
Offline
Зарегистрирован: 01.10.2015

Среда Ардуино удобна чем. Вы можете иметь несколько .ino в рабочей папке. Все они будут собраны и оттранслированы в алфавитном порядке после вашего главного скетча. Т.е., всё так, как если бы вы писали все .ino в своём одном главном скетче.

leks
Offline
Зарегистрирован: 22.10.2017

Ну такой практики я ещё не осуществлял). Плохо только что эта среда  очень обидчива на ошибки). После перехода в режим ожидания загрузки скетча можно жать только загрузка скетча (, если послать любой символ по ошибке, потом нажать загрузить скетч - всё повиснет насмерть и иногда приходиться перезагружать комп, соединение-опознание с внешним блютуз модулем, снова открывать скетч, перевключать питание на конструкции (в общем опять как в первый раз))).

leks
Offline
Зарегистрирован: 22.10.2017
//тест "блинк" для дистанционной загрузки скетчей в плату ардуино уно
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(), работать стало стабильнее. Посмотрел и понял что надо придумывать общую функцию обработки входящих данных, которая будет понимать и команды управления и команды на перезаливку скетча, а не использовать две с переключением по флагу.

leks
Offline
Зарегистрирован: 22.10.2017

Расколол скетч на два, сделал одну функцию обработки входящих данных, попробовал на про мини 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

попробовал сделать программную перезагрузку - сэкономить провод и вывод ) - зря. Всё нафиг повисло, еле откачал ПК. Видимо программная перезагрузка не перезагрузка.

Green
Offline
Зарегистрирован: 01.10.2015

Ну так программный сброс (jmp 0) перезапускает пользовательскую программу, а не запускает загрузчик.
Но даже если вы напишите jmp на начало загрузчика, это ещё не значит что он будет выполнять загрузку.)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Green пишет:

Ну так программный сброс (jmp 0) перезапускает пользовательскую программу, а не запускает загрузчик.
Но даже если вы напишите jmp на начало загрузчика, это ещё не значит что он будет выполнять загрузку.)

да, загрузчик надо научить выполнять загрузку, сейчас не вспомню у кого, но встречал, там правда загрузчик сделан под шилд W5100 и обновляет прошивку через TFTP,

leks
Offline
Зарегистрирован: 22.10.2017

Ясно, - овчинка выделки не стоит, раз и так хорошо работает.

Теперь захотелось решить вопрос с включением-выключением дистанционным всей конструкции опять же через блютуз модуль. У Дмитрия Осипова нашёл такой вариант снижения потребления модулем до 3-4 мА. Правда команда АТ, используемая им совсем не про энергосбережение.

https://www.youtube.com/watch?v=3-wqQu3AKh0

Подумал, что включать МК и периферию можно передавая любые символы и запуская низким уровнем с TX модуля RS триггер (на полевых транзисторах), перебрасывая из одного состояния в другое его. Может проще есть решение?

leks
Offline
Зарегистрирован: 22.10.2017

Пардон, ссылку не на тот урок дал.

https://www.youtube.com/watch?v=McDeejrLgT8