logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Atmega8 Bascom - Jak się pozbyć zmiennej typu single

Gronczyński 04 Gru 2013 01:55 2256 17
  • #1 13022820
    Gronczyński

    Poziom 19  
    Witam
    Mam taki oto problem:
    Chcę z kodu programu pozbyć się zmiennych typu single.
    Chodzi o możliwie szybkie wykonanie pętli, a zmienne typu single bardzo ją spowalniają.
    Tu zamieszczam fragment kodu obrazujący to co chcę uzyskać.
    W tym przykładzie w pętli jest wyświetlanie danych w każdym przejściu pętli for - next ale jest to zrobione tylko do celów symulacji. Normalnie "wynik" wysyłany jest jako zmienna ustawiająca counter1 timera.

    Zmienne X oraz Y są wielkościami, które przyjmują różne wartości ale w podanych zakresach.
    Zmienne wynikowe Z oraz Prc muszą pozostać typu word
    Wynik Z ma się zmieniać proporcjonalnie do wartości zmiennej Cykl


    Kod: text
    Zaloguj się, aby zobaczyć kod


    Proszę o pomoc czym zastąpić te zmienne Pomoc1, Pomoc2 oraz Pomoc3, tak aby wynik działania pozostawić bez zmian?
  • #2 13022842
    tomus2k
    Poziom 27  
    Najwięcej czasu procka zajmuje komenda LCD, więc reszta tu dużo nie przyśpieszy.

    pozdrawiam
  • #3 13022848
    Gronczyński

    Poziom 19  
    tomus2k napisał:
    Najwięcej czasu procka zajmuje komenda LCD


    Gronczyński napisał:
    W tym przykładzie w pętli jest wyświetlanie danych w każdym przejściu pętli for - next ale jest to zrobione tylko do celów symulacji. Normalnie "wynik" wysyłany jest jako zmienna ustawiająca counter1 timera.

    W docelowym programie te zmienne wynikowe nie są wyświetlane, służą do czego innego.
    W zamieszczonym kodzie obsługa LCD wstawiona jest tyko dla zobaczenia poprawności liczenia wyniku. Wiem, że komenda LCD jest czasochłonna i w docelowym kodzie jej tam nie ma. Chodzi mi o eliminację zmiennych typu single i jej podobnych czterobitowych liczb.
  • #4 13022975
    Fredy
    Poziom 27  
    Zwykle bardzo łatwo jest zastąpić operacje na liczbach zmiennoprzecinkowych, operacjami na liczbach całkowitych.
    U ciebie w kodzie masz taki kwiatek:

    Pomoc3 = Cykl / Y
    Prc = Pomoc3 * 100

    Czyli najpierw liczysz wartość która u ciebie jest ułamkiem, a póżniej praktycznie zamieniasz ją na liczbę całkowitą.
    A wystarczy zamienić kolejność i operować na liczbach całkowitych.
    Krótko mówiąc - sztucznie mnożysz liczbę przez 10, 100, 1000 itd, potem robisz operacje na liczbach całkowitych i otrzymujesz wynik któremu brakuje przecinka.
    Wyświetlenie przecinka w odpowiednim miejscu nie jest jednak wielkim problemem.
  • #5 13022998
    Gronczyński

    Poziom 19  
    Myślałem o tym tylko, że dla Y=1200 przekraczam dopuszczalną wartość dla (Y*100) 65535.
    Zmienną tą ostatecznie można zaniedbać, albo tak jak piszesz zrobić Y*10, wynik będzie mniej dokładny ale to w moim przypadku nie ma znaczenia.
    Jednakże nie bardzo widzę jak to zastosować do zmiennej Z - tu na taką niedokładność nie mogę sobie pozwolić.
  • #6 13024340
    Fredy
    Poziom 27  
    Nie ma większych zakresów aniżeli liczba 2bajtowa?
    Jeśli przekracza rozmiar 0xffff to dajesz longa i po kłopocie.
    Myślę że nie do końca rozumiesz o co chodzi w tym.
    Więc raz jeszcze: czym różnią się liczby 1.234 od 1234? Otóż tylko umiejscowieniem przecinka. Zamiast obliczać 1.234*2.345 mozna policzyć 1234*2345 a nastepnie wyświetlając wynik na LCD tylko zadbać, aby w odpowiednim miejscu wyświetlić przecinek. Czy to takie trudne?
  • #7 13024736
    Gronczyński

    Poziom 19  
    Wygląda jednak na trudniejsze niż się wydaje.
    Dla rozjaśnienia wyrzuciłem LCD bo nie o to tu chodzi żeby coś wyświetlać.
    Działająca poprawnie z punktu widzenia logiki i matematyki pętla.
    Kod: text
    Zaloguj się, aby zobaczyć kod

    Czas jej wykonania 270ms
    Wynik na końcu pętli
    Prc=100
    Z=456
    Podczas wykonywania pętli Z oraz Prc zwiększają się liniowo i tak właśnie ma być.

    Tu zgodnie z sugestiami na zmiennych typu long

    Kod: text
    Zaloguj się, aby zobaczyć kod

    Czas jej wykonania 130ms
    Wynik na końcu pętli
    Prc=0
    Z=61
    Podczas wykonywania pętli Z oraz Prc zmienia się losowo, a przynajmniej bardzo nie tak jak powinno być.
    Tak samo dzieje się w przypadku Dword
    Fajnie, że działa szybciej tylko coś źle liczy.
    Z tego co zauważyłem problemem jest to przeliczanie z long na word.
    Jeśli przepisuję wartość z long do word za pośrednictwem zmiennej single to wynik jest prawie dobry, tj.
    Z=455 (idealnie gdyby wyszło 457)
    Prc=100
    Ale z takim dodatkowy przepisywaniem pętla wykonuje się 377ms - LIPA :cry:

    Co robię źle?
  • #8 13026163
    Fredy
    Poziom 27  
    a może powiedziałbyś o co Ci chodzi?
    Tak zagmatwany kod ciężko sie analizuje.
    To co wkleiłeś to może być przestroga przed wyborem Bascoma jako język programowania.

    Już na pierwszy rzut oka widac że zmienna Z jest za mała.
    Zamień wszystkie zmienne na long, bo najprawdopodobniej przekraczasz ich zakresy.
  • #9 13026353
    Gronczyński

    Poziom 19  
    Wartość wynikowa Z musi być typu word jest podstawiana do ustawień Timera w dalszej części programu i musi pozostać tego typu.
    Wartość wynikowa Proc ma charakter informacyjny jej rola jest drugoplanowa.
    W zależności od dwóch zmiennych wejściowych X oraz Y, które określają zakres pracy pętli, gdzie X może przyjmować wartości od 1 do 510 natomiast Y może przyjmować wartości od 10 do 1200.
    Y to czas w milisekundach w jakim zmienna Z ma "płynnie" zwiększyć swoją wartość od zera do nastawionej wartości X.
    Mam nadzieję, że to tłumaczenie trochę rozjaśni o co mi chodzi.
    Ze względu na czas wykonywania pętli powstaje mi błąd w stromości narastania zmiennej Z dochodzący do 20%.
    Wydaje mi się, że po prostu muszę zmienić kwarc na taki o wyższej częstotliwości, a pewnie i będę musiał zmienić sam mikrokontroler na szybszy. Jeśli to nic nie da to zapewne nie obejdzie się bez zmiany języka programowania.
  • #10 13029587
    Fredy
    Poziom 27  
    Co z tego , że później potrzebujesz zmienną Z później do ustawień timera jako word.
    W tej pętli ta zmienna bardzo szybko się przepełni bo jest zbyt małej pojemności i pojawią się bzdury.
    Jeśli już bardzo potrzebujesz zawęzić później tą zmienną do innego rozmiaru to rzutujesz ją wprost na liczbą dwubajtową, i po problemie.
    Jak myślisz, czemu na twoje pytania nikt nie odpowiada?
    Odpowiedź jest prosta - ten kod jest okropny. Czy nie możesz zastąpić tych idiotycznych zmiennych typu x,y,z,pomoc1,pomoc2 itd na coś bardziej logicznego?
    Jeśli coś jest czasem to czemu to nie nazwać po prostu czas.

    I jeszcze jedno ten program natychmiast poprawisz używając symulatora w którym co pętlę wyświetlisz wartości wszystkich zmiennych.

    A tak poza tym to polecam ci bardzo - przesiąść się na C.
    W C taki program wyglądałby bajecznie. Wszystkie obliczenia wykonałbyś w jednej linii.
  • #11 13029827
    Gronczyński

    Poziom 19  
    Fredy napisał:
    I jeszcze jedno ten program natychmiast poprawisz używając symulatora w którym co pętlę wyświetlisz wartości wszystkich zmiennych.
    A jak myślisz dlaczego na początku tych kodów jest $sim?
    Fredy napisał:
    co z tego , że później potrzebujesz zmienną Z
    Nie później, a w trakcje wykonywania pętli.
    Cytat:
    W tej pętli ta zmienna bardzo szybko się przepełni bo jest zbyt małej pojemności i pojawią się bzdury.
    Co niby się przepełnia?
    Jeśli przepisuję wartość z long do word za pośrednictwem zmiennej single to wynik jest prawie dobry, tj.
    Z=455 (idealnie gdyby wyszło 457)
    Prc=100

    Ten końcowy błąd wynika z zaokrągleń, które są nie do uniknięcia.
    Fredy napisał:
    Jeśli już bardzo potrzebujesz zawęzić póżniej tą zmienną do innego rozmiaru to rzutujesz ją wprost na liczbą dwubajtową, i po problemie.
    I może to jest odpowiedź na moje pytanie, napisz tylko jak to "rzutować" i będzie po problemie?
    Cytat:
    Jak myślisz, czemu na twoje pytania nikt nie odpowiada?
    Może brak motywacji :?:
    Za pomoc w rozwiązaniu problemu nagroda 100pkt. :D
  • Pomocny post
    #12 13030518
    domind
    Poziom 14  
    Moze zmien algorytm tych obliczen.
    Wydaje mi ze ze jak po "Do" zrobisz od razu:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    to bedziesz mial co potrzebujesz i to bez uzywania single
    Nie znam dobrze Bascom, wiec jak nie mozna robic tylu operacji w jednej linii to dodaj zmienna pomocnicza Pom1

    Kod: text
    Zaloguj się, aby zobaczyć kod
  • #13 13030650
    Gronczyński

    Poziom 19  
    Po drobnej zmianie kodu działa dobrze (matematycznie)
    Kod: text
    Zaloguj się, aby zobaczyć kod

    Co prawda pętla wykonuje się nieco dłużej niż w "oryginale" ale liczy bez pudła.
    Stówa poszła do kolegi domind
    A na razie problem rozwiązałem tak, że od zadanej wartości Y odejmuję zakładany czas wykonania pętli i jest OK.
  • #14 13030718
    domind
    Poziom 14  
    Dluzej, czyli ile czasu?
    Czemu "tracisz czas" na przepisanie Pom3 do Prc ? Nie mozna do Prc od razu wpisac wyniku Pom1 \ Y ? Jakies ograniczenie Bascom'a?

    Z - szybciej sie policzy jak bedzie:
    Pom2 = Cykl * X
    Z = Pom2 \ Y

    Ciekaw jestem ile to zajmuje czasu po zmianach.
  • #15 13030736
    Gronczyński

    Poziom 19  
    domind napisał:
    Z = Pom2 \ Y
    Przy takim przepisaniu dla Pom2>65535 następuje przepełnienie Z.
    domind napisał:
    Ciekaw jestem ile to zajmuje czasu po zmianach.
    280ms, a "oryginał" 270ms
  • #16 13030819
    domind
    Poziom 14  
    Zrezygnuj z liczenia informacyjnej Prc, to bedzie 2x szybciej ;)
  • #17 13041177
    Gronczyński

    Poziom 19  
    Wygląda na to, że nie da się pozbyć zmiennych typu single, a jeśli nawet to i tak proces liczenia danych jest dłuższy niż przy użyciu zmienne tego typu.
    Problem na tą chwilę rozwiązany jest tylko tak, że od zadanej wartości Y odejmuję zakładany czas wykonania pętli i jest OK.
    Jeśli nie znajdzie się jakieś rozwiązanie przyspieszające działanie pętli to temat do zamknięcia.
  • #18 13041318
    domind
    Poziom 14  
    Sam pisales ze Prc jest informacyjna. Zrezygnuj z liczenia jej, to bedzie szybciej. Jak potrzebujesz ja informacyjnie to wyswietl jako wartosc "Cykl" z zakresu "Y"
    Jak mozesz tak zrobic - to w pentli daj na calkowitych tylko:
    Pom1 = Cykl * X
    Z = Pom1 \ Y

    Szybciej chyba nie wymysle.
REKLAMA