Elvis Napisano Sierpień 10, 2010 Udostępnij Napisano Sierpień 10, 2010 Poprzednia lekcja Lekcja 8 - PWM ciąg dalszy Następna lekcja Rejestry cienie Poprzedni program był bardzo prosty, niestety miał kilka mankamentów. Pierwszy to problem zmiany wartości zmiennej pwm_led_0. Jeśli zmienimy wartość tej zmiennej podczas działania PWM to możemy uzyskać dość dziwne działanie - zmienimy wartość na mniejszą, a na w efekcie na chwilę dioda zapali się na bardzo długo (cały okres PWM). Wyobraźmy sobie następującą sytuację. Nasz PWM miał wypełnienie 50%, zmieniamy na 10%. Jeśli zmiany dokonamy, gdy licznik jest pomiędzy 10%, a 50% to procedura PWM nie wygasi diody! Przy następnym okresie będzie już działać poprawnie, ale jeśli często będziemy zmieniać wartość wypełnienia, nasz PWM będzie działać niepoprawnie. Problem taki pojawia się, gdy zmieniamy wypełnianie PWM podczas pracy. Najlepiej byłoby zmieniać wypełnianie dopiero po zakończeniu okresu PWM. Możemy to zrealizować tworząc rejestr cień (ang. shadow). Rejestr ten będzie przechowywał aktualnie używaną wartość PWM, po zakończeniu okresu PWM wartość zwykłego rejestru będzie kopiowana do rejestru cienia. Nowa procedura obsługi PWM wygląda następująco: void pwm_proc() { static unsigned int pwm_led_0_shadow = 0; if (++pwm_counter>=PWM_PERIOD) { pwm_led_0_shadow = pwm_led_0; pwm_counter = 0; GPIO1_IOSET = LED_0; } if (pwm_counter==pwm_led_0_shadow) GPIO1_IOCLR = LED_0; } Zmienna pwm_led_0_shadow została zadeklarowana jako static. Zachowuje się jak zmienna globalna, ale poza procedurą nie ma do niej dostępu - dzięki temu "przypadkiem" nie zmienimy jej wartości. Warto przeanalizować ten program - większość procesorów ma wbudowaną obsługę rejestrów cieni w sprzętowych modułach PWM. program12.zip zawiera przykładowy kod płynnie zapalający i wygaszający diodę. Poniżej filmik z rezultatem działania: Więcej linii PWM Gdy potrafimy już sterować jedną linią (i diodą) możemy rozbudować program o obsługę wielu (w naszym przypadku 8) diod. Moglibyśmy wykorzystać metodę „kopiuj-wklej” i 8 razy skopiować poprzedni program. Nie jest to oczywiście dobra metoda, więc my postąpimy inaczej. Wykorzystamy tablice. Procedura obsługi PWM wygląda tak: void pwm_proc() { static unsigned int pwm_counter = 0; static unsigned int pwm_led_shadow[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; int i; if (++pwm_counter>=PWM_PERIOD) { for (i=0;i<8;i++) pwm_led_shadow[i] = pwm_led[i]; pwm_counter = 0; GPIO1_IOSET = LED_MASK; } for (i=0;i<8;i++) if (pwm_counter==pwm_led_shadow[i]) GPIO1_IOCLR = LED_PIN[i]; } Od poprzedniej różni się głównie dodaniem pętli oraz wykorzystaniem tablic zamiast zmiennych. Nowy program będzie wykorzystywał wartości pwm_led[0] ... pwm_led[7] do ustawiania jasności diod D0...D7. Program program13.zip zapala i gasi na zmianę diody D0 i D1. Stała: #define LIGHT_N 20 definiuje w ilu krokach będziemy zapalać/gasić diody. Funkcja set_led_light(int value) realizuje niejako przechodzenie świecenia od D0 do D1. Dla parametru value=0 zapalana jest D0, następnie zwiększając value przygaszana jest D0, a rozjaśniana D1. Dla value=LIGHT_N w pełni świeci D1. Kod jest następujący: void set_led_light(int value) { pwm_led[0] = (LIGHT_N-value)*PWM_PERIOD/LIGHT_N; pwm_led[1] = value*PWM_PERIOD/LIGHT_N; } Działanie programu pokazuje film: W pliku program14.zip znajdziemy jeszcze jeden przykład zastosowania naszego PWM - kolejne zapalanie wszystkich 8 diod. Program jest nieco bardziej rozbudowany, diody zamiast liniowo, wygaszane i zapalane są stablicowaną funkcją sinus - takie sterowanie daje nieco ładniejszy efekt i jest bardzo ważne gdybyśmy sterowali silnik za pomocą PWM. Film z rezultatem działania: Program14.zip Program13.zip Program12.zip
OldSkull Październik 15, 2010 Udostępnij Październik 15, 2010 Mam pytanie odnośnie do tablicowania, pamięci itd. Czy deklarując stałą np.: const unsigned int[20] = {...}; zostanie ona umieszczona w pamięci RAM, czy w pamięci programu? Jeżeli jest przechowywana w pamięci RAM, wpisanie jej jako stałej ma średni sens, jedyna zaleta takiego rozwiązania jest taka, że ją chroni przed zmainami. Czy w WinARMie można sprawdzić jaka jest przewidywana zajętość pamięci RAM? Rozumiem, że pamięć flash jest podawana jako "image size", tak?
Elvis Październik 16, 2010 Autor tematu Udostępnij Październik 16, 2010 Aby sprawdzić, gdzie są przechowywane zmienne funkcje itd. najlepiej otworzyć plik z rozszerzeniem .map (znajduje się w katalogu z plikiem wynikowym). Przykładowo w program14.map znajdziemy fragment: Memory Configuration Name Origin Length Attributes ROM 0x00000000 0x0001e000 xr RAM 0x40000000 0x00004000 rw *default* 0x00000000 0xffffffff Tutaj zdefiniowana jest mapa pamięci naszego mikrokontrolera. Od adresu 0 mamy Flash, od 0x40000000 pamięć RAM. Dalej odnajdujemy adresy zmiennych, czy funkcji. Przykładowo stała: const unsigned int SIN_TABLE[] = { 0, 15, 31, 46, 61, 76, 90, 104, 117, 129, 141, 152, 161, 170, 178, 184, 190, 194, 197, 199, 200 }; Daje wynikowo: *(.rodata) .rodata 0x00000418 0x74 program14.o 0x00000438 SIN_TABLE 0x00000418 LED_PIN Więc jak widać const działa zgodnie z oczekiwaniami, stała umieszczana jest w pamięci Flash.
Pomocna odpowiedź
Bądź aktywny - zaloguj się lub utwórz konto!
Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony
Utwórz konto w ~20 sekund!
Zarejestruj nowe konto, to proste!
Zarejestruj się »Zaloguj się
Posiadasz własne konto? Użyj go!
Zaloguj się »