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

[ATmega16][C] - Zmiana prescalera w trakcie trwania programu

Shock0991 10 Sty 2015 15:37 723 7
  • #1 14314380
    Shock0991
    Poziom 10  
    Witam serdecznie forumowiczów.
    Jestem w trakcie budowy generatora sygnału PWM o zmiennym wypełnieniu oraz częstotliwości. Wypełnienie 0-100% co 5%, częstotliwość 1-50 kHz co 1 kHz (plus kilka częstotliwości poniżej 1k). Generator będzie częścią nieco większego projektu.
    Całość ma działać mniej więcej w taki sposób: odpalam timer1 w trybie PWM z korekcją fazy i częstotliwości (tryb 8 w tym uC), robię odczyt z ACD (potencjometr 1), w zależności od odczytu podstawiam odpowiednią wartość pod ICR1 (który ustala mi wartość TOP przy zliczaniu impulsów (mam już zadaną częstotliwość)), robię odczyt ADC (potencjometr 2), w zależności od odczytu wybieram wypełnienie, liczę wypełnienie na podstawie pomiaru i ICR1, podstawiam obliczoną ilość taktów pod OCR1A (który odpowiada za zmianę stanu). Wszystko ładnie pięknie, działa tak jak chcę, ale niestety tylko powyżej 10kHz. Przy niższych częstotliwościach wypełnienie wariuje. Wydaje mi się, że program gubi się przy obliczaniu wypełnienia, ze względu na duże wartości liczbowe. W związku z tym chciałbym zmienić prescaler dla częstotliwości niższych niż 10kHz (domyślnie działam na prescalerze = 1), co automatycznie zmniejszy mi wartości liczbowe dla ICR1 i OCR1A. I tutaj pojawia się moje pytanie, czy jest możliwość zmiany prescalera w trakcie działania programu? Jeśli tak, to jak to zrobić? Próbowałem zmieniać bit TCCR1B, ale niestety bez rezultatów. Pracuję na ATmega16 w języku C.
  • #2 14314455
    BlueDraco
    Specjalista - Mikrokontrolery
    Pokaż program. Preskaler timera można zmieniać modyfikując pole CS1x.
  • #3 14314544
    Shock0991
    Poziom 10  
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    W tych seriach if wybieram wartości wg obliczonych. Kod jeszcze do uporządkowana. Generalnie chciałbym mieć prescaler = 8 dla linijek w których jest komentarz //pr8. W tych linijkach będą zmienione wartości ICR1, jeśli uda się ustawić dla nich prescaler = 8. Dziękuję za zainteresowanie ;)
  • Pomocny post
    #4 14314817
    tmf
    VIP Zasłużony dla elektroda
    Problemem może byc:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Domyślnie jest to liczone na typie int, a dla niektórych kombinacji argumentów znacznie przekraczasz pojemność tego typu. Dodaj rzutowanie na uint32_t i przynajmniej jeden problem powinien znkinąć.
  • #5 14315055
    BlueDraco
    Specjalista - Mikrokontrolery
    A mnie bardzo ubawł kod, w którym po sprawdzeniu że ADCW jest mniejsze od 50 wykonujesz jeszcze sprawdzeni, czy nie jest ono większe od 20 kolejnych wartości większych od 51.

    Przy okazji: co ma zrobić program, kiedy ADCW będzei równe 50?

    Skasuj te dwa fragmenty z seriami porównań i napisz je całkiem od nowa. Pierwsze 50 porównań można zastąpić jedną linijką

    duty = ADCW / 50 * 5;
  • #6 14315269
    Shock0991
    Poziom 10  
    Kolumny porównań docelowo zostaną zastąpione czymś prostszym, jednak do testów moim zdaniem się nadają.

    tmf napisał:
    Problemem może byc:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Domyślnie jest to liczone na typie int, a dla niektórych kombinacji argumentów znacznie przekraczasz pojemność tego typu. Dodaj rzutowanie na uint32_t i przynajmniej jeden problem powinien znkinąć.


    Problemem faktycznie jest ta linijka. Spróbowałem rzutowania, jednak chyba robię coś źle, ponieważ nic się nie zmieniło. Po rozbiciu tej setki na 2-3 cyfry jest poprawa. Niestety program przy niskich częstotliwościach nadal błędnie oblicza wypełnienie (teraz poniżej 2kHz, wcześniej poniżej 10).

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


    Czy powyższa linijka jest prawidłowym sposobem rzutowania?
  • Pomocny post
    #7 14315317
    BlueDraco
    Specjalista - Mikrokontrolery
    Sposób rzutowania jest prawidłowy, ale wynik będzie niezgodny z Twoimi oczekiwaniami.

    Prawdopodobnie chodzi Ci o:

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


    Te serie porównań są i bezsensowne i całkowicie błędne. W złośliwym przypadku może nigdy nie nastąpić podstawienie wartości DutyCycle.
  • #8 14315438
    Shock0991
    Poziom 10  
    Pokombinowałem, spróbowałem każdą zmienną rzutować osobno w następujący sposób:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    i zadziałało. Teraz przy każdej częstotliwości mam zmianę wypełnienia zgodnie z założeniami ;) Dziękuję bardzo za pomoc.
REKLAMA