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

Funkcja _delay_us(double us); - jak działa?

dziechu 22 Sie 2010 11:09 4748 53
  • #1 8424747
    dziechu
    Poziom 27  
    Witam.

    W moim programie używam funkcji _delay_us(); z dość dużymi wartościami, np. 11250. W dokumentacji opisującej tą funkcję znalazłem, że max. wartość dla tej funkcji to 768/F_CPU w Mhz, czyli w moim przypadku 192 us. Jeżeli wartość jest większa, automatycznie zostaje przekazana do funkcji _delay_ms(); Co to znaczy? Czy mogę w tych funkcjach korzystać z wartości niecałkowitych, np. _delay_ms(11,25); ??? Bo program działa prawidłowo z poleceniem _delay_us(11250);
  • #2 8424814
    tadzik85
    Poziom 38  
    Można, ale to zawsze wiąże się z dokładnością. _delay_ms powyżej 262/F_CPU przyjmuje dokładność do 0,1 ms. Dla bardzo dokładnych odczekań zalecam jeden z timerów.
  • #3 8424976
    nsvinc
    Poziom 35  
    Wywołuj __delay_us() kilka razy pod rząd z odpowiednimi wartościami.
    Jeśli chcesz w sumie mieć delay 11,25ms, to wywołaj __delay_ms(11); a następnie bezpośrednio linijke niżej __delay_us(150); __delay_us(100);

    proste...

    Ale pamiętaj, że pomiary czasu dokonywane w ten sposób nie są dokładne!.
    Twoje 11,25ms w rzeczywistości będzie trwało więcej jak będziesz
    wywoływać funkcje, musisz doliczyć czasy skoków itp, a dodatkowo
    wziąć pod uwagę możliwość, że wykonanie funkcji delay może zostać
    przerwane przerwaniem.
  • #4 8425196
    dziechu
    Poziom 27  
    Wywoływane czasy nie muszą być dokładne w sensie wartości, bo są jednorazowo dobierane ekperymentalnie. Natomiast muszą być bardzo dokładne w sensie powtarzalności. Z tego też względu zrezygnowałem z wewnętrznego oscylatora na rzecz kwarcu, oraz na czas odliczania czasu zatrzymuję wszystkie przerwania. Myślę że z powtarzalnością nie powinno być problemów.

    Dodano po 5 [minuty]:

    A dlaczego te funkcje przyjmują zmienną typu double, skoro mają takie ograniczenia?
  • #5 8425222
    nsvinc
    Poziom 35  
    Jeśli wyłączasz przerwania na czas odliczania, to nie ma wyjścia, będziesz
    miał 100% powtarzalności. Procesor nie myśli - nie ubzdura mu się,
    żeby zamiast odliczyć np. 200 zegarów odliczy tylko 191, bo ma zły humor.

    Możesz więc mieć pewność, że sumaryczne wykonanie funkcji
    odmierzających czas zawsze będzie trwało tyle samo, o ile
    nie wystąpi wyjątek.

    Nie wiem co to za funkcje, więc nie wiem dlaczego przyjmują double, nie int.
    Ja wolę nie dotykać zmiennychprzecinków pisząc na mikrokontroler...i robię
    to tylko w ostatecznej ostateczności. Głupotą programistyczną jest podawanie
    double do funkcji odmierzającej czas...:]
  • #6 8425283
    dziechu
    Poziom 27  
    No widzę że wszędzie używając tych funkcji podaje się wartości całkowite, jednak w opisach tych funkcji jako wartość wejściowa podawane jest double a nie int, czy dokładniej uint.

    http://www.nongnu.org/avr-libc/user-manual/group__util__delay.html

    To raczej chyba anie nie błąd, ani głupota programistów, dlatego drążę temat:)

    Co do zmiennoprzecinkowych liczb - pisząc do tej pory wszystko w assemblerach też nie miałem tego problemu nie używając ich:) Ten program dlatego właśnie jest napisany w C, bo muszę w nim między innymi obliczać log10(a/b) z dokładnością co najmniej dwóch miejsc po przecinku (a dzielenie a/b z dokładnością czterech). Nie znalazłem bibliotek zmiennoprzecinkowych w asm, a pisanie samemu takich procedur to masakra (log10 to prawie 2kB kodu).
  • #7 8425447
    nsvinc
    Poziom 35  
    po pierwsze rzuca się w oczy nongnu :]

    Po drugie, cięzko przewidzieć co mysleli sobie programiści stosując
    double na 8bitowym prostym rdzeniu bez FPU. Chyba chcieli marnować
    czas w bardziej finezyjny sposób zuzywając moc obliczeniową rdzenia
    na uprawianie seksu z liczbą zmiennoprzecinkową, i to jeszcze taką o
    podwójnej precyzji... :):)

    Jak dla mnie - bezsens. Nawet marnowanie czasu powinno być zrealisowane
    prosto, a nie w oparciu o software'owe biblioteki umożliwiające
    przetwarzanie double...

    Jeśli masz konieczność pracy z liczbami zmiennoprzecinkowymi i matematyką
    je przetwarzającą, może rozważ zastosowanie procesora w którym umieszczono
    koprocesor matematyczny. Na obliczanie jakichkolwiek logarytmów, funkcji
    trygonometrycznych i podobnego badziewia zuzyjesz niesamowitą ilość czasu
    na czymś takim jak 8bitowy AVR.
  • Pomocny post
    #8 8425612
    mirekk36
    Poziom 42  
    Panowie, panowie - nie rozpędzajcie się w tych wyjaśnieniach o rdzeniach 8-bitowych i dziwnych myślach programistów tworzących funkcje typu _delay_ms()

    nsvinc napisał:

    Jak dla mnie - bezsens. Nawet marnowanie czasu powinno być zrealisowane
    prosto, a nie w oparciu o software'owe biblioteki umożliwiające
    przetwarzanie double....


    Bo jest prosto, i to bardzo prosto - mega prosto - czytaj dalej .... ;)


    dziechu napisał:

    To raczej chyba anie nie błąd, ani głupota programistów, dlatego drążę temat:)


    I to się nazywa podejście, zamiast od razu jak niektórzy narzekać, że ktoś źle pomyślał tworząc funckje z takimi argumentami ;)

    To jest bardzo dobry pomysł a na dodatek dzięki takiemu rozwiązaniu , uwaga!!! wcale wbrew pozorom nie używa się liczb typu double o ile ma się pojęcie jak należy używać tych funkcji: _delay_us() oraz _delay_ms()

    Podałeś link do definicji gnu a tam jest jasno napisane:

    Cytat:
    The idea behind is that compile-time constant expressions will be eliminated by compiler optimization so floating-point expressions can be used to calculate the number of delay cycles needed based on the CPU frequency passed by the macro F_CPU.


    co oznacza ni mniej ni więcej, że można używać jako argumenty "stałych dosłownych" typu double, które zostaną w wyniku optymalizacji zmienione na odpowiednią stałą i nie zmiennoprzecinkową ;) liczbę cykli zegara. Dzięki temu można sobie w zakresie

    od 0 do 262.14 ms super dokładnie regulować opóźnienie korzystając ze stałych podkreślam stałych zmiennoprzecinkowych. Zatem jeśli wpiszę sobie np tak:

    _delay_us( 100.2 );


    to rzućcie sobie panowie przeciwnicy ych funkcji okiem na asemblerowy kod, to powinno wszystko chyba jendoznacznie wyjaśnić i pokazać, że po drodze nie została użyta ŻADNA LICZBA ZMIENNOPRZECINKOWA ;)

         caa:	8a ee       	ldi	r24, 0xEA	; 234
         cac:	93 e0       	ldi	r25, 0x03	; 3
         cae:	24 e1       	ldi	r18, 0x14	; 20
         cb0:	31 e0       	ldi	r19, 0x01	; 1
         cb2:	f9 01       	movw	r30, r18
         cb4:	31 97       	sbiw	r30, 0x01	; 1
         cb6:	f1 f7       	brne	.-4      	; 0xcb4 <main+0x20>
         cb8:	01 97       	sbiw	r24, 0x01	; 1
         cba:	d9 f7       	brne	.-10     	; 0xcb2 <main+0x1e>


    A jednocześnie można z precyzją zmiennoprzecinkową choć najlepiej w postaci stałych robić super dokładnie opóźnienia co do pojedynczych taktów zegara, szczególnie gdy masz wyłączone przerwania w tym czasie.


    ....ale jeśli użyjesz jako argumentu takiej funkcji zmiennej, co do której kompilator nie może się domyśleć jaką będzie miała wartość gdyż po drodze np w jakiejś pętli ulega ona obliczeniom to już nie ważne czy będzie taka zmienna typu double czy int - to i tak kompilator zaprzęgnie całe swoje biblioteki do obliczeń zmiennoprzecinkowych (ok 2kb kodu) i o tyle od razu wzrośnie cały kod wynikowy a w asemblerze nie będę tu zamieszał listingu takiej funkcji bo za długi byłby ;)
    Dziwią się czasem ludzie piszący np na procku ATtiny, że nagle kod po kompilacji nie mieści się w procku - co się stało ?!?!? .... auto muchę przejechało - bo się zmienną doble jako argument zapodało ;)

    czyli :

    	uint8_t a=50;
    	uint8_t i;
    
    	for(i=0;i<10;i++) _delay_ms(a*i);


    już ci zrobi masakrę w kodzie tzn może nie masakrę - po prostu trzeba o tym wiedzieć bo czasem jak masz duuużo pamięci to może cię czochrać takie coś

    ale jeśli dasz tak:

    	uint8_t a=50;
                 _delay_ms(a);


    to znowu będzie krótki kodzik, gorzej jak gdzieś znowu dalej w kodzie zmienna a będzie mogła ulec zmianie w trakcie obliczeń to już zostanie znowu rozwinięty kod o biblioteki zmiennoprzecinkowe.

    Wiedząc o tym wszystkim chyba należy przyznać, że stwórcy mieli łeb na karku a nie tam jakieś głupoty popełniali czy byki strzelali - prawda ?

    mam nadzieję, że to wyjaśnia ten problem - zagadkę ?
  • #9 8425668
    dziechu
    Poziom 27  
    Wyjaśnia, wielkie dzięki za tak wartościową wypowiedź. To mnie bardzo zadowala, bo tam gdzie używam tej funkcji, mam (czy raczej mogę mieć) zmiennoprzecinkową stałą:) Czy zatem zamiast _delay_us(11250); lepiej będzie napisać _delay_ms(11.25); żeby kompilator nie musiał naprawiać moich błędów??? Chyba tak. Tak na marginesie - zauważyłem że w większości operacji matematycznych kompilator przyjmuje zarówno kropki jak i przecinki, np. a = x * 2.5 i a = x * 2,5. W wypadku jednak kiedy wartość jest argumentem funkcji np. tej rozpatrywanej, napisanie t = 11.25 jest ok, a t = 11,25 wywala błąd - za dużo argumentów, w tym przypadku przecinek jest traktowany jako rozdzielenie dwóch argumentów.

    Dodano po 5 [minuty]:

    P.S. co do marnowania czasu procesora operacjami zmiennoprzecinkowymi. Moje urządzenie jest na MEGA32 taktowane 4MHz. Mierzy i wyswietla po przeliczeniu zmiennoprzecinkowym pewne wartości. Robi to na tyle szybko, że w pęli głównej jest opóźnienie 300ms, bo wyświetlacz graficzny nie nadąża za pomiarami (czy może raczej oko nie nadąża), 3 pomiary /sek. to optimum kiedy jeszcze pomiary są czytelne. Tak więc i tak procek pewnie 90% czasu siedzi w pustej petli. Wszystko zależy od zastosowań.
  • #10 8425702
    nsvinc
    Poziom 35  
    Ok, zwracam honor. Nie widziałem źródeł tych funkcji, więc
    założyłem sobie, że funkcja na tej liczbie zmiennoprzecinkowej przeprowadza
    jakieś obliczenia, np. w pętli odejmuje od jednego double'a drugiego
    double'a...

    A faktem jest, że jeśli przetwarzanie tych liczb zmiennoprzecinkowych
    odbywa się na poziomie kompilacji, a rdzen wykonuje już pracę na
    intach, to jest szybko i przyjemnie.

    Ale ja nadal jestem zwolennikiem delayów wyglądających tak:
    
    void delay(u32 de)
    {
    while(de--);
    }
    

    Jeszcze prościej :D
    A kompiluje się w cztery instrukcje Thumb2...

    Znając swój zegar i budowę rdzenia (no i asma), można sobie też
    obliczyć, co podać do funkcji dla danego czasu...

    Cytat:

    np. a = x * 2.5 i a = x * 2,5.

    Co to za zonk? W ANSI C 2,5 to nie jest liczba zmiennoprzecinkowa!. W co to się kompiluje, nie wiem (jest reguła to opisująca, ale jej nie pamiętam bo nie muszę...)
  • #11 8425748
    mirekk36
    Poziom 42  
    dziechu napisał:
    Wyjaśnia, wielkie dzięki za tak wartościową wypowiedź. To mnie bardzo zadowala, bo tam gdzie używam tej funkcji, mam (czy raczej mogę mieć) zmiennoprzecinkową stałą:) Czy zatem zamiast _delay_us(11250); lepiej będzie napisać _delay_ms(11.25); żeby kompilator nie musiał naprawiać moich błędów??? Chyba tak. .


    Zdecydowanie TAK, ponieważ jeśli chodzi o _delay_us() to super dokładne obliczenie co do taktu zegara możliwe jest tylko dla wartości

    od 0 do 768 us

    zatem twoja wartość zostaje niejawnie przekonwertowana z lekką stratą precyzji na wykorzystanie _delay_ms()

    Więc masz rację, że stosujesz _delay_ms(11.25);

    co do kropków i przecinków to ja zawsze używam kropki w liczbach zmiennoprzecinkowych a przecinek jak sam powiadasz zwykle używany jest do rozdzielania argumentów i stąd mogą się brać później dziwne reakcje Qńpilatora ;)


    Uwaga! oczywiście nie oznacza to, że nie można podawać większych wartości do _delay_ms() niże te 262.14 a przypadku _delay_us() niż 768

    Tylko właśnie przy wartości np _delay_ms( 5600 ) będziemy mieli opóźnienie ok 5.6s z nieco mniejszą dokładnością niż co do jednego taktu zegara. No ale po co komu taka duża precyzja przy tak długich delay'ach ? ;)

    i tak jak mówisz, wszystko zależy od kontekstu programu, kiedy trzeba i można to się używa tych funkcji i już
  • #12 8425756
    dziechu
    Poziom 27  
    To mój pierwszy program w C. Być może dlatego że od 20 lat piszę w różnych assemblerach, jakoś poszło mi i z C, choć filozofia całkiem inna:) A program dość skomplikowany, wiele funkcji, rozbudowane menu z ekranem graficznym, skomplikowane zmiennoprzecinkowe obliczenia, obsługa zewnętrznych urządzeń jak cyfrowy czujnik RGB itd... Sam jestem zdumiony że poszło wszystko w tydzień i działa bez zarzutu. Bałem się że się nie zmieszczę w 32 kB. Nowe urządzenie gotowe do produkcji:) Nawet instrukcji obsługi nie musiałem zmieniać (poprzednie miało program w asm, ale z powodu mało dokładnych obliczeń musiałem łyknąć C).

    Ja też używam kropek w liczbach. Po prostu zauważyłem że po błędnym wpisaniu zamiast kropki przecinka, kompilator nie zgłosił żadnego błędu i wszystko dobrze policzył.
  • #13 8425789
    mirekk36
    Poziom 42  
    nsvinc napisał:

    Ale ja nadal jestem zwolennikiem delayów wyglądających tak:
    
    void delay(u32 de)
    {
    while(de--);
    }
    

    Jeszcze prościej :D
    A kompiluje się w cztery instrukcje Thumb2...

    Znając swój zegar i budowę rdzenia (no i asma), można sobie też
    obliczyć, co podać do funkcji dla danego czasu...


    No ale za to funkcje _delay_ są uniwersalne i nie trzeba się martwić czy pilnować jaki się ma w danym momencie zegar. A gdy kod przeniosę na podobny procek albo nawet na ten sam ale z innym zegarem to co? to znowu mam sobie sprawdzać i przeliczać milion wystąpień takich funkcji w kodzie ????

    właśnie to mieli na myśli stwórcy _delay_ms() i _delayus() ;) tak mi się wydaje. Dzięki temu czochra mnie jaki mam F_CPU a wiem na 100% że korzystając z tej funkcji błędu nie popełnię nie mówiąc o tym, że zajmuje to także tylko kilka linijek kodu w asm.

    A takie funkcje bywają nieocenione np gdy się generuje kody w podczerwieni - wtedy można spokojnie zamiast korzystać nawet z timera użyć _delay_us() ... zresztą nie tylko w takich przypadkach ale w wielu wielu innych i co najważniejsze zawsze uniwersalnie mając pewność, że jak swój kod odpalę na innym AVR to nie muszę się martwić o to czy mam dobre opóźnienia.

    Ja jak już to stosuję:

    void mkdelay(u16 ms) {
       while(ms--) _delay_ms(1);
    }


    i też się dobrze sprawdza tym bardziej że mogę jeszcze w niej wstawić nasłuchiwanie czy coś np na RS232 nie przyleciało, a zwykle super dokładnie odmierzanie czasu w takich przypadkach nie jest mi potrzebne

    Dodano po 2 [minuty]:

    dziechu napisał:
    To mój pierwszy program w C.


    No i chyba nie ostatni ;) prawda ? po takim miłym zaskoczeniu, że uruchamia się o wiele szybciej oprogramowanie pisane w C niż w ASM - bo taka jest prawda. Nie trzeba pamiętać o setkach różnych rzeczy, bawić się z budowaniem pętli itp itd itp itd

    a o obliczeniach juz nie wspomnę ;)
  • #14 8425809
    dziechu
    Poziom 27  
    Włąsnie ta uniwersalność to główna zaleta C i jego bibliotek.
    Poza dokładnością obliczeń, drugim powodem (a może nawet ważniejszym) napisania programu w C jest ta uniwersalność/przenoszalność. W ostatnim czasie były i są chyba nadal problemy z kontrolerami Atmela. Żeby przejść z urządzeniem na np. PIC trzeba w asemblerze pisać wszystko od zera (a nie lubię asemblera PIC, przynajmniej do PIC16, to jakaś beznadzieja mały sprzętowy stos, brak PUSH i POP, pamieć programu dzielona na strony, które samemu trzeba pilnować i przełączac... horror). Mając program w C i biblioteki sprawa wydaje się sporo łatwiejsza.

    Dodano po 3 [minuty]:

    Teraz wszystko będzie w C, tylko ewentualne krytyczne fragmenty w asm:)
  • #15 8427915
    kubus_puchatek
    Poziom 18  
    Wręcz przeciwnie. funkcje ...delay ze standardowej biblioteki to typowy niewypał w stylu języka basic. Opóźnienie nigdy nie będzie precyzyjne gdy są włączone przerwania. w skrajnych przypadkach zamiast sekundy możemy sekund .... kilkanascie. aby było sensownie zrealizowane odmierzanie opóźnień należy się oprzeć na zegarze sprzętowym. Osobiście proponuję napisać prostego sheludera który w jednym wątku odmierza czasy i ustawia 0 w liczniku opóźnienia.
  • #16 8427967
    dziechu
    Poziom 27  
    Kubus - poczytaj wątek od początku:) To zaden niewypał. Wyłączyć przerwania a potem je włączyć to dwa rozkazy. Żeby z 1 sek. zrobiło się kilkanaście, to przerwania musiałyby stanowić 99,9% kodu, co oczywiście czasem może się zdarzyć. A napisałem że zależy mi nie tyle na dokładności odmierzanego czasu co powtarzalności, co po wyłączeniu przerwania mam z dokładnością do jednego cyklu zegarowego. Na liczniku sprzetowym mam przerwanie dla zegara używanego w innym celu - wyłączania podswietlania ekranu i potem całego urządzenia po ustawionym czasie bezczynności. ;)

    Dodano po 7 [minuty]:

    No pominę fakt, że i przerwanie na liczniku sprzetowym może zrobić z 1 sek. kilkanaście... jeżeli będzie istniało inne przerwanie o wyższym priorytecie, zajmujące 99,9% kodu i ciągle wywoływane;)
  • #17 8428009
    mirekk36
    Poziom 42  
    kubus_puchatek napisał:
    Wręcz przeciwnie. funkcje ...delay ze standardowej biblioteki to typowy niewypał w stylu języka basic. Opóźnienie nigdy nie będzie precyzyjne gdy są włączone przerwania. w skrajnych przypadkach zamiast sekundy możemy sekund .... kilkanascie. aby było sensownie zrealizowane odmierzanie opóźnień należy się oprzeć na zegarze sprzętowym. .


    Weź ty kolego rzeczywiście troszkę poczytaj ten wątek a także zrozum, że nikt takich funkcji nie używa do odmierzania precyzyjnych czasów gdy działają przerwania (Nie do tego one są. Zechcij więc poczytać o nich szeczegóły, które opisałem, bo dalej w innych tematach, tak jak wielu innych będziesz opowiadał na ich temat fantasmagorie) . Te twoje tłumaczenia są właśnie na poziomie języka Basic - o konieczności zastosowania Timera w 100% przypadków.
  • #18 8428123
    tmf
    VIP Zasłużony dla elektroda
    nsvinc napisał:
    Ok, zwracam honor.
    A faktem jest, że jeśli przetwarzanie tych liczb zmiennoprzecinkowych
    odbywa się na poziomie kompilacji, a rdzen wykonuje już pracę na
    intach, to jest szybko i przyjemnie.


    Jeśli do funkcji podajesz stałą to przy włączonej optymalizacji kompilator wszystkie możliwe obliczenia robi na etapie kompilacji, więc nie generuje to zbędnego kodu. Stąd też w w/w przypadku do programu wstawiana jest pętla, która realizuje zadaną liczbę cykli wyliczoną na etapie kompilacji. Podobnie jeśli wywołasz własną funkcję ze znanym w czasie kompilacji stałym argumentem, to kompilator wstawi najpewniej wynik jej działania, a nie kod, który ten wynik wylicza.

    nsvinc napisał:

    Ale ja nadal jestem zwolennikiem delayów wyglądających tak:
    
    void delay(u32 de)
    {
    while(de--);
    }
    

    Jeszcze prościej :D
    A kompiluje się w cztery instrukcje Thumb2...


    Ten kod kompiluje się do niczego. Przy włączonej optymalizacji kompilator powinien go wywalić. Żeby go nie wywalił de musi być volatile, lub w pętli musi być asm volatile nop. Jak widać na tak prostym przykładzie nie ma sensu być "mądrzejszym" niż twórcy bibliotek standardowych, bo zazwyczaj mądrzejszym się nie jest.
  • #20 8428344
    nsvinc
    Poziom 35  
    tmf napisał:

    Ten kod kompiluje się do niczego. Przy włączonej optymalizacji kompilator powinien go wywalić. Żeby go nie wywalił de musi być volatile, lub w pętli musi być asm volatile nop. Jak widać na tak prostym przykładzie nie ma sensu być "mądrzejszym" niż twórcy bibliotek standardowych, bo zazwyczaj mądrzejszym się nie jest.


    #pragma o0....

    Wiedzialem ze ktoś się do tego przyczepi :]
    Poza tym mogę napisać to w asmie ARM czy Thumb czy Thumb2 jeśli to coś
    wyjaśni. Moj przykład niestety kompiluje się do 4 instrukcji. I gdy ja
    piszę takiego delaya w asmie, to też są to 4 instrukcje...

    tmf napisał:

    Jeśli do funkcji podajesz stałą to przy włączonej optymalizacji[...]

    Ja wiem co robi kompilator. Stwierdziłem, że nie widziałem źródeł tych funkcji,
    więc mogę zakładać, że funkcja robi cokolwiek, i wcale nie musi to być
    optymalne. Mam nieciekawe doświadczenia z rozmaitymi funkcjami
    bibliotecznymi, więc darzę je bardzo ograniczonym zaufaniem.
  • #21 8428470
    tmf
    VIP Zasłużony dla elektroda
    #pragma jest małokompatybilnym rozszerzeniem kompilatora. Kompilator wg standardu może zignorować nierozpoznane pragmy, bez ostrzeżenia, więc użytkownik może dostać błędny kod i nawet nie będzie wiedział o co chodzi. Np. aktualnie gcc supportuje zmiany opcji optymalizacji jedynie w odrębnych jednostkach kompilacji. Ponieważ taki delay z natury powinien być funkcją inline, więc na większości platform to nie ma prawa działać. W tym nie będzie to działać na avr-gcc, a przypominam, że jesteśmy na forum poświęconym AVRom.
    Co do argumentu double - ciało funkcji jest bez znaczenia, to kompilator ewaluuje stałe. Więc bez zaglądania do funkcji można przyjąć, że funkcja wywołana z argumentem, który jest stałą, powinna zostać zastąpiona wynikiem jej działania. I tak się tu dzieje. Już pomijam, że nieładnie jest pisać o autorach AVR-gcc lib, że robią coś bezsensownie, jeśli nawet nie sprawdziło się źródeł.

    Dodano po 1 [minuty]:

    BTW, na rdzeniach z pipeline trudno powiedzieć jaki jest bezwzględny czas wykonywania instrukcji. Pomijając już fakt, że na różnych rdzeniach ARM zapewne ten czas też jest różny.
  • #22 8428544
    nsvinc
    Poziom 35  
    tmf napisał:
    więc na większości platform to nie ma prawa działać

    Większość komercyjnych kompilatorów to obsługuje. Nie precyzowałem,
    pod jaki kompilator jest mój kod (a pod MDK-ARM nawet ta pragma nie jest
    wymagana przy -o3, a kompiluje sie dobrze )
    Nie znam ogolnie gcc, a tym bardziej avr-gcc... Kod miał być tylko
    przykładem. A to czy będzie działał, zależy już od skilla programisty,
    który go implementuje.

    tmf napisał:
    [...]funkcja wywołana z argumentem, który jest stałą, powinna zostać zastąpiona wynikiem jej działania.

    Nie jest to żaden pewnik, jeśli nie wiadomo co funkcja robi...Wystarczy że
    w grę wchodzi jakis inny parametr, który jest zmienny i kompilator nie
    może przewidzieć na 100% jaką wartość będzie on zawsze przyjmować.

    tmf napisał:
    Już pomijam, że nieładnie jest pisać o autorach AVR-gcc lib, że robią coś bezsensownie, jeśli nawet nie sprawdziło się źródeł.

    zwróciłem honor...

    Pracując z konkretnym rdzeniem i konkretnym zegarem można prosto
    oszacować czas takiego delaya. I stosuję go w miejscach, gdzie trzeba opóźnić
    kontrolę o jakiś czas, a nie 192834ns....
    A zdaje się, że autorowi tematu chodziło o powtarzalność delaya, a nie o jego
    precyzyjny czas trwania
  • #23 8428572
    dziechu
    Poziom 27  
    Nie ma sie o co spierać, sprawa jest dość prosta - jeżeli program działa bez zarzutu i wymaga jednej linijki, to mam gdzieś jak się kompiluje i nie mam zamiaru 'dla zasady' pisać 50 linijek, po czym program będzie działał zupełnie tak samo. Jak już pisałem, robię programy od ponad 20 lat, nie dla siebie, ale na zlecenia. Czasem oprogramowanie które jest potem testowane przez pół roku na wszelkie możliwe kombinacje, bo zależy od niego życie ludzi (wieloprocesorowe systemy ostrzegawczo alarmowe). Zawsze pisałem wszystko sam, od 0, nigdy nie korzystałem z cudzych bibliotek i już mam trochę tego dość. Chcę też troszkę iść na 'łatwiznę':) Pierwsze programy w latach 80' pisałem w zeszycie, bezpośrednio w kodach maszynowych. A za to C miałem się zabrać już wiele lat temu...;)
  • #24 8428674
    tmf
    VIP Zasłużony dla elektroda
    nsvinc - przykład, który nie działa to raczej kiepski przykład, niesądzisz? Obstawiam, że 99% użytkowników tego forum, piszących w C, korzysta z gcc. Bez wyłączenia optymalizacji (a jej wyłączenie jest raczej miernym pomysłem) każdy sensowny kompilator taki kod powinien wywalić i gcc tak właśnie zrobi. Jeśli jakiś kompilator tego nie robi, to stawia to pod znakiem zapytania skuteczność jego optymalizacji.
    Co do reszty to raczej wiemy co funkcja delay robi:) Myślisz, że dodatkowo korzysta ze zmiennych globalnych? :) Niezły pokręt musiałby ją pisać.
    Kolejna sprawa, że jedną z zalet pisania w C jest łatwiejsze przenoszenie między platformami/rodzinami procesorów. Lepiej skorzystać z gotowej funkcji bibliotecznej, która na każdej platformie będzie działać tak samo, niż pisać własne potworki. Potem taki kod przerzucasz na inny rdzeń i pracowicie przepisujesz te funkcje od nowa?
  • #26 8428884
    Konto nie istnieje
    Konto nie istnieje  
  • #27 8428914
    tmf
    VIP Zasłużony dla elektroda
    Tak, przenieś kod assemblerowy z AVR na '51, ARMa lub PC :) Jest to łatwe i intuicyjne, i wcale nie trzeba świetnie znać assemblera każdego z tych procesorów. W dodatku idzie to strasznie szybko i już po jakimś roku masz przeniesiony kilkunasto kB program :)
  • #28 8428938
    mirekk36
    Poziom 42  
    albertb napisał:
    Kilka luźnych refleksji.
    Używanie funkcji z delay.h - jak pisze mirekk łatwe o ile się ma pojęcie ;-)

    Po to tyle już jest wałkowany ten temat z _delay'ami, żeby właśnie mieć pojęcie i korzystać z nich z głową ;)

    albertb napisał:
    Dobrze napisany kod w ASM także łatwo się przenosi, czego o kiepsko napisanym w C nie można powiedzieć.
    Dla mnie raczej różnica jest raczej w szybkości pisania na dowolny CPU


    Oooo Matko! no panie kolego ;) litości - kod w ASM łatwo się przenosi pomiędzy np chociażby pierwszym z brzegu AVR i PIC ????? Nie wspomnę o innych o których kolega wyżej napisał. A jeśli miałeś na myśli uruchamianie swoich "bibliotek" asemblerowych na różnych prockach AVR czyli w ramach tej samej rodziny - to , to nie jest żadna przenośność kodu. Toż gdyby kolega pisał w asemblerze na PIC'ach to już by miał spore problemy przenosić kod asemblerowy nawet w ramach tejże jednej rodziny. Więc takie stwierdzenie jest MOCNO przesadzone.

    Przeniesienie byle jak napisanego kodu w C byłoby milion razy szybsze pomiędzy w/w prockami niż najlepiej napisanego programu w C. I to bez 2 zdań.
  • #29 8429039
    dziechu
    Poziom 27  
    Rozumiem że przeniesienie programu w C polega na zmianie kompilatora, bibliotek i definicji procesora, to chyba wszystko? Chciałbym zobaczyć jak kolega łatwo przenosi 32kB kodu ASM AVR na PIC..... wspomnę tylko drobne różnice - inna arytmetyka stosowana w PIC (szczególnie daje się we znaki przy odejmowaniu), AVR dokonuje operacji na dowolnych rejestrach (dozwolonych dla operacji), podczas gdy PIC zawsze na rejestrze roboczym, brak w PIC rozkazów PUSH i POP, które trzeba zastępować inaczej, przełączanie stron pamięci programu i aktualnego zestawu rejesrów w PIC... łatwo się przenosi, heheh. Jasne że całej filozofii programu nie trzeba wymyślać, jednak trzeba go przepisać linijka po linijce z całkiem sporymi zmianami. No chyba że istnieją jakieś do tego programy, robiące to automatycznie i bez błędu, ja nie znam.
  • #30 8429173
    mirekk36
    Poziom 42  
    dziechu napisał:
    Rozumiem że przeniesienie programu w C polega na zmianie kompilatora, bibliotek i definicji procesora, to chyba wszystko?

    No nie, na pewno będzie troszkę roboty z dostosowaniem się do chociażby peryferiów, ustawień timerów czy przerwań - no ale to inicjalizacja hardware. Natomiast duże części kodu czy jakieś funkcje uniwersalne, obliczeniowe a szczególnie te które nie odwołują się bezpośrednio do sprzętu to już stosunkowo łatwo przenieść.


    dziechu napisał:
    No chyba że istnieją jakieś do tego programy, robiące to automatycznie i bez błędu, ja nie znam.
    No właśnie język C jest takim "programem" hyhyhy a do usunięcia ew błędów służy mu człowiek.
REKLAMA