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

[Atmega8] [Atmega8][C] - Jak zaimplementować odliczanie godzin od 100 do 0?

dardaw2 28 Paź 2014 20:49 1620 26
  • #1 14082602
    dardaw2
    Poziom 10  
    Witam
    Buduję sterownik na własne potrzeby, mam już zrobioną obsługę wyświetlacza segmentowego poprzez multipleksowanie, czujnik DS18b20, do tego diody i switche.
    Chciałbym też zrobić odliczanie czasu od 100 godzin do 0(skok co godzinę, minuty i sekundy są nieważne). Niestety nie wiem jak to zrobić.
    Najlepiej byłoby wykorzystać samą Atmegę, nie chce dodawać dodatkowego osprzętu, chyba że to konieczne.
    Czekam na propozycje.
  • #2 14082732
    piotrva
    VIP Zasłużony dla elektroda
    Uruchom timer, koniecznie tak doliczony, żeby nie wprowadzać dodatkowych błędów ewentualnymi ułamkami w ilości impulsów na sekundę/minutę.
    Potem w przerwaniu zliczasz minuty/sekundy/cokolwiek i odmierzasz czas.
    Można też zastosować kwarc zegarkowy podłączony do pinów TOSC1/TOSC2 (XTAL) i z niego czerpać sygnał bardziej precyzyjny niż z normalnego sygnału taktującego procesor (wewnętrzny generator jest mało precyzyjny).
  • #3 14082975
    dardaw2
    Poziom 10  
    Potrzebuję zliczać godziny i nie musi być do dokładnie. Jeśli zamiast godziny, będę miał godzinę i minutę, albo 59 minut, to nic się nie stanie.

    Mam już uruchomiony jeden timer do multipleksowania: ISR(TIMER2_COMP_vect)
    Jak dodać drugi, żeby się to nie gryzło? Po wyzwoleniu przerwania zewnętrznego przez switch, zamiast temperatury wyświetlić się ma ilość tych godzin.
    Aha, bo tego nie napisałem. Tych odliczeń chciałbym mieć 3 różne. Jedno od 100, drugie od 200, trzecie od 300. Każdy ma działać niezależnie.

    Wyświetlacz ustawiony jest w ten sposób(3 sekcje):
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Jak obliczyć wartość timera dla tak dużego czasu zmiany?
  • #4 14083051
    piotrva
    VIP Zasłużony dla elektroda
    Samym timerem tego nie zrobisz - ustawiasz po prostu drugi timer na jakiś długi okres (zależnie od kwarcu, ale powinieneś być w stanie osiągnąć około 1 minuty) i potem w przerwaniu zliczasz minuty, i po zliczeniu 60 odejmujesz godzinę.

    Jeśli masz przerwanie powiedzmy co 1 minutę to możesz w nim zmniejszać wartość kilku liczników.
  • #5 14083087
    BlueDraco
    Specjalista - Mikrokontrolery
    Nie potrzebujesz drugiego timera. W obsłudze przerwania timera wyświetlacza dokładasz blok:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • Pomocny post
    #6 14083137
    piotrva
    VIP Zasłużony dla elektroda
    Racja - jeżeli pierwszy timer masz ustawiony na odliczanie jakiejś podwielokrotności sekundy to wtedy wszystko zrobisz na tym samym timerze.
  • #7 14083173
    vonar
    Poziom 28  
    dardaw2 napisał:
    Potrzebuję zliczać godziny i nie musi być do dokładnie. Jeśli zamiast godziny, będę miał godzinę i minutę, albo 59 minut, to nic się nie stanie.

    Ale wewnętrzny oscylator ma marną dokładność, zamiast 100 godzin możesz mieć 103 albo 97. Potrzebny będzie kwarc, jak już piotrva zasugerował.
  • #8 14083290
    dardaw2
    Poziom 10  
    BlueDraco napisał:
    Nie potrzebujesz drugiego timera. W obsłudze przerwania timera wyświetlacza dokładasz blok:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Przerwanie Timera mam na 150Hz(3 bloki wyświetlacza). Jak to przyrównać do odliczenia godziny?

    Nie za bardzo rozumiem ten fragment:
    -- div_1s

    vonar napisał:
    dardaw2 napisał:
    Potrzebuję zliczać godziny i nie musi być do dokładnie. Jeśli zamiast godziny, będę miał godzinę i minutę, albo 59 minut, to nic się nie stanie.

    Ale wewnętrzny oscylator ma marną dokładność, zamiast 100 godzin możesz mieć 103 albo 97. Potrzebny będzie kwarc, jak już piotrva zasugerował.

    Sądzę, że taka dokładność będzie wystarczająca. To ma sygnalizować konieczność wymiany elementów eksploatacyjnych. Czy będzie to trcohę po 100 czy przed 100 godzinami, to i tak będzie dobrze.
  • #9 14083317
    BlueDraco
    Specjalista - Mikrokontrolery
    Miało być:
    if (-- div_1s == 0)
    - poprawiłem w listingu powyżej.
    Zmienna div_1s służy do odliczania sekundy, czyli po wyzerowaniu inicjujesz ją na wartość równą częstotliwości przerwań. 150Hz to decydowanie za mało do poprawnej obsługi wyświetlacza. Częstotliwość przerwań powinna wynosić ok. 300 lub 400 * liczba_cyfr - inaczej wyświetlacz "pływa" lub "wibruje" w oczach obserwatora.
  • #10 14083357
    dardaw2
    Poziom 10  
    Domyśliłem się, że ma to być porównanie, ale nie wiem w jakim celu są te 2 minusy przed div i jakiego typu ma być ta zmienna div_1s? volatile?

    Nie widzę problemu, żeby zwiększyć częstotliwość, lecz dane są z książki "Mikrokontrolery AVR język C" Mirosław Kardaś. I jak tłumaczy to autor, 50Hz jest wystarczające, aby oko ludzkie, nie wyłapało zmiany.

    Wracając do tematu. Jak mam ją zainicjować do częstotliwości timera?
  • Pomocny post
    #11 14083401
    vonar
    Poziom 28  
    dardaw2 napisał:
    nie wiem w jakim celu są te 2 minusy

    Operator predekrementacji. Zmniejsza div_1s o jeden.

    dardaw2 napisał:
    jakiego typu ma być ta zmienna div_1s? volatile?

    Może być np. unsigned short. Lokalna statyczna w procedurze obsługi przerwania.

    dardaw2 napisał:
    50Hz jest wystarczające, aby oko ludzkie, nie wyłapało zmiany.

    Nie jest wystarczające (no, może dla żarówek... :D ).

    dardaw2 napisał:
    Jak mam ją zainicjować do częstotliwości timera?

    Tak jak pokazał BlueDraco w poście #5 (chyba, że chodzi o coś innego).


    Wykorzystujesz oscylator 2 MHz?
  • #12 14083649
    BlueDraco
    Specjalista - Mikrokontrolery
    Częstotliwości odświeżania:
    30 Hz - cyfry pływają i podskakują
    50 Hz - cyfry mrowią
    100 Hz - jeśli weźmiesz głowę w imadło i patrzysz na wprost na wyświetlacz - jest ok
    150 Hz - możesz już nawet ruszać głową (byle niezbyt szybko), tylko nie chodź
    300 Hz - jeśli wyświetlacz nie jest zamontowany na pojeździe, a obserwator stoi lub idzie - jakoś to wygląda
    1500 Hz - można jeździć i biegać i wciąż widać to, co trzeba.

    ;)
  • Pomocny post
    #13 14084598
    dondu
    Moderator na urlopie...
    dardaw2 napisał:
    ... nie wiem w jakim celu są te 2 minusy przed div ?

    Operatory dekrementacji, a dokładniej predekrementacji: http://mikrokontrolery.blogspot.com/2011/02/kurs-jezyka-c-spis-tresci.html

    Są jeszcze operatory postdekrementacji - dobrze opanuj różnicę, bo w tym przypadku jest istotna.
  • #14 14085339
    dardaw2
    Poziom 10  
    @ vonar
    Tak żebym dobrze zrozumiał.
    Czyli w prostszy sposób wyglądało by to tak?
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    vonar
    vonar napisał:
    Wykorzystujesz oscylator 2 MHz?

    Wykorzystuje wewnętrzny z Atmega8, czyli 8Mhz.

    BlueDraco napisał:
    Częstotliwości odświeżania:
    30 Hz - cyfry pływają i podskakują
    50 Hz - cyfry mrowią
    100 Hz - jeśli weźmiesz głowę w imadło i patrzysz na wprost na wyświetlacz - jest ok
    150 Hz - możesz już nawet ruszać głową (byle niezbyt szybko), tylko nie chodź
    300 Hz - jeśli wyświetlacz nie jest zamontowany na pojeździe, a obserwator stoi lub idzie - jakoś to wygląda
    1500 Hz - można jeździć i biegać i wciąż widać to, co trzeba.

    ;)

    Zrozumiałem, zastosuje twoje rady. Dlaczego p. Kardaś wypisuje takie rzeczy w swojej książce?

    dondu napisał:
    dardaw2 napisał:
    ... nie wiem w jakim celu są te 2 minusy przed div ?

    Operatory dekrementacji, a dokładniej predekrementacji: http://mikrokontrolery.blogspot.com/2011/02/kurs-jezyka-c-spis-tresci.html

    Są jeszcze operatory postdekrementacji - dobrze opanuj różnicę, bo w tym przypadku jest istotna.

    Dzięki za link, na pewno się przyda. Faktycznie różnica występuje w kolejności wykonywania czynności przypisania i zmiany wartości.
  • Pomocny post
    #15 14085706
    BlueDraco
    Specjalista - Mikrokontrolery
    Nie potrzebujesz volatile, a jeśli chcesz skomplikować kod, to faktycznie zapis:
    div_1s=div_1s-1;
    if (div_1s == 0)

    działa podobnie (tylko może trochę wolniej), jak
    if (--div_1s == 0)

    Zmienna div_1s powinna być zadeklarowana w procedurze przerwania timera jako
    static uint16_t (i zapewne powinna zliczać w dół od wartości znacznie większej, niż 150).

    Książki MK zawierają sporo dość kontrowersyjnych (delikatnie rzecz ujmując) tez. Ja w każdym razie za ich treść nie odpowiadam.
  • #16 14085864
    dardaw2
    Poziom 10  
    BlueDraco dondu vonar piotrva Dzięki chłopaki za pomoc i wytłumaczenie kilku kwestii. Wszystko działa jak powinno. Do godziny nie chciało mi się już czekać, ale sekundy są odliczane wystarczająco dokładnie.

    Wszystkie zmienne zrobiłem na volatile(nawyk spowodowany powyższą książką).

    Jeszcze raz dziękuje i pozdrawiam :D
  • #17 14088900
    dardaw2
    Poziom 10  
    Mam jeszcze jedno pytanie.
    Teraz wyświetlacz pokazuje mi na okrągło jeden czas.
    Mam ustawione przerwanie INT1 i po jednym wciśnięciu przycisku chciałbym odliczanie od 100, po drugim od 200, po trzecim od 300 godzin.

    Jak ustawić zmienianie tego co ma pokazywać wyświetlacz?
    Dodać if-a w timerze, który reaguje na ilość wciśnięć zliczanych w przerwaniu INT1?
  • #18 14089121
    BlueDraco
    Specjalista - Mikrokontrolery
    Nie używaj przerwania od przycisku. Testuj przycisk w przerwaniu timera. Było już na ten temat ze 100 wątków. Ile masz tych przycisków? Schemat jakiś by się przydał i opis, jak to ma działać.
  • #19 14092820
    dardaw2
    Poziom 10  
    BlueDraco
    Chciałbym użyć przerwania zewnętrznego, z tego powodu, że mam już opanowaną jego obsługę i chciałbym, żeby wyzwalało się w dowolnym momencie programu.

    Przełącznikiem mam wybierać, który licznik ma się aktualnie wyświetla, bo będzie ich 3.
    dardaw2 napisał:

    ...po jednym wciśnięciu przycisku chciałbym odliczanie od 100, po drugim od 200, po trzecim od 300 godzin.


    W planach mam jeszcze drugi przycisk, który będzie resetował licznik, który jest wyświetlany w danym momencie. Nie ma go na schemacie.

    Schemat:
    [Atmega8] [Atmega8][C] - Jak zaimplementować odliczanie godzin od 100 do 0?
  • #20 14092828
    piotrva
    VIP Zasłużony dla elektroda
    Obsługę przycisków też zrób w przerwaniu timera, jak radzi BlueDarco - nie ma sensu obsługa przerwania zewnętrznego, bo zniszczy Cię drganie styków...
  • #21 14092877
    dardaw2
    Poziom 10  
    A w obsłudze przycisku w timerze nie uświadczę drgań styków? To fizyczne zjawisko.
    Jak obsłużyć przycisk w timerze? Podobnie jak z przykładu poniżej?

    Obsługę przerwania robiłem w ten sposób:
    Kod: text
    Zaloguj się, aby zobaczyć kod

    Delay załatwił drganie styków. W while-u sprawdzałem ile było wciśnięć i zapalałem diodki. Po dojściu do jakiegoś poziomu wciśnięć lub drugim przyciskiem(kolejne przerwanie), zerowałem zmienną przycisk.
  • #22 14092970
    piotrva
    VIP Zasłużony dla elektroda
    Toż to najgorsza możliwa rzecz - opóźnienie w przerwaniu! To zbrodnia dla programu!

    Jak się to robi profesjonalnie? Np. tak:
    W każdym przerwaniu sprawdzam stan przycisku, jeśli jest wciśnięty to liczę liczbę przerwań podczas których jest wciśnięty, jeśli jest puszczony to tę liczbę zeruję. Jeśli liczba przekroczy zadaną ilość (~czas drgań) to wykonuję działanie.

    Poszukaj bo na prawdę było o tym sporo.
  • #23 14093134
    dardaw2
    Poziom 10  
    piotrva rozumiem, że mówisz o obsłudze w timerze? Zliczać ilość przerwań, tak samo jak w liczniku powyżej?
    Jak duża ma być ta liczba, o której mówisz? Cykli timera jest 150 na sekunde. Czas drgania styku(wg. deklaracji producenta) to około 20us.

    piotrva napisał:
    Toż to najgorsza możliwa rzecz - opóźnienie w przerwaniu! To zbrodnia dla programu!

    Wiem, że tak się nie robi, lecz chciałem powoli ruszyć z uruchomieniem całości. Gdy zaczęło by to działać, zastosowałbym tę metodę eliminacji:
    Link
  • #25 14094002
    dardaw2
    Poziom 10  
    Próbuje przerobić ten kod pod mój projekt i coś mi nie wychodzi.
    Sterownik sam zmienia, który licznik się wyświetla. Zmiany są losowe, tak jak by wariowało zmienianie. Raz wolniej raz szybciej. Odpiałęm fizycznie przycisk, a zmiany nadal występują.

    Przycisk mam podpięty pod port PD6, a zmiany jakie zrobiłem to:
    Kod: text
    Zaloguj się, aby zobaczyć kod


    Kod oryginalny:
    Kod: text
    Zaloguj się, aby zobaczyć kod


    Zliczanie wciśnięć mam w ten sposób:
    Kod: text
    Zaloguj się, aby zobaczyć kod


    Zrobiłem zmianę wyświetlanych liczników na INT1 i z delay, lecz już widzę problem w postaci zawieszenia wyświetlania i zliczania sekund na czas wciśnięcia. Wygląda to mało profesjonalnie, lecz realizuje swoje zadanie.
    Chciałbym to poprawić.
  • Pomocny post
    #26 14095082
    piotrva
    VIP Zasłużony dla elektroda
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Przemyśl dobrze tę linijkę...
  • #27 14095140
    dardaw2
    Poziom 10  
    piotrva napisał:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Przemyśl dobrze tę linijkę...

    Wszystko jasne.
    Poprawiłem to na takie coś:
    Kod: text
    Zaloguj się, aby zobaczyć kod

    Tylko teraz jest tak. Jak przycisk nie jest wciśnięty to wyświetla się jeden timer, jak przycisk trzymam to wyświetla się drugi. Gdy puszczę przycisk powraca do wyświetlania pierwszego(docelowo liczników ma być 3). Jak sprawdzić parametr stan_przyciskow jaki ma stan, czyli jak zliczać wciśnięcia przycisku?
REKLAMA