• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Serial. wyszukiwanie i zaciągnie danych
#1
Chciałbym wyciągać konkretne informacje z portu szeregowego. Taki podsłuch drukarki. Sypią się informacje co kilka minut. Około 10 stringów do 30 znaków ale nie jest to sztywna ilość. 
np: 
2.5.3:023461289474
2.6.2:2621
2.7.3:2654(*5335)
itp...

Chciałbym olać wszystko prócz kilku komunikatów. Zacznijmy może na jednym. Chce wyssać wartość po 2.6.2:

Kod:
String Str1;

void setup() {
  Serial.begin(9600);
}
void loop() {
  if (Serial.available() > 0) {
     Str1 = Serial.readString();
    if (Str1.startsWith("2.6.2:")) {
      Serial.println(Str1);
    }
  }
}

Jeżeli wypuszczę "2.6.2:2621" na port to otrzymam "2.6.2:2621". A jak wyświetlić wszystko poza "2.6.2:" Rozumiem że jak dam Str1[6] da mi "2" ale jak dać wszystko większe niż znak szósty ? Na pewno jest mądry sposób przecież nie będę wyświetlał Stringa z pętli for. Proszę o podpowiedź
 
Odpowiedź
#2
Do przechowywania zmiennych tekstowych w arduino służą tablice znaków i stringi. Tablice znaków możemy deklarować na różne sposoby. I jak najbardziej w tablicy właśnie użyłbyś for by pokazać wszystko od znaku 7 do końca tablicy zakończonej zawsze znakiem NULL, 0, '\0' czy tam NEW LINE. Są też funkcje do tablic tekstów jeśli nie znasz długości (wtedy oczywiście szukasz NULL na piechotę gdy nie korzystasz z funkcji), a np. części są rozdzielone znanym znakiem ','   ':'    ' '  itp. Te funkcje biorą sobie ten znak jako argument i po kolei porównują komórki tablicy. Jest to upierdliwe bo trzeba pamiętać o dodatkowej komórce na ten NULL i o liczeniu indexu od 0. Stringi jako tekst nie są tablicami i do nich nie należy odwoływać się w taki sposób Str1[6] bo ten zapis leci po kolejnych komórkach pamięci, niekoniecznie zmiennej, a stringi nie muszą być zapisywane w kolejnych. Pół biedy jak odczytasz dane nie będącą twoją zmienną, albo nawet nie będącą w obszarze pamięci Twojego programu (na PC). Najwyżej zobaczysz głupoty w swoim programie. Ale jak zapiszesz tam głupoty (z punktu widzenia innego programu, innych danych Twojego programu) to system dostanie KUKU. Można skrajnie zapisać coś w bity konfiguracyjne procka i go zabić. Powinieneś użyć funkcji do tego przeznaczonej, dla stringa charAt(). Nie mniej jednak akurat w Arduino AVR są to kolejne komórki pamięci, program wyszukuje obszar gdzie może zmieścić całego stringa i teoretycznie nawet w opisie klasy jest pokazane, że oba zapisy są równoważne. Nie nabierałbym jednak takiego nawyku i przejrzał funkcje przeznaczone do stringów - zaraz przejdziesz na PC by sobie dane zapisać do jakieś bazy, pokazać na stronie i zaczniesz się bawić JS, PHP, Java, C#.  Dla string Ciebie interesuje funkcja/metoda substring()
Kod:
Syntax
string.substring(from)

string.substring(from, to)
Parameters
string: a variable of type String

from: the index to start the substring at

to (optional): the index to end the substring before
czyli
nowystring=Str1.substring(6);
I pomimo że stringi są wygodne, ta dynamiczna rezerwacja pamięci jest częstą przyczyną, że coś źle działa, przepełnia się stos, coś jednak jest nadpisywane i procek dostaje na głowę. Jest 2048b ramu, a nie raz ktoś wpadnie na pomysł wczytania pliku tekstowego do ram. Twój wybór czy bezpieczniej jest korzystać ze starego C stringa, ze sztywno zarezerwowaną pamięcią i po prostu ciąć nadmiar danych niemieszczących się w tablicy narażając się na głupotki tutaj, czy stosować string i nie wiedzieć kiedy coś zacznie odwalać. I jak już tego gwoździa wbiłem do końca, to teraz można skorzystać z przykładu serialEvent przerobionego na C-string:
Kod:
#define buffsize 32
char input[buffsize];
uint32_t dane [1]; // jakie i ile  zmiennych odbieramy z UART
byte index = 0;
boolean stringComplete = false;  // gdy cale polecenie/napis odebrany


void   parsujpolecenia()
 {

   
    uint8_t index=0;
   char * polecenie=input;
   Serial.print("Otrzymane polecenie: ");
   Serial.println(polecenie);

   char* command1 = strtok(polecenie, ":");

if (strcmp(command1 , "2.6.2")==0){  //sprawdzenie czy czesc przed znakiem = jest rowna cmd
//tylko reszta napisu za :
command1 = strtok(NULL, ",");
 Serial.print("Zmienna 1 jako napis = ");
 Serial.println(command1);
 dane[index]=atol(command1); //atol() dla long, atoi() dla int lub atof() dla float
/* To jest do dluzszych danych oddzielonych np. jak tu ,
while (command1 != 0)
{
Serial.println(command1);
command1 = strtok(NULL, ","); //dzielimy reszte napisu w miejscach gdzie jest ","

// Find the next command in input string
if(index<4) dane[index]=atoi(command1); //konwersja napisu na INT i zapisanie do kolejnej pozycji w tablicy
index++;
} */
}
 else Serial.println("Polecenie nieprawidlowe");
 Serial.println("Aktualne parametry:");
 Serial.print("Zmienna 1 jako wartosc liczbowa = ");
 Serial.println(dane[0]);

 stringComplete = false;
 }


// Arduino initialization function.
void setup()
{
 Serial.begin(115200);
}


void loop()
{

if (stringComplete) parsujpolecenia();
// Teraz mozna cos zrobic ze zmiennymi
}
 


void serialEvent() {
 while (Serial.available()>0) {

char aChar = Serial.read();
    if(aChar == '\n')
    {
      // wykryto znak konca linii \n, koniec odbioru
      input[index] = 0;
      index = 0;
      stringComplete = true;
    }
    else
    {
       input[index] = aChar;
       if(index<buffsize) index++;
       input[index] = '\0'; // Na koncu napisu wstawiamy 0  
    }
 }
}
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#3
(29-03-2018, 00:43)Burakko napisał(a): Jeżeli wypuszczę "2.6.2:2621" na port to otrzymam "2.6.2:2621". A jak wyświetlić wszystko poza "2.6.2:" Rozumiem że jak dam Str1[6] da mi "2" ale jak dać wszystko większe niż znak szósty ? Na pewno jest mądry sposób przecież nie będę wyświetlał Stringa z pętli for. Proszę o podpowiedź

Konkretnie w tym przypadku, to możesz podzielić stringa w miejscu dwukropka funkcją getValue.

Na przykład tak:
Kod:
void loop() {
 if (Serial.available() > 0) {
    Str1 = Serial.readString();
    String Str2 = getValue(Str1, ':' , 1)
     Serial.println(Str2);
   }
Pierwszy argument funkcji getValue, określa stringa na którym będzie pracować.
Drugi argument, to znak separatora.
Ostatni argument to indeks, określa którą część podzielonego stringa ma zwrócić.
Jeśli 0, to część przed znakiem separatora, jeśli 1, to część za tym znakiem.
Jeśli masz problem z kodem lub sprzętem, zadaj pytanie na forum. Nie odpowiadam na PW, jeśli nie dotyczą one spraw forum lub innych tematów prywatnych.

[Obrazek: SsIndaG.jpg]
 
Odpowiedź
#4
Witam
Nawiązuję do posta z względu na funkcję "getValue"
Próbuję ją uruchomić w programie i cały czas pojawia się komunikat 

"exit status 1 'getValue' was not declared in this scope"



Program wygląda tak:

#include <SoftwareSerial.h>

SoftwareSerial mySerial(2, 3); //RX, TX

void setup() {
  Serial.begin(9600);
  mySerial.begin(9600);
  String getValue();
}

void loop()
{
  if(mySerial.available() > 1){
    String input = mySerial.readStringUntil('\n');
    String UpDown = getValue(input, ':', 0); //wycina ze zmiennej input to co przed dwukropkiem
    String RightLeft = getValue(input,':',1); //wycina z input to co za dwukropkiem
    Serial.println("Góra" + UpDown + "Boki" +RightLeft+);   
  }
  delay(20);
}



Program dopiero jest pisany, ma służyć do odbioru danych przesyłanych z pilota. W zmiennej "input" jest ciąg znaków składających się z 2 liczb. Jedna wskazuje na wychylenie manipulatora w płaszczyźnie góra/dół i lewo/prawo.

Póki co, nie jestem go w stanie skompilować.

Ma ktoś jakiś pomysł???
 
Odpowiedź
#5
Usuń z setup linię Strng getValue();
Jeśli masz problem z kodem lub sprzętem, zadaj pytanie na forum. Nie odpowiadam na PW, jeśli nie dotyczą one spraw forum lub innych tematów prywatnych.

[Obrazek: SsIndaG.jpg]
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości