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

Kod tmf i zasięg zmiennych

janbernat 29 Lip 2011 21:23 3180 52
  • #31 29 Lip 2011 21:23
    janbernat
    Poziom 38  

    tmf- Twojego menu nie zmienię- za wysokie progi...
    A to że chcę multitasking- to prawda.
    Ale dlaczego "od tyłu"?
    Zawsze mogę pominąć te _delay() i po prostu zapalać diodę że "przyjęło".
    Multitasking to jest chyba oczywiste- kilka działających programów chcę połączyć- a tu d... blada.
    Każdy oddzielnie działa- a razem nie.
    A obsługę silnika robi się na przerwaniach w pętli głównej- albo nawet na odczycie flagi przerwania- skasuj i obsłuż- bez obsługi przerwania.
    Ale nie wtedy gdy jest gdzieś _delay().
    Próbuję z Twojego kodu wycisnąć co się da.
    Fajny jest- tylko 12 bajtów RAM.
    Ale jak nie da się z tego zrobić multitaskingu- to dla mnie będzie tylko ciekawostka- a nie coś użytecznego.
    Masz napisać coś na gwiazdkę- pomyśl nad tym.

  • Arrow Multisolution Day
  • #32 29 Lip 2011 21:43
    tmf
    Moderator Mikrokontrolery Projektowanie

    No dobra, to powoli wiemy co chcesz :)
    Delay w niczym nie przeszkadza, o ile obsługa silnika jest zrobiona w przerwaniu. Klasycznie wszyscy piszą, żeby w przerwaniu zmieniać flagi, a w pętli głównej reagować na zmiany. Zrób odwrotnie - w pętli głównej zmieniaj flagi, w przerwaniu zrób całą brudną robotę. Dzięki temu przerwanie "wywłaszcza" aktualny "proces" i jest ok. Tak będzie najprościej. Inną możliwością jest stworzenie czegoś w rodzaju maszyny stanów. Ale to IMHO w tym przypadku jest mniej naturalne.

  • #33 29 Lip 2011 22:14
    janbernat
    Poziom 38  

    Dobrze- zmontuję z powrotem ten układ gdzie na silnik krokowy wystawia się 8 kroków.
    Ale obawiam się że przerwanie nie nadąży z "brudną robotą".
    Zresztą- to tylko przykład.
    Tak jak napisałem- można zrezygnować z _delay() i zarazem z tego fajnego "potwierdzenia" że coś układ przyjął.
    Ale to że kod ma być potencjalnie "multitaskowalny" to podtrzymuję.
    Bo takich przykładów- jak odczytać 1wire- i tylko to- albo jak zrobić transmisję RS- i tylko to to jest mnóstwo.
    A to ma wszystko działać razem.
    Multitasking jest podstawą- a reszta to tylko przyczynki.

  • Arrow Multisolution Day
  • Pomocny post
    #34 29 Lip 2011 22:33
    94075
    Użytkownik usunął konto  
  • #35 29 Lip 2011 23:13
    janbernat
    Poziom 38  

    Dzięki albert- postaram się zrozumieć.
    tmf- żeby nie było że od pomysłu Mirka jestem uzależniony- załozyłem kiedyś taki temat:
    https://www.elektroda.pl/rtvforum/viewtopic.php?t=1781091&highlight=
    To było zanim o książce Mirka się dowiedziałem.
    No i takie małe piekiełko uruchomiłem.
    Ale ta zasada ulęgła mi się w głowie- nie można napisać że coś działa- jak działa samo- bez interakcji z reszta programu.
    Mirek znalazł że się to nazywa Round Robin- najprostsza implementacja systemów czasu rzeczywistego.
    Ty to nazywasz multitasking.
    No to trzeba tak pisać aby ten multitasking czy RoundRobin mieć stale na uwadze- jakieś światełko w tyle głowy.
    Bo napisać coś co tylko jedno obsługuje- to nawet taki głupi jak ja jestem w stanie- oczywiście mecząc się i błądząc.

  • #36 29 Lip 2011 23:16
    94075
    Użytkownik usunął konto  
  • #37 29 Lip 2011 23:33
    tmf
    Moderator Mikrokontrolery Projektowanie

    janbernat: opisz proszę dokładnie o co ci chodzi, ale nie jakieś hipotetyczne przykłady, tylko konkretnie. W pełni multitasking wymaga jakiegoś OSa, chociażby prostego, ale jednak. To na AVR jest rozwiązaniem takim sobie. Można więc zaimplementować jakąś protezę. Ale żeby nie mieszać lepiej będzie to wyjaśnić na bardzo konkretnym przykładzie, a nie uogólniać. Zresztą w pokazanym przez ciebie wątku masz pokazaną pewną ideę jak to zrobić. albertb też ci podrzucił pomysł. Weź pod uwagę, że program w C wykonywany jest sekwencyjnie, multitasking to nie jest cecha tego języka, trzeba go protezować.

  • #38 30 Lip 2011 10:10
    LordBlick
    VIP Zasłużony dla elektroda

    tmf napisał:
    Weź pod uwagę, że program w C wykonywany jest sekwencyjnie(...).
    Hmm... a jaki język na µC nie jest sekwencyjny ?

  • #39 30 Lip 2011 10:59
    tmf
    Moderator Mikrokontrolery Projektowanie

    A ja napisałem, że jakiś jest?
    Natomiast są dostępne rozszerzenia, które taką funkcjonalność dodają.

  • #40 30 Lip 2011 11:13
    94075
    Użytkownik usunął konto  
  • #41 30 Lip 2011 11:21
    LordBlick
    VIP Zasłużony dla elektroda

    albertb napisał:
    Hmm.. a jaki µC nie jest sekwencyjny ;-)
    O, o to mi chodziło, tylko lepiej się upewnić... ;)

  • #42 30 Lip 2011 17:48
    janbernat
    Poziom 38  

    No i zrobiłem. :D
    Jeszcze nie bardzo w to wierzę- i jeszcze trzeba to poprawić.

    Kod: c
    Zaloguj się, aby zobaczyć kod

    A do głównej pętli dodałem:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Jeszcze jest tak że po wyświetleniu >Menu1 nie pojawia się >Menu2> w następnej linijce.
    Dopiero jak przekręcę enkoder to się pojawia.
    No i nie udało mi się tego zrobić na Timer0- on sie kręci bez przerwy a ja potrzebuję włączyć i wyłączyć timer.
    Tak że na razie na Timer1- szkoda bo 16 bitów- ale zrobię na Timer2.
    Teraz kod zajmuje 14 bajtów RAM a nie 12 jak było.
    Ale nie ma _delay() a działa chyba podobnie.
    No i jeszcze jedno- to jest tylko dla jednej funkcji- menufunc1.
    Nie wiem jak będzie dla wszystkich- no i nie wiem jak to dla wszystkich ładnie zrobić.

  • Pomocny post
    #43 31 Lip 2011 10:53
    DXFM
    Poziom 20  

    janbernat napisał:

    No i nie udało mi się tego zrobić na Timer0- on sie kręci bez przerwy a ja potrzebuję włączyć i wyłączyć timer.
    Tak że na razie na Timer1- szkoda bo 16 bitów- ale zrobię na Timer2.

    Spokojnie użyj Timer0, który będzie zgłaszał przerwanie np. co 1ms. W procedurze obsługi tego timera dekrementuj zmienną, jeśli osiągnie 0 to należy zatrzymać dekrementowanie, a w programie głównym sprawdzać, czy jest równa 0. Przed odliczaniem zmienną ustawia się na zadany czas. W tym wypadku jeśli potrzeba odmierzyć 200ms to wpisujesz 200 w chwili rozpoczęcia odliczania do zmiennej.
    W ten sposób za pomocą jednego timera sprzętowego można sobie zrobić wiele programowych o takiej samej rozdzielczości, ale działających niezależnie.

    W niektórych kodach zauważyłem, że ludzie zapalają bit zmiennej przeznaczonej na flagi po przekroczeniu czasu, ale wydaje mi się niepotrzebne zwiększanie zmiennych i czasu operacji.

    A to wycinek z jakiegoś mojego programu pokazujący sposób na sprawdzenie upłynięcia czasu:
    timers.c
    Kod: c
    Zaloguj się, aby zobaczyć kod


    main.c
    Kod: c
    Zaloguj się, aby zobaczyć kod

  • Pomocny post
    #44 31 Lip 2011 12:49
    nsvinc
    Poziom 35  

    Jestem troche zdziwiony implementacją softwareowych licznikow według opisywanych tu sposobów...
    Po co wykonywać zbędny kod w ISRrze (czyli load, wyifowanie, dekrementacja,store), i to jeszcze oddzielnie dla kazdej zmiennej "timer", tak jak tu:

    Kod: C
    Zaloguj się, aby zobaczyć kod


    Można przecież ograniczyć się do budowy jednego globalnego licznika idącego sobie po prostu do przodu...
    Kod: C
    Zaloguj się, aby zobaczyć kod

    ...a potem w pętli głównej używać:
    Kod: C
    Zaloguj się, aby zobaczyć kod

    W efekcie w przerwaniu jest jeden raz load, dekrementacja, store (bez ifa), niezależnie od ilości timeoutów czy timerów których będziemy używać...
    Ponadto w powyższym ifie łatwo zaimplementować "włącznik" (flagę), i napisać
    Kod: C
    Zaloguj się, aby zobaczyć kod

    [A] - elsa z ifem mozna pogonić, jeśli dopuszczalne jest aby kod w "duzym" ifie wykonał się raz natychmiastowo po ustawieniu _pracuj...

  • #45 31 Lip 2011 13:18
    Zbych_
    Poziom 24  

    nsvinc napisał:
    W efekcie w przerwaniu jest jeden raz load, dekrementacja, store (bez ifa), niezależnie od ilości timeoutów czy timerów których będziemy używać...
    Ponadto w powyższym ifie łatwo zaimplementować "włącznik" (flagę), i napisać
    Kod: C
    Zaloguj się, aby zobaczyć kod


    Pomysł dobry, tylko błąd w implementacji:
    (u16)(flicznik-lastTimeout1Flicznik)
    Wynik odejmowania musi być liczbą ze znakiem, inaczej nie będzie to dobrze działało przy przepełnianiu licznika.

  • #46 31 Lip 2011 13:23
    DXFM
    Poziom 20  

    nsvinc, masz rację, twój kod jest prostszy i szybszy w przerwaniu, a sprawdzanie warunku w programie głównym będzie na oko tak samo szybkie. Posiada jednak niebezpieczeństwo zagubienia odmierzenia czasu w przypadku zbyt rzadkiego testowania warunku. Może to wyniknąć np. z czasu wykonania innej części kodu.
    Ja najczęściej wykorzystuję swój sposób, bo dla mnie jest przejrzysty. Nie oznacza, że jest najlepszy. Taki zaproponowałem.

  • Pomocny post
    #47 31 Lip 2011 13:27
    nsvinc
    Poziom 35  

    rly? Dziwne, u mnie działa...

    A ile to jest (u16)((u16)1-(u16)65530)? ;] Właśnie dlatego tam wszędzie musi być unsigned, i ten sam typ, żeby działało przy "przekręceniach" tego typu (jak tu 0-1==65535,65535+1==0)

    DXFM napisał:
    Posiada jednak niebezpieczeństwo zagubienia odmierzenia czasu w przypadku zbyt rzadkiego testowania warunku.

    Zgadza się, dlatego też takie "flicznik"-i robi się u32 lub więcej bitów. Na AVR męczenie 32bitowej zmiennej jest wszystko inne niż wydajne, ale na ARM (a z nimi pracuję na codzień) cala operacja na 32bitowym liczniku zamyka się w trzech instrukcjach (LDR,ADD,STR) i zajmuje 6 cykli zegara...

  • #48 31 Lip 2011 13:43
    Zbych_
    Poziom 24  

    nsvinc napisał:
    rly? Dziwne, u mnie działa...

    A ile to jest (u16)((u16)1-(u16)65530)? ;] Właśnie dlatego tam wszędzie musi być unsigned, i ten sam typ, żeby działało przy "przekręceniach" tego typu (jak tu 0-1==65535,65535+1==0)


    Sorry za zamieszanie, masz rację.

  • #49 31 Lip 2011 14:01
    janbernat
    Poziom 38  

    Próbuję z kodem DXFM- ale coś nie tak:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Komentarze w kodzie.

  • Pomocny post
    #50 31 Lip 2011 14:16
    nsvinc
    Poziom 35  

    Oczywiście że nie ma prawa działać.
    Zasymulujmy:
    - Włazisz w if (flaga_menufunc1), wykonujesz kod w nim, uzbrajasz timer itp itd. if(Timer1==0) się nie wykona, bo właśnie na świeżo uzbroiłeś timer, więc procek będzie kontynuował kod jak gdyby nigdy nic, a następnie zgasi flagę flaga_menufunc1=0; i opuści ciało "dużego" ifa. Tyle...
    Co z tego, że w końcu zmienna Timer1 doleci do zera, skoro nikt nie ustawia flagi flaga_menufunc1, ktora jest niezbędna aby sprawdził się if(Timer1==0)....

    Musisz wywalić if(Timer1==0) poza "dużego" ifa ( if (flaga_menufunc1) ), dopisać flagę...

    Kod: C
    Zaloguj się, aby zobaczyć kod

  • #51 31 Lip 2011 18:31
    janbernat
    Poziom 38  

    Działa- tak samo jak na oddzielnym liczniku.
    Jeden licznik TIMER0- i wywalone _delay().

    nsvinc napisał:
    Musisz wywalić if(Timer1==0) poza "dużego" ifa ( if (flaga_menufunc1) ), dopisać flagę...

    Dzięki za gotowca- to dopisanie flagi poza pętlą to jest to.
    Już usiłowałem tę dodatkową flagę wsadzić w przerwanie od Timer0.

  • #52 01 Sie 2011 09:09
    94075
    Użytkownik usunął konto  
  • #53 01 Sie 2011 12:54
    nsvinc
    Poziom 35  

    No tak, wystarczy timer....;] o ile jest wolny timer, co w moich układach się zdarza raz na 5 projektów. U mnie najczęsciej "flicznik" jest inkrementowany w systicku...

    A, i operacja flicznik++; zajmuje 5 cykli, nie 6...