Как подружить две библиотеки iBUSTelemetry.h и SoftwareSerial.h ?

kuzan67
Offline
Зарегистрирован: 02.10.2022

ua6em пишет:

kuzan67 пишет:

кругом Евгении  )

кругом ложь, наглая ложь или умалчивание...невозможно сделать на одном излучателе качественный сонар

да повторюсь . у меня караблик из го...и палок . и качесво не нужно а примерно знать что я с метра выплываю на 2 )   . так и могазинные эхолоты типо утёнка на одном излучателе orig

kuzan67
Offline
Зарегистрирован: 02.10.2022

просто когда я обратился к вам в этой теме . многой инфу не знал . а теперь понимаю что всё что я попросил в ( наглую) )  зделать. уже зделаи и продают . поэтому бесплатно некто не подгонит скейтчь ))для ардуинки . и буду делать из проэкта Сернгея . авось получется то что хотелась а нет . буду на угад кидать кормушки ))

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

тебе не показалось странным, что все используют STM?

kuzan67
Offline
Зарегистрирован: 02.10.2022

ua6em пишет:

тебе не показалось странным, что все используют STM?

думал дела в цене ))повторюсь я не селён и ток внекаю в тонкости что и почему )

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

kuzan67 пишет:

ua6em пишет:

тебе не показалось странным, что все используют STM?

думал дела в цене ))повторюсь я не селён и ток внекаю в тонкости что и почему )

так STM дешевле вдвое как минимум )))
там более развитые таймера и можно включать последовательно

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

kuzan67 пишет:
я не селён и ток внекаю в тонкости что и почему )
Ну, это поправимо! Как внекнете, так сел то и прибавится.

Atamanu
Offline
Зарегистрирован: 07.12.2021
Bună prieteni.
Încerc să rezolv o problemă și nu pot
Poate mă poți ajuta.
Acest lucru m-a inspirat... https://www.youtube.com/watch?v=K4oMha3MAzU&ab_channel=%D0%92%D0%93%D0%9... %A5 %D0%A3%D0%98%D0%9D%D0%96%D0%95%D0%9D%D0%95%D0%A0%D0%90
 
Acesta este codul...
//Pentru a calcula antetul și antetul
  #include <TinyGPS++.h>
//************************************

//Pentru scrierea și citirea EEPROM
#include <EEPROM.h>
        double read_Latitude_EEPROM = 54,628668; //variabilă pentru citirea din memorie comună pentru calculele căilor
        dublu citire_Longitudine_EEPROM = 52,536966; //variabilă pentru citirea din memorie comună pentru calculele căilor     
        citire dublă_Latitude_EEPROM_p1; // variabilă de citit din memorie
        dublu citire_Longitudine_EEPROM_p1; // variabilă de citit din memorie
        citire dublă_Latitude_EEPROM_p2; // variabilă de citit din memorie
        dublu citire_Longitudine_EEPROM_p2; // variabilă de citit din memorie       
        citire dublă_Latitude_EEPROM_p3; // variabilă de citit din memorie adăugată pentru a crește numărul de puncte de salvare
        citire dublă_Longitudine_EEPROM_p3; // variabilă de citit din memorie adăugată pentru a crește numărul de puncte de salvare
        citire dublă_Latitude_EEPROM_p4; // variabilă de citit din memorie adăugată pentru a crește numărul de puncte de salvare
        citire dublă_Longitudine_EEPROM_p4; // variabilă de citit din memorie adăugată pentru a crește numărul de puncte de salvare




         
//********************************

//Pentru a afișa valorile pe ecran
// include codul bibliotecii:
#include <LiquidCrystal.h>
// inițializați biblioteca prin asocierea oricărui pin de interfață LCD necesar
// cu numărul de pin arduino la care este conectat
const int rs = 8, en = 7, d4 = 6, d5 = 5, d6 = 3, d7 = 4;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
//****************************

//Pentru modulul radio
#include <SPI.h>
#include „nRF24L01.h”
#include „RF24.h”
radio RF24 (9, 10); // „creează” modul pe pinii 9 și 10 pentru Uno
adresa de octet[][6] = {"1Node", "2Node", "3Node", "4Node", "5Node", "6Node"}; //numerele posibile ale conductelor
//********************

octet pin_potent1 = 2; // potențiometru pe 0 analog - canalul 2 al telecomenzii
octet pin_potent2 = 3; // potențiometru pe 1 analog - 1 canal telecomandă

int transmit_data[4]; // matrice care stochează datele transmise
telemetrie dublă[4]; // matrice de date de telemetrie primite de la receptor
byte rssi;
int trnsmtd_pack = 1, failed_pack;
RSSI_timer lung nesemnat;

//VARIABILE PENTRU GPS
//long latitude_nach;
dublu latitudine_prod;
//long length_nach;
dublu longitudine_prod;
//byte day_moy;
//octet luna_moy;
//int year_moy;
//octet oră_moy;
//octet minute_moy;
//octet secund_moy;
//viteză lungă_kmph_moy;
//float speed_mps_moy;
curs dublu_moy;
//long visota_moy;
sateliti dubli_moy;
//float hdop_moy;
//****************************************

//a calcula direcția de mișcare
float koef_asimut;
//************************************

//Pentru pilot automat
byte autopilot_on = 0; // poziția inițială a pilotului automat este oprită
octet avtotormoz_l = 0; //frână automată pe pilot automat pentru motorul din stânga
octet avtotormoz_r = 0; //frână automată pe pilot automat pentru motorul potrivit
octet auto frână = 50; // VALOAREA AUTO FRANEA SCHIMBABILĂ ÎN AUTO PILOT
//****************

//variabile pentru motoare cu tracțiune diferită
int motor_l; //Motor stânga PWM variabil
int motor_r; // motor dreapta PWM variabil
int motor_z; // PWM invers variabil pentru ambele motoare
//************************************

  byte punkt_menu = 1; //selectați ecranul de meniu

  int reset = 0; // poziția inițială a butonului de resetare
//************************************************ **********************
void setup() {
  
//Pentru a afișa valorile pe ecran
  lcd.begin(16, 2);


//********************************

  
// Serial.begin(9600); //deschide portul pentru comunicare cu PC-ul

//Șiruri pentru modulul radio
  radio.begin(); //activează modulul
// radio setAutoAck(0); //Modul de confirmare, 1 pe 0 oprit comentat pentru a introduce feedback
  //inserați pentru feedback
  radio.setAutoAck(1); // modul de confirmare, 1 on 0 off----------------------------------------- ----
// radio.setRetries(0, 15); // (timpul dintre încercări de a ajunge, numărul de încercări)-------------------------------------
  radio.enableAckPayload(); // permite trimiterea de date ca răspuns la un semnal de intrare-----------------------------------
// radio.setPayloadSize(32); // dimensiunea pachetului, în octeți------------------------------ ------------- --------  
  //termină inserarea pentru feedback  
  radio.openWritingPipe(adresa[0]); // suntem conducta 0, deschidem un canal pentru transmiterea datelor
  radiosetChannel(0x60); //selectați un canal (care nu are zgomot!)
  radio.setPALevel(RF24_PA_HIGH); //nivelul puterii emițătorului. Alegeți RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH, RF24_PA_MAX
  radio.setDataRate(RF24_250KBPS); // Rata de schimb. Alegere RF24_2MBPS, RF24_1MBPS, RF24_250KBPS
  //ar trebui să fie același pe receptor și transmițător!
  //la cea mai mica viteza avem cea mai mare sensibilitate si raza de actiune!!
  radio.powerUp(); //incepe munca
  radio.stopListening(); // nu asculta radioul, suntem emițători
//****************************
  
}
//************************************************ ** ************************
void loop() {

if (autopilot_on == 0) {; // dacă pilotul automat este oprit, atunci autofrânele sunt resetate la zero
octet avtotormoz_l = 0; //frână automată pe pilot automat pentru motorul din stânga
octet avtotormoz_r = 0; //frână automată pe pilot automat pentru motorul potrivit
}

int in_ch1 = analogRead(pin_potent1); //citește pinii analogici
int in_ch2 = analogRead(pin_potent2); //citește pinii analogici

// Subrutină „Dacă maneta de accelerație este sus, atunci mergi înainte”
if (in_ch1 <= 504) {

in_ch1 = constrain(in_ch1,0,504); //restrângerea canalului de gaz de la mijloc spre sus
in_ch1 = map(in_ch1, 0, 504, 255-0, 0); // scalarea canalului de accelerație în format PWM. PROCENTUL DIN CURSA TOTALĂ ESTE MINUS. costurile cu gazele sunt încă în limitele de limitare a motoarelor individuale (mai jos).

int in_ch2_l = constrain(in_ch2,508,1023); // face restricții pe laturi
int in_ch2_r = constrain(in_ch2,0,506);

in_ch2_l = (hartă(în_ch2_l, 507, 1023, 0, 255))/3; //scalați laturile de la 0 la 255. DUPĂ TAXE DE TAXI FRACȚIUNE
in_ch2_r = (hartă(în_ch2_r, 506, 0, 0, 255))/3; //scalați laturile de la 0 la 255. DUPĂ TAXE DE TAXI FRACȚIUNE

//formule pentru motoare cu tracțiune diferită
motor_l = in_ch1 - in_ch2_l + in_ch2_r - 15; // -15 ACEASTA ESTE UN TRIM DREPT GENERAL DE CURSA
motor_r = in_ch1 - in_ch2_r + in_ch2_l;
//************************************

motor_l = constrain(motor_l,0,255-avtotormoz_l-0); // limitează numărul de motoare. PROCENTUL DIN DECLAREA TOTALĂ ȘI FRÂNE AUTOMATICE PILOT AUTOMAT SUNT ÎN MINUS. costurile cu gazul sunt încă în scala canalului de gaz (mai sus).
motor_r = constrain(motor_r,0,255-avtotormoz_r-0); // limitează numărul de motoare. PROCENTUL DIN DECLAREA TOTALĂ ȘI FRÂNE AUTOMATICE PILOT AUTOMAT SUNT ÎN MINUS. costurile cu gazul sunt încă în scala canalului de gaz (mai sus).
motor_z = 0; //Canal de viteză inversă dezactivat
}
// Sfârșitul subrutinei „Dacă maneta de accelerație este sus, atunci mergeți înainte”

//Subrutină „Dacă maneta de accelerație este în jos, atunci deplasați-vă înapoi”
dacă (in_ch1 >= 510) {
in_ch1 = constrain(in_ch1,510,1023); //restrângerea canalului de gaz de la mijloc spre jos
motor_z = map(in_ch1, 510, 1023, 0, 255-0); // scalarea canalului de gaz invers în format PWM. CHELTUIELI CURSULUI TOTAL ESTE MINUS.
motor_l = 0; // motorul față stânga este oprit
motor_r = 0; // motorul din fata dreapta este oprit
}
// Sfârșitul subrutinei „Dacă stick-ul de accelerație este jos, atunci treceți înapoi”

//Creează o matrice de transmis
transmit_data[0] = motor_l; //canaliza viteza de avans a motorului stâng
transmit_data[1] = motor_r; // canalul vitezei înainte a motorului drept
transmit_data[2] = resetare; // canal de aruncare a marfurilor
transmit_data[3] = motor_z; //Canal de viteză inversă pentru ambele motoare

//Șiruri pentru modulul radio
    radio.powerUp(); // activează transmițătorul
  //radio.write(&transmit_data, sizeof(transmit_data)); // trimite prin radio

  //inserați trimitere cu feedback și RSSI
  if (radio.write(&transmit_data, sizeof(transmit_data))) { // trimite pachetul transmit_date
    trnsmtd_pack++;
    if (!radio.available()) { // dacă primim un răspuns gol
    } altfel {
      while (radio.available() ) { // dacă există ceva în răspuns
        radio.read(&telemetria, dimensiunea(telemetria)); // citit
        // a primit o matrice de telemetrie plină de date a răspunsului de la receptor
      }
    }
  } altfel {
    failed_pack++;
  }
  if (millis() - RSSI_timer > 1000) { // RSSI timer
    // calculul calității legăturii (0 - 100%) pe baza numărului de erori și a numărului de transmisii reușite
    rssi = (1 - ((float)failed_pack / trnsmtd_pack)) * 100;
    // resetează valorile
    failed_pack = 0;
    trnsmtd_pack = 0;
    RSSI_timer = milis();
  }
  //termină inserarea transferului de feedback și RSSI
    radio.powerDown(); // opriți emițătorul
//****************************

//Pentru a calcula antetul și antetul
      distanta dublaToLondon =
        TinyGPSPlus::distanceBetween(
          telemetrie[0],
          telemetrie[1],
          read_Latitude_EEPROM,
          citire_Longitudine_EEPROM);
      curs dubluLa Londra =
        TinyGPSPlus::courseTo(
          telemetrie[0],
          telemetrie[1],
          read_Latitude_EEPROM,
          citire_Longitudine_EEPROM);
// Serial.print(distanțăToLondon, 2);
// Serial.print("m Course-to=");
// Serial.println(courseToLondon, 0);

//************************************

//Pentru a afișa valorile pe ecran

//Selectați ecranul de meniu
      if (analogRead(1)>1000 && analogRead(0)<1000)
       {
        punkt_menu = punkt_menu+1;
        dacă (punkt_menu >= 13)
       {
          punkt_menu = 1;
       }
      }
        lcd.clear();
        lcd.setCursor(0, 0); lcd.print(punkt_menu);
        lcd.setCursor(0, 1); lcd print(rssi);        

//Ecranul #1
if (punkt_menu == 1){
  lcd.setCursor(2, 0); lcd.print("RC FPV Aviator");
  lcd.setCursor(3, 1); lcd.print("Pilot automat");  
}
//Ecranul #0
if (punkt_menu == 0){
// lcd.setCursor(2, 0); lcd print("*");  

// lcd.setCursor(3, 0); lcd.print(read_Latitude_EEPROM, 6); lcd print(" "); lcd.print(read_Longitude_EEPROM, 6);

  //linia de sus cu coordonatele
  lcd.setCursor(7, 0); lcd.print(read_Longitude_EEPROM, 6);
  lcd.setCursor(0, 0); lcd.print(read_Latitude_EEPROM, 6); lcd print(" ");
  lcd.setCursor(0, 0); lcd.print(punkt_menu);     
  lcd.setCursor(1, 0); lcd.print("*");   
  //----------------------
  //linia de jos cu coordonatele
  lcd.setCursor(7, 1); lcd.print(telemetrie[1], 6);
  lcd.setCursor(0, 1); lcd.print(telemetrie[0], 6); lcd print(" ");
  lcd.setCursor(0, 1); lcd print(rssi);     
  lcd.setCursor(2, 1); lcd print(" ");
  //----------------------
}
//Ecranul #2
if (punkt_menu == 2){

        dacă (analogRead(1)>1000 && analogRead(0)>1000){ //dacă sunt apăsate tastele dreapta și stânga, valoarea de activare a pilotului automat se modifică
        autopilot_on = !autopilot_on;
        }
        //Subrutină pentru calcularea direcției de mișcare
        curs_moy = telemetrie[3]; //datele din telemetrie sunt atribuite variabilei cursului curent
        koef_asimut = (course_moy - courseToLondon)/180; //delta cursului se împarte la 180. dacă mai mult de 1 - la dreapta, dacă mai puțin de 1 - la stânga
        dacă (koef_asimut > 1.005){
            lcd.setCursor(4, 0); lcd.print(">>>>>>>"); lcd.setCursor(13, 0); lcd.print(curs_moy,0); //afișează rata curentă
                if (autopilot_on == 1){ //Dacă autopilot este activat, atunci
                    auto brake_l = 0; //motorul din stânga nu încetinește
                    avtotormoz_r = avtotormoz; //apoi încetinește motorul potrivit
                    lcd.setCursor(4, 0); lcd.print(">>AUTO>>");
                }altfel{
                    auto brake_l = 0; //motorul din stânga nu încetinește
                    auto brake_r = 0; // motorul drept nu încetinește                  
                }
        }
        if (koef_asimut < -0,005){
            lcd.setCursor(4, 0); lcd.print(">>>>>>>"); lcd.setCursor(13, 0); lcd.print(curs_moy,0); //afișează rata curentă
                if (autopilot_on == 1){ //Dacă autopilot este activat, atunci
                    auto brake_l = 0; //motorul din stânga nu încetinește
                    avtotormoz_r = avtotormoz; //apoi încetinește motorul potrivit
                    lcd.setCursor(4, 0); lcd.print(">>AUTO>>");
                }altfel{
                    auto brake_l = 0; //motorul din stânga nu încetinește
                    auto brake_r = 0; // motorul drept nu încetinește                  
                }
        }        
        dacă (koef_asimut > 0,005 && koef_asimut < 0,994){
            lcd.setCursor(4, 0); lcd.print("<<<<<<<"); lcd.setCursor(13, 0); lcd.print(curs_moy,0); //afișează rata curentă
                if (autopilot_on == 1){ //Dacă autopilot este activat, atunci
                    avtotormoz_l = avtotormoz+10; //aceasta incetineste motorul din stanga // +10 ASTA ESTE ACCELERARE TAXI LA STÂNGA ÎN AUTOPILOTO. FĂRĂ EL, STÂNGA IA MAI LENT DECÂT DREAPTA!!!!!!!!!
                    auto brake_r = 0; // motorul drept nu încetinește
                    lcd.setCursor(4, 0); lcd.print("<<AUTO<<");
                }altfel{
                    auto brake_l = 0; //motorul din stânga nu încetinește
                    auto brake_r = 0; // motorul drept nu încetinește                  
                }
        }
        if (koef_asimut >= 0,994 && koef_asimut <= 1,005){
            lcd.setCursor(4, 0); lcd.print("<<< >>>"); lcd.setCursor(13, 0); lcd.print(curs_moy,0); //afișează rata curentă
                if (autopilot_on == 1){ //Dacă autopilot este activat, atunci
                    auto brake_l = 0; //motorul din stânga nu încetinește
                    avtotormoz_r = avtotormoz; //apoi încetinește motorul potrivit
                    lcd.setCursor(4, 0); lcd.print(">>AUTO>>");
                }altfel{
                    auto brake_l = 0; //motorul din stânga nu încetinește
                    auto brake_r = 0; // motorul drept nu încetinește                  
                }
        }
        if (koef_asimut >= -0,005 && koef_asimut <= 0,005){
            lcd.setCursor(4, 0); lcd.print(">>>o<<<"); lcd.setCursor(13, 0); lcd.print(curs_moy,0); //afișează rata curentă
                if (autopilot_on == 1){ //Dacă autopilot este activat, atunci
                    auto brake_l = 0; //motorul din stânga nu încetinește
                    auto brake_r = 0; // motorul drept nu încetinește
                    lcd.setCursor(4, 0); lcd.print(">>AUTO<<");
                }altfel{
                    auto brake_l = 0; //motorul din stânga nu încetinește
                    auto brake_r = 0; // motorul drept nu încetinește                  
                }
        }
                
        //************************************************
  //lcd.setCursor(4, 0); lcd.print("Curs:"); lcd.setCursor(13, 0); lcd.print(telemetrie[3],0); //afișează rata curentă
  lcd.setCursor(4, 1); lcd.print(distanțăToLondon, 2); lcd.print("m"); lcd.setCursor(12, 1); lcd print(" "); lcd.print(cursToLondra, 0); //afișează distanța și cursul până la punctul dorit
}

//Ecranul #3
if (punkt_menu == 3){
  lcd.setCursor(4, 0); lcd.print("SBROS???");
  lcd.setCursor(7, 1); imprimare lcd(sbros);
    dacă (analogRead(1)>1000 && analogRead(0)>1000){
        resetare=1;
      }altfel{
        resetare=0;
      }
}

//Ecranul #4
if (punkt_menu == 4){
  lcd.setCursor(4, 0); lcd.print("Sateliți:");
  lcd.setCursor(4, 1); lcd.print(telemetrie[2],0);
}
//Ecranul #5
if (punkt_menu == 5){
  lcd.setCursor(3, 0); lcd.print("Salvați punctul 1?");
  //linia de jos cu coordonatele
  lcd.setCursor(7, 1); lcd.print(telemetrie[1], 6);
  lcd.setCursor(0, 1); lcd.print(telemetrie[0], 6); lcd print(" ");
  lcd.setCursor(0, 1); lcd print(rssi);     
  lcd.setCursor(2, 1); lcd print(" ");    
  //------------------------------------
  dacă (analogRead(1)>1000 && analogRead(0)>1000){
        EEPROM_double_write(0, telemetrie[0]); // scrie în memorie. apel de funcție
        EEPROM_double_write(10, telemetrie[1]); // scrie în memorie. apel de funcție
  }
}
//Ecranul #6
if (punkt_menu == 6){
  lcd.setCursor(3, 0); lcd.print("Citiți punctul 1?");
  //linia de jos cu coordonatele
  lcd.setCursor(7, 1); lcd.print(read_Longitude_EEPROM_p1, 6);
  lcd.setCursor(0, 1); lcd.print(read_Latitude_EEPROM_p1, 6); lcd print(" ");
  lcd.setCursor(0, 1); lcd print(rssi);     
  lcd.setCursor(2, 1); lcd print(" ");    
  //------------------------------------
  
  dacă (analogRead(1)>1000 && analogRead(0)>1000){
        read_Latitude_EEPROM_p1 = EEPROM_double_read(0); //citind din memorie. apel de funcție
        read_Longitude_EEPROM_p1 = EEPROM_double_read(10); //citind din memorie. apel de funcție
        read_Latitude_EEPROM = read_Latitude_EEPROM_p1;// această valoare este folosită pentru calculele traseului
        read_Longitude_EEPROM = read_Longitude_EEPROM_p1;// această valoare este folosită pentru calculele traseului
  }
}
//Ecranul #7
if (punkt_menu == 7){
// lcd.setCursor(2, 1); lcd print(" ");  
  lcd.setCursor(3, 0); lcd.print("Salvați punctul 2?");
// lcd.setCursor(3, 1); lcd.print(telemetrie[0]/1000); lcd print(" "); lcd.print(telemetrie[1]/1000);
  //linia de jos cu coordonatele
  lcd.setCursor(7, 1); lcd.print(telemetrie[1], 6);
  lcd.setCursor(0, 1); lcd.print(telemetrie[0], 6); lcd print(" ");
  lcd.setCursor(0, 1); lcd print(rssi);     
  lcd.setCursor(2, 1); lcd print(" ");    
  //------------------------------------  
  dacă (analogRead(1)>1000 && analogRead(0)>1000){
        EEPROM_double_write(20, telemetrie[0]); // scrie în memorie. apel de funcție
        EEPROM_double_write(30, telemetrie[1]); // scrie în memorie. apel de funcție
  }
}
//Ecranul #8
if (punkt_menu == 8){
// lcd.setCursor(2, 1); lcd print(" ");  
  lcd.setCursor(3, 0); lcd.print("Citiți punctul 2?");
// lcd.setCursor(3, 1); lcd.print(read_Latitude_EEPROM_p2/1000); lcd print(" "); lcd.print(read_Longitude_EEPROM_p2/1000);
  //linia de jos cu coordonatele
  lcd.setCursor(7, 1); lcd.print(read_Longitude_EEPROM_p2, 6);
  lcd.setCursor(0, 1); lcd.print(read_Latitude_EEPROM_p2, 6); lcd print(" ");
  lcd.setCursor(0, 1); lcd print(rssi);     
  lcd.setCursor(2, 1); lcd print(" ");    
  //------------------------------------  
  dacă (analogRead(1)>1000 && analogRead(0)>1000){
        read_Latitude_EEPROM_p2 = EEPROM_double_read(20); //citind din memorie. apel de funcție
        read_Longitude_EEPROM_p2 = EEPROM_double_read(30); //citind din memorie. apel de funcție
        read_Latitude_EEPROM = read_Latitude_EEPROM_p2;// această valoare este folosită pentru calculele traseului
        read_Longitude_EEPROM = read_Longitude_EEPROM_p2;// această valoare este folosită pentru calculele traseului     
  }
}
//În continuare, pentru a crește numărul de puncte salvate de la 2 la 4, adaug încă 4 ecrane de meniu, similare pentru primele două puncte, dar schimb parametrii memoriei și numele variabilelor


//Ecranul #9
if (punkt_menu == 9){
  lcd.setCursor(3, 0); lcd.print("Salvați punctul 3?");
  //linia de jos cu coordonatele
  lcd.setCursor(7, 1); lcd.print(telemetrie[1], 6);
  lcd.setCursor(0, 1); lcd.print(telemetrie[0], 6); lcd print(" ");
  lcd.setCursor(0, 1); lcd print(rssi);     
  lcd.setCursor(2, 1); lcd print(" ");    
  //------------------------------------
  dacă (analogRead(1)>1000 && analogRead(0)>1000){
        EEPROM_double_write(40, telemetrie[0]); // scrie în memorie. apel de funcție
        EEPROM_double_write(50, telemetrie[1]); // scrie în memorie. apel de funcție
  }
}
//Ecranul #10
if (punkt_menu == 10){
  lcd.setCursor(3, 0); lcd.print("Citiți punctul 3?");
  //linia de jos cu coordonatele
  lcd.setCursor(7, 1); lcd.print(read_Longitude_EEPROM_p3, 6);
  lcd.setCursor(0, 1); lcd.print(read_Latitude_EEPROM_p3, 6); lcd print(" ");
  lcd.setCursor(0, 1); lcd print(rssi);     
  lcd.setCursor(2, 1); lcd print(" ");    
  //------------------------------------
  
  dacă (analogRead(1)>1000 && analogRead(0)>1000){
        read_Latitude_EEPROM_p3 = EEPROM_double_read(40); //citind din memorie. apel de funcție
        read_Longitude_EEPROM_p3 = EEPROM_double_read(50); //citind din memorie. apel de funcție
        read_Latitude_EEPROM = read_Latitude_EEPROM_p3;// această valoare este folosită pentru calculele traseului
        read_Longitude_EEPROM = read_Longitude_EEPROM_p3;// această valoare este folosită pentru calculele traseului
  }
}
//Ecranul #11
if (punkt_menu == 11){
// lcd.setCursor(2, 1); lcd print(" ");  
  lcd.setCursor(3, 0); lcd.print("Salvați punctul 4?");
// lcd.setCursor(3, 1); lcd.print(telemetrie[0]/1000); lcd print(" "); lcd.print(telemetrie[1]/1000);
  //linia de jos cu coordonatele
  lcd.setCursor(7, 1); lcd.print(telemetrie[1], 6);
  lcd.setCursor(0, 1); lcd.print(telemetrie[0], 6); lcd print(" ");
  lcd.setCursor(0, 1); lcd print(rssi);     
  lcd.setCursor(2, 1); lcd print(" ");    
  //------------------------------------  
  dacă (analogRead(1)>1000 && analogRead(0)>1000){
        EEPROM_double_write(60, telemetrie[0]); // scrie în memorie. apel de funcție
        EEPROM_double_write(70, telemetrie[1]); // scrie în memorie. apel de funcție
  }
}
//Ecranul #12
if (punkt_menu == 12){
// lcd.setCursor(2, 1); lcd print(" ");  
  lcd.setCursor(3, 0); lcd.print("Citiți punctul 4?");
// lcd.setCursor(3, 1); lcd.print(read_Latitude_EEPROM_p2/1000); lcd print(" "); lcd.print(read_Longitude_EEPROM_p2/1000);
  //linia de jos cu coordonatele
  lcd.setCursor(7, 1); lcd.print(read_Longitude_EEPROM_p4, 6);
  lcd.setCursor(0, 1); lcd.print(read_Latitude_EEPROM_p4, 6); lcd print(" ");
  lcd.setCursor(0, 1); lcd print(rssi);     
  lcd.setCursor(2, 1); lcd print(" ");    
  //------------------------------------  
  dacă (analogRead(1)>1000 && analogRead(0)>1000){
        read_Latitude_EEPROM_p4 = EEPROM_double_read(60); //citind din memorie. apel de funcție
        read_Longitude_EEPROM_p4 = EEPROM_double_read(70); //citind din memorie. apel de funcție
        read_Latitude_EEPROM = read_Latitude_EEPROM_p4;// această valoare este folosită pentru calculele traseului
        read_Longitude_EEPROM = read_Longitude_EEPROM_p4;// această valoare este folosită pentru calculele traseului     
  }
}

 întârziere (100);
//********************************    
    
// Serial.print(in_ch1); imprimare în serie(" "); Serial.print(in_ch2); Serial.print("l_"); Serial.print(in_ch2_l); Serial.print("r_"); Serial.print(in_ch2_r);
// Serial.print("M_l_"); Imprimare în serie (motor_l); Serial.print("M_r_"); Imprimare în serie (motor_r);
// Serial.print(" "); Serial.print(analogRead(pin_potent1)); imprimare în serie(" "); Serial.println(analogRead(pin_potent2));
// Serial.print(" "); Serial.print(telemetrie[0]); imprimare în serie(" "); Serial.print(telemetrie[1]); imprimare în serie(" "); Serial println(rssi);

} //END LOOP ********************


// Funcția de scriere EEPROM
void EEPROM_double_write(int addr, double num) {
  octet brut[4];
  (dublu&)raw = num;
  for(byte i = 0; i < 4; i++) EEPROM.write(addr+i, raw[i]);
}
//****************************

// Funcție de citit din EEPROM
double EEPROM_double_read(int address) {   
  octet brut[4];
  for(byte i = 0; i < 4; i++) raw[i] = EEPROM.read(addr+i);
  dublu &num = (dublu&)brut;
  return num;
}
//********************************
if (citire analogică(1)>1000 && citire analogică(0)<1000)
        {
         meniu_item = meniu_item+1;
         dacă (articol_meniu >= 13)
        {
           element_meniu = 1;
        }
 
ca in codul de mai jos... control prin IBus...
 
#include „SoftIBus.h”//Biblioteca SoftIBus
SoftwareSerial IBuspin(2, 3);//portul „serial” pe care vom rula conexiunea IBus. Deoarece pentru a citi valorile avem nevoie doar de Rx, conectați pinul 2 și lăsați 3 deschis

byte menu = 0;//puncul de pornire

void setup()
{
  IBuspin.begin(115200);//portul softserial trebuie să înceapă la acest baud înainte de a-l porni ca port IBus
  Serial.begin(115200);//hardserial pentru debigging
  IBus.begin(IBuspin);//porniți obiectul IBus
}

buclă goală ()
{
  bucla IBus();

  //Serial.println(IBus.readChannel(3));//=Stick St orizontal
  //Serial.println(IBus.readChannel(4));//=SwA
  dacă (IBus.readChannel(4) == 2000)
  {
    meniu=meniu+1;
    dacă (meniu >= 4)
    {
      meniu = 1;
    }
  }
  //================================================== ====================================
  dacă (meniu == 1)
  {
    Serial.println("1");
  }
  dacă (meniu == 2)
  {
    Serial.println("2");
  }
  dacă (meniu == 3)
  {
    Serial.println("3");
  }
  dacă (meniu == 4)
  {
    Serial.println("4");
  }
}//termină bucla


Vă mulțumesc pentru răbdarea dvs.



 

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Atamanu пишет:

Bună prieteni.
Încerc să rezolv o problemă și nu pot
Poate mă poți ajuta.

Buna prietene!
Acesta este un forum în limba rusă.
ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

Atamanu пишет:

Bună prieteni.
Încerc să rezolv o problemă și nu pot
Poate mă poți ajuta.

Buna prietene!
Acesta este un forum în limba rusă.

С вашим знанием 108 языков, не уж то сложно )))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

ua6em пишет:

С вашим знанием 108 языков, не уж то сложно )))

Вы меня с ELITE не путайте. Это он 20 языков знает на уровне выше университетского.

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

ЕвгенийП пишет:

ua6em пишет:

С вашим знанием 108 языков, не уж то сложно )))

Вы меня с ELITE не путайте. Это он 20 языков знает на уровне выше университетского.

а языки программирования не в счёт? ;-) просто прикололся от гугла, что он со 108 переводить может, нам дзэн-буддистам эта цифра о многом говорит...ох неспроста это...ох не спроста...таких случайностей не бывает

Atamanu
Offline
Зарегистрирован: 07.12.2021
Прошу простить мою ошибку и..
Спасибо за ваше терпение
 
Привет друзья.
Я пытаюсь решить проблему и не могу
Возможно ты можешь помочь мне.
Это вдохновило меня…
https://www.youtube.com/watch?v=K4oMha3MAzU&ab_channel=%D0%92%D0%93%D0%9... %A5 %D0%A3%D0%98%D0%9D%D0%96%D0%95%D0%9D%D0%95%D0%A0%D0%90
 
Это код...
//Для расчета курса и направления
#include <TinyGPS++.h>
//*******************************

//Для записи и чтения EEPROM
#include <EEPROM.h>
double read_Latitude_EEPROM = 54.628668; //переменная для чтения из памяти общая для расчетов пути
double read_Longitude_EEPROM = 52.536966; //переменная для чтения из памяти общая для расчетов пути
double read_Latitude_EEPROM_p1; //переменная для чтения из памяти
double read_Longitude_EEPROM_p1; //переменная для чтения из памяти
double read_Latitude_EEPROM_p2; //переменная для чтения из памяти
double read_Longitude_EEPROM_p2; //переменная для чтения из памяти
double read_Latitude_EEPROM_p3; //переменная для чтения из памяти     добавил для увеличения количества точек сохранения
double read_Longitude_EEPROM_p3; //переменная для чтения из памяти     добавил для увеличения количества точек сохранения
double read_Latitude_EEPROM_p4; //переменная для чтения из памяти     добавил для увеличения количества точек сохранения
double read_Longitude_EEPROM_p4; //переменная для чтения из памяти     добавил для увеличения количества точек сохранения





//**************************

//Для вывода значений на экран
// include the library code:
#include <LiquidCrystal.h>
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 8, en = 7, d4 = 6, d5 = 5, d6 = 3, d7 = 4;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
//***********************

//Для радиомодуля
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
RF24 radio(9, 10); // "создать" модуль на пинах 9 и 10 Для Уно
byte address[][6] = {"1Node", "2Node", "3Node", "4Node", "5Node", "6Node"}; //возможные номера труб
//****************

byte pin_potent1 = 2; // потенциометр на 0 аналоговом - 2 канал пульта
byte pin_potent2 = 3; // потенциометр на 1 аналоговом - 1 канал пульта

int transmit_data[4]; // массив, хранящий передаваемые данные
double telemetry[4];              // массив принятых от приёмника данных телеметрии
byte rssi;
int trnsmtd_pack = 1, failed_pack;
unsigned long RSSI_timer;

//ПЕРЕМЕННЫЕ ДЛЯ GPS
//long lalitude_nach;
double lalitude_prod;
//long longitude_nach;
double longitude_prod;
//byte day_moy;
//byte month_moy;
//int year_moy;
//byte hour_moy;
//byte minute_moy;
//byte second_moy;
//long speed_kmph_moy;
//float speed_mps_moy;
double course_moy;
//long visota_moy;
double sputniki_moy;
//float hdop_moy;
//****************************************

//для рассчета направления движения
float koef_asimut;
//*********************************

//Для автопилота
byte autopilot_on = 0; // начальное положение автопилота выключенное
byte avtotormoz_l = 0; //автотормоз при автопилоте для левого мотора
byte avtotormoz_r = 0; //автотормоз при автопилоте для правого мотора
byte avtotormoz = 50; // ИЗМЕНЯЕМОЕ ЗНАЧЕНИЕ АВТОТОРМОЗА ПРИ АВТОПИЛОТЕ
//**************

//переменные для моторов с разнотягом
int motor_l; //переменная шим левого мотора
int motor_r; //переменная шим правого мотора
int motor_z; //переменная шим заднего хода обоих моторов
//********************************

byte punkt_menu = 1; //выбор экрана меню

int sbros = 0; //начальное положение кнопки сброса
void setup() {

  //Для вывода значений на экран
  lcd.begin(16, 2);


  //****************************


  //  Serial.begin(9600); //открываем порт для связи с ПК

  //Строки для радиомодуля
  radio.begin(); //активировать модуль
  //  radio.setAutoAck(0);         //режим подтверждения приёма, 1 вкл 0 выкл закомментировано для вставки обратной связи
  //вставка для обратной связи
  radio.setAutoAck(1);        // режим подтверждения приёма, 1 вкл 0 выкл---------------------------------------------
  //  radio.setRetries(0, 15);    // (время между попыткой достучаться, число попыток)------------------------------------
  radio.enableAckPayload();   // разрешить отсылку данных в ответ на входящий сигнал----------------------------------
  //  radio.setPayloadSize(32);   // размер пакета, в байтах--------------------------------------------------------------
  //конец вставки для обратной связи
  radio.openWritingPipe(address[0]);   //мы - труба 0, открываем канал для передачи данных
  radio.setChannel(0x60);  //выбираем канал (в котором нет шумов!)
  radio.setPALevel (RF24_PA_HIGH); //уровень мощности передатчика. На выбор RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH, RF24_PA_MAX
  radio.setDataRate (RF24_250KBPS); //скорость обмена. На выбор RF24_2MBPS, RF24_1MBPS, RF24_250KBPS
  //должна быть одинакова на приёмнике и передатчике!
  //при самой низкой скорости имеем самую высокую чувствительность и дальность!!
  radio.powerUp(); //начать работу
  radio.stopListening();  //не слушаем радиоэфир, мы передатчик
  //***********************

}

void loop() {

  if (autopilot_on == 0) {
    ; // если автопилот выключен, то автотормоза обнуляются
    byte avtotormoz_l = 0; //автотормоз при автопилоте для левого мотора
    byte avtotormoz_r = 0; //автотормоз при автопилоте для правого мотора
  }

  int in_ch1 = analogRead(pin_potent1); //чтение аналоговых пинов
  int in_ch2 = analogRead(pin_potent2); //чтение аналоговых пинов

  //Подпрограмма "Если джойстик газа вверх, то движение вперед"
  if (in_ch1 <= 504) {

    in_ch1 = constrain(in_ch1, 0, 504); //ограничение канала газа от середины до верха
    in_ch1 = map(in_ch1, 0, 504, 255 - 0, 0); //масштабирование канала газа в шим формат. МИНУСУЕТСЯ ПРОЦЕНТ ОБЩЕГО ХОДА. расходы газа есть еще в строках ограничения отдельных моторов (ниже).

    int in_ch2_l = constrain(in_ch2, 508, 1023); //делаю ограничения по сторонам
    int in_ch2_r = constrain(in_ch2, 0, 506);

    in_ch2_l = (map(in_ch2_l, 507, 1023, 0, 255)) / 3; //масштабирую стороны от 0 до 255. ПОСЛЕ ДРОБИ РАСХОДЫ РУЛЕНИЯ
    in_ch2_r = (map(in_ch2_r, 506, 0, 0, 255)) / 3; //масштабирую стороны от 0 до 255. ПОСЛЕ ДРОБИ РАСХОДЫ РУЛЕНИЯ

    //формулы для моторов с разнотягом
    motor_l = in_ch1 - in_ch2_l + in_ch2_r - 15; // -15 ЭТО ОБЩИЙ ТРИММЕР ХОДА ПРЯМО
    motor_r = in_ch1 - in_ch2_r + in_ch2_l;
    //********************************

    motor_l = constrain(motor_l, 0, 255 - avtotormoz_l - 0); //ограничиваю цифры моторов. МИНУСУЕТСЯ ПРОЦЕНТ ОБЩЕГО ХОДА И АВТОТОРМОЗ АВТОПИЛОТА. расходы газа есть еще в масштабировании канала газа (выше).
    motor_r = constrain(motor_r, 0, 255 - avtotormoz_r - 0); //ограничиваю цифры моторов. МИНУСУЕТСЯ ПРОЦЕНТ ОБЩЕГО ХОДА И АВТОТОРМОЗ АВТОПИЛОТА. расходы газа есть еще в масштабировании канала газа (выше).
    motor_z = 0; //канал задней скорости отключен
  }
  //Конец подпрограммы "Если джойстик газа вверх, то движение вперед"

  //Подпрограмма "Если джойстик газа вниз, то движение назад"
  if (in_ch1 >= 510) {
    in_ch1 = constrain(in_ch1, 510, 1023); //ограничение канала газа от середины до низа
    motor_z = map(in_ch1, 510, 1023, 0, 255 - 0); //масштабирование канала газа заднего хода в шим формат. МИНУСУЕТСЯ РАСХОД ОБЩЕГО ХОДА.
    motor_l = 0; //передний левый мотор стоит
    motor_r = 0; //передний правый мотор стоит
  }
  //Конец подпрограммы "Если джойстик газа вниз, то движение назад"

  //Создание массива для передачи
  transmit_data[0] = motor_l; //канал передней скорости левого мотора
  transmit_data[1] = motor_r; //канал передней скорости правого мотора
  transmit_data[2] = sbros; // канал сброса груза
  transmit_data[3] = motor_z; //канал задней скорости на оба мотора

  //Строки для радиомодуля
  radio.powerUp(); // включить передатчик
  //radio.write(&transmit_data, sizeof(transmit_data)); // отправить по радио

  //вставка отправки с обратной связью и RSSI
  if (radio.write(&transmit_data, sizeof(transmit_data))) {    // отправка пакета transmit_data
    trnsmtd_pack++;
    if (!radio.available()) {                                  // если получаем пустой ответ
    } else {
      while (radio.available() ) {                    // если в ответе что-то есть
        radio.read(&telemetry, sizeof(telemetry));    // читаем
        // получили забитый данными массив telemetry ответа от приёмника
      }
    }
  } else {
    failed_pack++;
  }
  if (millis() - RSSI_timer > 1000) {    // таймер RSSI
    // расчёт качества связи (0 - 100%) на основе числа ошибок и числа успешных передач
    rssi = (1 - ((float)failed_pack / trnsmtd_pack)) * 100;
    // сбросить значения
    failed_pack = 0;
    trnsmtd_pack = 0;
    RSSI_timer = millis();
  }
  //конец вставки передачи с обратной связью и RSSI
  radio.powerDown(); // выключить передатчик
  //**********************

  //Для расчета курса и направления
  double distanceToLondon =
    TinyGPSPlus::distanceBetween(
      telemetry[0],
      telemetry[1],
      read_Latitude_EEPROM,
      read_Longitude_EEPROM);
  double courseToLondon =
    TinyGPSPlus::courseTo(
      telemetry[0],
      telemetry[1],
      read_Latitude_EEPROM,
      read_Longitude_EEPROM);
  //      Serial.print(distanceToLondon, 2);
  //      Serial.print(" m   Course-to=");
  //      Serial.println(courseToLondon, 0);

  //*******************************

  //Для вывода значений на экран

  //Выбор экрана меню
  if (analogRead(1) > 1000 && analogRead(0) < 1000)
  {
    punkt_menu = punkt_menu + 1;
    if (punkt_menu >= 13)
    {
      punkt_menu = 1;
    }
  }
  lcd.clear();
  lcd.setCursor(0, 0); lcd.print(punkt_menu);
  lcd.setCursor(0, 1); lcd.print(rssi);

  //Экран №1
  if (punkt_menu == 1) {
    lcd.setCursor(2, 0); lcd.print("RC FPV Aviator");
    lcd.setCursor(3, 1); lcd.print("  Autopilot");
  }
  //Экран №0
  if (punkt_menu == 0) {
    //  lcd.setCursor(2, 0); lcd.print("*");

    //  lcd.setCursor(3, 0); lcd.print(read_Latitude_EEPROM, 6); lcd.print(" "); lcd.print(read_Longitude_EEPROM, 6);

    //верхняя строка с координатами
    lcd.setCursor(7, 0); lcd.print(read_Longitude_EEPROM, 6);
    lcd.setCursor(0, 0); lcd.print(read_Latitude_EEPROM, 6); lcd.print(" ");
    lcd.setCursor(0, 0); lcd.print(punkt_menu);
    lcd.setCursor(1, 0); lcd.print(" *");
    //-----------------------------
    //нижняя строка с координатами
    lcd.setCursor(7, 1);  lcd.print(telemetry[1], 6);
    lcd.setCursor(0, 1);  lcd.print(telemetry[0], 6); lcd.print(" ");
    lcd.setCursor(0, 1); lcd.print(rssi);
    lcd.setCursor(2, 1); lcd.print(" ");
    //-----------------------------
  }
  //Экран №2
  if (punkt_menu == 2) {

    if (analogRead(1) > 1000 && analogRead(0) > 1000) { //если нажимаются клавиши правая и левая, то значение включения автопилота меняется
      autopilot_on = !autopilot_on;
    }
    //Подпрограмма расчета направления движения
    course_moy = telemetry[3]; //присваиваются переменной действующего курса данные с телеметрии
    koef_asimut = (course_moy - courseToLondon) / 180; //дельта курсов делится на 180. если больше 1-направо, если меньше 1-налево
    if (koef_asimut > 1.005) {
      lcd.setCursor(4, 0); lcd.print(">>>>>>>"); lcd.setCursor(13, 0); lcd.print(course_moy, 0); //показывает действующий курс
      if (autopilot_on == 1) { //Если автопилот включен, то
        avtotormoz_l = 0; //левый мотор не тормозит
        avtotormoz_r = avtotormoz; //то тормозит правый мотор
        lcd.setCursor(4, 0); lcd.print(">>AUTO>>");
      } else {
        avtotormoz_l = 0; //левый мотор не тормозит
        avtotormoz_r = 0; //правый мотор не тормозит
      }
    }
    if (koef_asimut < -0.005) {
      lcd.setCursor(4, 0); lcd.print(">>>>>>>"); lcd.setCursor(13, 0); lcd.print(course_moy, 0); //показывает действующий курс
      if (autopilot_on == 1) { //Если автопилот включен, то
        avtotormoz_l = 0; //левый мотор не тормозит
        avtotormoz_r = avtotormoz; //то тормозит правый мотор
        lcd.setCursor(4, 0); lcd.print(">>AUTO>>");
      } else {
        avtotormoz_l = 0; //левый мотор не тормозит
        avtotormoz_r = 0; //правый мотор не тормозит
      }
    }
    if (koef_asimut > 0.005 && koef_asimut < 0.994) {
      lcd.setCursor(4, 0); lcd.print("<<<<<<<"); lcd.setCursor(13, 0); lcd.print(course_moy, 0); //показывает действующий курс
      if (autopilot_on == 1) { //Если автопилот включен, то
        avtotormoz_l = avtotormoz + 10; //то тормозит левый мотор // +10 ЭТО УСКОРЕНИЕ РУЛЕНИЯ В ЛЕВО ПРИ АВТОПИЛОТЕ. БЕЗ НЕГО ВЛЕВО РУЛИТ МЕДЛЕННЕЕ ЧЕМ В ПРАВО!!!!!!!!!
        avtotormoz_r = 0; //правый мотор не тормозит
        lcd.setCursor(4, 0); lcd.print("<<AUTO<<");
      } else {
        avtotormoz_l = 0; //левый мотор не тормозит
        avtotormoz_r = 0; //правый мотор не тормозит
      }
    }
    if (koef_asimut >= 0.994 && koef_asimut <= 1.005) {
      lcd.setCursor(4, 0); lcd.print("<<< >>>"); lcd.setCursor(13, 0); lcd.print(course_moy, 0); //показывает действующий курс
      if (autopilot_on == 1) { //Если автопилот включен, то
        avtotormoz_l = 0; //левый мотор не тормозит
        avtotormoz_r = avtotormoz; //то тормозит правый мотор
        lcd.setCursor(4, 0); lcd.print(">>AUTO>>");
      } else {
        avtotormoz_l = 0; //левый мотор не тормозит
        avtotormoz_r = 0; //правый мотор не тормозит
      }
    }
    if (koef_asimut >= -0.005 && koef_asimut <= 0.005) {
      lcd.setCursor(4, 0); lcd.print(">>>o<<<"); lcd.setCursor(13, 0); lcd.print(course_moy, 0); //показывает действующий курс
      if (autopilot_on == 1) { //Если автопилот включен, то
        avtotormoz_l = 0; //левый мотор не тормозит
        avtotormoz_r = 0; //правый мотор не тормозит
        lcd.setCursor(4, 0); lcd.print(">>AUTO<<");
      } else {
        avtotormoz_l = 0; //левый мотор не тормозит
        avtotormoz_r = 0; //правый мотор не тормозит
      }
    }

    //*****************************************
    //lcd.setCursor(4, 0); lcd.print("Course:"); lcd.setCursor(13, 0); lcd.print(telemetry[3],0); //показывает действующий курс
    lcd.setCursor(4, 1); lcd.print(distanceToLondon, 2); lcd.print("m" ); lcd.setCursor(12, 1); lcd.print(" "); lcd.print(courseToLondon, 0); //показывает расстояние и курс до нужной точки
  }

  //Экран №3
  if (punkt_menu == 3) {
    lcd.setCursor(4, 0); lcd.print("SBROS???");
    lcd.setCursor(7, 1); lcd.print(sbros);
    if (analogRead(1) > 1000 && analogRead(0) > 1000) {
      sbros = 1;
    } else {
      sbros = 0;
    }
  }

  //Экран №4
  if (punkt_menu == 4) {
    lcd.setCursor(4, 0); lcd.print("Satellites:");
    lcd.setCursor(4, 1); lcd.print(telemetry[2], 0);
  }
  //Экран №5
  if (punkt_menu == 5) {
    lcd.setCursor(3, 0); lcd.print("Save point 1?");
    //нижняя строка с координатами
    lcd.setCursor(7, 1);  lcd.print(telemetry[1], 6);
    lcd.setCursor(0, 1);  lcd.print(telemetry[0], 6); lcd.print("    ");
    lcd.setCursor(0, 1); lcd.print(rssi);
    lcd.setCursor(2, 1); lcd.print("    ");
    //----------------------------
    if (analogRead(1) > 1000 && analogRead(0) > 1000) {
      EEPROM_double_write (0, telemetry[0]); //запись в память. обращение к функции
      EEPROM_double_write (10, telemetry[1]); //запись в памяь. обращение к функции
    }
  }
  //Экран №6
  if (punkt_menu == 6) {
    lcd.setCursor(3, 0); lcd.print("Read point 1?");
    //нижняя строка с координатами
    lcd.setCursor(7, 1);  lcd.print(read_Longitude_EEPROM_p1, 6);
    lcd.setCursor(0, 1);  lcd.print(read_Latitude_EEPROM_p1, 6); lcd.print("    ");
    lcd.setCursor(0, 1); lcd.print(rssi);
    lcd.setCursor(2, 1); lcd.print("    ");
    //----------------------------

    if (analogRead(1) > 1000 && analogRead(0) > 1000) {
      read_Latitude_EEPROM_p1 = EEPROM_double_read(0); //чтение из памяти. обращение к функции
      read_Longitude_EEPROM_p1 = EEPROM_double_read(10); //чтение из памяти. обращение к функции
      read_Latitude_EEPROM = read_Latitude_EEPROM_p1;// для расчетов пути применяется именно это значение
      read_Longitude_EEPROM = read_Longitude_EEPROM_p1;// для расчетов пути применяется именно это значение
    }
  }
  //Экран №7
  if (punkt_menu == 7) {
    //  lcd.setCursor(2, 1); lcd.print(" ");
    lcd.setCursor(3, 0); lcd.print("Save point 2?");
    //  lcd.setCursor(3, 1); lcd.print(telemetry[0]/1000); lcd.print(" "); lcd.print(telemetry[1]/1000);
    //нижняя строка с координатами
    lcd.setCursor(7, 1);  lcd.print(telemetry[1], 6);
    lcd.setCursor(0, 1);  lcd.print(telemetry[0], 6); lcd.print("    ");
    lcd.setCursor(0, 1); lcd.print(rssi);
    lcd.setCursor(2, 1); lcd.print("    ");
    //----------------------------
    if (analogRead(1) > 1000 && analogRead(0) > 1000) {
      EEPROM_double_write (20, telemetry[0]); //запись в память. обращение к функции
      EEPROM_double_write (30, telemetry[1]); //запись в памяь. обращение к функции
    }
  }
  //Экран №8
  if (punkt_menu == 8) {
    //  lcd.setCursor(2, 1); lcd.print(" ");
    lcd.setCursor(3, 0); lcd.print("Read point 2?");
    //  lcd.setCursor(3, 1); lcd.print(read_Latitude_EEPROM_p2/1000); lcd.print(" "); lcd.print(read_Longitude_EEPROM_p2/1000);
    //нижняя строка с координатами
    lcd.setCursor(7, 1);  lcd.print(read_Longitude_EEPROM_p2, 6);
    lcd.setCursor(0, 1);  lcd.print(read_Latitude_EEPROM_p2, 6); lcd.print("    ");
    lcd.setCursor(0, 1); lcd.print(rssi);
    lcd.setCursor(2, 1); lcd.print("    ");
    //----------------------------
    if (analogRead(1) > 1000 && analogRead(0) > 1000) {
      read_Latitude_EEPROM_p2 = EEPROM_double_read(20); //чтение из памяти. обращение к функции
      read_Longitude_EEPROM_p2 = EEPROM_double_read(30); //чтение из памяти. обращение к функции
      read_Latitude_EEPROM = read_Latitude_EEPROM_p2;// для расчетов пути применяется именно это значение
      read_Longitude_EEPROM = read_Longitude_EEPROM_p2;// для расчетов пути применяется именно это значение
    }
  }
  //Далее для увеличения количества сохраняемых точек с 2-х до 4-х добавляю еще 4 экрана меню, аналогичные для первых двух точек, но изменяю параметры памяти и названия переменных


  //Экран №9
  if (punkt_menu == 9) {
    lcd.setCursor(3, 0); lcd.print("Save point 3?");
    //нижняя строка с координатами
    lcd.setCursor(7, 1);  lcd.print(telemetry[1], 6);
    lcd.setCursor(0, 1);  lcd.print(telemetry[0], 6); lcd.print("    ");
    lcd.setCursor(0, 1); lcd.print(rssi);
    lcd.setCursor(2, 1); lcd.print("    ");
    //----------------------------
    if (analogRead(1) > 1000 && analogRead(0) > 1000) {
      EEPROM_double_write (40, telemetry[0]); //запись в память. обращение к функции
      EEPROM_double_write (50, telemetry[1]); //запись в памяь. обращение к функции
    }
  }
  //Экран №10
  if (punkt_menu == 10) {
    lcd.setCursor(3, 0); lcd.print("Read point 3?");
    //нижняя строка с координатами
    lcd.setCursor(7, 1);  lcd.print(read_Longitude_EEPROM_p3, 6);
    lcd.setCursor(0, 1);  lcd.print(read_Latitude_EEPROM_p3, 6); lcd.print("    ");
    lcd.setCursor(0, 1); lcd.print(rssi);
    lcd.setCursor(2, 1); lcd.print("    ");
    //----------------------------

    if (analogRead(1) > 1000 && analogRead(0) > 1000) {
      read_Latitude_EEPROM_p3 = EEPROM_double_read(40); //чтение из памяти. обращение к функции
      read_Longitude_EEPROM_p3 = EEPROM_double_read(50); //чтение из памяти. обращение к функции
      read_Latitude_EEPROM = read_Latitude_EEPROM_p3;// для расчетов пути применяется именно это значение
      read_Longitude_EEPROM = read_Longitude_EEPROM_p3;// для расчетов пути применяется именно это значение
    }
  }
  //Экран №11
  if (punkt_menu == 11) {
    //  lcd.setCursor(2, 1); lcd.print(" ");
    lcd.setCursor(3, 0); lcd.print("Save point 4?");
    //  lcd.setCursor(3, 1); lcd.print(telemetry[0]/1000); lcd.print(" "); lcd.print(telemetry[1]/1000);
    //нижняя строка с координатами
    lcd.setCursor(7, 1);  lcd.print(telemetry[1], 6);
    lcd.setCursor(0, 1);  lcd.print(telemetry[0], 6); lcd.print("    ");
    lcd.setCursor(0, 1); lcd.print(rssi);
    lcd.setCursor(2, 1); lcd.print("    ");
    //----------------------------
    if (analogRead(1) > 1000 && analogRead(0) > 1000) {
      EEPROM_double_write (60, telemetry[0]); //запись в память. обращение к функции
      EEPROM_double_write (70, telemetry[1]); //запись в памяь. обращение к функции
    }
  }
  //Экран №12
  if (punkt_menu == 12) {
    //  lcd.setCursor(2, 1); lcd.print(" ");
    lcd.setCursor(3, 0); lcd.print("Read point 4?");
    //  lcd.setCursor(3, 1); lcd.print(read_Latitude_EEPROM_p2/1000); lcd.print(" "); lcd.print(read_Longitude_EEPROM_p2/1000);
    //нижняя строка с координатами
    lcd.setCursor(7, 1);  lcd.print(read_Longitude_EEPROM_p4, 6);
    lcd.setCursor(0, 1);  lcd.print(read_Latitude_EEPROM_p4, 6); lcd.print("    ");
    lcd.setCursor(0, 1); lcd.print(rssi);
    lcd.setCursor(2, 1); lcd.print("    ");
    //----------------------------
    if (analogRead(1) > 1000 && analogRead(0) > 1000) {
      read_Latitude_EEPROM_p4 = EEPROM_double_read(60); //чтение из памяти. обращение к функции
      read_Longitude_EEPROM_p4 = EEPROM_double_read(70); //чтение из памяти. обращение к функции
      read_Latitude_EEPROM = read_Latitude_EEPROM_p4;// для расчетов пути применяется именно это значение
      read_Longitude_EEPROM = read_Longitude_EEPROM_p4;// для расчетов пути применяется именно это значение
    }
  }

  delay (100);
  //****************************

  //    Serial.print(in_ch1); Serial.print("    "); Serial.print(in_ch2); Serial.print("    l_"); Serial.print(in_ch2_l); Serial.print("    r_"); Serial.print(in_ch2_r);
  //    Serial.print("        M_l_"); Serial.print(motor_l); Serial.print("    M_r_"); Serial.print(motor_r);
  //    Serial.print("          "); Serial.print(analogRead(pin_potent1)); Serial.print("   "); Serial.println(analogRead(pin_potent2));
  //    Serial.print("          "); Serial.print(telemetry[0]); Serial.print("   "); Serial.print(telemetry[1]); Serial.print("   "); Serial.println(rssi);

} //КОНЕЦ LOOP ***********************


// Функция записи в EEPROM
void EEPROM_double_write(int addr, double num) {
  byte raw[4];
  (double&)raw = num;
  for (byte i = 0; i < 4; i++) EEPROM.write(addr + i, raw[i]);
}
//*************************

// Функция чтения из EEPROM
double EEPROM_double_read(int addr) {
  byte raw[4];
  for (byte i = 0; i < 4; i++) raw[i] = EEPROM.read(addr + i);
  double &num = (double&)raw;
  return num;
}
//**************************

 

  if (analogRead(1) > 1000 && analogRead(0) < 1000)
  {
    punkt_menu = punkt_menu + 1;
    if (punkt_menu >= 13)
    {
      punkt_menu = 1;
    }
  }
 
как в коде ниже... управление через IBus...
 
#include "SoftIBus.h"//SoftIBus library
SoftwareSerial IBuspin(2, 3);//"serial" port on which we will be running the IBus connection. Since to read values we only need the Rx, just connect pin 2 and leave 3 open

byte menu = 0;//puncul de pornire

void setup()
{
  IBuspin.begin(115200);//the softserial port has to begin at this baud prior to starting it as the IBus port
  Serial.begin(115200);//hardserial for debigging
  IBus.begin(IBuspin);//start the IBus object
}

void loop()
{
  IBus.loop();

  //Serial.println(IBus.readChannel(3));//=Stick St orizontal
  //Serial.println(IBus.readChannel(4));//=SwA
  if (IBus.readChannel(4) == 2000)
  {
    menu = menu + 1;
    if (menu >= 4)
    {
      menu = 1;
    }
  }
  //====================================================================================
  if (menu == 1)
  {
    Serial.println(" 1 ");
  }
  if (menu == 2)
  {
    Serial.println(" 2 ");
  }
  if (menu == 3)
  {
    Serial.println(" 3 ");
  }
  if (menu == 4)
  {
    Serial.println(" 4 ");
  }
}//end loop

 

 

 

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

так в чём проблема?

Atamanu
Offline
Зарегистрирован: 07.12.2021
Спасибо за ответ.
Хочу в коде IBus иметь возможность менять меню с флешки, а не с кнопки, но не получается.
Когда я нажимаю стик на 2000, он очень быстро проходит все меню, я могу остановиться только на одном из них с большим трудом...
ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

вставлять delay() не пробовали?

Atamanu
Offline
Зарегистрирован: 07.12.2021
Да, я пытался, я до сих пор с трудом могу остановиться там, где хочу.
В исходном коде также есть задержка (я думаю), после нажатия кнопки.....если (analogRead(1) > 1000 ..(1000= 1 сек), я так думаю,
но здесь я не знал, как это реализовать.
ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

в 16 строке поставить delay(250); к примеру, если заработает можно перевести на millis() чтобы цикл не тормозить

Atamanu
Offline
Зарегистрирован: 07.12.2021
Только там не пробовал, поставил 500 и работает лучше чем с 250.
Задержка может усложнить код, я сделаю это с помощью millis().
Спасибо за вашу помощь и время.
ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Atamanu пишет:

Только там не пробовал, поставил 500 и работает лучше чем с 250.
Задержка может усложнить код, я сделаю это с помощью millis().
Спасибо за вашу помощь и время.

на миллис вообще на остальной код не повлияет, я рад, что смог вам помочь! удачи!!!

Atamanu
Offline
Зарегистрирован: 07.12.2021
Завершение...
Вы помогли мне во второй раз... Удачи....
Atamanu
Offline
Зарегистрирован: 07.12.2021
Добрый вечер.
Я изменил код, как показано ниже, и это удовлетворительно, но иногда я нажимаю больше, и он переходит в следующее меню.
Я не хочу увеличивать Mills(), и мне интересно, как изменить код, чтобы он менял меню только при повторном нажатии.
Спасибо.

#include "SoftIBus.h"            
SoftwareSerial IBuspin(2, 3);   // "serial" port on which we will be running the IBus connection.

#include <iBUSTelemetry.h>
iBUSTelemetry telemetry(12); // I use only PCINT0 interrupt vector, so you can use D8 to D13 pins.
#define UPDATE_INTERVAL 500
uint32_t prevMillis = 0; // Necessary to updateValues() method. Look below.
float i = 0;

void updateValues()
{
  uint32_t currMillis = millis();
  if (currMillis - prevMillis >= UPDATE_INTERVAL)
    // Code in the middle of these brackets will be performed every 500ms.
  {
    prevMillis = currMillis;
  }
}
byte menu = 0; 
unsigned long previousMillis = 0;
const long interval = 500;

void setup()
{
  IBuspin.begin(115200);//the softserial port has to begin at this baud prior to starting it as the IBus port
  Serial.begin(115200);//hardserial for debigging
  IBus.begin(IBuspin);//start the IBus object

}

void loop()
{
  updateValues();
  telemetry.run();
  IBus.loop();//

  //Serial.println(IBus.readChannel(3));// test

  //=================================================================================
 
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval)
  {
  if (IBus.readChannel(3) < 1100)
  {
    menu = menu + 1;
    if (menu >= 5)
    {
      menu = 1;
    }
  }
  previousMillis = currentMillis;
  }
  //==========================================================

  if (menu == 1)  
  {
    Serial.println(" 0 ");
  }

  //1 -------------------------------------------------------- 

  if (menu == 2) 
  {
    Serial.println(" 1 ");
  }

  //2 -------------------------------------------------------- 
  if (menu == 3)
  {
    Serial.println(" 2 ");
  }

  //3 -------------------------------------------------------- 
  if (menu == 4)
  {
    Serial.println(" 3 ");
  }
}

 

 

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

Перейти на какую нибудь библиотеку для работы с кнопками понимающую onclick, и дальше переделать меню на CASE

Atamanu
Offline
Зарегистрирован: 07.12.2021
Спасибо за ответ.
Да, я знаю метод Кассе. Я использую пульт FS-I6 и у меня есть только сигнал IBus, я так понимаю, что в этом случае это невозможно!? У меня нет онклика.
На данный момент я использую один из двух потенциометров для выбора меню, я хотел использовать стик.

 

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

в библиотеке это считаем за нажатие кнопки -  if (IBus.readChannel(3) < 1100)

Atamanu
Offline
Зарегистрирован: 07.12.2021
Я думал так же, но если я нажимаю и удерживаю, он не останавливается, он переходит из одного меню в другое, я бы хотел, чтобы он останавливался в одном меню, а когда я нажимаю снова, чтобы перейти к следующему...
Спасибо за ответ.
ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Atamanu пишет:

Я думал так же, но если я нажимаю и удерживаю, он не останавливается, он переходит из одного меню в другое, я бы хотел, чтобы он останавливался в одном меню, а когда я нажимаю снова, чтобы перейти к следующему...
Спасибо за ответ.

это on_push но всё равно есть ограничения на длительность удержания или самому писать обработчик, для этого режима попадать в цикл пока не сменится удержание, но как в таком случае читать IBUS - только внутри этого цикла

Atamanu
Offline
Зарегистрирован: 07.12.2021
Дело в том, что это возможно, я видел в видео, как выбрать из палки ... Я настаиваю на том, чтобы попытаться решить это.
Спасибо за терпеливость.
andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Atamanu пишет:

Дело в том, что это возможно, я видел в видео, как выбрать из палки ... Я настаиваю на том, чтобы попытаться решить это.
Спасибо за терпеливость.

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

Что такое IBus, я не знаю, но если Вы хотите, вместо кнопок использовать потенциометр, причем так, чтобы он не давал "автоповтор", это, естественно, сделать можно.

Но, возможно, я чего-то не понял, например, Вам нужно управление не от потенциометра, а от дистанционного пульта.

В общем, для того, чтобы решить задачу, нужно сначала описать ее в понятных терминах (IBus к таковым не относится).

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

andriano пишет:

Atamanu пишет:

Дело в том, что это возможно, я видел в видео, как выбрать из палки ... Я настаиваю на том, чтобы попытаться решить это.
Спасибо за терпеливость.

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

Что такое IBus, я не знаю, но если Вы хотите, вместо кнопок использовать потенциометр, причем так, чтобы он не давал "автоповтор", это, естественно, сделать можно.

Но, возможно, я чего-то не понял, например, Вам нужно управление не от потенциометра, а от дистанционного пульта.

В общем, для того, чтобы решить задачу, нужно сначала описать ее в понятных терминах (IBus к таковым не относится).

IBUS выдаёт значение от 1000 до 2000, в среднем положении стика 1500, и таки да там в основе своей потенциометр, ТС надо значение менее 1100 трактовать как нажатие и удержание кнопки

Atamanu
Offline
Зарегистрирован: 07.12.2021
Спасибо за ваше время.
Я учел полученные показания и нашел этот код.
int ledPin1 = 11;
int ledPin2 = 10;
int ledPin3 = 9;
int switchPin = 8;
int count = 0;
boolean lastButton;
boolean currentButton = false;
boolean ledOn = false;

void setup() {

  pinMode(switchPin, INPUT);
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  pinMode(ledPin3, OUTPUT);
  count = 0;
}
//debounce function to stabilise the button
boolean debounce(boolean last)
{
  boolean current = digitalRead(switchPin);
  if (last != current)
  {
    delay(5);
    current = digitalRead(switchPin);
  }
  return current;  
}
void loop() {
  lastButton = currentButton;
  currentButton = debounce(lastButton);
  if (lastButton == false && currentButton == true)
  {
    if (count == 0) 
    { 
      count++;
      digitalWrite(ledPin1, HIGH);
      digitalWrite(ledPin2, LOW);
      digitalWrite(ledPin3, LOW); 
    }

    else if (count == 1)
    { 
      count++;
      digitalWrite(ledPin1, LOW); 
      digitalWrite(ledPin2, HIGH);
      digitalWrite(ledPin3, LOW);
    }

    else if (count == 2)
    { 
      count = 0;
      digitalWrite(ledPin1, LOW);
      digitalWrite(ledPin2, LOW);
      digitalWrite(ledPin3, HIGH); 
    }
  } 
}
Я заменил после каждого count++ (digitalWrite) на
Серийный.println("0");
Серийный.println("1");
Серийный.println("2");
Пробовал, переключается нормально, но вижу, что каждое выражение в каждом выбранном аккаунте выполняется только один раз.
Я хотел бы, чтобы оператор выполнялся в цикле для каждой выбранной учетной записи, если это возможно (попытка с прошлой ночи и неудача).
 
Хороший день.

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Atamanu пишет:

Я думал так же, но если я нажимаю и удерживаю, он не останавливается, он переходит из одного меню в другое, я бы хотел, чтобы он останавливался в одном меню, а когда я нажимаю снова, чтобы перейти к следующему...
Спасибо за ответ.

Цитата:

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

 

Atamanu
Offline
Зарегистрирован: 07.12.2021
Первая часть решена, она останавливается каждый раз, когда я удерживаю ее.
Но каждый Serial.println() печатается только один раз, когда выбран count1, 2 или 3.
Мне нужно, чтобы он печатался непрерывно, пока счетчик не изменится, когда будет напечатан следующий Serial.println().
P75NF75
Offline
Зарегистрирован: 18.10.2022

Попробую сформулировать Ваши пожелания, хотя мне до сих пор до конца не понятно. Итак. Вы нажимаете на кнопку и держите ее нажатой. В это время с определенной частотой (допустим через секунду или две секунды, то есть так, чтобы Вы успели увидеть) начинают выполняться какие-то события - или загораются по очереди светодиоды или меняются экраны меню. Когда Вы видите, что произошло нужное событие Вы отпускаете кнопку и выполнение событий останавливается на нужном Вам месте. Так или нет? Если нет, то опишите Ваши требования подробно. 

Atamanu
Offline
Зарегистрирован: 07.12.2021
Я заменил после каждого count++ (digitalWrite) на
Серийный.println("0");
Серийный.println("1");
Серийный.println("2");
Пробовал, переключается нормально, но вижу, что каждое выражение в каждом выбранном аккаунте выполняется только один раз.
Я хотел бы, чтобы оператор выполнялся в цикле для каждой выбранной учетной записи, если это возможно (попытка с прошлой ночи и неудача).
 
Что я изменил и что я хочу сделать.
Спасибо за терпеливость.

 

Atamanu
Offline
Зарегистрирован: 07.12.2021
Теперь он работает нормально.
 
Я думаю, что это могло бы быть еще проще, но это все, что я мог сделать, и это прекрасно работает.
int ledPin1 = 11;
int ledPin2 = 10;
int ledPin3 = 9;
int switchPin = 8;
int count = 0;
boolean lastButton;
boolean currentButton = false;
boolean ledOn = false;

void setup() {

  pinMode(switchPin, INPUT);
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  pinMode(ledPin3, OUTPUT);
  count = 0;
}
//debounce function to stabilise the button
boolean debounce(boolean last)
{
  boolean current = digitalRead(switchPin);
  if (last != current)
  {
    delay(5);
    current = digitalRead(switchPin);
  }
  return current;
}
void loop() {
  lastButton = currentButton;
  currentButton = debounce(lastButton);
  if (lastButton == false && currentButton == true)
  {
    if (count == 0) {
      count++;
    }
    else if (count == 1) {
      count ++;
    }
    else if (count == 2) {
      count ++;
    }
  }
  //====================================================
  if (count == 0) {
    Serial.println(" 0 ");
  }
  if (count == 1) {
    Serial.println(" 1 ");
  }
  if (count == 2) {
    Serial.println(" 2 ");
  }
}

 

 
 
Mulțumesc celor care și-au făcut timp să mă ajute.
ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Atamanu пишет:

Теперь он работает нормально.
 
Я думаю, что это могло бы быть еще проще, но это все, что я мог сделать, и это прекрасно работает.
 
Mulțumesc celor care și-au făcut timp să mă ajute.

Mult noroc