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.

jak stworzyć zwłokę czasową

songeta 03 Lut 2014 15:22 2841 32
  • #1 03 Lut 2014 15:22
    songeta
    Poziom 10  

    Witam
    Jak w temacie nie wiem jak obliczyć zwłokę czasową. Piszę w języku C dla mikrokontrolera 8051.
    Dokładnie to chodzi mi o sam wzór do obliczenia zwłoki czasowe. Nie chodzi mi o kod czy gotowe komendy dla tego mikrokontrolera tylko o samo obliczanie konkretnego czasu dla konkretnej częstotliwości.
    Dla przykładu chce uzyskać zwłokę czasową równej 1 sekundzie o częstotliwości 1Mhz i jak to się oblicza?

    0 29
  • #2 03 Lut 2014 15:32
    GanzConrad
    Poziom 21  

    1MHz to 1mln "tyknięć" na sekundę. Jeśli zliczysz wszystkie 1 000 000 tyknięć jakimś licznikiem/Timerem to uzyskasz "zwłokę czasową" równą 1 sekundzie. Nie pamiętam jak to się robiło dla 8051, ale w innych uP np AVR masz preskalery w Timerach (dzielniki częstotliwości) + dodatkowo liczniki 8 lub 16 bitowe. To wszystko daje ci komfort liczenia mniejszych liczb niż miliony (MHz).

    Dodano po 1 [minuty]:

    weź jeszcze pod uwagę fakt, że cykl maszynowy procesora 8051 jest różny od częstotliwości zegara taktującego uP (nie chce strzelać bo nie pamiętam już jaki był).

    0
  • #3 03 Lut 2014 15:43
    songeta
    Poziom 10  

    czyli jedna operacja trwa mikrosekunde, w tym przypadku..
    więc zwłoka czasowa to po prostu "czas[s]*częstotliwość" ?
    np jak bym chciał uzyskać 0,5s dla częstotliwości 18Mhz to wystarczy zrobić
    for(int i=0; i<9000000; i++) tak?

    0
  • #4 03 Lut 2014 15:49
    BlueDraco
    Specjalista - Mikrokontrolery

    Najpierw musiałbyś sprawdzić, ile i jakich instrukcji procesora zawiera ta pętla i jaki jest czas wykonania obiegu. Na tej podstawie należałoby dopiero wyznaczyć liczbę powtórzeń. Tylko że taki sposób - to czysta amatorszczyzna, nadająca się tylko do programów z serii "umiem pomigać diodą przy użyciu mikrokontrolera".

    W praktyce programowanie zaczynasz zawsze od ustawienia timera, który zgłasza przerwania ze stałą częstotliwością, rzędu np. 100 Hz. Wszelkie opóźnienia robisz przez "timery programowe", czyli zmienne dekrementowane warunkowo w przerwaniu timera. Wyzerowanie takiej zmiennej oznacza upłynięcie określonego odcinka czasu.

    0
  • #5 03 Lut 2014 16:12
    songeta
    Poziom 10  

    szczerze to nie mam pojęcia o "timerach programowych" zostańmy na poziomie "umiem pomigać diodą".
    Co do zwłoki czasowej to chcę zrobić ją w pętli coś w stylu powyższego przykładu. Jeśli się mylę co do mojego powyższego postu to mógłby mi ktoś wytłumaczyć jak to działa?

    1
  • #6 03 Lut 2014 16:21
    BlueDraco
    Specjalista - Mikrokontrolery

    A co konkretnie mamy Ci wytłumaczyć poza tym, co napisałem w poprzednim poście?

    0
  • #7 03 Lut 2014 16:56
    emarcus
    Poziom 35  

    songeta napisał:
    szczerze to nie mam pojęcia o "timerach programowych" zostańmy na poziomie "umiem pomigać diodą".
    Co do zwłoki czasowej to chcę zrobić ją w pętli coś w stylu powyższego przykładu. Jeśli się mylę co do mojego powyższego postu to mógłby mi ktoś wytłumaczyć jak to działa?

    Należałoby zacząć od podstaw:
    W dziedzinie uControlerów są dwie metody pomiaru czasu; pierwsza to (wyjątkowo nie eknomiczna) -wykorzystanie processora do liczena czasu czyli naliczania tych 'tyknięć' zegara i nie robić NIC (ileśtam nop)- powszechnie referowane jako "delay". Processor liczy te tyknięcia (rozwiązanie bez sensu!!!!)_
    Druga preferowana metoda to użycie timerów (układów licznikowch) w które każdy microcontroler jest wyposażony. Niektóre maja jeden, inne mają ich kilka, niezależnych z wieloma dość skomplikowanymi progamowanymi funkcjami, które nie muszą być zawsze wykorzystywane lub programowane.
    Twój processor ma ich dwa. Zacznij je użuywać, niech timer zajmie się liczeniem tych 'tyknięć', a processor w tym czasie może robić coś bardziej porzyteczego dla programu.
    Jeżeli j. ang nie jest barierą, to zaglądnij na stronę:
    http://www.8052.com/tuttimer.phtml#How%20Count

    Jestem pewny że wiele informacji o timerach znajdziesz także w j. polskim.
    Od tego w zasdzie powinieneś zacząć.

    0
  • #8 03 Lut 2014 17:40
    Badmaneq
    Poziom 23  

    songeta napisał:
    czyli jedna operacja trwa mikrosekunde, w tym przypadku..
    więc zwłoka czasowa to po prostu "czas[s]*częstotliwość" ?
    np jak bym chciał uzyskać 0,5s dla częstotliwości 18Mhz to wystarczy zrobić
    for(int i=0; i<9000000; i++) tak?


    NIE !
    Cykl maszynowy w standardowych 8051'kach trwa FXTAL/12, np. rezonator kwarcowy 12 MHz to cykl maszynowy 1 MHz. Dla częstotliwości 18 MHz cykl maszynowy wynosi 1,5 MHz, bo 18/12=1,5.
    W języku C pętla for(int i=0; i<9000000; i++) może nie rozwiązać problemu ponieważ kompilator w procesie optymalizacji może ją poprostu wyrzucić. W miarę dokładne opóźnienie uzyskasz pisząc wstawki asemblerowe.
    Żeby łatwo się liczyło załóżmy, że FXTAL = 12 MHz, zatem cykl maszynowy = 1 MHz, czyli 1 us.
    Aby uzyskać 0,5 s musi wykonać się 500000 cykli maszynowych, bo 0,5 s = 500000 us. Rozkazem wykonującym się 1 cykl jest np. NOP czyli nic nie rób. Można by w pętli wykonywać 500000 razy wstawkę NOP, tyle że tak naprawdę będzie to troszeczkę więcej niż 0,5 s. Dlaczego ?
    Ponieważ rejestry w 8051 są 8 bitowe, więc pętla for(int i=0; i<255; i++) nie zrobi narzutu czasowego, jednak kiedy i > 255 kompilator podzieli ją na mniejsze kawałki, a co się z tym wiąże dodatkowe cykle maszynowe.

    Jeżeli chcesz uzyskać bardzo dokładne opóźnienia to robi się to na timerach...

    0
  • #9 03 Lut 2014 19:23
    songeta
    Poziom 10  

    ilość operacji na sekundę w 8051 to jest częstotliwość/12 ponieważ cykl zegarowy trwa 12 cykli maszynowych, tego właśnie szukałem.
    domyślam się, że są łatwiejsze i bardziej sensowe metody ale chodzi mi tylko o to czy poniższy kawałek kody zadziała - poczeka 0,5s dla 18MHz? dopiero się uczę

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #10 03 Lut 2014 19:31
    BlueDraco
    Specjalista - Mikrokontrolery

    Cały czas zapominasz, że jeden obieg pętli - to od 1 do kilkunastu instrukcji (przy 32-bitowym liczniku pętli na przykład), a czas wykonania niektórych z nich może wynieść dwa cykle maszynowe.

    0
  • #11 03 Lut 2014 19:39
    Badmaneq
    Poziom 23  

    songeta: nie wiadomo ile funkcja czekaj będzie się wykonywała, zależny jak sobie to "przetłumaczy" kompilator na asembler + dodatkowy narzut na zapamiętanie pewnych rejestrów na stosie, a przed powrotem z funkcji pobranie ich ze stosu.
    Tak jak wcześniej wspomniałem bez wstawki asemblerowej się nie obejdzie. Jakiego środowiska programistycznego używasz ?

    0
  • #12 03 Lut 2014 19:54
    songeta
    Poziom 10  

    piszę w Keil-u
    j++; nie trwa jeden cykl? to istnieje coś co trwa jeden cykl?
    wstawka z asemblera jak będzie wyglądać? a nie da się tego jakoś zrobić w C?

    0
  • #13 04 Lut 2014 11:18
    BlueDraco
    Specjalista - Mikrokontrolery

    j++ na zmiennej 8-bitowej trwa jeden cykl, na 16-bitowej - 2 do 5. Sprawdzenie. czy zmienna osiągnęła jakąś wartość i skok zamykający trwa 2 cykle dla 8-bitowej, min. 4 cykle dla 16-bitowej. Procesor to nie cylinder magika - każda operacja zapisana w programie jest rozwijana na ciąg instrukcji, dotyczy to również konstrukcji warunkowych - obliczenie wyrażenia, sprawdzenie wartości.

    0
  • #14 04 Lut 2014 18:15
    songeta
    Poziom 10  

    ale to będą nie wielkie różnice rzędu mikrosekund. Dla tego przykładu w zupełności mi wystarczy. Ale żeby uniknąć w przyszłości niepotrzebnych pytań jakby ktoś podrzucił kawałkiem kodu to byłbym wdzięczny.

    0
  • #15 04 Lut 2014 18:24
    BlueDraco
    Specjalista - Mikrokontrolery

    To będą różnice kilku- lub kilkunastokrotne.

    0
  • #16 04 Lut 2014 19:07
    songeta
    Poziom 10  

    poddaje się..
    mógłby ktoś pokazać jak zrobić zwłokę czasowa? w jak najbardziej prymitywny/prosty sposób

    0
  • #17 07 Lut 2014 09:51
    pimpuk
    Poziom 22  

    Najprymitywniej, to sobie policz liczbę X, żeby taka pętelka:
    for (j=0;j<X;j++) trwała 1ms.
    Pewnie wyjdzie X=1500, ale znając życie, to powinno być gdzieś około 1300. (Oczywiście dla Twojego kwarca 18MHz)

    Potem zadeklaruj funkcję:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    No i sobie wywołuj:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    No ale, też namawiam, abyś zainteresował się tymi timerami.
    Są w sieci fajne przykłady wstawek assemblerowych, warto się rozwijać.

    0
  • #18 07 Lut 2014 11:13
    BlueDraco
    Specjalista - Mikrokontrolery

    Nieuzasadniony optymizm -
    for (j=0;j<X;j++);

    - to kilkanaście instrukcji procesora '51 zajmujących po 1 lub 2 cykle, czyli ponad 20 cykli na jeden obieg.

    Takie opóźnienia, jeśli już ktoś bardzo nie chce używać timerów, robi się wyłącznie w asemblerze w postaci kilku pętli zagnieżdżonych z 8-bitowymi licznikami powtórzeń. Inaczej zmiana wersji kompilatora, poziomu optymalizacji, użycia zmiennych w programie lub czegokolwiek innego zmieni czas wykonania pętli.

    0
  • #19 07 Lut 2014 13:56
    pimpuk
    Poziom 22  

    BlueDraco napisał:
    Nieuzasadniony optymizm

    No tak. Dlatego napisałem, że tak jest najprymitywniej.
    songeta napisał:
    mógłby ktoś pokazać jak zrobić zwłokę czasowa? w jak najbardziej prymitywny/prosty sposób

    Ja podałem że będzie gdzieś 1300 pętli, w/g Twoich sugestii może być 900 albo mniej.
    Niech sobie kolega songeta to dobierze doświadczalnie, albo pomierzy na oscyloskopie.
    Ale powtarzam: fajne wstawki assemblerowe w sieci krążą.

    0
  • #20 07 Lut 2014 15:01
    atom1477
    Poziom 43  

    A ja tak tylko dodam bo się nie mogę powstrzymać, że to na pewno nie będzie 1300 pętli. Na moje oko jakieś 200...500. Przy 1300 jeden obieg pętli musiał by trwać 1,15 cyklu co jest nierealne. Absolutne minimum dla '51, gdyby kompilator był megasprytny i to zoptymalizował do dekrementacji zamiast inkremenntacji, to chyba będzie 3 cykle. A i to tylko dla przypadku jak by operować na liczbie 8-bitowej, czyli 1300 się tam nie mieści.
    Ciekawe więc jestem jak policzyłeś że to może być 1300 obiegów pętli.

    0
  • #21 07 Lut 2014 16:41
    pimpuk
    Poziom 22  

    atom1477 napisał:
    na pewno nie będzie 1300 pętli

    A kto napisał, że na pewno?
    Policzyłem 1500 dla jednego cyklu, i sobie myślę: jak trzeba jeszcze w międzyczasie wykonać dodatkowe instrukcje, to może zająć nam to trochę, więc palnąłem 1300. No ale faktycznie, następna instrukcja, to następny cykl, i spada nam do 750 przebiegów.
    Równie dobrze Ciebie mogę spytać, skąd wziąłeś te 200 obiegów. Przecież 200 obiegów to 7,5 cykli co jest nierealne.

    0
  • #22 07 Lut 2014 16:48
    atom1477
    Poziom 43  

    Nie chodziło mi o to że to jest ułamek (1,15cykla), tylko o to że to jest mała wartość.
    Moje 200 cykli to na oko. W rzeczywistości będzie to oczywiście trochę mniej albo więcej (aby wyszło równo 7 albo 8 cykli na obieg). Oczywiście może być zupełnie inna wartość (i wyjdzie np. 10...20 cykli na obieg).

    0
  • #23 07 Lut 2014 17:18
    pimpuk
    Poziom 22  

    W ogóle nasza wymiana zdań jest bez sensu, bo i tak nigdy nie policzymy ile to właściwie potrzeba tych obiegów. Wystarczy zmienić poziom optymalizacji, albo co się zdarza, przedefiniować jakąś zmienną i cały program nam się wykrzacza przez te delay'e. Takie rzeczy robi się na timerach, ostatecznie w ASM.

    pimpuk napisał:
    Ale powtarzam: fajne wstawki assemblerowe w sieci krążą.

    0
  • #24 08 Lut 2014 08:20
    songeta
    Poziom 10  

    jeśli Wy macie problemy z tym to zostaje mi nauczyć się asemblera bądź tych timerów
    dzięki za wyjaśnienie

    0
  • #25 08 Lut 2014 11:49
    pimpuk
    Poziom 22  

    My nie mamy z tym problemów, bo opóźnienia obsługujemy narzędziami, które są do tego stworzone.
    To ty masz problem ze zrozumieniem że z twoim podejściem

    songeta napisał:
    najbardziej prymitywny/prosty sposób
    daleko nie zajdziesz.
    Chcesz pomigać diodą, zastosuj kod, który podałem wcześniej.
    Możesz wykorzystać też prostą wstawkę ASM (nie musisz się uczyć assemblera).

    Kod: c
    Zaloguj się, aby zobaczyć kod


    No oczywiście znowu się ktoś przyczepi, no ale myślę, że nop to na pewno jeden cykl maszynowy=12 cykli zegara.

    0
  • #26 08 Lut 2014 12:03
    BlueDraco
    Specjalista - Mikrokontrolery

    Pimpuk: akurat taka "wstawka" żadnego sensu nie ma, bo większość czasu procesor spędzi w rozwinięciu instrukcji for(), a nie na NOPach, więc NOP mogłoby nie być wcale. Co za różnica, ile cykli zajmuje NOP, skoro nie masz żadnej kontroli nad tym, co kompilator zrobi z for(), który tych cykli na pewno zajmie duuużo więcej, i w dodatku nie wiemy ile dokładnie, dopóki nie zajrzymy w kod wygenerowany przez kompilator (a ten zależy od wielu czynników, m.in. od użycia zmiennych w sąsiednich fragmentach programu)?

    Podejście z pętlą opóźniającą w C na 51 nie ma sensu.

    0
  • #27 08 Lut 2014 12:47
    Badmaneq
    Poziom 23  

    Pimpuk: Owszem do mrugania diodą o jakieś tam częstotliwości się nada, lecz do wygenerowania opóźnienia o przybliżonym czasie kod powyższy się nie nadaje.
    Wystarczy spojrzeć jak zrobiono to w dealy.h dla AVR:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Tak jak było wcześniej wspomniane na 8 bitach max. to 255, jest warunek else if (__tmp > 255), czyli wstawka asemblerowa funkcji _delay_loop_1 wykona się dla wartrtości <= 255. Powyżej tej wartości dodatkowe obliczenia, czytaj dodatkowe cykle...

    0
  • #28 08 Lut 2014 13:12
    pimpuk
    Poziom 22  

    BlueDraco napisał:
    akurat taka "wstawka" żadnego sensu nie ma

    No akurat z taką funkcją opóźniającą się spotykamy bardzo często, np. przy resetowaniu linii kontrolnych LCD, więc nie pisz, że nie ma sensu, bo ludzie z tego korzystają na co dzień.

    0
  • #29 08 Lut 2014 14:05
    tsiu
    Poziom 13  

    A proszę bardzo - najbardziej prymitywny sposób:

    zrób funkcję która ma duuużo NOPów
    coś w stylu

    Code:

    asm("nop");
    asm("nop");
    asm("nop");
    [...]
    asm("nop");


    Daj tego dużo, np tysiąc. Wiedząc jakie masz taktowanie zegara będziesz wiedzial ile ta funkcja będzie trwała. Jeśli masz 1MHz i dasz 1000 operacji NOP to będzie trwała 1/1000 sekundy.

    No i tyle, teraz wystarczy wywołać to w petli for tysiąc razy i masz opóźnienie sekundę.
    W rzeczywistości będzie oczywiście więcej niż sekundę, ale będzie to pomijalne ;)

    To rozwiązanie bije pętlę for do opóźniania, w której nie do końca wiesz ile cykl zajmuje, chociaż mógłbyś też zrobić fora, popatrzyć na wygenerowany kod w asm i sobie policzyć cykle. Ale to trudniejsza opcja i lepiej od razu zrobić na timerze niż w takie coś się bawić.

    pozdro !! :)

    0
  • #30 08 Lut 2014 14:37
    BlueDraco
    Specjalista - Mikrokontrolery

    Pimpuk:

    Z czego niby "ludzie korzystają na codzień"? Chyba nie z pętli w C o nieznanym, znacznym czasie wykonania ze wstawioną instrukcją o znanym czasie wykonania, znacznie krótszym od tego nieznanego?

    Mocno przesadziłeś. Czym innym jest sekwencja opóźniająca złożona z iluś NOP, a czym innym pętla złożona z jednego NOP i nieznanej liczby innych instrukcji.

    0