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

Atmega8: Jak generować PWM na OC1A i przerwanie co 1s z timer0?

pier 10 Mar 2013 18:50 2883 14
  • #1 12042810
    pier
    Poziom 24  
    Witam.

    Koledzy trochę skomplikowałem sobie życie. Zaprojektowałem i wykonałem już płytkę i teraz widzę że mam problem.

    Otóż potrzebuję na wyjściu OC1A generować sygnał pwm ale TIMER1(16-bit) jest mi potrzebny do generowania przerwania co 1s.
    Czy dało by radę generować sygnał pwm z timera0 ale na wyjściu OC1A? Port PD.4 mam zajęty.

    A może nie komplikować i pwm normalnie odpalić z timera1 a przerwanie co 1s za pomocą timera0?

    Tylko żeby wygenerować przerwanie co 1s z timer0 to pewnie trzeba zliczyć ileś tam impulsów aby wyszła 1s.

    Z tego co liczę to przy kwarcu 8MHz i prescalerze ustawionym na 1024 przerwanie z timera0 nastąpi co 0,03276800s. Czy dobrze liczę?

    Jak więc za pomocą timera0 wywołać przerwanie co 1s?

    Jak Radzicie rozwiązać mój problem?
  • #2 12043166
    excray
    Poziom 41  
    Wykorzystaj licznik 8-mio bitowy i w przerwaniu zwiększaj o 1 zmienną i jednocześnie sprawdzaj czy ta zmienna osiągnęła jakąś wyliczoną wartość - powiedzmy 1000. Jeśli nie to wychodzisz z przerwania a jeśli tak to wykonujesz kod który ma być wykonany w przerwaniu. W ten sposób zwiększysz programowo rozdzielczość licznika.
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #3 12043261
    BlueDraco
    Specjalista - Mikrokontrolery
    Ustaw okres PWM na timerze 1 tak, żeby był podwielokrotnością sekundy, czyli n * okres = 1 sekunda

    W przerwaniu timera odliczaj od n do 0, a jak odliczysz - wywołaj procedurę, który ma być uruchamiana raz na sekundę i przeładuj licznik na n.

    Aha, no właśnie ktoś coś podobnego napisał powyżej, tylko ja proponuję zostawić timer 1, który pędzi PWM.
  • #4 12043639
    pier
    Poziom 24  
    Excray właśnie nad czymś takim myślałem. I nawet poczyniłem wstępne obliczenia po których wyszło mi że timer0 przy kwarcu 8MHz i prescaler ustawiony na 1024 przepełni się po 0,03276800s. Tylko jak wyliczyć ile muszę zliczyć tych przerwań aby wyszła 1s?
    Moje wyliczenia są kiepskie bo cały czas wychodzą ułamki.
    Pewnie trzeba ładować jakąś wartość początkową do timera ale jaką?
  • #5 12043808
    excray
    Poziom 41  
    T0 w Atmega8 jest mało użyteczny bo nie ma CTC. Użyj T2. Ustawiasz preskaler na 64 a następnie przerwanie co:
    1. 125 i masz w funkcji wpisać 1000 aby uzyskać 1 s
    2. 250 i masz w funkcji wpisać 500 aby uzyskać 1s
    Albo jeszcze lepiej wykorzystaj ten sam timer co jest od PWM tak jak wspominał BlueDraco
  • #6 12044705
    pier
    Poziom 24  
    Excray a co Masz na myśli pisząc "w funkcji wpisać"? Trochę nie rozumie tego co Napisałeś.
    Pisze program w Bascomie.
  • #7 12045081
    excray
    Poziom 41  
    W funkcji w sensie w tej funkcji którą Ci podałem. Musisz zamiast tego co jest wpisać ++zmienna<250. Niestety nie wiem jak to ma wyglądać w Bascomie.
  • #8 12045349
    Konto nie istnieje
    Poziom 1  
  • #9 12047604
    perlon
    Poziom 20  
    Dla timer 8it bez błędu odliczania można zastosować preskaler 64 i następującą procedurę obsługi ( kod w C )
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    dla preskalera 1024 TCNT0 = 61 przerwanie co 25ms i licznik w przerwaniu do 40
    Błąd odliczenia czasu będzie wynosił -0,16% ale obciążenie procesora mniejsze. Zależy o jak dokładnej 1s mówimy. Jest to jednak angażowanie procesora w odliczanie tej 1s.
  • #10 12047781
    BlueDraco
    Specjalista - Mikrokontrolery
    perlion: błąd tak zaprogramowanego timera będzie nieokreślony, zapewne nie mniejszy niż -0.16%, ale górnej granicy nie da się łatwo podać nie widząc całego programu. Tak się tego nie robi.
    Do odmierzania czasu timer musi pracować w trybie automatycznego ładowania, albo "w kółko". W przypadku, którego dotyczy ten wątek, aż się prosi, żeby do wszystkiego użyć timera 1.
  • #11 12048052
    perlon
    Poziom 20  
    pier napisał:

    Jak więc za pomocą timera0 wywołać przerwanie co 1s?

    To zaproponowałem. Oczywiście błąd będzie nieco większy bo nie uwzględnia czasu jednego cyklu maszynowego na TCNT0=61 (przypisanie jednobajtowe) ale nie będzie dramatycznie większy. Zależy co rozumiemy przez odliczanie 1s.
    Jakiś lepszy patent na ww. zadane pytanie?
  • #12 12048203
    BlueDraco
    Specjalista - Mikrokontrolery
    Nie uwzględniłeś:
    - czasu zakończenia obsługi przerwania, które było obsługiwane w momencie zawinięcia timera,
    - czasu dokończenia bieżącej instrukcji albo sekwencji instrukcji wykonywanej przy zablokowanych przerwaniach,
    - czasu sprzętowej obsługi przerwania przez procesor (składowanie kontekstu, wywołanie procedury,
    - czasu wykonania prologu procedury programowej obsługi przerwania.

    Estymowałbym łączny czas na od kilkunastu do kilku tysięcy cykli maszynowych, w sprzyjających warunkach do kilkudziesięciu. W dodatku ten czas zwykle nie jest deterministyczny.

    Moja propozycja jest wciąż ta sama. Zaprogramować timer 1 jako PWM z limiitem w ICR1, dobierając długość cyklu tak, aby na jedną sekundę wchodziła całkowita liczba cykli PWM.
  • #13 12048611
    perlon
    Poziom 20  
    BlueDraco napisał:
    Nie uwzględniłeś:
    - czasu zakończenia obsługi przerwania, które było obsługiwane w momencie zawinięcia timera,

    OK. Nie wiemy nic o innych przerwaniach, ale może się zdarzyć przepełnienie podczas innego przerwania.
    Cytat:

    - czasu dokończenia bieżącej instrukcji albo sekwencji instrukcji wykonywanej przy zablokowanych przerwaniach,

    OK. Szczególny przypadek krytycznych czasowo sekwencji gdzie celowo blokuje się przerwania. O tym też nic nie wiemy. Blokowanie przerwań dla wykonywania jakiś bloków kodu jest uważane za błąd programisty, ale nie chciałbym tu wywoływać na ten temat dyskusji. Racją jest że może to opóźnić wejście do procedury przerwania timera0.
    Cytat:

    - czasu sprzętowej obsługi przerwania przez procesor (składowanie kontekstu, wywołanie procedury,

    OK
    Cytat:

    - czasu wykonania prologu procedury programowej obsługi przerwania.

    OK
    Cytat:

    Estymowałbym łączny czas na od kilkunastu do kilku tysięcy cykli maszynowych, w sprzyjających warunkach do kilkudziesięciu. W dodatku ten czas zwykle nie jest deterministyczny.

    Hmmm.... z 20 przerwań oprogramujmy 10 pustą obsługą ale tak żeby kompilator jej nie zredukował (chociaż 1 nop) to mamy 10000*10=100000 cykli maszynowych (1% czasu procesora to same wejścia do procedur przerwań nie licząc wyjść i samej obsługi). Trochę sporo.
    Przy zliczaniu przez Timer1 większość z powyższych może również zaburzyć odliczenie tej nieszczęsnej 1s.
    Kolega excray w zasadzie napisał to samo co ja tylko proponował wsadzić kod obsługi do przerwania. Ja zaproponowałem semafor i podałem dokładniejszą konfigurację timer0
    Ponawiam pytanie. Jakiś lepszy patent na timer0?
  • #14 12048810
    BlueDraco
    Specjalista - Mikrokontrolery
    źle postawione pytanie. Problemem jest odliczenie jednej sekundy a nie użycie na siłę timera 0. :)
  • #15 12049490
    pier
    Poziom 24  
    Witajcie.
    Dziękuję wszystkim za zainteresowanie problemem.
    Spróbuje dziś zastosować rozwiązanie proponowane przez excray i emarcus z timerem2 bo tylko to wystarczająco pojmuje(niestety).
    Emarcus a czy wartości 250 nie trzeba ładować do timera po każdym wykonaniu procedury jednosekundowej?

    Już doczytałem i wiem.
    W trybie CTC wartość timera jest porównywana z wartością w rejestrze :D
REKLAMA