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

[AVR GCC] funkcja memcmp nie działa poprawnie

11 Maj 2011 00:38 1977 14
  • Poziom 16  
    Witajcie !

    Zaznaczam że dopiero co zaczynam programować ale rzuciłem się na wielką wodę i jakoś trzeba to przepłynąć ;)

    Problem mam taki, że próbuję napisać funkcję wyszukującą/porównującą dwa 8 bajtowe ciągi (ROM układów DS18B20) z wykorzystaniem funkcji memcmp.

    W jednej tablicy dwuwymiarowej mam 10x8 bajtów (dla 10 czujników po 8 bajtów), zaś w drugiej jednowymiarowej tablicy mam 8 bajtów z jednego czujnika. Wymyśliłem że będę porównywał 8 bajtowe ciągi i jeśli memcmp zwróci 0 wtedy wykorzystam to do odnotowania numeru znalezionego wiersza w tej tablicy dwuwymiarowej.

    Ukleciłem taką funkcję:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    a wowołuję ją tak:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    i za każdym razem dostaję w wyniku 8 po wyświetleniu buforaLCD.
    Nie działa mi to poprawnie :) Nakierowała by mnie jakaś dobra dusza cóż robię źle ? Albo jak to inaczej zrobić poprawnie

    PS. w funkcji jest 7 w pętli for ale to tymczasowe, zmienione podczas prób...
  • Poziom 38  
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Wystarczy?
  • Poziom 16  
    myślałem że wystarczy, ale jednak nie działa...

    po każdym przebiegu pętli wskaźnik miałby pokazywać na kolejny wiersz... gdzieś popełniam błąd, tylko nie wiem gdzie :|

    próbowałem jeszcze teraz coś takiego:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    i tak samo nie działa...
  • Specjalista - Mikrokontrolery
    NIe ma to prawa działać, zastanów się jak działa
    &dest[i] gdzie i = (0 ... 7)

    Dodano po 3 [minuty]:






    podpowiedź: &dest[i * 8]
  • Poziom 42  
    michalko12 napisał:

    podpowiedź: &dest[i * 8]


    Czy na pewno ? przecież przekazywana jest tablica dwuwymiarowa,

    więc chyba powinno być tak:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    ??
  • Poziom 16  
    Kod: c
    Zaloguj się, aby zobaczyć kod
  • Moderator Mikrokontrolery Projektowanie
    Niestety nie, przekazywany jest wskaźnik o typie void, a następnie robisz &dest[i] - czyli jest to typowa tablica jednowymiarowa. Trzeba zrobić i*8, albo zrzutować dest na tablicę dwuwymiarową i potem się odwoływać &dest[i][0]. Swoją drogą operacja void *ptr[i] jest nieokreślona, bo nie ma sizeof(void) - to jest tylko rozszerzenie gcc, zakładające, że *void to jeden bajt, lepiej więc zrobić wskaźnik o typie uint8_t.
    BTW, po co porównywać i przechowywać 8 bajtów ROMCodde, skoro ostatni to CRC wyliczone z 7 poprzednich. Jeśli są one takie same to CRC też musi się zgadzać.
  • Poziom 32  
    tmf napisał:
    BTW, po co porównywać i przechowywać 8 bajtów ROMCodde, skoro ostatni to CRC wyliczone z 7 poprzednich. Jeśli są one takie same to CRC też musi się zgadzać.
    czy na pewno ? W końcu CRC 8-bitowe ma tylko 256 stanów a sum kontrolnych dla 7 bajtów na pewno jest więcej, czyli muszą się powtarzać.
  • Poziom 28  
    GienekS napisał:

    W końcu CRC 8-bitowe ma tylko 256 stanów a sum kontrolnych dla 7 bajtów na pewno jest więcej, czyli muszą się powtarzać.

    Zapewne jest kilka (może nawet kilkaset) takich kombinacji wartości siedmiu bajtów, przy których otrzymujemy taką samą sumę kontrolną, za to konkretna kombinacja wartości ma zawsze taką samą sumę kontrolną. Jak porównasz, czy wszystkie 7 bajtów dwóch tablic mają takie same wartości, to suma kontrolna na pewno będzie taka sama.
    Moim zdaniem koledze tmf nie chodziło o sprawdzanie tylko samego CRC, a o pominięcie sprawdzania ostatniego bajtu, którym jest CRC. To zaoszczędzi nieco pamięci i przyspieszy nieco działanie programu. Mam wrażenie, że źle go zrozumiałeś.
    tmf napisał:

    BTW, po co porównywać i przechowywać 8 bajtów ROMCodde, skoro ostatni to CRC wyliczone z 7 poprzednich. Jeśli są one takie same to CRC też musi się zgadzać.
  • Moderator Mikrokontrolery Projektowanie
    Rzeczywiście ten skrót można interpretować różnie. Oczywiście chodzi o to, że jeśli poprzedzające 7 bajtów jest takich samych to i CRC musi być takie samo, więc nie ma sensu go przechowywać. Tak naprawdę nie ma sensu sprawdzać i przechowywać także pierwszego bajtu, który stanowi tzw. FamiliCode, który dla danej rodziny urządzeń OW jest taki sam. Oczywiście jeśli na magistrali są różne urządzenia, należące do różnych rodzin, to jest on potrzebny.
  • Poziom 16  
    Kod: c
    Zaloguj się, aby zobaczyć kod


    tak próbowałem i taż nie zadziałało... wewnątrz wywoływanej funkcji tablica zdaje się powinna być widziana jako dwuwymiarowa i automatycznie mielibyśmy przeskakiwać o 8 bajtów przy każdej iteracji pętli for, jednak tak się nie dzieje ;(

    Próbowałem w inny sposób, który wymieniany też był wcześniej i tak samo nic, nadal otrzymuję 6 w wyniku działania funkcji...

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Warunek sprawdzający czy w wyniku funkcji memcmp otrzymuję zero chyba jest poprawny ? Dobrze myślę ? Bo już zgłupiałem a wtedy człowiek masakryczne błędy robi :)


    Próbuję dalej... może w końcu coś zadziała...
  • Moderator Mikrokontrolery Projektowanie
    A to co: &src? Pobierasz adres wskaźnika i przekazujesz go do memcpy. &src, gdzie src jest uint8_t* to uint8_t**, czyli wskaźnik na wskaźnik, a nie o to ci chodzi, prawda?
    BTW, tablice są domyślnie przekazywane przez wskazanie, więc &tablica nie ma sensu, powinno być po prostu tablica, lub &tablica[indeks].
  • Poziom 16  
    Dziękuję Ci kolego tmf !!!
    zadziałało... jednak wychodzi brak praktyki obycia i przede wszystkim wiedzy... dzisiejszy wieczór przeznaczony już został na jeszcze lepsze przyswojenie sobie wiedzy o wskaźnikach i ich użyciu jako argument funkcji ;)

    Kod: c
    Zaloguj się, aby zobaczyć kod



    Jeszcze mam pytanie odnośnie ewentualnego rzutowania wskażnika *dest na tablicę dwuwymiarową abym mógł np. się odwołać w tej funkcji do tablicy z danymi w ten sposob:

    &dest[i][0]

    Podpatrując inne przykłady stworzyłem coś takiego:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    funkcja działa poprawnie, przynajmniej tak to wynika z testów.
    (BTW czy tak to się powinno zrobić czy może jakiś bardziej elegancki/praktyczny sposób na to jest ?)

    Otrzymuję jednak takie ostrzeżenie:

    warning: initialization from incompatible pointer type

    Pewnie coś trzeba by dodatkowo rzutować aby pozbyć się warninga, tylko co ?
  • Poziom 16  
    Posiłkując się książką Kerningham, Ritchie "Język ANSI C" udało sie stworzyć funkcję "prawie idealną" ;)
    Kod wstawiam dla potomnych...

    Kod: c
    Zaloguj się, aby zobaczyć kod


    funkcja zwraca 0 jeśli nie znajdzie ROM code lub liczbę z numerem wiersza numerując je od 1.

    Tak zaś powinno wyglądać w pełni prawidłowe jej wywołanie (kompilator nie wyświetli wtedy żadnego ostrzeżenia o nieprawidłowym typie danych):
    Kod: c
    Zaloguj się, aby zobaczyć kod



    W międzyczasie podczas lektury książki okazało się, iż można także zastosować do moich potrzeb tablicę wskaźników zamiast tablicy dwuwymiarowej (zdaje się może to wpłynąć na ew. zwiększenie wydajności otrzymanego kodu). To jednak zostawiam sobie na czas późniejszy ;)
    BTW Czy ktoś ma jakieś doświadczenia w kwestii takiej różnicy i ewentualnej wydajności ;)

    W każdym bądź razie nie wdając się za bardzo w szczegóły wtedy definiować mógłbym tablice wskaźników w taki sposób:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    przesuwając tylko wskaźnik na kolejny wiersz/ROM.


    Jeśli mowa o wcześniej poruszanym problemie zapisywania i porównywania ROM code, to dodam ze swojej strony jeszcze że zapisywanie FamilyCode ma swoje uzasadnienie w przypadku używania różnych typów czujników temperatury na magistrali:

    Poniżej FamilyCode dla czujników które m.in. można zastosować do pomiaru temperatury:
    Code:

    DS18S20_FAMILY_CODE       0x10
    DS18B20_FAMILY_CODE       0x28
    DS1822_FAMILY_CODE        0x22


    Jak widać, aby to było kompatybilne i działało z różnymi czujnikami FamilyCode musi być zapisywany/porównywany.

    Co do kwesti CRC. Jego zapisywanie ma uzasadnienie w przypadku wygodnego wyświetlania/obróbki pełnego 64bitowego adresu czujnika. Faktycznie nie jest konieczne porównywanie pełnych 8 bajtów ROMcode a jedynie jego pierwsze 7bajtów bo CRC powinen zawsze być taki sam.

    Aby nie porównywać CRC przy wyszukiwaniu ROM'a w tablicy wystarczy tylko odjąć ten jeden bajt podczas wywołania funkcji:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    w ten sposób nieznacznie przyspieszymy działanie urządzenia, ilość generowanego kodu przez kompilator się nie zmienia ;)
  • Moderator Mikrokontrolery Projektowanie
    To małe podpowiedzi - użyj typedef, żeby nie tworzyć takich typecastowych potworków :) I druga - pamiętaj, że tablica wskaźników to tylko tablica wskaźników. Zasadniczo implikuje to użycie dynamicznej alokacji pamięci, albo przypasanie wskaźnikom wyłącznie adresów zmiennych globalnych, nigdy nie lokalnych. Ale K&R to dobry trop, tylko czytaj go od początku, a nie od środka :)