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

Atmega8, programowy PWM, bascom

musznik 12 May 2008 23:25 11291 24
  • #1
    musznik
    Level 10  
    Mam zamiar wykorzystać wszystkie dostepne porty do sterowania diodami led, oczywiscie PWM - niestety tylko programowy ;/

    Mam kilka wskazowek, lecz nie dzialaja.

    Code:

    $regfile = "m8def.dat"
    $crystal = 8000000

    Config Pind.0 = Output                                      'Konfiguracja 4 pinów wyjściowych PWM
    Config Pind.1 = Output
    Config Pind.2 = Output
    Config Pind.3 = Output

    Reset Portd.0
    Reset Portd.1
    Set Portd.2                                                 'ustawiamy druga pare jako zanegowana
    Set Portd.3

    Dim Wyp(4) As Byte                                          'zmienne wypełnienia
    Dim Licz As Byte                                            'zmienna głównego licznika



    Config Timer0 = Timer , Prescale = 64                       'konfiguracja Timer0 jako timer
    On Timer0 Przerwanie                                        'wywołanie procedury liczącej przy przerwaniu
    Enable Timer0                                               'włączamy Timer0
    Enable Interrupts                                           'włączamy przerwania

    '###########################################

    Wyp(1) = 48                                                 ' przykładowe wartości początkowe wypełnień
    Wyp(2) = 64
    Wyp(3) = 128
    Wyp(4) = 250

    Do
    Rem tu obsługa przycisków i wyświetlacza LCD
    Loop

    End

    Przerwanie:
     Incr Licz
     If Licz = Wyp(1) Then Toggle Portd.0
     If Licz = Wyp(2) Then Toggle Portd.1
     If Licz = Wyp(3) Then Toggle Portd.2
     If Licz = Wyp(4) Then Toggle Portd.3
     If Licz = 0 Then
       Portd.0 = 0                                              ' zerowanie portów
       Portd.1 = 0
       Portd.2 = 1
       Portd.3 = 1
     End If
    Return


    To przyklad na ktorym sie opierałem, diody zamiast przygasać..mrugaja z odstepem 1sek..- 5sek.., modyfikowalem program,ale nie bardzo ;)

    prosze o jakies rozwiazanie,podpowiedz;) pozdrawiam.
  • #2
    Mariusz Ch.
    VIP Meritorious for electroda.pl
    Przenoszę z "Początkujący Nauka".
  • #3
    hefid
    R.I.P. Meritorious for the elektroda.pl
    Post był raportowany Reg. pkt 8.3.
    Przeniosłem z: Początkujący Nauka
  • #5
    Sabre
    Level 18  
    Jeśli masz nowy procesor to działa on na wewnętrznym rezonatorze 1MHz. Zmień w programie linijkę:
    $crystal = 8000000
    na
    $crystal = 1000000

    lub zmień fuse bity na zewnętrzny rezonator i w programie wpisz w tą linijkę taką wartość jakiego używasz.
  • #6
    JmL(TM)
    Level 24  
    To nie problem z rezonatorem i fuse bit'ami tylko z konfiguracja timera.
    Ponizej zamieszczam moja przerobiona wersje twojego kodu [numery portow musisz pozmieniac bo ja akurat mialem podpiete diody do tych wyprowadzen ;)]

    Code:
    $regfile = "m8def.dat"
    
    $crystal = 8000000

    Config Portd = Output                                       'Konfiguracja 4 pinów wyjściowych PWM

    Dim Wyp(6) As Byte                                          'zmienne wypełnienia
    Dim Licz As Byte                                            'zmienna głównego licznika

    Dim X As Byte
    Dim A As Byte , B As Byte , C As Byte , D As Byte

    Config Timer0 = Timer , Prescale = 1                        'konfiguracja Timer0 jako timer
    On Timer0 Przerwanie                                        'wywołanie procedury liczącej przy przerwaniu
    Enable Timer0                                               'włączamy Timer0
    Enable Interrupts                                           'włączamy przerwania

    Wyp(1) = 4                                                  ' przykładowe wartości początkowe wypełnień
    Wyp(2) = 16
    Wyp(3) = 32
    Wyp(4) = 64
    Wyp(5) = 96
    Wyp(6) = 128

    Do
    Loop

    End

    Przerwanie:
       Incr Licz

       For X = 2 To 7
          If Licz = Wyp(x -1) Then
             Toggle Portd.x
          End If
       Next X

       If Licz = 0 Then
          Portd = &B11111111                                    ' zerowanie portów
       End If
    Return


    Jakies pytania? ;)
  • #7
    musznik
    Level 10  
    Skompilowalem,wrzucilem,nadal nic..zmienile fusy na

    0100 = wewnętrzny oscylator 8MHz,

    Diodki niby szybciej mrygaja, ale poziom jasnosci jest prawie wszedzie taki sam.
  • #8
    mirekk36
    Level 42  
    Code:


    Przerwanie:
     Incr Licz
     If Licz = Wyp(1) Then Toggle Portd.0
     If Licz = Wyp(2) Then Toggle Portd.1
     If Licz = Wyp(3) Then Toggle Portd.2
     If Licz = Wyp(4) Then Toggle Portd.3
     If Licz = 0 Then
       Portd.0 = 0                                              ' zerowanie portów
       Portd.1 = 0
       Portd.2 = 1
       Portd.3 = 1
     End If
    Return


    bo to nie może działać jako programowy PWM, spróbuj tak:

    Code:


    Przerwanie:
     Incr Licz

     If Licz <= Wyp(1) Then
         reset Portd.0
     Else
         set Portd.0
     End If

     If Licz <= Wyp(2) Then
         reset Portd.1
     Else
         set Portd.1
     End If

     If Licz <= Wyp(3) Then
         reset Portd.2
     Else
         set Portd.2
     End If

     If Licz <= Wyp(4) Then
         reset Portd.3
     Else
         set Portd.3
     End If


    Return


    wtedy dla kwarca lub oscylatora 8MHz i preskalera = 64, będziesz miał PWM 8bitowy z częstotliwością 15,625KHz i wszystko powinno chulać

    Dodano po 8 [minuty]:

    tylko, że jednak przy taktowaniu procka 8MHz czas w tym przerwaniu masz zaledwie 8us - to może być za mało żeby obsłużyć tą ilość IF'ów (nie wiem musisz sprawdzić empirycznie) a jeśli się nie będzie wyrabiać to i PWM będzie się rozjeżdżał. Jeśli natomiast 8us starczy na wykonanie tego przerwania w Bascomie z zapasem to masz ładny PWM.

    Gdy nie zadziała to daj zewnętrzny kwarc np 12MHz lub większy. Wtedy użyj preskalera 256. Dzięki temu w przerwaniu będziesz miał więcej niż 20us a to powinno wystarczyć na taką ilość kodu w Bascomie żeby się wszystko ładnie wyrobiło. Zresztą można to przerwanie (bo proste) rozpisać w żywym asemblerze i wtedy starczy nawet 8us)

    pozdrówka
  • #9
    ZbeeGin
    Level 39  
    Napisałem ten kod kiedyś by pokazać mniej więcej jak to ma wyglądać. To NIE był żaden gotowiec.

    mirekk36 wrote:
    bo to nie może działać jako programowy PWM, spróbuj tak:

    Może. Nie zauważyłeś że przy liczniku = 0 porty wracają do stanu początkowego?
  • #10
    musznik
    Level 10  
    Jest postep , fix od mirekk36 daje rezulataty,ale... z prescale=1 ( inne powoduja widoczne dlugie miganie ).

    Pozostaje jescze jasność diodek,
    nawet przy Wyp(1) = 1 - swieci sie, moze nie tak juz jasno,ale wciaz jest to za duzo. Co jest problemem?

    [ Ustawilem nawet 1 IF'a dla testu ]
  • #11
    mirekk36
    Level 42  
    musznik - no właśnie mówiłem ci żebyś pokombinował jeszcze z preksalerem aby dobrać czasy no i wyszło

    a jeśli chodzi o diodki i ich nie do końca wygaszanie - to mogę się założyć o całą skrzynkę JOHNY WALKERA, że diody do procka podłączyłeś w ten sposób, że do nogi procka masz podłączoną ANODĘ diody LED a jej KATODĘ do masy(GND) ??? prawada ???? (oczywiście gdzieś po drodze jeszcze masz rezystor to zrozumiałe)

    może dzięki tym ćwiczeniom z PWM'em raz na zawsze zapamięsz, że diody LED najlepiej sterować z procka w ten sposób, że do nóżki procka podłączasz bezpośrednio jej KATODĘ !!! - a ANODĘ diody LED przez rezystor do VCC.

    zobaczysz wtedy, że będzie śmigało tak jak powinno.

    pozdrawiam i powodzenia Mirek
  • #12
    musznik
    Level 10  
    No i przegrales skrzynke Johny Walkera :P bo mam tak jak mowisz ;P z malym niuansem, po zlej stronie jest rezystor... ;]
  • #13
    mirekk36
    Level 42  
    ooo kurczę ;) hmmm no to jakoś kiedyś obalimy tę skrzynkę ;) w końcu do Gorzowa nie mam daleko

    ... ale na pewno przenieś rezystor na drugą stronę

    i ew spróbuj zmienić w IF ach - załączanie i wyłączanie portów. Czyli zamiast set zrób reset i odwrotnie
  • #14
    musznik
    Level 10  
    :D

    Tak,że... lipa, zmienilem,rezystor,zmienilem nawet diode i opornosc na nich (-+ 100-150ohm ) - dioda nie chce sie bardziej sciemnic.

    Pozostaje mi tylko ,albo zmienic kwarc na szybszy ,albo pobawic sie w avr gcc (w najgorszym razie asm :o ) albo..sie napic Johnyego Walkera..
  • #15
    mirekk36
    Level 42  
    no tak trza na szybszym karcu zobaczyć. Ale nawet z 1 Ifem i PWM dla 1 diody też tak samo się dzieje?

    no tak ale jak dałeś preskaler = 1 to nie ma co się dziwić z jednej strony bo wtedy nawet ten jeden IF w Bascomie może się za długo wykonywać.

    aha spróbuj jeszcze z opcją NOSAVE przy definicji przerwania (żeby nie odkładał wszystkich rejestrów na stos)
  • #16
    zumek
    Level 39  
    mirekk36 wrote:
    dla kwarca lub oscylatora 8MHz i preskalera = 64, będziesz miał PWM 8bitowy z częstotliwością 15,625KHz i wszystko powinno chulać
    Zakładając , że zmienna Licz jest 8-bitowa , to mi wychodzi , że okress takiego PWM-a jest < 2Hz :!: Ale rozumiem , późno było ;)
    mirekk36 wrote:
    ... ale na pewno przenieś rezystor na drugą stronę
    Hmmm... a jaka to różnica :?: Czyżbyś się już dobrał do Johnny'ego Walker'a :D
    może w taki sposób zadziała
    Code:

    $regfile = "m8def.dat"
    $hwstack = 32
    $swstack = 32
    $framesize = 32
    $crystal = 8000000

    Dim Licz As Byte , Wyp(4) As Byte

    Portd = Portd Or &B00001111
    Ddrd = Ddrd Or &B00001111

    Config Timer0 = Timer , Prescale = 1
    On Timer0 Przerwanie
    Enable Interrupts
    Enable Timer0

    Wyp(1) = 31
    Wyp(2) = 63
    Wyp(3) = 95
    Wyp(4) = 127

    Do
       Wait 10
       Set Wyp(2).7   'LED-ka wygaszona
       Wait 10
       Reset Wyp(2).7   'LED-ka PWM-uje ;)
    Loop



    Przerwanie:
     Decr Licz
     If Licz = 255 Then
       Portd = Portd Or &H0F
       Licz = 127                      '128 kroków/~241Hz
     End If
     If Licz = Wyp(1) Then Reset Portd.0
     If Licz = Wyp(2) Then Reset Portd.1
     If Licz = Wyp(3) Then Reset Portd.2
     If Licz = Wyp(4) Then Reset Portd.3
    Return

  • #17
    mirekk36
    Level 42  
    zumek wrote:
    mirekk36 wrote:
    dla kwarca lub oscylatora 8MHz i preskalera = 64, będziesz miał PWM 8bitowy z częstotliwością 15,625KHz i wszystko powinno chulać
    Zakładając , że zmienna Licz jest 8-bitowa , to mi wychodzi , że okress takiego PWM-a jest < 2Hz :!: Ale rozumiem , późno było ;)


    kurczę, masz rację, miałem chyba pomroczność jasną zapomniałem o podziale jeszcze przez 265 od timera , ale to z tego samego powodu tego wieczora i mi tak długo szło zrobienie sterowania fazowego triakiem ;)

    zumek wrote:

    mirekk36 wrote:
    ... ale na pewno przenieś rezystor na drugą stronę
    Hmmm... a jaka to różnica :?: Czyżbyś się już dobrał do Johnny'ego Walker'a :D


    jeszcze nie ... ale kiedyś gdzieś jakoś tak zaczytałem w necie i chyba tak mi się jakoś - jak z tego wynika ubzdurało skoro spec od uC mówi że nie ma żadnej różnicy.

    .... a tak nawiasem mówiąc to fajny sposób na obniżenie częstotliwości PWM'a.
  • #18
    ZbeeGin
    Level 39  
    Ludziska. Skoro dodatkowy licznik programowy Wam się nie podoba, to trzeba kopiować wartość licznika sprzętowego do zmiennej i porównywać (mniejsze, większe) z tablicą wypełnień. Cały "PWM" wtedy należy przenieść do pętli głównej.
    Oczywiście Prescaler = 1 nie jest najlepszym rozwiązaniem w takim wypadku.

    Jeśli nie jest potrzebna dokładna synchronizacja czasów zmian na portach to takie rozwiązanie jest do przyjęcia.
    _____

    A w oryginalnym programie można sobie skrócić cykl licznika sprzętowego włączając opcję CTC (Clear Timer = 1) i ładując wartość skracającą do rejestru COMPARE.
  • #19
    neo_84
    Level 15  
    Może sie komuś przyda ... działajacy kod sprawdzałem testowalem niby wszystko działa czestotliwosc PWM = 123 Hz

    Code:
    $regfile = "m8def.dat"
    
    $crystal = 8000000

    Config Pinb.1 = Output                                      'Konfiguracja 4 pinów wyjściowych PWM
    Config Pinb.2 = Output
    Config Pinb.3 = Output
    Config Pinb.4 = Output



    Dim Wyp(4) As Byte                                          'zmienne wypełnienia
    Dim Licz As Byte                                            'zmienna głównego licznika

    Config Timer0 = Timer , Prescale = 256                      'konfiguracja Timer0 jako timer
    On Timer0 Przerwanie                                        'wywołanie procedury liczącej przy przerwaniu
    Enable Timer0                                               'włączamy Timer0
    Enable Interrupts                                           'włączamy przerwania

    '###########################################






    Do
    Wyp(1) = 128                                                ' przykładowe wartości początkowe wypełnień
    Wyp(2) = 20
    Wyp(3) = 30
    Wyp(4) = 40

    Loop

    End

    Przerwanie:
    Load Timer0 , 1
     Incr Licz
     If Licz = Wyp(1) Then Set Portb.1
     If Licz = Wyp(2) Then Set Portb.2
     If Licz = Wyp(3) Then Set Portb.3
     If Licz = Wyp(4) Then Set Portb.4

     If Licz = 0 Then
       Portb.1 = 0
       Portb.2 = 0
       Portb.3 = 0
       Portb.4 = 0                                              ' zerowanie portów

     End If
    Return
  • #20
    FastProject
    Level 28  
    neo_84 wrote:
    Może sie komuś przyda ... działajacy kod sprawdzałem testowalem niby wszystko działa czestotliwosc PWM = 123 Hz

    Code:
    $regfile = "m8def.dat"
    
    $crystal = 8000000

    Config Pinb.1 = Output                                      'Konfiguracja 4 pinów wyjściowych PWM
    Config Pinb.2 = Output
    Config Pinb.3 = Output
    Config Pinb.4 = Output



    Dim Wyp(4) As Byte                                          'zmienne wypełnienia
    Dim Licz As Byte                                            'zmienna głównego licznika

    Config Timer0 = Timer , Prescale = 256                      'konfiguracja Timer0 jako timer
    On Timer0 Przerwanie                                        'wywołanie procedury liczącej przy przerwaniu
    Enable Timer0                                               'włączamy Timer0
    Enable Interrupts                                           'włączamy przerwania

    '###########################################






    Do
    Wyp(1) = 128                                                ' przykładowe wartości początkowe wypełnień
    Wyp(2) = 20
    Wyp(3) = 30
    Wyp(4) = 40

    Loop

    End

    Przerwanie:
    Load Timer0 , 1
     Incr Licz
     If Licz = Wyp(1) Then Set Portb.1
     If Licz = Wyp(2) Then Set Portb.2
     If Licz = Wyp(3) Then Set Portb.3
     If Licz = Wyp(4) Then Set Portb.4

     If Licz = 0 Then
       Portb.1 = 0
       Portb.2 = 0
       Portb.3 = 0
       Portb.4 = 0                                              ' zerowanie portów

     End If
    Return


    Czy przy tej metodzie procesor wyrobi się dla 40 kanałów PWM, z tym, że wysyłanie stanów LED realizowane jest za pomocą rejestrów 74hc164?
  • #22
    piotrva
    VIP Meritorious for electroda.pl
    Dajesz Timer i w jego przerwaniu instrumentujesz zmienną Byte (np. Pwm_ct) i jednocześnie jeśli wartość pwm dla danego kanału (zapisana w innej zmiennej modyfikowanej z programu) jest <Pwm_ct to wtedy podajesz na dany pin stan niski, w przeciwnym wypadku podajesz tam stan wysoki.
  • #24
    piotrva
    VIP Meritorious for electroda.pl
    Dokładnie połączenie Twoich 2 pomysłów jest najbardziej optymalne. regulacja zmienną tablicową w zakresie 0-255, lub jeśli dodasz If Licznik = 100 Then Licznik = 0 to wtedy w zakresie 0-100. Oczywiście możesz dodać analogicznie więcej kanałów.
    Code:

     Prztimer:
     Incr Licznik
     If Licznik < Pwm(1) Then Set PORTD.0 Else Reset PORTD.0
     If Licznik < Pwm(2) Then Set PORTD.1 Else Reset PORTD.1
    Return

    I bardzo fajnie, że ruszyłeś głową, a nie czekałeś na gotowca, masz u mnie wielkiego plusa ;-)