Skocz do zawartości

[Kurs] Kurs programowania ARM cz.07 - PWM


Elvis

Pomocna odpowiedź

Poprzednia lekcja

Lekcja 7 - PWM

Następna lekcja

Zacznijmy od omówienia wad procesorów. Są to urządzenia czysto cyfrowe. Pracują w logice zero-jedynkowej (binarnie). Oodczytują lub wypisują logiczne 0, co odpowiada zwarciu linii do masy, albo logiczne 1, czemu odpowiada podłączenie linii do zasilania (w przypadku LPC2114, 3.3V).

Gdy sterujemy np. świeceniem diody LED, oznacza to że możemy albo wyłączyć diodę, albo zapalić ją z maksymalną jasnością. Nie mamy możliwości sterowania jasnością świecenia.

Jak to się dzieje, że w komputerach, telefonach itd. można regulować jasność podświetlenia?

Z pomocą przychodzi nam właśnie PWM.

Sztuczka polega na tym, że procesor przez chwilę zapala diodę, po czym na moment ją wygasza.

Gdy dzieje się to odpowiednio szybko, oko ludzkie nie jest w stanie zarejestrować migania diody i widzimy jedynie słabiej świecącą diodę.

Jak sterujemy jasnością? Jeśli czas wygaszania jest dłuższy, a świecenia krótszy to dioda świeci słabiej. Podobnie, im dłuższy jest czas świecenia, tym świeci jaśniej.

Dla ułatwienia przyjmuje się, suma czasu świecenia i wygaszenia diody jest stała. Czas ten dobiera się, tak aby nie było widać migotania. Następnie steruje się czasem świecenia diody - pozostały czas to wygaszenie. Czas świecenia można wyrażać w sekundach, albo co często jest łatwiejsze w procentach. Mówimy, że PWM ma wypełnienie 25%, jeśli przez 1/4 czasu dioda świeci, a przez 3/4 jest wygaszona.

Oscylogram PWM o wypełnieniu 25%:

Wypełnienie 25% oznacza, że sygnał ma poziom wysoki przez 25% czasu, co widać na obrazku.

Podobnie dla wypełnienia 95%, tylko przez krótki czas pojawią się impulsy o niskim poziomie:

Sprzętowy PWM

Wiele procesorów ma wbudowane układy PWM. Wystarczy wysterować odpowiednie rejestry i na linii procesora pojawia się sygnał PWM.

Najpierw omówimy jak wykorzystać sprzętowy PWM w procesorze LPC2114.

Procesor ma maksymalnie 6 kanałów PWM. Mają one bardzo rozbudowane możliwości konfiguracji, każdy może pracować z innym wypełnieniem.

Linie, które mogą pracować jako PWM na schemacie oznaczone są jako PWM1, PWM2 ... PWM6.

Jak widać każda linia może spełniać jedną z wielu funkcji. W przypadku większości linii do dyspozycji są 4 możliwości.

Przykładowy program uruchomi PWM5 na linii P0.21 procesora. Efekt działania programu był pokazany wcześniej - wypełnienie 95%:

void pwm_init()
{
 PCB_PINSEL1 |= 0x00000400;
 PWM_PR = 0x00000000; 
 PWM_PCR = 0x2000; 
 PWM_MCR = 0x0001; 
 PWM_MR0 = 15000;
 PWM_MR5 = 15000 * 0.95; 
 PWM_LER = 0x21; 
 PWM_TCR = 0x01; 
 PWM_TCR = 0x09; 
}

Za pomocą rejestru PCB_PINSEL1 ustawiamy, którą funkcję będzie pełnił dany pin P0.21.

Większość linii procesora może pełnić kilka funkcji. Za pomocą rejestrów PCB_PINSEL0, PCB_PINSEL1 oraz PCB_PINSEL2 ustawiamy jaką funkcje pełni dana linia.

Domyślnie większość linii to zwykłe linie I/O.

Kolejny interesujący rejestr to PWM_MR0. Jest to licznik dla kanału 0 oraz podstawa czasu (okres) w naszej konfiguracji.

Jak pamiętamy zegar peryferiów ma częstotliwość 15MHz. Gdy wpiszemy do PWM_MR0 wartość 15000, otrzymamy częstotliwość 15Mhz/15000, czyli 1kHz. Więc okres naszego PWM będzie wynosił 1ms. To zgadza się z odczytem z oscyloskopu, który widzieliśmy wcześniej.

Następny interesujący rejestr to PWM_MR5. Odpowiada on za wypełnienie dla PWM5, czyli tego, który konfigurujemy. Wpisujemy do niego wartość 14250 (15000 * 95%).

Pozostałe rejestry opisane są w dokumentacji procesora. Liczba opcji i możliwości jest naprawdę spora.

Niestety nasza linia nie jest podłączona do żadnego układu w płytce prototypowej.

Do testów wykorzystaliśmy oscyloskop, jednak dla większości użytkowników takie rozwiązanie może nie być idealne.

Gdyby jednak ktoś był zainteresowany programem przykładowym, znajduje się on w archiwum program18.zip.

Programowy PWM

Sprzętowy PWM jest najdokładniejszy i w wielu zastosowaniach niezastąpiony. W naszym przypadku niestety nie mamy jak sprawdzić jego działania.

Pozostaje nam napisać program, który wygeneruje przebieg odpowiadający PWM.

Użyjemy naszego „programowego” PWM do płynnego sterowania jasnością diod LED. Taki sam kod można wykorzystać np. do sterowania wieloma serwomechanizmami.

Do utworzenia PWM wykorzystamy znany nam już Timer0. Przerwanie wywoływane jest co 100us i taki właśnie będzie miał minimalny krok nasz PWM.

W pierwszej wersji przyjmiemy okres PWM bardzo długi, tak abyśmy gołym okiem mogli sprawdzić działanie programu.

#define PWM_PERIOD	10000

Procedura obsługi PWM będzie wołana co 100us, czyli okres naszego PWM będzie wynosił:

100us * 10000 = 1ms * 1000 = 1s

Przy każdym wywołaniu procedury PWM zwiększany będzie licznik PWM

unsigned int pwm_counter;

Gdy osiągnie wartość PWM_PERIOD, licznik będzie zerowany i rozpocznie się kolejny okres PWM.

W zmiennej globalnej:

volatile unsigned int pwm_led_0 = 0;

Będziemy przechowywać wypełnienie PWM (poziom jasności diody).

Warto zwrócić uwagę na słowo kluczowe volatile. Zmienna będzie wykorzystywana zarówno w przerwaniach, jak i w kodzie głównym. Bardzo ważne jest, aby kompilator unikał optymalizowania odwołań do takiej zmiennej.

Na początku okresu PWM będziemy zapalać diodę D0. Gdy licznik PWM zrówna się z wartością pwm_led_0, dioda będzie gaszona.

Kompletny kod procedury PWM wygląda następująco:

void pwm_proc()
{
if (++pwm_counter>=PWM_PERIOD) {
	pwm_counter = 0;
	GPIO1_IOSET = LED_0;
}
if (pwm_counter==pwm_led_0)
	GPIO1_IOCLR = LED_0;
}

Gdy do zmiennej pwm_led_0 wpiszemy 5000 (czyli PWM_PERIOD/2), przez pół sekundy dioda będzie zapalona, przez kolejne pół zgaszona.

Dla pwm_led=500 (czyli PWM_PERIOD/10) dioda będzie zapalać się na bardzo krótko (100ms), a przez pozostały czas pozostanie zgaszona.

Warto poeksperymentować z różnymi wartościami, aby zrozumieć działanie PWM.

W archiwum progam11.zip znajdziemy przykładowy program.

Poniżej oscylogram dla wypełnienia 10% oraz film z rezultatem działania.

"Prawdziwy" PWM

Dotychczas używaliśmy PWM o okresie 1s.

Taka wartość jest najczęściej za duża w prawdziwych programach.

Zmienimy wartość stałej PWM_PERIOD, tak aby uzyskać sterowanie jasnością diod zamiast ich migania.

Przyjmijmy okres PWM równy 20ms. Ponieważ procedura jest wołana co 100us, więc okres PWM_PERIOD powinno wynosić:

20ms / 100us=20000/100 = 200

Po zmianie kodu na:

#define PWM_PERIOD	200

Warto sprawdzić działanie diody.

Teraz dla pwm_led=100 (PWM_PERIOD/2) dioda będzie świecić w mniej więcej połowie jasności.

Dla pwm_led=20 (PWM_PERIOD/10) dioda będzie świecić bardzo słabo.

Program18.zip

Program11.zip

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.