Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[Atmega8][C] Generowanie Przebiegu z użyciem Timrów

killerwo 02 Jan 2009 17:54 1229 4
  • #1
    killerwo
    Level 10  
    Witam.

    Niestety mam problem dotyczący wygenerowanie przebiegu prostokątnego ALE przy użyciu tylko Timerów bez PWMa. Musze Wygenerować sygnał o okresie 270ms i wypełnieniu 90%( czyli po 243ms wartość na wyjściu musi być 0 przez resztę czasu) Później po naduszeniu przycisku okres ma sie zwiększyć do 810ms.Problem juz mam na samym początku z kodem:

    Code:
    #include <avr/io.h> 
    
    #include <avr/interrupt.h>

    #define F_CPU 8000000L

    SIGNAL(SIG_OVERFLOW1)
    {

       
            PORTB &= ~_BV(1); // na jak długo bedzie ustawione 0?
          TCNT0 = 0;

    }
    int main(void)
    {



    DDRB = 0xff;
    DDRC = 0x00;
    PORTC = 0xFF;

    while(1)


    {

       PORTB |= _BV(1)
       TCNT1L = 53643; // start licznika
       TCCR1A = 0x00; // wartość końcowa licznika
       TCCR1B =(1 << CS12) | (1 << CS10); //prescaler 1024
       TIMSK = _BV(TOIE1); //zgoda na przerwanie?
       
       sei();
     
     if bit_is_set(PORTC,1)



    }

    }


    skoro juz mam wyliczone ze 90% gdzie ma być 5V to 1893 cykle az do przeładowania przechodzimy tam i ustawiamy na wyjściu 0 i tu pojawia sie problem co dalej , czy w przerwaniu mamy zdeklarować po jakim czasie ma być znowu stan wysoki?to by musiały być 2 rodzaje przerwań ze po jednym czasie ma przejsc na niski a drugi raz na wysoki, idzie to jakoś uwzględnić w kodzie? a pozniej przy pomocy przycisku zmienić okres? Proszę o wskazówkę jestem zielony w C i w uC;/
  • #2
    emarcus
    Level 38  
    killerwo wrote:
    Witam.

    Niestety mam problem dotyczący wygenerowanie przebiegu prostokątnego ALE przy użyciu tylko Timerów bez PWMa. Musze Wygenerować sygnał o okresie 270ms i wypełnieniu 90%( czyli po 243ms wartość na wyjściu musi być 0 przez resztę czasu) Później po naduszeniu przycisku okres ma sie zwiększyć do 810ms.Problem juz mam na samym początku z kodem:

    ............
    skoro juz mam wyliczone ze 90% gdzie ma być 5V to 1893 cykle az do przeładowania przechodzimy tam i ustawiamy na wyjściu 0 i tu pojawia sie problem co dalej , czy w przerwaniu mamy zdeklarować po jakim czasie ma być znowu stan wysoki?to by musiały być 2 rodzaje przerwań ze po jednym czasie ma przejsc na niski a drugi raz na wysoki, idzie to jakoś uwzględnić w kodzie? a pozniej przy pomocy przycisku zmienić okres? Proszę o wskazówkę jestem zielony w C i w uC;/


    Dlaczego akurat wybrales prescaler 1024? W zaden sposob nie jest on podzielny z twoimi danymi. Aby uzyskac/odliczyc czas 243 ms musialbys odliczyc "dokladnie" - 1898,4375 cykli i odpowiednio 2109,375 dla okresu (270ms) tworzonej fali.
    Gdybys np. wybral prescaler = 64 potrzeba byloby 30375 impulsow, dla przerwania (toggle), oraz 33750 odpowiednio dla calego cyklu.
    Skoro projekt ten ma byc tylko z timerami (NO PWM) wiec mozesz tu wykorzystac dwa przerwania OC1A i OC1B, (zw, toggle i CTC).
    Ewntualnie mozes posluzyc sie takze trzecim przerwaniem dla zmany 3 krotnie dluzszego okresu fali.

    emarcus
  • #3
    BoskiDialer
    Level 34  
    Najłatwiej bez PWM było by ustawić któryś timer, aby przepełniał się (lub pojawiało się przerwanie compare match) co 1ms (/64, 125 cykli), całą resztę zrealizować programowo. Potem tylko odpowiednio krótki kod, na 4 zmiennych powinno dać się zmieścić (jak długi ma być stan wysoki, jak długi stan niski, ile pozostało do końca aktualnego stanu i jaki aktualnie jest stan) - w przerwaniu aktualizować wyprowadzenie, w programie głównym odpowiednio aktualizować stan.
  • #4
    killerwo
    Level 10  
    Witam.

    Jak by ktoś miał trochę dobrej woli i napisał kod do tego działania bo mimo że wasze podpowiedzi dużo dają to nie umiem ich zrealizować a z gotowym kodem łatwiej było by zrozumieć...zrozumiem jak uznacie ze to gotowiec i nie będziecie chcieli jednak to jest przykład jedynie treningowy.Pozdrawiam
  • #5
    BoskiDialer
    Level 34  
    Tak, uznamy to za gotowca, jedyne co Cię ratuje, to że mam trochę wolnego czasu, chociaż nie zwykłem pisać gotowce:
    Code:
    #include <avr/io.h>
    
    #include <stdint.h>

    volatile uint16_t state_hi_time = 243;
    volatile uint16_t state_lo_time = 27;
    volatile uint16_t state_curr_timeout = 243;
    volatile uint8_t state_curr = 0;

    ISR(TIMER0_OVF_vect)
    {
       // t0 jest zbyt prosty, trzeba załadować TCNT0 ręcznie
       TCNT0 = (unsigned char)-125;
       
       uint16_t cto = state_curr_timeout;
       cto--;
       if(cto == 0)
       {
          // zmiana stanu
          if(state_curr)
          {
             state_curr = 0;
             cto = state_lo_time;

             // TODO: ustawienie stanu niskiego na pinie
          } else
          {
             state_curr = 1;
             cto = state_hi_time;
             
             // TODO: ustawienie stanu wysokiego na pinie
          }
       }
       state_curr_timeout = cto;
    }

    int main(void)
    {
       // TODO: konfiguracja wyjścia, pinu wejściowego od przycisku

       // t0: /64, 125ck
       TCCR0 = _BV(CS01)+_BV(CS00);
       TCNT0 = (unsigned char)-125;
       // zezwolenie na przerwanie TOV0 (pozostałe przerwania od timerów wyłączone)
       TIMSK = _BV(TOIE0);
       
       sei();
       
       while(1)
       {
          // TODO: jeśli przycisk naciśnięty
          if(0)
          {
             uint8_t _sreg = SREG;
             cli();

             state_hi_time = 729;
             state_lo_time = 81;
             
             SREG = _sreg;
          }
       }
       return 0;
    }
    kod napisany od ręki, nawet nie sprawdzany czy się kompiluje.