Skocz do zawartości

Wprowadzanie kilku danych


Rayu85

Pomocna odpowiedź

Witam,

Z góry przepraszam jeśli temat już był ale nie mam koncepcji pod jakim hasłem szukać, a te które mi przyszły do głowy nie dały rezultatu.

Przerobiłem sobie kurs Arduino Poziom I i zabieram się za proste konstrukcje własne.

Mam pytanie w jaki sposób wprowadzać kila danych do programu.

Chodzi mi o taki przykład:

Mam silniczek i serwo.

I chciałbym za pomocą UART móc wpisać

"Serwo 140" - i serwo ustawia się na pozycję 140.

następnie wpisuję "Silniczek ON" i silniczek zaczyna pracować a ja mogę wydawać dalej polecenia serwu. (Wiem jak zrobić obydwie rzeczy w osobnych programach ale nie wiem jak to złączyć w jeden)

Niestety do tej pory jedynie dzialaliśmy na 1 wartości wprowadzanej z klawiatury.

W jaki sposób poprzez UART podać aby konkretna wartość została zmieniona na tą którą wpisze?

Do tej pory zawsze działało to na zasadzie "watość odczytana = to co andurio odebrało z klawiatury".

A mi chodzi o to że jak wpiszę "A 150" to wartość A będzie ustawiona na 150 a jak "B 100" to wartość b na 100 (oczywiście A zostaje na 150)

Mam nadzieję że ktoś zrozumie o co pytam bo mam problem z sformułowaniem pytania. Pewnie dlatego nie mogę wygooglować odpowiedzi na nie:P

Link do komentarza
Share on other sites

Musisz ustalić jakiś kilkuznakowy algorytm ( tak jak opisałeś ) i go obsługiwać. Dla prostoty ustal jakiś znak specjalny, który jest początkiem komendy i określoną ilość znaków dla każdej komendy.

Czyli np. 5 znaków, gdzie 1 to początek, 2 to typ rozkazu i 3/4/5 to liczba podawana w rozkazie.

Początek to znak specjalny np $, 2 to typ rozkazu np A to może być serwo 1 , a S to silnik gdzie 0..999 oznacza pozycje serwa / prędkość silnika.

Teraz musisz zrobić obsługę uarta. Przyjmijmy, że masz jakąś funkcję wywoływaną za każdym razem po odebraniu znaku z uarta, jej implementacja może wyglądać tak (kod w C):

void NowyZnak(char znak)
{
 static unsigned char iloscOdczytanych = 0;
 static unsigned char typ;
 static unsigned short wartość;

 if (iloscOdczytanych == 0)
 { // czy to poczatek nowej komendy?
   if (znak=='$') iloscOdczytanych=1; // odczytalismy znak poczatku
 }
 else if (iloscOdczytanych == 1)
 {
   if ((znak == 'A') || (znak == 'S')) 
   { // typ rozkazu rozpoznany
     typ = znak;
     iloscOdczytanych++;
   }
   else
   { 
     iloscOdczytanych = 0; // nierozpoznany rozkaz - ignoruj
   }
 }
 else if (iloscOdczytanych > 2)
 { // liczba
   if ((znak>='0') && (znak <='9'))
   { // poprawna cyfra
     znak -= '0'; // chcemy, żeby zmienna znak była od 0 do 9, a nie reprezentowała znaku z tabeli ascii
     if (iloscOdczytanych == 2) wartosc = ((int)znak) * 100;
     if (iloscOdczytanych == 3) wartosc += ((int)znak) * 10;
     if (iloscOdczytanych == 4)
     { // odczytalismy piaty, ostatni znak komendy - wykonaj komende
       wartosc += (int)znak;
       if (typ == 'A') serwo(wartosc);
       if (typ == 'S') silnik(wartosc);
       iloscOdczytanych = 0; // koniec tej komendy, czekaj na nastepna
     }
     else iloscOdczytanych ++; // to nie jest koniec komendy - czekaj na nastepny znak
   }
   else iloscOdczytanych = 0; // dostalismy znak inny niz cyfre
 }
 else iloscOdczytanych = 0; // blad - za duzo odczytanych znakow
}

a) Słowo kluczowe static w funkcji oznacza, że ta zmienna będzie zapamiętana, czyli przy każdym wywołaniu funkcji jak zmienisz wartość iloscOdczytanych to dostaniesz taką wartość z jaką wcześniej ta funkcja skończyła swoje działanie

czyli funkcja typu

int dodaj()

{

static int a = 0;

a++;

return a;

}

po każdym wywołaniu będzie zwracała liczbę o 1 większą ( 1,2,3,4,5.... )

b) Kody ascii dla znaku '0' to 48, a kolejne znaki cyfr mają kolejne wartości, czyli odejmując od znaku 48 mamy faktyczną liczbę 0..9. Tak naprawdę po uart najlepiej przesyłać liczbę zapisaną binarnie, bo wtedy nie potrzebujesz żadnej konwersji, ale dla człowieka to trudne do przeczytania, bo to nie jest tekst.

PS. Od strony czytelności dla profesjonalisty kod można napisać dużo lepiej - wykorzystać enumy, komendę switch itd. - ,ale chciałem, żeby kod był czytelny dla nowicjuszy.

PPS. Kodu nie sprawdzałem, więc może mieć jakiś błąd.

Link do komentarza
Share on other sites

myślę, że jest to to o co chodziło 🙂

Muszę na spokojnie usiąść i przeanalizować ten kod. Wstępnie go rozumiem choć jest kilka miejsc które w tej chwili budzą wątpliwość.

Jak przeanalizuję i zrobię pierwsze próby to odezwę się czy działą czy coś jednak trzeba wyjaśnić🙂

[ Dodano: 30-10-2016, 08:34 ]

Pojawiło mi się pierwsze dość istotne pytanie. Czy według twojego kodu wprowadzane dane są na zasadzie:

1. "$A140" - wszystko w jednym ciągu

2. "$

A

140" - w formie 3 komend (po karzdej enter)

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

W końcu mam wolny wieczór i zabrałem się za analizowanie kodu który mi podałeś, niestety bardzo szybko trafiłem na ścianę.

Postanowiłem rozbić funkcję na kila etapów i starać się zrozumieć ją po koleji.

Wydzieliłem etap 1:

- wprowadzenie danych

- rozpoznanie czy jest to komenda (Czy pojawia się nasz znak $)

- rozpoznanie czy komenda dotyczy serva czy silnika ("A" czy "S")

- wypisanie tych wartości.

Czyli w praktyce po wpisaniu w lini komend $A lub $S chciałbym aby andurio potwierdziło mi odebranie komendy wypisując: w pierwszej linijce to co ja wpisałem (np. "$A) a w 2 giej wartość odebranych danych (czyli na tym etapie cyfrę 2), (1 za pojawienie się znaku $ + 1 za pojawienie się 'A' lub 'S')

niestety ścianą okazło się już samo wprowadzenie danych.

My wprowadzamy komendę jako String. Natomiast nasza funkcja pracuje na char.

i niestety nie mogę sobie poradzić z przekształceniem wprowadzonych danych z String do char.

Jak rozumiem wywołując funkcję w nawiasach podaję to zmienną generowaną poprzez odczytanie wprowadzonego tekstu.

Załączam mój kod:

String odebraneDane; // odebrane dane z klawiatury
char odebraneDaneChar; // ofebrane dane w formacie char któy podamy do funkcji

 static unsigned char iloscOdczytanych = 0; // zmienne wyciągnąłem przed funkcję aby móc printować je, docelowo wrócą od funkcji
 static unsigned char typ; // zmienne wyciągnąłem przed funkcję aby móc printować je, docelowo wrócą od funkcji
 static unsigned short wartosc; // zmienne wyciągnąłem przed funkcję aby móc printować je, docelowo wrócą od funkcji


void setup() {
Serial.begin(9600);

}

void loop() 
{
if(Serial.available() > 0) 
   { //Czy Arduino odebrano dane
   odebraneDane = Serial.readStringUntil('\n'); // wprowadzamy tekst
   odebraneDane = char(odebraneDane); // próbujemy przekonwertować wprowadzony text ze string na char

   NowyZnak(odebraneDaneChar); // uruchomienie funkcji
   Serial.print("odebraneDane: "); 
   Serial.println(odebraneDane);// podanie danych kontrolnych
   Serial.print("iloscOdczytanych: ");
   Serial.println(iloscOdczytanych);// podanie danych kontrolnych

   }
}

void NowyZnak(char znak)
{

 if (iloscOdczytanych == 0)
 {
    if (znak=='$') iloscOdczytanych=1; // odczytanie znaku wywoławczego
 }
     else if (iloscOdczytanych == 1)
    {
     if ((znak == 'A') || (znak == 'S'))
     { // typ znaku rozpoznany
          typ = znak;
     iloscOdczytanych++;
     }
     else
      {
       iloscOdczytanych = 0; // nierozpoznany znak - ignoruj
      }
}
}
Link do komentarza
Share on other sites

Skoro masz takie piękne narzędzia jak readStringUntil to po co chcesz to zmieniać ponownie na znaki?

Napisz coś w stylu


void NowyZnak(String in)
{
 if (in.length()!=5) return; // zła długość komendy, ignorujemy ( dostosuj - nie wiem czy ten string liczy ze znakiem końca linii - EOL - czy bez
 if (in.charAt(0)!='$') return; // błędny znak początka komendy, ignorujemy

 ... tutaj kod odczytujący liczbę ze znaków 2,3,4 i składający ją w jedną wartość - napisz sam


 // sprawdz typ komendy i wywołaj odpowiednią funkcję
 if (in.charAt(1) == 'A')
 { //obsługa serwa
    pozycjaSerwa(odczytanaWartosc);
 }
 else if (in.charAt(1) == 'S')
 { // obsługa silnika
   predkoscSIlnika(odczytanaWartosc);
 }
 else
 { // komenda nie została rozpoznana - można dodać ew. obsługę błędu itp.
 }
}

Jak widać implementacja dużo prostsza, bo mamy za jednym zamachem całą linijkę...

Link do komentarza
Share on other sites

Teraz już się kładę ale jutro przeanalizuję co mi napisałeś🙂

Czekając na odpowiedz napisałem swoją wersję tego programu:) I działa 🙂 Może nie jest taka zaawansowana jak twoja ale swoją funkcję też spełnia:) nie jest to skończona wersja kodu:) mam kilka pomysłów na ulepszenie ale pomału padam:P

wklejam kod:)

String static komenda = "start";
int static silnikInt = 0;
int static servoInt = 0;

int czaswprowadzenia = 500;


void setup() {
Serial.begin(9600);
Serial.println("witaj, dostepne komendy: \n silnik \n servo \n pozycje");


}

void loop() {
 if(Serial.available() > 0) { //Czy Arduino odebrano dane
   komenda = Serial.readStringUntil('\n'); 


   if (komenda != "start") { // warunek dla zatrzymania pętli

     if (komenda == "silnik") { // wywołanie silnika
        String silnik;
          Serial.println("Wybrano Silnik");
          Serial.println("Podaj wartosc silnika!");
          delay(czaswprowadzenia);
          Serial.available() >0; // wprowadzenie watosci silnika
          silnik = Serial.readStringUntil('\n'); 
          silnikInt = silnik.toInt();
          Serial.print("Wartosc silnika: ");
          Serial.println(silnikInt);
          Serial.println();

        }
   }
     if (komenda == "servo") { // wywolanie serwa
        String servo;
          Serial.println("Wybrano Servo");
          Serial.println("Podaj pozycje serva!");
          delay(czaswprowadzenia);
          Serial.available() >0; // wprowadzenie wartosci serwa
          servo = Serial.readStringUntil('\n');
          servoInt = servo.toInt(); 
             if (servoInt <=180 && servoInt >= 0) {
               Serial.print("Pozycja serwa: ");
               Serial.println(servoInt);
               Serial.println();}
             else
               Serial.println("Pozycja poza zakresem!");
               }

      if (komenda == "pozycje") { // wywolanie pogladu aktualnych ustawien
          Serial.print("Wartosc silnika: ");
          Serial.println(silnikInt);
          Serial.print("Pozycja serwa: ");
          Serial.println(servoInt);
          Serial.println();}
      }
   }

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.