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

[AVR][C] Tablice - kopiowanie całych tablic (przez wskaźnik?)

GanzConrad 19 Mar 2017 21:37 957 19
  • #1 19 Mar 2017 21:37
    GanzConrad
    Poziom 21  

    Witam,
    Robię coś w rodzaju konsoli na lcd nokii (6 linii po 14 znaków) i nie wiem jak najsprawniej dodać jedną linię tekstu na dole ekranu, jednocześnie przenosząc wyżej poprzednie linie i tracąc pierwszą.
    stworzyłem zmienną przechowującą zawartość ekranu:

    unsigned char LCD_Content [6][15]; // tablica 2 wymiarowa z całą zawartością ekranu 6 wierszy x 14 znaków + null na końcu

    oraz funkcję, która ma dodawać dolną linię.
    Problem niby banalny, ale czy da się to zrobić bez kopiowania znak po znaku w pętli, tylko podmieniać miejscami całe tablice? Z tego co pamiętam wskaźnik do tablicy to tak naprawdę wskaźnik na jej pierwszy element, a ja chciałbym podmienić całą tablicę w miejsce innej. Dokładnie zamienić miejscami tablice jednowymiarowe wewnątrz zmiennej dwuwymiarowej, a następnie na miejscu 6 wstawić tablicę jednowymiarową.
    poniższy kod jest błędny, ale obrazuje o co mi chodzi.

    Kod: c
    Zaloguj się, aby zobaczyć kod


    da się wskaźnikami, czy może jakieś memcopy?

    Dodano po 15 [minuty]:

    znalazłem coś takiego:
    http://www.nongnu.org/avr-libc/user-manual/gr...tring.html#ga5f60008005ea7557430149926cf583d7
    działa, chyba że ktoś ma lepszy pomysł

    Kod: c
    Zaloguj się, aby zobaczyć kod

  • Pomocny post
    #2 19 Mar 2017 21:41
    tmf
    Moderator Mikrokontrolery Projektowanie

    @GanzConrad Prościej nic nie kopiować, a tylko wprowadzić wskaźnik na pierwszą wyświetlaną linię i zadbać o jego zawijanie po dojściu do końca tablicy. W takim układzie przesunięcie o jeden wiersz to tylko zmiana tego wskaźnika.

  • #3 19 Mar 2017 21:58
    GanzConrad
    Poziom 21  

    @tmf zawartość wierszy nie ma być zawijana, jeśli będą dłuższe niż 14 znaków (szer LCD) to po prostu będą tracone.
    Całe to kombinowanie jest po to, aby w jednej zmiennej (tablica 2 wym) trzymać zawartość ekranu, przesunąć wszystko w górę (wierszami) i dodać do dolnej linii inną tablicę (1-wym) zawierającą komendy AT przychodzące z USART (będą różnej długości). Jak będą dłuższe od szer. lcd to będą skracane.
    Dlatego myślałem nad kopiowaniem całych wierszy poprzez wskaźnik do pierwszego elementu.

  • Pomocny post
    #4 19 Mar 2017 23:05
    BlueDraco
    Specjalista - Mikrokontrolery

    Przeczytaj jeszcze raz odpowiedź TMF i ją zrozum. To naprawdę dobra rada.

  • #5 20 Mar 2017 08:59
    GanzConrad
    Poziom 21  

    Czy chodzi o to, aby nową, przychodzącą linię tekstu wstawiać za każdym razem w inne miejsce tak aby zastępowała ostatnią znikającą, a wyświetlanie realizować podobnie, czyli za każdym razem od innego wiersza (na innej pozycji, np. od 3), a po dojściu do końca tablicy wyświetlić pominięte wiersze 1 i 2, które tym razem będą ostatnimi ?
    ekran to :
    unsigned char LCD_Content [6][15]
    - wyświetlam od góry, po kolei liniami 0-5, czyli linia 0 jest pierwszą od góry.
    - przychodzi nowa linia (powinna zastąpić ostatnią linię nr 5 w tablicy)
    - wstawiam ją na pozycję 0
    - wyświetlam ekran ponownie od góry, ale zaczynając od linii 1 (zamiast 0), a po dojściu do linii 5, wyświetlam 0
    nast krok:
    - przychodzi nowa linia
    - wstawiam ją na pozycję 1
    - wyświetlam od 2-5, a potem 0 i 1
    - itd...

  • Pomocny post
    #6 20 Mar 2017 10:31
    BlueDraco
    Specjalista - Mikrokontrolery

    Zapewne o to chodzi. Czy Twój wyświetlacz naprawdę ma tylko 15 znaków w wierszu?

  • #7 20 Mar 2017 10:40
    GanzConrad
    Poziom 21  

    BlueDraco napisał:
    tylko 15 znaków

    dokładnie 14, null dodaję na końcu tablicy (miały być operacje na stringach, ale może się ogarnę bez tego)
    to LCD od nokii 3310 na pcd8544
    chciałem "na szybko" zrobić konsolę do usart, bo nie mam drugiego usart do wyświetlania tego co biega po pierwszym, a przesiadanie się na xmega nie ma sensu...

  • Pomocny post
    #8 20 Mar 2017 10:54
    Sparrowhawk
    Poziom 21  

    @tmf: Moim zdaniem potrzebuje dwóch wskaźników. Jeden na wyświetlaną linię, a drugi na linię do modyfikacji. W sumie, to potrzeba jeszcze dwóch z informacją o pierwszym i ostatnim adresie, aby zawijać te wskaźniki.

    Mnie wyszło coś takiego:

    Kod: c
    Zaloguj się, aby zobaczyć kod

  • Pomocny post
    #9 20 Mar 2017 11:26
    BlueDraco
    Specjalista - Mikrokontrolery

    Nie rób zmiennych ze stałych - first i last są zbędne.

    Nie deklaruj tablic wewnątrz funkcji - spowalnia to wykonanie i grozi przepełnieniem stosu.
    Nie potrzebujest wskaźników na bufory 15- elementowe - przedeklaruj je jako wskaźniki na char.

  • Pomocny post
    #10 20 Mar 2017 12:49
    Sparrowhawk
    Poziom 21  

    Jeśli chcesz korzystać z więcej niż jednej takiej struktury zmienne first i last jako zmienne są potrzebne. Fakt, że taki bufor z dużym prawdopodobieństwem będzie jeden sprawia, że mogą to być stałe.

    Tablicę zadeklarowałem w main, bo jest to kod testowy, napisany na PC, ale w µc faktycznie będzie to raczej zmienna statyczna o zasięgu plikowym.

    Co do trzeciej uwagi, to nie rozumiem. Przecież operujemy na tablicy tablic typu char, a nie na tablicy stałych literałów znakowych.

  • #11 20 Mar 2017 13:51
    GanzConrad
    Poziom 21  

    wszystko ładnie, pięknie, ale czy mógłby mi ktoś pokazać palcem, gdzie jest to słowo "prościej", o którym wspomniał tmf? ;-)

  • #12 20 Mar 2017 14:44
    Sparrowhawk
    Poziom 21  

    Zapewne miał na myśli uproszczenie dokonywanych operacji. Zawsze to tylko zabawa z dwoma wskaźnikami, a nie kopiowanie tablic 2D.

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Kod: c
    Zaloguj się, aby zobaczyć kod

    Kod: c
    Zaloguj się, aby zobaczyć kod


    PS. Dlaczego, jak dam podgląd postu, to z kodu usuwane są wszystkie białe znaki?

  • Pomocny post
    #13 20 Mar 2017 14:48
    tmf
    Moderator Mikrokontrolery Projektowanie

    Jest prościej, tylko @Sparrowhawk niepotrzebnie komplikuje. Skoro zawsze dopisujesz na końcu nowy element, a tablica ma określoną liczbę elementów to początek i koniec można zidentyfikować jednoznacznie przy pomocy jednego wskaźnika. Drugi powód dla którego jest prościej wynika z uniknięcia wielokrotnego kopiowania danych, co jest czasochłonne. Sama tablica może się składać ze wskaźników na twoje łańcuchy, a tylko funkcja odpowiedzialna za ich przesłanie na LCD będzie brała po prostu pierwszych 14 znaków.

  • Pomocny post
    #14 20 Mar 2017 15:03
    Sparrowhawk
    Poziom 21  

    @tmf Masz rację, cały czas miałem to na końcu ..., ale mi to umykało ;-)

    Wersja z jednym wskaźnikiem:

    Kod: c
    Zaloguj się, aby zobaczyć kod

  • #15 07 Kwi 2017 14:33
    GanzConrad
    Poziom 21  

    Ostatni miałem mało czasu na sen, więc przepraszam za zwłokę.
    Dzięki Panowie za pomoc, zwłaszcza @Sparrowhawk za podanie wszystkiego "na tacy" (potrzebne jedynie drobne modyfikacje).
    Nie do końca rozumiem zwiększanie i zmniejszanie wskaźnika do kolejnych linii:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Czy chodzi o to, że SB_2DCHAR_PTR jest zdefiniowany jako wskaźnik do całej tablicy 1-wymiarowej (cała linia) i samo działanie ++(A) "przesuwa" wskaźnik o wartość całej tablicy? (w tym wypadku będzie się przesuwać wewnątrz tablicy 2 wymiarowej: char text[NUMBER_OF_LINES][LINE_SIZE] )

  • Pomocny post
    #16 07 Kwi 2017 14:47
    Piotrus_999
    Poziom 39  

    Proponuję abyś się nie uczył tego obrzydliwego stylu pisania gdzie funkcje, które powinny byc inline sa w postaci definicji. Nie bierz z tego przykładu. Jest to złe, niewłaściwe, ciężko debugowalne, bez kontroli typów itd itd. Tego się nawet na trzeźwo czytać nie da.

  • Pomocny post
    #17 07 Kwi 2017 14:53
    drobok
    Poziom 18  

    Wskaźnik wskazuje miejsce w pamięci, a co pod nim jest wie tylko ten co tam coś wpisał. Preinkrementując go przesuwasz go w następne miejsce następnej wartości zgodnie z typem jaki przyjmujesz. Więc będziesz miał np drugi element tablicy (o ile typy się zgadzają) (o ile przekroczysz granic w których się ona znajduje, dlatego masz tam te ify)

  • Pomocny post
    #18 07 Kwi 2017 14:59
    Piotrus_999
    Poziom 39  

    Zresztą kod @Sparrowhawk jest nie do końca prawidłowy (słaby). Spojrzałem na jedną funkcję SB_add i dalej już nie czytałem

    jak dodajesz linie to co się stanie jak długość dodawanego stringa bedzie równa lub większa niż długość linii. strncpy nie jest bezpieczne a kol @Sparrowhawk nie zabezpieczył kodu przed taką ewentualnością. Podejrzewam że takich kwiatków może być więcej.

  • #19 07 Kwi 2017 15:31
    GanzConrad
    Poziom 21  

    @Piotrus_999 strncpy kopiuje tylko konkretną liczbę znaków (nie więcej). Jeśli długość jest mniejsza to resztę wypełnia zerami (null):

    Cytat:

    The strncpy() function is similar to strcpy(), except that not more than n
    bytes of src are copied. Thus, if there is no null byte among the first n
    bytes of src, the result will not be null-terminated.

    In the case where the length of src is less than that of n, the remainder
    of dest will be padded with nulls.

  • #20 07 Kwi 2017 15:53
    Piotrus_999
    Poziom 39  

    A jak jest większa to nie dodaje końcowego zera i w tym jest problem.

    Naprawdę nie musisz mi cytować jak działają standardowe biblioteki a ciekawy fragnent jest tu:

    GanzConrad napisał:
    Thus, if there is no null byte among the first n
    bytes of src, the result will not be null-terminated.

    Nie wiesz nawet przyczyną jakiej ilości błedów w opragramowaniu była ta funkcja i pominięcie tej drobnej kwestii w pisaniu.