Самопальный терминал под Андроид для связи с Ардуиной

bl
Offline
Зарегистрирован: 10.11.2018

Заделал я некий терминал под Андроид для связи с Ардуиной. Терминал заточен для работы с дата-логгером (SD-карта + RTC). В одно-два нажатия возможно: чтение дерева файлов SD-карты, копирование файлов с SD-карты на телефон, установка и чтение времени RTC, перезагрузка Ардуины, отправка любых команд с клавиатуры. Плюс 2 кнопочки для "любимых команд". Связь телефона с Ардуиной возможна либо по USB OTG кабелю, либо через блютузный модуль. Сейчас поддерживается ТОЛЬКО Bluetooth LE, т.к. обычного модуля (Bluetooth Classic) нет под рукой. Соответсвеноо терминал на телефоне и скетч в Ардуине работают в паре. Интресно кому?

   

svm
Offline
Зарегистрирован: 06.11.2016

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

a5021
Offline
Зарегистрирован: 07.07.2013

BLE-модуль вы уже прикрутили к своему котлу?

bl
Offline
Зарегистрирован: 10.11.2018

"Обычных" терминалов для COM-порта в ПлейМаркете навалом. Я-то свой затачивал под выгрузку файла в одно касание. Т.к. мой проги еще нет в ПлейМаркете, могу лишь дать APK-файл. Придется на телефоне разрешать "установку из непроверенных источников". Можно ли APK-файл и скетч как-то прикрутить к этому форуму, или надо давать ссылку на куда-то?

a5021 пишет:

BLE-модуль вы уже прикрутили к своему котлу?

Что там прикручивать-то? Два проводка Tx и Rx, питание, и ни каких библиотек лишних. Но это чтоб вообще в котельную не ходить)) А BLE я купил лишь потому, что он оказался в 1.5 раза дешевле обычных.

svm
Offline
Зарегистрирован: 06.11.2016

Нет пока только  COM  порт, и в стадии обкатки NRF 24. Но по ней только контроль и изменение уставок. Чтобы сменить прошивку, приходится или ноут таскать, или ардуинку поднимать к компу.

svm
Offline
Зарегистрирован: 06.11.2016

Скетч вставляется без проблем, есть специальная кнопочка на форме. А насчет АРК - наверное тоько ссылка на внешний ресурс, или на что-то типа яндекс диска.

bl
Offline
Зарегистрирован: 10.11.2018

Завтра окончательно подчищу прогу и выложу куда-нибудь.

svm
Offline
Зарегистрирован: 06.11.2016

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

a5021
Offline
Зарегистрирован: 07.07.2013

bl пишет:
А BLE я купил лишь потому, что он оказался в 1.5 раза дешевле обычных.

Это ж какие такие? Дешевле обычных я тоже хочу.

bl
Offline
Зарегистрирован: 10.11.2018

APK-файл с терминалом доступен тут 

Скетч для Ардуины

#include <SD.h>
#include "RTClib.h"

RTC_DS1307 RTC;

const int chipSelect = 10;
String ComBuff = "";


/*  
    2 - создать папку [путь]
    3 - удалить папку [путь]
    4 - создать пустой файл [путь/имя.ext]
    5 - удалить файл [путь/имя.ext]
    6 - выдать в порт текущее время или задать время (millis)
    7 - записать строку в файл [путь/имя.ext] [текст]
    8 - считать файл [путь/имя.ext]
    9 - RESET
    10 - выдать дерево файлов
    11 - включить 4 ногу
    12 - ВЫключить 4 ногу
    
 */   
 
void(* resetFunc) (void) = 0; // Reset MC function

void setup() {

    Serial.begin(9600);
    pinMode(chipSelect, OUTPUT);
    if(SD.begin(chipSelect)){
    Serial.println(F("SD-card ready!"));
    
    } 
    else {
      Serial.println(F("SD-card initialization failed!"));
      return;
    }

  pinMode(4, OUTPUT);
  
  RTC.begin();
    
}

void loop() {
  
  while (Serial.available() > 0){
    
    char comByte = Serial.read();
    if(comByte == '\n') {
      parseComString (ComBuff);
      ComBuff = "";
    } else {
      ComBuff += comByte;
    }
  }  
}



void parseComString (String EnterString){
   
  int command = 0;
  String FileName = "";
  String Text = "";
  
  if(EnterString.indexOf(' ') < 0){
    // если нет пробела - вся строка - команда
    command = EnterString.toInt();
  } else {
    // иначе, до пробела - команда, после - имя файла
    command = EnterString.substring(0,EnterString.indexOf(' ')).toInt();
    String Argument = EnterString.substring(EnterString.indexOf(' ') + 1);
    
    if(Argument.indexOf(' ') < 0){
      // если нет пробела - весь Argument - имя файла
      FileName = Argument;
      Text = "";
    }
    else {
      // иначе, до пробела - имя файла, после - текст
      FileName = Argument.substring(0,Argument.indexOf(' '));
      Text = Argument.substring(Argument.indexOf(' ') + 1);
    }
        
  }


  switch (command){

    case 2://MKDIR [FolderName] - создать папку --------------------------------------------------------------
      mkDir(FileName);
      break;

    case 3:// RMDIR [FolderName] - удалить папку (папка должна быть пустая)---------------------------------------
      rmDir(FileName);
      break;

    case 4:// NF [path/name.ext] - создать файл --------------------------------------------------------------
      newFile(FileName);
      break;
  
    case 5:// DEL [path/name.ext] - удалить файл --------------------------------------------------------------
      delFile(FileName);
      break;

    case 6:// TIME [DateTime]- установить/выдать в порт текущее время -------------------------------------
      getOrSetTime(FileName);
      break;
      
    case 7:// WRITE - записать строку в файл -------------------------------------
      Serial.println(FileName);
      Serial.println(Text);
      writeLineToFile(FileName, Text);
      break;

    case 8:// READ [path/name.ext] - считать файл --------------------------------------------------------------
      readFile(FileName);
      break;

    case 9:// RESET - ---------------------------------------------------------------------------
      Serial.println(F("Resetting!"));
      delay(500);
      resetFunc();
      break;

    case 10:// TREE - считать дерево файлов --------------------------------------------------------------
      filesTree();
      break;

    case 11://  --------------------------------------------------------------
      digitalWrite(4, HIGH);
      break;

    case 12://  --------------------------------------------------------------
      digitalWrite(4, LOW);
      break;
    

    default:
      Serial.println(F("Unknown command!"));
     
  }
  


}

// создать папку --------------------------------------------------------------
void mkDir(String FileName){
  SdFile::dateTimeCallback(cb_dateTime); // датаВремя создания файла
    if(SD.mkdir(FileName)){
      Serial.print(F("Created folder "));
      Serial.println(FileName);
    }
    else{
      Serial.println(F("Fail!"));
    }
}


// удалить папку (папка должна быть пустая)---------------------------------------
void rmDir(String FileName){
  if(SD.rmdir(FileName)) {
      Serial.print(F("Deleted  folder "));
      Serial.println(FileName);
    }
     else{
      Serial.println(F("Fail!"));
    }
}

// чтение дерева карты -------------------------------------------------------------------
void filesTree(){

  Sd2Card card;
  SdVolume volume;
  SdFile root;
  root.openRoot(volume);
  card.init(SPI_HALF_SPEED, 10);
  volume.init(card);
  root.openRoot(volume);
  Serial.print(F("------------Start Files Tree-------------\n"));// метка начала дерева
  root.ls(LS_R | LS_DATE | LS_SIZE); //
  Serial.println(F("-------------End Files Tree--------------"));// метка конца дерева
  root.close();
  
}

// чтение файла -------------------------------------------------------------------
void readFile(String FileName){
      File CurrFile = SD.open(FileName);
      
      if (CurrFile) {
        
        while (CurrFile.available()) {
          Serial.write(CurrFile.read());
        }
        
        delay(200);
        Serial.print(F("\nEOFS:"));// метка конца файла
        Serial.println(CurrFile.size());// размер файла
        CurrFile.close();
         
       } else {
        Serial.print(F("Error opening "));
        Serial.println(FileName);
      
       }
}

// вывод в времени в порт -------------------------------------------------------------------
void digitalClockDisplayRTC(){
    // Определяем время
    DateTime now = RTC.now();
    
    // Выводим время в монитор порта
    Serial.print(print2digits(now.day()));
    Serial.print('.');
    Serial.print(print2digits(now.month()));
    Serial.print('.');
    Serial.print(print2digits(now.year()));  
    Serial.print(' ');
    Serial.print(print2digits(now.hour()));
    Serial.print(':');
    Serial.print(print2digits(now.minute()));
    Serial.print(':');
    Serial.print(print2digits(now.second()));
    Serial.println(F(" - Arduino"));
}

// добавление нулей во время -------------------------------------------------------------------
String print2digits(int number) {
  if (number < 10) {
      return "0" + String(number);
  }
  return String(number);
}

// установить или прочитать время -------------------------------------------------------------------
void getOrSetTime(String FileName){
  if(FileName.length() != 0) {// если не запрос времени - устанавливаем время ------------------------
      DateTime set_time = DateTime(FileName.toInt());
      RTC.adjust(set_time);
      
   } 
    //выдаем время в порт
  digitalClockDisplayRTC();
    
}

// установка времени создания файла ------------------------------------------------
void cb_dateTime(uint16_t* date, uint16_t* time) {
    DateTime now = RTC.now();
    *date = FAT_DATE(now.year(), now.month(), now.day());// return date using FAT_DATE macro to format fields
    *time = FAT_TIME(now.hour(), now.minute(), now.second());// return time using FAT_TIME macro to format fields
}

// запись строки в файл ------------------------------------------------
void writeLineToFile(String FileName, String Text){
    //SdFile::dateTimeCallback(cb_dateTime); // датаВремя создания файла
    // Определяем время
    DateTime now = RTC.now();
    
    File CurrFile = SD.open(FileName, FILE_WRITE);
    if (CurrFile) {
      CurrFile.print(print2digits(now.day()));
      CurrFile.print('.');
      CurrFile.print(print2digits(now.month()));
      CurrFile.print('.');
      CurrFile.print(print2digits(now.year()));  
      CurrFile.print(' ');
      CurrFile.print(print2digits(now.hour()));
      CurrFile.print(':');
      CurrFile.print(print2digits(now.minute()));
      CurrFile.print(':');
      CurrFile.print(print2digits(now.second()));
      CurrFile.print("\t");
      
      CurrFile.println(Text);

      CurrFile.close();
    }
    else {
        Serial.print(F("Error opening "));
        Serial.println(FileName);
    }

}

// удаление файла ------------------------------------------------
void delFile(String FileName){
    if(SD.remove(FileName)) {
      Serial.print(F("Removed file "));
      Serial.println(FileName);
    }
    else{
      Serial.println(F("Fail!"));
    }
}

// создание файла  ------------------------------------------------
void  newFile(String FileName){
  SdFile::dateTimeCallback(cb_dateTime); // датаВремя создания файла
    File CurrFile = SD.open(FileName, FILE_WRITE);
        
    if(CurrFile) {
      Serial.print(F("Created file "));
      Serial.println(CurrFile.name());
    }
    else{
      Serial.println(F("Fail!"));
    }
   CurrFile.close();
}


    

Что касается терминалов из ПлейМаркета, то мне нравятся вот эти.

 

dr.arntholcz
Offline
Зарегистрирован: 23.02.2022

bl пишет:

Заделал я некий терминал под Андроид для связи с Ардуиной. Терминал заточен для работы с дата-логгером (SD-карта + RTC). В одно-два нажатия возможно: чтение дерева файлов SD-карты, копирование файлов с SD-карты на телефон, установка и чтение времени RTC, перезагрузка Ардуины, отправка любых команд с клавиатуры. Плюс 2 кнопочки для "любимых команд". Связь телефона с Ардуиной возможна либо по USB OTG кабелю, либо через блютузный модуль. Сейчас поддерживается ТОЛЬКО Bluetooth LE, т.к. обычного модуля (Bluetooth Classic) нет под рукой. Соответсвеноо терминал на телефоне и скетч в Ардуине работают в паре. Интресно кому?

   


Очень интересно. Можно apk перезалить?
Ваше приложение работает на всех ведройдах?
По подробной инструкции написал приложение для ведройда. Оно отправляет строки по rs232 на ардуино уно(at16u2). На One Plus 6 приложение работает, строки отправляются. Андройд 10й на ванпласе. Ардуина определяется ttyACM0.
Есть Honor 4C. На нём приложение запускается, но команды никуда НЕ отправляются. Ардуина определяется как usb0. Ведройд 6. Оба телефона рутованы.

(Драйверы поставить -- где их взять; ардуину на другом контроллере взять; библиотеки использовать с драйверами. Библиотеки находил, но тяму не хватало их правильно подключить)
Есть на GitHub'е библиотеки mik3y/usb-serial-for-android и felHR85/UsbSerial. Хотелось бы узнать, это драйверы ардуины для андройда или они довавляют только возможность передачи данных по rs232, а необходимость в драйверах возлагается на производителя ведройда/конечного пользователя?

infyniti
Offline
Зарегистрирован: 15.07.2017

dr.arntholcz пишет:

Есть Honor 4C. На нём приложение запускается, но команды никуда НЕ отправляются. Ардуина определяется как usb0. Ведройд 6. Оба телефона рутованы.
 

Ведройд здесь не причем. Скорее это железо. Если телефон не отправляет, то эту функцию он не поддерживает. Бюджетники, дешевые андройды, этим страдают.