Elektroda.pl
Elektroda.pl
X
Elektroda.pl
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[ATMega8][c] PWM czas się nauczyć

dondu 24 Lis 2010 13:22 2522 4
  • Moderator Mikrokontrolery Projektowanie
    Już wszystko jasne - jedyne pytanie zadaję na końcu.

    Przygodę z PWM zaczynam od sterowania jasnością diody.

    Atmega8 + diody + rezystorki 330Ω

    Ćwiczenie polega na cyklicznym rozjaśnianiu i ściemnianiu diody
    3 diody podłączone do PB1, PB2, PB3 w założeniu tylko PB1 (OC1A) powinna świecić zgodnie z PWM.

    Ustawiłem tryb Fast PWM 8bit

    Kod:

    Code:

    #include <avr/io.h>
    #include <util/delay.h>

    int main(void) {

       unsigned int licznik;

       DDRB=0xFF;           // PORTB jako wyjścia


       //Ustawiamy PWM w Fast 8 bits mode -> WGM13,WGM12,WGM11,WGM10 = 0b0101
       TCCR1A |= (1<<WGM10);
       TCCR1A &= ~(1<<WGM11);
       TCCR1B |= (1<<WGM12);
       TCCR1B &= ~(1<<WGM13);

       //Preskaler
       TCCR1B &= ~((1<<CS10) | (1<<CS10) | (1<<CS10));   //wyzeruj bity preskalera
       TCCR1B |= (1<<CS10);   //ustaw preskaler 1:1


       TCNT0 = 0;           // Resetuj TCNT0


       // PĘTLA GŁÓWNA

       for(;;) {           

          //Najpierw zwiększamy napięcie na LED-zie

           licznik=0;

           while (licznik <= 255) {

             OCR1A = licznik++;

             _delay_ms(2);    // Delay 2 millisecond

           }


          //a teraz zmniejszamy napięcie na LED-zie

           licznik=255;

           while (licznik >= 0) {

             OCR1A = licznik--;

             _delay_ms(2);   

           }


          // przerwa przy zgaszonym LED-zie
           _delay_ms(500);   


         }

      return 0;           
    }


    LED na PB1 (OC1A) świeci światłem o jednakowej jasności zamiast cyklicznie rozjaśniać się i ściemniać. Gdzie robię błąd?

    Dodano po 16 [minuty]:

    Chyba już doszedłem ... oprócz ustawienia PB1 jako wyjścia, trzeba jeszcze włączyć :
    Code:

    Clear OC1A/OC1B on Compare Match, set OC1A/OC1B at BOTTOM, (non-inverting mode)
    TCCR1A |= (1<<COM1A1);
    TCCR1A &= ~(1<<COM1A0);

    Czy dobrze myślę?


    Teraz coś się dzieje choć nie do końca zgodnie z założeniami czasowymi - sprawdzę to ...

    Dodano po 11 [minuty]:

    No tak, na wyjściu jest jakby przebieg piłokształtny czyli LED rozjaśnia się sukcesywnie do max po czym gaśnie i przebieg powtarza się od początku. Czyli brakuje:
    1 powolnego gaśnięcia LED-a
    2 przerwy przy stanie wygaszonym

    ad pkt 1 faktycznie nie może działać inaczej ponieważ druga pętla WHILE także w tym trybie rozjaśnia a nie ściemnia (narasta a nie opada). Muszę nad tym pokombinować.

    ad pkt 2 PWM działa cały czas bo go nie zatrzymuję i daltego sam fakt wprowadzenia pętli niczego nie zmienia. Czyli powinienem zatrzymać timer. Czy zatrzymywanie timera realizuje się poprzez ustawienie CS02:0 = 0 czyli No clock source (Timer/Counter stopped) czy w jakiś inny sposób?

    Dodano po 25 [minuty]:

    NA RAZIE PROSZĘ NIE ODPISYWAĆ
    Postaram się dobrnąć do celu sam, a pytania zadam na końcu.


    Dodano po 1 [godziny] 27 [minuty]:

    Zmiana w układzie (dla porządku):
    - LED na PB1 przez rezystor do masy (by nie było inwersji sygnału).

    Nowy kod:
    Code:

    #define F_CPU 9600000UL

    #define NOP asm("nop");
    #include <avr/io.h>
    #include <util/delay.h>

    int main(void) {

       unsigned int licznik;

       DDRB=0xFF;           // PORTB jako wyjścia


       //Ustawiamy PWM w Fast 8 bits mode -> WGM13,WGM12,WGM11,WGM10 = 0b0101
       TCCR1A |= (1<<WGM10);
       TCCR1A &= ~(1<<WGM11);
       TCCR1B |= (1<<WGM12);
       TCCR1B &= ~(1<<WGM13);

       //włącz przekazywanie sygnału PWM na pin PB1 (OC1A)
       //Clear OC1A/OC1B on Compare Match, set OC1A/OC1B at BOTTOM, (non-inverting mode) str. 97
       TCCR1A |= (1<<COM1A1);
       TCCR1A &= ~(1<<COM1A0);
       

       //Preskaler
       TCCR1B &= ~((1<<CS12) | (1<<CS11) | (1<<CS10));   //wyzeruj bity preskalera
       TCCR1B |= (1<<CS10);   //ustaw preskaler 1:1


       TCNT0 = 0;           // Resetuj TCNT0



          //Najpierw zwiększamy napięcie na LED-zie

           licznik=0;

           while (licznik <= 255) {

             OCR1A = licznik++;

             _delay_ms(2);   

           }
          


          //a teraz zmniejszamy napięcie na LED-zie

           licznik=255;

           while (licznik >= 0) {

             OCR1A = licznik--;

             _delay_ms(15);   

           }

          //zatrzymaj timer
          TCCR1B &= ~((1<<CS12) | (1<<CS11) | (1<<CS10));   //wyzeruj bity preskalera ustawiając: No clock source. (Timer/Counter stopped)




       // PĘTLA GŁÓWNA nieroba :)

       for(;;) {           

          NOP
          NOP
          NOP
          NOP
          NOP
          NOP
         }

      return 0;           
    }




    Kod powinien wykonać:
    1. szybkie rozjaśnienie diody - (działa OK)
    2. powolne zgaszenie diody - (działa OK)
    3. zapętlić się (dioda zgaszona) - NIE DZIAŁA

    Ad. pkt 3
    Po zgaszeniu diody zgodnie z pkt 2, powinien przejść do pętli nic nierobiącej. Niestety efekt jest inny - na LED-zie obserwuję powtarzający się cyklicznie przebieg generowany przez drugą pętlę WHILE czyli gaszenie LED-a. Innymi słowy LED jest zapalany na max i powoli gaszony, i tak w kółko (bez rozjaśniania).
    Licznik nie został wyłączony więc wyzerowaniem CS12:10 tylko pętla jakby działała na okrągło, co sugeruje że sobie nie radzę z C :) lub popełniam jakiś inny błąd.

    Dodano po 13 [minuty]:
    Błąd był w warunku w pętli powinno być:
    Code:
     while (licznik >= 1){
    
    ....



    Pytanie:

    Czy zatrzymywanie timera realizuje się poprzez ustawienie CS02:0 = 0 czyli No clock source (Timer/Counter stopped) czy w jakiś inny sposób?
  • Pomocny post
    Poziom 21  
    Tak.
  • Pomocny post
    Poziom 13  
    dondu, zahaczając o temat nauki, bardzo fajnie opisany PWM jest na http://aquaticus.info/pwm , to chyba najlepszy opis jaki znalazłem, razem z przykładami, do tego polecam Ci zapoznać się z polską dokumentacja ATmegi 16 napisanej przez Wydział Elektroniki, Telekomunikacji i Informatyki Politechniki Gdańskiej, jak byś nie mógł znaleźć to pisz na PW, podeślę Ci na maila.
  • Moderator Mikrokontrolery Projektowanie
    dzarek1 napisał:
    dondu, zahaczając o temat nauki, bardzo fajnie opisany PWM jest na http://aquaticus.info/pwm , to chyba najlepszy opis jaki znalazłem, razem z przykładami, ...

    Zapoznam się bo właśnie ćwiczę sterowanie silnikami DC przez PWM Phase correct - już działa, właśnie kalibruję software do mini robota

    dzarek1 napisał:
    ... do tego polecam Ci zapoznać się z polską dokumentacja ATmegi 16 napisanej przez Wydział Elektroniki, Telekomunikacji i Informatyki Politechniki Gdańskiej, ...

    Czy chodziło Ci o to?
    http://www.pg.gda.pl/~zbczaja/pdf/atmega16mmr.pdf
  • Pomocny post
    Poziom 13  
    dokładnie ten plik ;)