Pyra pisze:Jeśli dobrze zrozumiałem...
Jako zegar pracuje przepełnienie sprzętowego PWM, jego impulsy są cały czas zliczane.
Dokładnie tak. Procedurę obsługi przerwania mam podpiętą pod przepełnienie timera i tam inkrementuję sobie liczniki przy każdym pełnym cyklu timera.
I to one przy dobrze przyjętych podziałach są moim "zegarem czasu rzeczywistego" z wystarczającą rozdzielczością.
Pyra pisze:Klik powoduje zczytanie wartości "timera" i dalej mierzy czas klika.
Robię to prościej - pierwszy klik zeruje liczniki czasu - dzięki temu nie muszę odejmować
Pyra pisze:Klik powoduje ustawienie jakiejś zmiennej, jeśli natomiast przed upływem sekundy pojawi się następny klik, zmienna jest zwiększana o jeden i proces odliczania sekundy jest wznawiany itd.
Dokładnie tak - liczę czas od ostatniego kliku (nie ważne, czy pojedynczego, czy wielokrotnego), a na drugiej zmiennej zliczam liczbę klików złapanych w oknie czasowym <1s (by grupować wielokliki). Przy użyciu tego samego licznika czasu realizuję zabezpieczenie przed odbiciami styków. Aby stan został uznany za stabilny musi trwać przez N cykli timera (u mnie przyjąłem ok. 1/64s)
Pyra pisze:Jeśli po upływie sekundy nie nastąpi kolejny klik, to odczytywana jest zmienna zawierająca liczbę klików, interpretowana i zerowana.
Można też tak, ale Twoje rozwiązanie będzie miało niezbyt szczęśliwą cechę sekundowego opóźnienia - cokolwiek byś nie kliknął, to rezultat pojawi się po 1s.
Jest to intrygujące. Ja robię tak, że na bieżąco wykonuje czynności (sterowanie trybami) na podstawie bieżącej wiedzy.
Pojawi się 1-wszy klik, to od razu (gdy przejdzie sito na odbiciach styków) wykonuję zmianę jakby to był pojedynczy klik, gdy w czasie (np.1 sek) pojawi się drugi klik, to wykonuję procedurę obsługi 2-klika itd. Dzięki temu podejściu (nieco bardziej złożonemu) reakcja mojego sterownika jest natychmiastowa.
Pyra pisze:Ja przyjąłem też w jednej z wersji podobne rozwiązanie, z tym, że nie wykorzystuję timera a generuję przerwy (no cóż nie ten poziom znajomości programowania
)
Po wykryciu stanu na porcie program skacze do procedury obsługi, tam sprawdza minimalny czas klika, jeśli ok, zwiększa zmienną KLIk o 1 i skacze do pętli odliczającej 1s i sprawdzającej stan portu. Przy ponownej zmianie stanu portu, zmienna KLIK jest ponownie zwiększana o 1 i ponownie wchodzi do pętli. Jeśli sekunda minie, zawartość zmiennej KLIk jest interpretowana jako skok do określonej części programu i zerowana.
Takie rozwiązanie też działa, z pewnością jest dużo prostsze w realizacji, choć prawdopodobnie zajmuje więcej miejsca w kodzie.
Pyra pisze:Z przerwaniami miało być podobnie, po prostu odpadła by część sprawdzająca stan portu w różnych miejscach programu.
Wyniesienie "przycisku" (detekcji zaniku zasilania) na przerwanie też jest dobrym pomysłem - zyskujesz na czystości kodu i jednym miejscu obsługi.
W procedurze przerawnia robisz całą implementację wieloklików z odbiciami itd. i wystawiasz na jakiś zmiennych same stany typu (0-brak kliku, 1-klik,... 3-kliki itd.) które w głównym kodzie interpretujesz już synchricznie odczytując kody z w/w zmiennej.
Pyra pisze:i tu jest problem, bo program się rozrasta....
Dlatego też ja piszę w asm... (nie tylko szybciej pracuje kod, ale i mniej miejsca zajmuje - a poza tym wiem, co procesor w każdym takcie robi)
Pyra pisze:Tylko, że w assemblerze to ja pisałem programy 20 lat temu na procesor Z80
Ja też... i 20 lat temu i na Z80
Chwilę później przesiadłem się na rewelacyjną jak dla mnie serię 8051 - to był niesamowity przeskok, dużo uniwersalnych rejestrów, peryferia, wersje z EEPROMem w środku (a później z Flashem), alternatywnie na zewnątrz też jednym ruchem można było wyprowadzić współdzieloną magistralę i połówki 8-bitowe adresu zatrzaskiwało by uzyskać 16 bitów adresu do zewnętrznej pamięci kodu itd.
A później przeszedłem z asm na 80x86 - ale tam już nie było tak fajnie jak w małych RISC`ach... mało rejestrów, silna specjalizacja rejestrów (mała uniwersalność) - bez stosu ciężko jest cokolwiek zrobić. A w takim ATtiny to wszystko mam na rejestrach, które traktuje jak zwykłe zmienne - stosu praktycznie nie używam (poza zachowywaniem stanu rejestru statusowego w czasie proc.obsł.przerwania).
Później 10 lat przerwy z MCU i radosny come-back z ATtiny
Dziś jak patrzę jak wygląda tworzenie oprogramowania na dzisiejsze MCU, czego to one w środku nie mają itd. to łezka się w oku kręci. Ile razy latałem do kasownika UV kasować EPROMy, bo coś nie zadziałało tak jak powinno ile godzin spędzałem na symulatorach, by się upewnić, że działa jak należy itd...
Dziś ładuję w 2 sek. kod do układu na płytce docelowej i klikam na docelowym układzie - nieporównywalnie szybciej i łatwiej. A i oprogramowanie o niebo lepsze (korzystam z darmowego AVR studio).
Pyra pisze:Pamiętasz gdzie on był? Teraz tylko BASCOM
No pewnie... ZX-81, ZX-Spectrum, jakieś Atari, Amstrady itd. generalnie pierwsze 8-miobitowce.
8051 zaś popularne są w sterownikach klawiatór PC-towych - robią skanowanie klawiszy, komunikację i proste funkcje (pamięć caps/scroll/num-locków, auto-repetycje itd.)
Z "większych" RISC`ów to miałem okazję bawić się Sparc`ami - też fajnie to wyglądało - znacznie prościej i szybciej niż na x86.
Pyra pisze:df pisze: Jak najbardziej _można_ wyzwalać przerwania z portu zarówno stanem (L lub H) jak i zboczem (R lub F). A zbocza tu wykrywa się nie przejściem z niskiego w wysoki lub odwrotnie, ale zmianą stanu w kolejnych cyklach zegarowych (zegar portów I/O) - dobrze to widać na diagramach w PDF`ie, że zatrzaskiwany jest stan i w każdym cylku porównywany stan portu z jego wartością (zatrzaśniętą w poprzednim cyklu - coś jak J-K master-slave).
A ja gdzieś wyczytałem, że ATTiny ma przerwania wyzwalane tylko poziomami i program obsługi w skrajnych wypadkach może się zapętlać, dlatego z rezerwą podchodziłem do tego rozwiązania
Być może chodziło o budzenie z power-down.
Zobacz (cytuję za:
http://atmel.com/dyn/resources/prod_doc ... oc8126.pdf)
9.2 External Interrupts
The INT0 interrupts can be triggered by a falling or rising edge or a low level.
9.3.1 MCUCR – MCU Control Register
Table 9-2. Interrupt 0 Sense Control
ISC01 ISC00 Description
0 0 The low level of INT0 generates an interrupt request.
0 1 Any logical change on INT0 generates an interrupt request.
1 0 The falling edge of INT0 generates an interrupt request.
1 1 The rising edge of INT0 generates an interrupt request.
Zgadza się?
Natomiast tak jak napisałem z uwagi na brak zegara w power-down detekcja jest na stanach:
7.1 Sleep Modes
Note: 1. For INT0, only level interrupt.
7.1.3 Power-down Mode
... an external level interrupt on INT0, or a pin change interrupt can wake up the MCU.
This sleep mode halts all generated clocks, allowing operation of asynchronous modules only.
Natomiast sam sposób detekcji zmiany stanu (detekcja zboczy R / F) ładnie ujęta jest na diagramie np.
9.2.2 Pin Change Interrupt Timing
Pozdrawiam,