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

Dziwne zachowanie timera2 w atmega8

oskar777 31 Gru 2010 08:54 1826 8
REKLAMA
  • #1 8938014
    oskar777

    Poziom 26  
    Witam Was mam takie pytanie, być może wynika one z mojej niewiedzy.
    Mam program, który będzie odczytywał temperaturę , ponieważ czujników jest sztuk 4 to chciałem po 2 pomiary pokazać na LCD.

    Pierwszy pomysł jaki mi przyszedł do głowy to funkcja przełączająca i delay na 3-5 sekund. Niestety założenie było błędne, ponieważ w głównej pętli mam jeszcze odwołanie do takiego mini menu z ustawieniami różnymi i taki pomysł skutecznie blokował wszystko.

    Tak więc znajomy podpowiedział mi by skorzystać z licznika oraz licznika timera.
    Timer2 trochę za szybko się przepełnia (timer 0,1 mam zajęty). Tak więc pomysłem było wsadzenie w przerwanie licznika który zliczy np do 10000 i zmieni flagę. Tą flagę potem odczytuje w pętli głównej i zmieniam wyświetlaną treść.


    Problem jest z tym że timer działa dosyć dziwnie.
    Kod na wstępie najważniejszy

    
    // deklaracja licznika jako globalna zmienna
    uint16_t ccc; 
    
    // main nie w pętli
    TCCR2 |= (1 << CS22);   
    TCCR2 |= (1 << CS20);   
    TCCR2 |= (1 << CS21);   
    //TCNT2 |= (0 << CS20) | (0 << CS21) | (1 << CS22);   
    TIMSK |= (1 << TOIE2); // zezwolenie na przerwania
    
    // przerwanie
    ISR(TIMER2_OVF_vect) // przerwanie dla timer2 - 8bit
    {
    ccc++;
    uint16_t buff;
    itoa(ccc, buff, 10); 
    LCD_WriteText(buff); 
    LCD_WriteText(" "); 
    _delay_ms(700);
    
    if(ccc >= 100) {
    
    LCD_Clear();	  
    }
    }
    

    I teraz kilka wyjaśnień, kod jest przykładowy w przerwaniu po uruchomieniu na LCD mam tak
    1 2 3 4 5 6 7 8 (potem dalszy zapis znika na LCD na 2-3 sekundy i pojawia się w drugim wierszu)
    drugi wiesz: 1113 311114 (miedzy nimi jest jedna jeszcze liczba ale ucięta) 811119 itd

    O co chodzi ?, czemu tak się dzieje i jak to naprawić.

    Druga dość dziwna sprawa taki zapis działa
    
    TCCR2 |= (1 << CS22);   
    TCCR2 |= (1 << CS20);   
    TCCR2 |= (1 << CS21);   
    ale ten
    TCNT2 |= (1 << CS20) | (1 << CS21) | (1 << CS22);   
    lub ten
    TCNT2 |= (1 << CS20 | 1 << CS21 | 1 << CS22);   
    Już nie.
    


    Moim zdaniem powinny być te zapisy równoważne. Niestety w dwóch ostatnich timer nie startuje.

    Będę wdzięczny za pomoc bo nie wiem o co biega, czemu ccc nie liczy prawidłowo.

    Pozdrawiam.
  • REKLAMA
  • #2 8938135
    landy13
    Poziom 31  
    TCNT2 |= (1 << CS20) | (1 << CS21) | (1 << CS22); 
    Gdybyś wpisywał to do rejestru TCCR2 to by działało.

    Kontroler wyświetlacza jest przewidziany do różnych wyświetlaczy, nawet tych, które mają 40 znaków w linii. Ty masz tylko 16. Niewidoczne znaki wyświetlane są na pozycjach, które fizycznie nie istnieją. Musisz sam zadbać o przeniesienie do drugiej linii.
    buff zadeklaruj: char buff[4];

    Czasochłonne operacje jak obsługa wyświetlacza a tym bardziej długi delay w przerwaniu przysporzą Ci jeszcze wielu kłopotów.
    Przerwanie nawet przy FCPU=1MHz wykonuje się co 262ms. A delay masz 700ms.
  • REKLAMA
  • #3 8938808
    oskar777

    Poziom 26  
    Dzięki z tym
    TCCR2 masz racje.

    Kod zaczął wstępnie działać, miałem jeszcze jakiś śmieć w głównej pętli oraz za duża wartość licznika.

    Teraz inne pytanie bo nie wiem jak sobie z tym poradzić kod na zmianę stanu wygląda tak
    
    ISR(TIMER2_OVF_vect, ISR_NOBLOCK)
    {
    ccc++;
    if(ccc > 100) {
    	stan = 1;
    	ccc = 0;
    } else {
    	stan = 0;
    }
    // "przełącznik"
    char blokada;
    unsigned char sw_pin(void) {
    _delay_ms(20);
    blokada ^= 1 << 0;
    return blokada;
    }
    
    // jego wywolanie
    if(stan == 0) {
    } else if(stan == 1) {
    sw_temperature = sw_pin();
    }
    

    sw_temperature przełącza temperaturę na LCD przez instrukcje switch.

    To działa tylko
    - przełączanie odbywa się nie proporcjonalnie tzn 0 jest 2-3x dłużej od 1 (prawdopodobnie dlatego, że 1 jest krótkim impulsem)
    - jak zrobić więcej stanów np 1,2,3 które przełączają się w jednakowych odstępach czasu.

    Próbowałem na różne sposoby robić warunki w przerwaniu ale nic z tego nie wychodziło.

    Może ktoś spotkał się z tym problemem i wie jak to naprawić ?.






    Próbowałem na chwilę zatrzymać timer ale też nie
  • REKLAMA
  • #5 8939665
    oskar777

    Poziom 26  
    W takim razie jak wektor przerwań powinien wyglądać ?
    tak ?
    
    ISR(TIMER2_COMP_vect, ISR_NOBLOCK) {...}
    


    Licznik liczy do wartości wpisanej w TCNT2 ?, jeżeli tak to wartość 0-255 wiele mi chyba nie da jak ja potrzebuje tak duże opóźnienia, ale mogę się mylić.
    znalazłem wzór na wartość tego rejestru

    Potrzebna ilość cykli = (1 / częstotliwość pożądana) / (preskaler / częstotliwość zegara)

    Jest to poprawny zapis ?

    A jeszcze się zapytam jeżeli dobrze rozumie to z któryś rejestrów zmienia się po przeładowaniu licznika, może bym to wykorzystał. Tylko, który to jest ?.
    Wtedy dał bym odczyt tego w głównej pętli jakiś mały licznik i po sprawie. Prawdopodobnie.
  • #6 8940366
    landy13
    Poziom 31  
    Kolega Light-I tak trochę nie na temat. Tryb CTC nic tu nie polepszy, bo licznik i tak chodzi dookoła bez przeładowywania. Także dokładność nie musi być wysoka, potrzebny czas 3-5s.

    Ad rem.
    ISR(TIMER2_OVF_vect)
    {
    ccc++;
    if(ccc > 100) {
       ccc = 0;
       stan++;
       if(stan>2) stan=0;}
    } 

    Masz trzy równo trwające stany: 0, 1 i 2. W pętli głównej reagujesz na nie wg potrzeb.
  • REKLAMA
  • #7 8940538
    Fredy
    Poziom 27  
    oskar777 napisał:


    Licznik liczy do wartości wpisanej w TCNT2 ?


    Licznik liczy do wartości wpisanej w rejestrze OCR2. Potem się zeruje i może dać w tym miejscu przerwanie a także zmienić stan na pinie OC. Tak więc możesz swobodnie regulować sobie ten czas zmieniając wpis w rejestrze.
  • #8 8943331
    oskar777

    Poziom 26  
    Witam udało mi się ustawić tak jak chciałem
    Kod wygląda tak:
    
    // main
    TCCR2 |= (1 << WGM12);     // Ustawia timer1 w tryb CTC 
    OCR2 = 250; // zliczanie do tej wartosci
    TCNT2 = 0;
    TCCR2 |= (1 << CS20) | (1 << CS21) | (1 << CS22);   
    TIMSK |= (1 << OCIE2); // zezwolenie na przerwania CTC
    // przerwanie
    ISR(TIMER2_COMP_vect, ISR_NOBLOCK) {
    stan= 1;
    if(licznik_stan >=5) {
    	licznik_stan =1;
    }
    if(counter >= 150){
    	licznik_stan++;
    	counter = 0;
    }		
    	counter++;		
    	stan = 0;
    }
    

    Akurat potrzebowałem, by zmieniał się stan więcej niż 0 / 1.

    Teraz jedno pytanie ważne dla mnie. Jaką funkcje i do czego służy rejestr
    TCNT2

    Z opisu mam tak

    Cytat:

    The 8-bit comparator continuously compares TCNT2 with the Output Compare Register
    (OCR2). Whenever TCNT2 equals OCR2, the comparator signals a match. A match will set the
    Output Compare Flag (OCF2) at the next timer clock cycle. If enabled (OCIE2 = 1), the Output
    Compare Flag generates an Output Compare interrupt




    Nie za bardzo rozumiem tego opisu. Tyle co ja rozumiem to wartość wpisana do
    TCNT2 pełni taką sama funkcje jak OCR2 oraz jeżeli timer przekroczy wartość wpisaną w TCNT2 to OCF2 chyba zmienia swój stan o ile jest włączone zezwolenie na przerwania.


    Jaką funkcje pełni jeszcze ten rejestr i z ciekawości jaki rejestr pozwala na aktualne odczytanie stanu / wartości licznika ?

    Pozdrawiam.
  • Pomocny post
    #9 8944006
    Fredy
    Poziom 27  
    W TCNT2 jest aktualna wartość timera2.
REKLAMA