Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[C] Funkcja porównująca ciagi

xantros 18 Kwi 2010 21:04 1995 22
  • #1 18 Kwi 2010 21:04
    xantros
    Poziom 10  

    Witam. Mam problem z funkcją, której zadaniem jest porównanie "ciągu" danych przesłanego przez RS232 z ciągiem zadanym (w domyśle ma to być przesyłanie i rozpoznawanie komend). Mam funkcję takiej postaci:

    Code:
    int sprawdz_komende(unsigned char text[])
    
    {
       for(i=0; i<sizeof(text); i++)
       {
          if( !(odebrane[i]==text[i]))  return 0;
       }
       return 1;
    }


    I chcę to wykorzystać w taki sposób:
    Code:
    if(sprawdz_komende("komenda"))
    
    {
        (...)
    }


    Przy kompilacji w miejscu gdzie wykorzystuję funkcję dostaję błąd: "implicit declaration of function". Po odpaleniu programu w symulatorze wygląda na to, że program nawet nei wchodzi do pętli FOR w mojej funkcji. Jakieś sugestie co do tego, co robię źle??

    PS. Bazując na czyimś kodzie stworzyłem też takiego potworka (który oczywiście nie działał..):
    Code:
    int sprawdz_komende(unsigned char *text)
    
    {
       uint8_t i;

       i=0;
       while(*text)
       {
          if(odebrane[i] == *text)
          {
             i++;
             *text++;
          } else return 0;
       }
       return 1;
    }

    0 22
  • #2 18 Kwi 2010 21:10
    Zumo
    Poziom 21  

    Czy jest zadeklarowany prototyp funkcji?

    Code:
    int sprawdz_komende(unsigned char text[]);

    0
  • #3 18 Kwi 2010 21:13
    tadzik85
    Poziom 38  

    A dlaczego nie działał?

    Dodano po 1 [minuty]:

    Nie pytaj o poprawna deklarację bo nie przekazuje się parametru funkcji jako tablicy.

    0
  • #4 18 Kwi 2010 21:15
    xantros
    Poziom 10  

    Nie jest. Ale czy to jest problem? Póki co udawało mi się żyć bez tego i programy działały ;)

    tadzik85 napisał:
    Nie pytaj o poprawna deklarację bo nie przekazuje się parametru funkcji jako tablicy.

    Na wszelki wypadek na końcu pierwszego posta zamieściłem też wersję na wskaźnikach, która może jest bardziej poprawna... Jak w takim razie ją zmienić?

    0
  • #5 18 Kwi 2010 21:22
    tadzik85
    Poziom 38  

    Spróbuj najpierw zrobić coś takiego

    Code:

    unsigned char zmienna[] = "komenda";

    if(sprawdz_komende(&zmienna[0]);
    {
       //wykonaj
    }

    0
  • #6 18 Kwi 2010 21:26
    BoskiDialer
    Poziom 34  

    Komunikat "implicit declaration of function" oznacza, że funkcję masz zadeklarowaną w kodzie niżej niż miejsce, w którym używasz tej funkcji. Musisz dodać przed funkcją wywołującą prototyp funkcji wywoływanej.

    W samej funkcji sprawdz_komende jest kilka błędów:
    - zmienna używana przez pętlę zdecydowanie powinna być zmienną lokalną.
    - sizeof zwraca rozmiar zmiennej, w tym przypadku będzie to wartość równa 2 jako że text jest wskaźnikiem.
    - funkcja po poprawieniu nie rozróżni przypadku, gdy ciąg text jest prefiksem ciągu odebrane. W takim przypadku należało by zbadać jeden znak więcej (porównanie znaku końca ciągu: znak o kodzie 0) albo porównać długości (lepiej sprawdzić znak 0).
    - po zamienieniu sizeof na strlen trzeba by przesunąć to wywołanie przed pętlę, aby nie spowodować, aby funkcja miała złożoność O(n^2) [funkcja strlen była by wywoływana przed każdym przebiegiem].

    Najlepiej użyć funkcji strcmp, opcjonalnie można napisać:

    Code:
    int sprawdz_komende(unsigned char* text)
    
    {
      unsigned char* odb = (unsigned char*)odebrane;
      while(1)
      {
        unsigned char c = *test++;
        if(c != *odb++)
          return 0;
        if(c == 0)
          return 1;
      }
    }


    tadzik85: Niepotrzebnie pobieranie adresu pierwszej komórki: przez nazwę tablicy rozumie się wskaźnik na pierwszy element, więc wystarczy sprawdz_komende(zmienna). niedomknięty nawias ujdzie, średnik na końcu linii z if'em już nie.

    0
  • #7 18 Kwi 2010 21:48
    xantros
    Poziom 10  

    @BoskiDialer

    Miałeś racje z deklaracją funkcji w późniejszej części kodu niż jej użycie. Głupi błąd..
    Niestety, ta wersja podana przez Ciebei też nie działa. Dziwne jest to, że w symulatorze program wchodzi do tych funkcji (tzn i moich i Twojej) i co bym nie wpisał jako komende to wchodzi do IFa, natomiast w mojej atmedze warunek IFa tak czy tak nie jest spełniany... Załamka. Teoretycznie taka prosta rzecz a sprawia tyle problemów..

    0
  • #8 18 Kwi 2010 22:00
    BoskiDialer
    Poziom 34  

    Sprawdziłem moją funkcję u siebie, poza błędem w nazwie zmiennej (w argumencie jest text, do c jest wczytywane po wskaźniku test) wszystko działa tak jak powinno. Jeśli jest inaczej, musisz szukać błędu w innym miejscu - np czy nie deklarujesz tablicy odebrane raz jako globalną oraz drugi raz jako lokalną w funkcji wywołującej, albo czy nie pracujesz na granicy stosu (w co wątpię) lub cokolwiek innego.

    0
  • #9 18 Kwi 2010 22:04
    xantros
    Poziom 10  

    Tablicę "odebrane" mam zadeklarowaną jako globalną w tej postaci:

    Code:
    char odebrane[50];


    Jest deklarowana tylko raz.

    0
  • #10 18 Kwi 2010 22:45
    mirekk36
    Poziom 42  

    A próbowałeś kiedyś użyć wbudowanych i gotowych już funkcji do tego? np:

    strcmp()

    albo

    strncmp()

    poszukaj sobie coś o nich w opisie AVR GCC i ile tego kompilatora używasz bo nie wiem jak jest w innych.

    0
  • #11 18 Kwi 2010 23:05
    xantros
    Poziom 10  

    Code:
    int sprawdz_komende(char text[])
    
    {
       if(strcmp(text,odebrane)==0) return 1;
       else return 0;
    }


    Niestety na atmedze dalej nie działa :(
    PS. Tak, używam AVR GCC.

    0
  • #12 18 Kwi 2010 23:58
    tmf
    Moderator Mikrokontrolery Projektowanie

    A łańcuchy są zakończone nullem? Bo jeśli nie to strcmp nie zadziała poprawnie. W takiej sytuacji użyj strncmp, podając ile znaków ma łańcuch.

    0
  • #13 19 Kwi 2010 00:14
    xantros
    Poziom 10  

    Nie są kończone nullem. Po zmianie funkcji dalej jest jak było. Ale ciekawa rzecz - w przypadku zarówno ze strcmp jak i strncmp w symulatorze program działa już chyba jak powinien (dodatkowo do kontroli wrzuciłem zapalanie diod i przy okazji mogę obserwować zmiany na PORTx w symulatorze), a w układzie rzeczywistym ciągle uzyskuję "negatywny" wynik porównania..

    0
  • #14 19 Kwi 2010 08:42
    Freddie Chopin
    Specjalista - Mikrokontrolery

    tadzik85 napisał:
    Nie pytaj o poprawna deklarację bo nie przekazuje się parametru funkcji jako tablicy.

    Bzdura!

    4\/3!!

    0
  • #15 19 Kwi 2010 09:48
    tmf
    Moderator Mikrokontrolery Projektowanie

    Skoro porównanie wypada negatywnie to znaczy, że łańcuchy się różnią -> najpewniej podajesz ich nieprawidłową długość. Szukaj błędu w innym miejscu swojego kodu.

    0
  • #16 19 Kwi 2010 12:53
    xantros
    Poziom 10  

    Sam już nie wiem co można jeszcze zrobić. Funkcja porównująca ciągi była zmieniana chyba z 10 razy i ciągle nie działa. Dorzuciłem nawet zapisywanie 0 (czyli null) do tablicy odebrane, żeby korzystać z funkcji strcmp. Może zamieszczę większy kawałek kodu i ktoś dostrzeże błąd w kodzie i/lub moim rozumowaniu..

    Code:
    char odebrane[50];
    

    (...)

    int sprawdz_komende(char text[])
    {
       uint8_t dlugosc;

    //   dlugosc=strlen(text);
    //   if(strncmp(text,odebrane,dlugosc)==0) return 1;
       if(strcmp(text,odebrane)==0) return 1;
       else return 0;
    }

    ISR(USART_RXC_vect)
    {
       char ReceivedByte;

       ReceivedByte = UDR;

       if(ReceivedByte==0x0D)
       {
           odebrane[odeb_poz]=0;
           odeb_poz++;
           if(sprawdz_komende("kom"))
           {
               PORTC=0xAA;
               odeb_poz=0;
           } else
           {
               PORTC=0xFF;
               odeb_poz=0;
           }
       } else
       {
           odebrane[odeb_poz]=UDR;
           odeb_poz++;
       }
    }


    Zrobiłem nawet tak, że wywaliłem tą funkcję porównującą i dałem bezpośrednio w IFie zamiast:
    Code:
    if(sprawdz_komende("kom"))

    Code:
    if(strcmp("kom",odebrane)==0)


    Reszta kodu powinna być bez znaczenia bo jest tam tylko inicjalizacja UARTu i LCD.

    0
  • #17 19 Kwi 2010 13:08
    AVRowiec
    Poziom 18  

    użyj gotowca jak pisał mirekk36

    strcmp i strncmp albo jeszcze lepiej strcmp_P i strncmp_P z pgmspace.h - zaoszczędzisz trochę pamięci na stringi.

    0
  • #18 19 Kwi 2010 13:13
    xantros
    Poziom 10  

    @AVRowiec
    Zerknij do kodu, chociażby w ostatnim poście :) Zacząłem korzystać z tych gotowych funkcji, ale też z miernym rezultatem..

    EDIT:
    Sprawdziłem coś jeszcze. To działa:

    Code:
    if(strncmp("kom","kom",3)==0)


    a to po podmianie jednego "kom" na tablicę liter odebranych przez RSa już nie działa:
    Code:
    if(strncmp("kom",odebrane,3)==0)

    0
  • #19 19 Kwi 2010 14:14
    Dr.Vee
    VIP Zasłużony dla elektroda

    Czy odeb_poz jest zadeklarowane jako volatile?
    Może jakieś bzdury odbierasz w uarcie - zrób echo z powrotem do komputera.

    Pozdrawiam,
    Dr.Vee

    0
  • #20 19 Kwi 2010 14:17
    xantros
    Poziom 10  

    Ok, problem już został rozwiązany. Naprawdę głupie przeoczenie - po przejrzeniu jeszcze raz kodu uzmysłowiłem sobie, że napierw zawartość rejestru UDR jest zapisywana do zmiennej ReceivedByte, a dalej w obsłudze przerwania robiłem coś takiego:

    Code:
    odebrane[odeb_poz]=UDR; 


    Po tym jak przypomniałem sobie, że rejestr UDR po odczytaniu zawartości jest czyszczony wszystko stało się jasne... Wstyd jest, ale przynajmniej czegoś człowiek się nauczył. (Dlaczego nikt nie zwrócił na to uwagi?? :) )

    Pozdrawiam i dziękuję za wszelką pomoc.
    Temat do zamknięcia.

    0
  • #21 19 Kwi 2010 14:38
    tmf
    Moderator Mikrokontrolery Projektowanie
  • #22 19 Kwi 2010 14:42
    xantros
    Poziom 10  

    Później już był pokazany :) Można sprawdzić to o czym mówię zaglądając do części dotycącej obsługi przerwania. Oczywiście tylko się droczę, najwazniejsze że problem rozwiązany.

    0
  • #23 19 Kwi 2010 15:08
    Freddie Chopin
    Specjalista - Mikrokontrolery

    tmf napisał:
    Może dlatego, że nie pokazałeś tego fragmentu kodu?
    Jak to mowią - shit in - shit out.

    LOL, dobre, muszę to zapamiętać!

    4\/3!!

    0