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

[MEGA 16][C] pwm - nie działa

ReGiS 28 Cze 2008 20:59 1755 6
  • #1 5294965
    ReGiS
    Poziom 11  
    Witam,

    Mam problem z opaleniem PWM na atmega16, z wewnętrznym taktowaniem 1MHz. Kompilator avr-gcc.
    Otóż chciałem zrobić sobie sterownik do zabawy z diodami rgb, jednak nijak nie mogę dojść jak używać pwm.
    Znalazłem w necie tutorial -> http://avr.elektroda.eu/?q=node/39 i postanowiłem go wypróbować <po wielokrotnych próbach samodzielnego uruchomienia pwm, ale niestety nie działa:(

    Nieco przerobiłem kod z tutoriala, by działał mi pod avr-gcc:
    #include <avr/io.h>                // dostęp do rejestrów
    #include <avr/interrupt.h>        // funkcje sei(), cli()
    #include <avr/signal.h>                // definicje SIGNAL, INTERRUPT
    #include <compat/deprecated.h>
    
    #if defined(__AVR_AT90S4414__) || defined(__AVR_AT90S8515__) || \
        defined(__AVR_AT90S4434__) || defined(__AVR_AT90S8535__) || \
        defined(__AVR_ATmega163__) || defined(__AVR_ATmega16__)
    #define PWM_out(value)        OCR1A=value
    #endif
    
    #ifdef __AVR_AT90S2313__
    #define PWM_out(value)        OCR1=value
    #endif
    
    uint16_t pwm=512;                // zmienna zawiarająca wartość wypełnienia
    
    void delay(void)                // prosta pętla opóźniająca
    {
      unsigned int i;
      for(i=0;i<50000;i++);
    }
    
    int main(void)                        // program główny
    {
      DDRD = 0x00;                // PORTD jako wejścia dla przycisków
      PORTD = 0xFF;                // podciągaj wejścia PORTD
    
    #if defined(__AVR_AT90S4414__) || defined(__AVR_AT90S8515__) || \
        defined(__AVR_AT90S4434__) || defined(__AVR_AT90S8535__) || \
        defined(__AVR_ATmega163__) || defined(__AVR_ATmega16__)
      sbi(DDRD,PD5);                 // ustawienie kierunku wyjscia PWM
    #endif
    #ifdef __AVR_AT90S2313__
      sbi(DDRB,PB3);                 // ustawienie kierunku wyjscia PWM
    #endif
    
      TCCR1A = _BV(COM1A1)|_BV(COM1A0)|_BV(WGM10)|_BV(WGM11);
                                      // czasomierz 1 w trybie 10 bitowego PWM
      TCCR1B = _BV(CS00);                 // czasomierz 1 taktowany F_CPU
      
      pwm=512;                        // przypisz wartość początkową PWM
      
      while(1)                        // pętla nieskończona
      {
        PWM_out(pwm);                // wpisz pwm do OCR1
    
        if (bit_is_clear(PIND,PD3))// jeżeli zwarto PD3 z masą
        {
          delay();                        // czekaj chwilę
          if (++pwm==1024) pwm=1023;// zwiększ i ogranicz pwm
        }
                                        
        if (bit_is_clear(PIND,PD2))// jeżeli zwarto PD2 z masą
        {
          delay();                        // czekaj chwilę
          if (--pwm==0xFFFF) pwm=0;        // zmniejsz i ogranicz pwm
        }
      }
    }
    


    Jeśli dobrze rozumuje to, gdy zwieram PD2 do masy, to dioda powinna słabiej świecić, a jeśli zewrę PD3 do masy to powinna się rozjaśnić. Niestety nic takiego się nie dzieje, dioda ciągle świeci tak samo.
    Diodę mam podłączoną tak jak opisano w tutorialu, czyli od plusa poprzez rezystor 470 ohm do diody i dalej do PD5.
    Czy ktoś jest w stanie mi pomóc zrozumieć o co tu chodzi?

    Pozdrawiam,
    regisu


    Regulamin pkt 11. Popraw temat! <Błażej>
  • #2 5296485
    shg
    Poziom 35  
    void delay(void)                // prosta pętla opóźniająca
    {
      unsigned int i;
      for(i=0;i<50000;i++);
    } 

    To nie działa.
    Kompilator na etapie optymalizacji usuwa tą pętlę, bo ona kompletnie nic nie robi (niczego nie zmienia).

    zainteresuj się gotowymi funkcjami opóźnienia z util/delay.h
  • #3 5300811
    dawid512
    Poziom 32  
    Zamiast tworzyć pętlę opóźniającą dodaj sobie bibliotekę:
    <avr/delay.h> a potem wystarczy np: _delay_ms(250); .
  • #4 5301114
    ReGiS
    Poziom 11  
    dawid512 napisał:
    Zamiast tworzyć pętlę opóźniającą dodaj sobie bibliotekę:
    <avr/delay.h> a potem wystarczy np: _delay_ms(250); .


    No cóż zrobiłem dokładnie jak zaleciłeś, próbując różnych czasów, ale nic z tego, kod nadal nie działa, dioda świeci stałym światłem tak jak świeciła poprzednio:(

    Nie łapie o co chodzi.
    Może ktoś ma gotowy, najprostszy działający kod w c pod atmegę? Potrzebuje jednego przykładu, który mi zadziała, by to sobie już powoli samemu rozpracować.

    Pozdrawiam,
    regisu
  • #5 5301356
    dawid512
    Poziom 32  
    Masz w kodzie:
    sbi(DDRD,PD5); 


    Dopiero poznaję C ale zawsze gdy używałem sbi i cbi kompilator wywalał mi błąd. Wyczytałem że tradycyjne cbi i sbi zmieniono. Jak masz nowsze Winavr( ja mam z 05 2007) to kompilator wyrzuci ci błąd.

    Zmień to na:
    DDRD |= _BV(5)


    Jeżeli się mylę, poprawcie mnie(dopiero ucze sie C).

    Pozdrawiam.
  • #7 5304767
    ReGiS
    Poziom 11  
    Balu napisał:
    Można sobie zrobić makra sbi i cbi ;-)
    Ale błagam te pomocniki z bibliotek
    "while_bit_is_clear(xx.y) są daremne:> O wiele czytelniej wygląda maskowanie bitowe w/g mnie:>


    No tak ale ja o te pomocniki itp nie pytałem. Jak już napisałem wcześniej to jest skopiowany z tutoriala kod, który jak miałem nadzieje, będzie działał.
    Chciałem zobaczyć czy i jak to działa, a potem pozmieniać sobie co trzeba tak żeby mi avr-gcc przyjęło. Jak widać jest to stary kod to użyłem <compat/deprecated.h> i kompiluje się bez błędu.
    Sprawdzałem ten kod także na drugiej atmedze, bo miałem podejrzenie w pewnym momencie, że tamtą poprostu wykończyłem, ale też nie działa.
    No nic będę walczył dalej spróbuje może to odpalić pod avrstudio i może debuggowanie co nieco mi podpowie.

    pozdrawiam,
    regisu
REKLAMA