Brak produktów
PWM to skrót od Pulse Width Modulation, czyli modulacja szerokością impulsu. Można powiedzieć, że PWM to najprostszy z możliwych przetworników cyfrowo-analogowych. W bardzo prosty sposób pozwala regulować napięcie, prąd, moc, a w konsekwencji prędkość silnika, jasność lampy i wiele innych.
Idea działania modulatora PWM jest bardzo prosta - sygnał wyjściowy przybiera wartość 1 lub 0, co odpowiada najwyższemu lub najniższemu napięciu, jakie jest na wyjściu. Generowany jest sygnał prostokątny o stałej częstotliwości. Trik polega na zmianie współczynnika wypełnienia tego sygnału. Przykładowo, jeśli czas trwania jedynki i zera jest taki sam, wówczas współczynnik wypełnienia wynosi 50%. Jeśli jedynka trwa przez 100us, a zero przez 900us, to mamy współczynnik wypełnienia rzędu 10%. Po przepuszczeniu takiego sygnału przez filtr dolnoprzepustowy uzyskujemy sygnał analogowy o napięciu, które możemy płynnie regulować. Elementy takie jak żarówki, grzejniki czy silniki nie wymagają stosowania filtrów.
Budowa generatora PWM w układzie FPGA/CPLD jest trywialnie prosta. Potrzebujemy zaledwie jeden licznik, jeden przerzutnik i kilka prostych elementów. Przyjrzyjmy się bliżej schematowi.
Potrzebujemy źródło sygnału zegarowego, które łączymy z najzwyklejszym licznikiem, liczącym w górę. Kiedy licznik osiągnie najwyższą wartość, wtedy resetuje się i zaczyna liczyć od początku. Wartość "granica" wyznacza współczynnik wypełnienia generowanego sygnału. Nazywa się to również wartością progową lub threshold. Oprócz tego mamy dwa komparatory. Pierwszy z nich daje na wyjściu 1, kiedy wartość licznika jest równa 0 (de facto jest to bramka NOR). Drugi porównuje aktualną wartość licznika z wartością graniczną.
Na początku cyklu, licznik ma wartość 0. Wykrywa to pierwszy komparator (=0) i natychmiast wystawia jedynkę na swoim wyjściu, połączonym z wejściem SET przerzutnika. Powoduje to pojawienie się stanu wysokiego na wyjściu generatora. Ten stan utrzymuje się przez pewien czas, a licznik liczy w górę. Kiedy stan licznika zrówna się z wartością graniczną, uaktywnia się drugi komparator, który jest połączony z wejściem RESET przerzutnika. W wyniku tego uzyskujemy zero na wyjściu układu. Ten stan utrzymuje się aż do przepełnienia licznika i powrotu do wartości początkowej. Wtedy cykl się powtarza.
Kod jest bardzo prosty i odpowiada powyższemu opisowi. Jedyna różnica polega na dodaniu wejścia resetującego, które zeruje licznik sterujący i ustawia wyjście w stan wysoki.
module pwm( input clk, input reset, input [7:0] granica, output reg wyjscie = 1'b1 ); // licznik sterujący reg [7:0] licznik = 8'h00; // generator pwm always @(posedge clk) if(reset) begin wyjscie = 1'b1; licznik = 8'h00; end else begin licznik = licznik + 1; if(licznik == granica) wyjscie = 1'b0; else if(licznik == 8'h00) wyjscie = 1'b1; end endmodule
Napiszmy jeszcze prosty moduł testowy.
`timescale 1 ns / 1 ns module pwm_tb; reg clk; reg reset; reg [7:0] granica; wire wyjscie; // instancja modułu pwm modul(clk, reset, granica, wyjscie); // sygnał zegarowy always #1 clk = ~clk; // procedura testowa initial begin clk = 0; reset = 0; granica = 8'd255; #10000 granica = 8'd192; #10000 granica = 8'd128; #10000 granica = 8'd64; #10000 granica = 8'd0; #10000 $finish; end endmodule
Po przeprowadzeniu symulacji dostajemy takie wykresiki. Po kliknięciu myszką powinny się powiększyć na cały ekran. Licznik i granica to wartości 8-bitowe, zatem maksymalna wartość jaką mogą przyjąć to 255. Kiedy próg przełączenia ustawiony jest na 255, wtedy sygnał wyjściowy ma wypełnienie 255/256 i widać krótkie szpilki. Współczynnik wypełnienia jest proporcjonalny do wartości granicznej.
Prezentowany generator PWM jest bardzo prosty, ale ma jeden poważny feler, co wyraźnie widać na poniższym obrazku. W chwili zaznaczonej czerwonym kursorem, wartość graniczna została zmieniona, jednak sygnał wyjściowy pozostał w stanie wysokim aż do zakończenia cyklu! Dlaczego tak się stało? Próg przełączenia został ustawiony w chwili, kiedy licznik miał wartość większą od granicznej. Zatem licznik i granica w tym cyklu nigdy się nie zrównały, przez co drugi komparator nie zresetował przerzutnika. Nie powinno się zmieniać zasad w trakcie gry :)
Inny sposób został przedstawiony na stronie FPGA4FUN. Po syntezie ten układ zajmuje trochę mniej zasobów niż rozwiązanie z komparatorami.
module pwm( input clk, input [7:0] granica, output wyjscie ); // licznik sterujący reg [8:0] akumulator = 9'd0; // generator pwm always @(posedge clk) akumulator = akumulator[7:0] + granica; // wyjście assign wyjscie = akumulator[8]; endmodule