4x PWM na Atmega8

To forum jest dla wszystkich pasjonatów mikrokontrolerów AVR Atmela. Wymiana doświadczeń i pomoc dla początkujących w pisaniu programów zarówno w C, Asemblerze jak i BASCOM. Zapraszam znawców tematu, aby pomogli wszystkim początkującym!
ODPOWIEDZ
Awatar użytkownika
M@ciej
Użytkownik
Posty: 736
Rejestracja: 13 sie 2005, 21:38
Lokalizacja: Szczecin

4x PWM na Atmega8

Post autor: M@ciej » 22 maja 2007, 17:42

Witam wszystkich :)

Mam pewien problem: chciałbym zrobić poczwórny generator PWM na Atmega8, żeby na 4 różnych końcówkach można było otrzymać 4 niezależne przebiegi , każdy o innym,regulowanym wypełnieniu. Ponoć sprzętowo można to zrobić tylko na jednej końcówce, ale żeby mieć 4 niezależne,to nie wiem,jak zrobić.

Czyżby pozostał mi tylko sposób programowy?

Awatar użytkownika
Aro
Użytkownik
Posty: 677
Rejestracja: 30 paź 2006, 18:49
Lokalizacja: Świerczyniec | Wrocław
Kontakt:

Post autor: Aro » 23 maja 2007, 16:43

Kuzyn zrobił coś podobnego. Sterownik 8 serwomechanizmów na Atmega8. program jest w bascomie. Jak wiadomo serwa są sterowane sygnałem PWM, więc jak ci to może pomóc, to spróbuje zdobyc program.

Awatar użytkownika
M@ciej
Użytkownik
Posty: 736
Rejestracja: 13 sie 2005, 21:38
Lokalizacja: Szczecin

Post autor: M@ciej » 25 maja 2007, 6:22

Fajnie by było, bo nie mam zupełnie pomysłu,jak to zrealizować dla 4-ech kanałów. Pozdrawiam :)

ZbeeGin

Post autor: ZbeeGin » 25 maja 2007, 17:34

Jeśli chciałbyś zrobić to samemu to musisz skonfigurować jeden liczniki w celu generacji cyklicznych przerwań z automatycznym zerowaniem (tryb CTC) lub przeładowaniem, albo bez - jeśli będziesz to robił programowo, czego nie polecam. W programie obsługi przerwania tworzysz następny licznik - tym razem programowy liczący w górę, a po przepełnieniu zerujący się. Będzie to tzw. tyb FastPWM. Możesz także zmienić kierunek liczenia otrzymując standardowy PWM, ale wydłuży to czas impulsów.
Następnie korzystając z 4 elementowej tablicy tworzysz rejestry porównawcze dla 4 kanałów. Procedura obsługi przerwania będzie te rejestry porównywać z bieżącym stanem licznika programowego. Jeśli wartość zostanie zrównana to odpowiedni pin będzie ustawiony/wyzerowany - w zależności jak chcesz sterować. Jeśli licznik programowy się przepełni to wszystkie piny zostaną wyzerowane/ustawione w trybie FastPWM. W trybie standard porównujesz tylko ponownie zmieniając stan pinu na przeciwny - to wystarczy.

Ważna będzie zależność czasowa pomiędzy poszczególnymi kanałami. Najlepiej stany pinów ustawiać jedocześnie, zawsze pod koniec procedury obsługi przerwania. Wtedy fazy poszczególnych kanałów będą zgodne. Pozostaje jeszcze kwestia drugiej zależności czasowej: procedura przerwania raz będzie trwała krócej, a raz dłużej (Mam nadzieje, że domyślasz się dlaczego...?) i lepiej będzie zsynchronizować modyfikacje stanu pinów z impulsami przerwania sprzętowego licznika, tak aby ta modyfikacja była zawsze opóźniona o jeden "takt" programowego licznika.

Niestety odpowiednią szybkość pracy takiego systemu będziesz mógł usyskać pisząc to w języku asembler lub w ostateczności w AVR-GCC. Druga sprawa to szybkość taktowania procesora. Tutaj poniżej 8MHz nie ma sensu schodzić. Przy większej ilości kanałów tą czestotliwość należy zwiększyć do 12MHz lub 16MHz.

Awatar użytkownika
M@ciej
Użytkownik
Posty: 736
Rejestracja: 13 sie 2005, 21:38
Lokalizacja: Szczecin

Post autor: M@ciej » 25 maja 2007, 18:43

Dziękuje wszystkim za podpowiedzi,zwłaszcza ZbeeGin'owi za podanie niemalże gotowej procedury. Zastanawiałem się także nad podobnym rozwiązaniem, żeby zastosować jedno przerwanie w roli generatora wzorcowego o częstotliwości powiedzmy 1kHz, by potem zliczać pojedyncze cykle i ustawiać/zerować bity na poszczególnych wyjściach mikrokontrolera. Wpadłem tez na to,ze przebiegi nie będą zsynchronizowane i będą sie nieco różniły.

Pomyślałem tez nad innym rozwiązaniem, bardziej "sprzętowym". Mam tu na myśli zastosowanie potencjometrów elektronicznych (np. DS1804) i wykonaniu oddzielnego generatora PWM (generator przebiegu trójkątnego, wspólny dla wszystkich), oraz 4 komparatory "sterowane" wspomnianymi potencjometrami.Wszystkim sterowałby Atmega8.

Choć taniej byłoby jakoś zsynchronizować 4 atmegi8 i każdy miałby swój pojedynczy sprzętowy PWM :P. Atmega8 - 8 PLN, DS1804 - ok. 13 PLN).

Pozdrawiam :)

ZbeeGin

Post autor: ZbeeGin » 25 maja 2007, 18:51

M@ciej pisze:Choć taniej byłoby jakoś zsynchronizować 4 atmegi8 i każdy miałby swój pojedynczy sprzętowy PWM
Wystarczą tylko 2 układy. Przecież licznik Timer1 ma dwa kanały PWM...

Dar.El
-
Posty: 65
Rejestracja: 10 lut 2007, 20:18
Lokalizacja: Warszawa

Post autor: Dar.El » 25 maja 2007, 21:32

Witam
Zastosuj ATmega162 a jeszcze lepiej ATMega128. Ceny tych scalaków są coraz niższe i nie warto kombinować.

Awatar użytkownika
Aro
Użytkownik
Posty: 677
Rejestracja: 30 paź 2006, 18:49
Lokalizacja: Świerczyniec | Wrocław
Kontakt:

Post autor: Aro » 26 maja 2007, 8:09

No właśnie, po co kombinowac! AVRy są na tyle szybkie że w sposób programowy można sterowac dużą liczbą PWM. Trochę cierpliwości, czekam na ten program.

Awatar użytkownika
M@ciej
Użytkownik
Posty: 736
Rejestracja: 13 sie 2005, 21:38
Lokalizacja: Szczecin

Post autor: M@ciej » 26 maja 2007, 13:42

Widzę, ze sprawa 4xPWM zainteresowała Formowiczów :)

Od kilku dni chodzi mi po głowie ten pomysł,lecz samo PWM,nawet 4-krotne nic nie da,jak nie zrobi się sterowania (switche) oraz jakiejś kontroli stanu (LCD 2x16), z tym jest tylko jeden problem, że zaczyna mi brakować pinów.

Korzystając z pomocy Kolegi ZbeeGin oraz książki M. Wiązani wymyśliłem taką koncepcję:

Będzie jedno przerwanie, jako wzorcowe. Nie wiem jeszcze, jaki ustawić preskaler,ale to najmniejszy problem. Trzeba będzie wiedzieć, ile cykli będzie trwało to przerwanie. Będzie to procedura, zwiększająca w ordynarny sposób (Inc) 4 zmienne. Po odliczeniu iluś tam cykli (ilu - zależy od ustawionego wypełnienia) stan określonych portów będzie zmieniał się na przeciwny, również w ordynarny sposób (Toggle). W ten sposób będę mógł zaprogramować parę pinów odwróconą w fazie. Ostatni cykl przerwania będzie zerował wszystkie liczniki i porty wyjściowe PWM, aby uzyskać synchronizację. Nie wiem jeszcze, jak dowiedzieć się o długości cyklu. Procka będę "napędzał" kwarcem 8 MHz.

Możliwe, że napisałem tu głupoty, więc poprawcie. Nie jestem tak dobry w programowaniu mikro kontrolerów, więc mogą pojawić się błędy w rozumowaniu.

ZbeeGin

Post autor: ZbeeGin » 26 maja 2007, 21:38

M@ciej pisze:Będzie jedno przerwanie, jako wzorcowe. Nie wiem jeszcze, jaki ustawić preskaler,ale to najmniejszy problem. Trzeba będzie wiedzieć, ile cykli będzie trwało to przerwanie.
Ustaw tak, by czas przerwań odpowiadał podwójnemu czasowi trwania procedury obsługi programowego PWM - w najgorszym wypadku w szystkimi prawdziwymi warunkami.
M@ciej pisze:W ten sposób będę mógł zaprogramować parę pinów odwróconą w fazie.
W takim wypadku możesz sobie zrobić 2 kanały i sterować oba pinami jednocześnie. Tylko sprawdź czy nie potrzebujesz czasu martwego (aby zmiany nie zachodziły na siebie).

Awatar użytkownika
M@ciej
Użytkownik
Posty: 736
Rejestracja: 13 sie 2005, 21:38
Lokalizacja: Szczecin

Post autor: M@ciej » 27 maja 2007, 9:37

Oto pierwsza,szkieletowa wersja programu. Program udało sie skompilować,wiec nie zawiera błędów składniowych, ale nie wiem, jak działa, bo nie zmontowałem jeszcze układu a symulator nic znaczącego mi nie pokazał.

Kod: Zaznacz cały

$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

Set Portd.2                             'ustawiamy druga pare jako zanegowana
Set Portd.3

Config Timer0 = Timer , Prescale = 256 , Edge = Rising       'konfiguracja Timer0 jako timer

On Timer0 Przerwanie                    'wywołanie procedury liczącej przy przerwaniu

Dim Wyp1 As Byte                        'zmienne wypełnienia
Dim Wyp2 As Byte
Dim Wyp3 As Byte
Dim Wyp4 As Byte

Dim Licz1 As Byte
Dim Licz2 As Byte                       'zmienne licznikowe
Dim Licz3 As Byte
Dim Licz4 As Byte

Dim Licz As Byte                        'zmienna głównego licznika


Enable Interrupts                       'włączamy przerwania
Enable Timer0                           'włączamy Timer0


Wyp1 = 48                               ' przykładowe wartości początkowe wypełnień
Wyp2 = 64
Wyp2 = 128
Wyp3 = 250

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

Loop

End

Przerwanie:
 Incr Licz

 Incr Licz1
 Incr Licz2
 Incr Licz3
 Incr Licz3

 If Licz1 >= Wyp1 Then Toggle Portd.0
 If Licz2 >= Wyp2 Then Toggle Portd.1
 If Licz3 >= Wyp3 Then Toggle Portd.2
 If Licz4 >= Wyp4 Then Toggle Portd.3

 If Licz > 254 Then
  Licz = 0                              'zerowanie zmiennych
  Licz1 = 0
  Licz2 = 0
  Licz3 = 0

   Portd.0 = 0                          'zerowanie portów
   Portd.1 = 0
   Portd.2 = 1
   Portd.3 = 1
 End If

Return


-----
Kody źródłowe wklejamy w tagi CODE. ZbeeGin
Ostatnio zmieniony 01 sty 1970, 1:00 przez M@ciej, łącznie zmieniany 1 raz.

Awatar użytkownika
Aro
Użytkownik
Posty: 677
Rejestracja: 30 paź 2006, 18:49
Lokalizacja: Świerczyniec | Wrocław
Kontakt:

Post autor: Aro » 27 maja 2007, 12:12

Po co aż 4 zmienne licz(!) Wystarczy jedna i do nie będą porównane zmienne wyp(x). Druga sprawa to polecenie Toggle - zmienia stan na przeciwny. Czyli zamiast wystawic na porcie stan wysoki będzie na przemian zmieniało jego stan. Należy wstawic Set Portd.0 i 1, oraz Reset dla Portd.2 oraz 3.
Zamiast Licz>=Wyp lepiej dac Licz=Wyp, wtedy też można pozostac przy poleceniu Toggle.

ZbeeGin

Post autor: ZbeeGin » 27 maja 2007, 15:44

M@ciej, masz tam kilka wpadek w tym programie, ale nie będę ich teraz pokazywał. Przerobiłem nieco Twój kod do postaci:

Kod: Zaznacz cały

$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
Symulacja nie wykazuje błędów w działaniu i istotnie program robi co do niego należy. Przerażające są jednak dla Mnie czasy - a zwłaszcza ten ostatni - uzyskane przy takim ustawieniu licznika:
Czas trwania procedury przerwania ~0,012ms
Czas pomiędzy kolejnymi przerwaniami ~2,04ms
Czas trwania pełnego impulsu (wypełnienie 100%) ~522,25ms (!!)


W związku z tym sugeruje drobną zmianę kosztem rozdzielczości. "Skracamy" licznik do 100 poprzez:

Kod: Zaznacz cały

 If Licz = Wyp(4) Then Toggle Portd.3
 If Licz = 100 Then
   Licz = 0
   Portd.0 = 0     
A poziomy wypełnień także skracamy do łatwych i czytelnych 0 - 100, co odpowiadać będzie bezpośrednio procentom wypełnienia przebiegu.

Czas trwania procedury przerwania ~0,013ms
Czas pomiędzy kolejnymi przerwaniami ~2,04ms
Czas trwania pełnego impulsu (wypełnienie 100%) ~ 204,8ms

Dalsze skracanie jest możliwe, ale będzie wiązać się z małym oknem czasowym na dalsze operacje.

Awatar użytkownika
M@ciej
Użytkownik
Posty: 736
Rejestracja: 13 sie 2005, 21:38
Lokalizacja: Szczecin

Post autor: M@ciej » 27 maja 2007, 17:50

Dzięki ZbeeGin za pomoc. Teraz to już tylko trzeba zbudować układ i zo9baczyć jak działa. Oscyloskop mam,więc powinno już coś z tego wyjść :)

Dzięki tez Aro za podpowiedzi,ale bez fizycznego układu możemy gdybać.Trzeba to sprawdzić w praktyce :)

ODPOWIEDZ