LinkedIn YouTube Facebook
Szukaj

Wstecz
Artykuły

[PROJEKT] Sterowanie silnikami – KA-Nucleo-F411CE oraz shield z układem L298

W projekcie będziemy sterować prędkością obrotową silników prądu stałego oraz kierunkiem ich obrotu, wykorzystamy mikrokontroler STM32 znajdujący się na płytce rozwojowej KA-Nucleo-F411CE oraz sterownik silników w postaci shielda z układem L298. Program przygotowano za pomocą pakietu STM32CUBE.

Do realizacji projektu będą potrzebne następujące elementy:

Rysunek 1. Shield do sterowania silnikami oparty na układzie L298

Sterownik w postaci shielda dla Arduino został wyposażony w układ L298, pozwala sterować dwoma silnikami prądu stałego, które mogą być zasilane napięciem 4,8…35 V, każdy z nich może pobierać prąd o maksymalnym natężeniu 2 A. Połączenie z płytką KA-Nucleo-F411CE jest bardzo, proste ponieważ posiada ona złącze kompatybilne z rozszerzeniami (shieldami) przeznaczonymi dla Arduino.

Moduł posiada 3 złącza śrubowe, dwa z nich służą do podłączenia silników którymi ma sterować układ (czerwona ramka rysunek 2), oraz złącze do podłączenie zewnętrznego zasilania dla silników (ramka niebieska na rysunku 2). Zworkami (żółta ramką rysunek 2) możemy wybierać z którego źródła ma pochodzić napięcie do sterowania silnikami, czy z podłączonego do złącza śrubowego (niebieska ramka) czy z złącza do DC znajdującego się w płytce KA-Nucleo. Ja użyje tego drugiego sposobu, moim źródłem zasilania będzie pakiet Li-pol 7,4 V, który będzie zasilał płytkę oraz silniki.

Rysunek 2. Złącza śrubowe do podłączenia silników oraz źródła zasilania dla nich.

 

Na czas programowania należy wyjmować zworki (żółta ramka na rysunku 2), aby nie uszkodzić portu USB w komputerze.

Teraz należy podłączyć nasze silniki do shielda:

Rysunek 3. Silniki podłączone do shielda ze sterownikiem silników 

Shield może pracować w dwóch trybach: PLL lub PWM. My wykorzystamy tryb PWM, aby pracować w tym trybie zworki konfiguracyjne muszą być umieszczone jak na rysunku

Rysunek 4. Zworki konfiguracyjne

Teraz przejdziemy do konfiguracji STM32, do tego celu wykorzystamy program CubeMX, który umożliwia szybkie i wygodne skonfigurowanie mikrokontrolera. CubeMX pozwoli nam ustawić odpowiednią prędkość pracy mikrokontrolera, oraz konfiguracje wyjść GPIO.

Rysunek 5. Program CubeMX

Po uruchomieniu CubeMX, tworzymy nowy projekt, pojawi się okno w którym musimy wybrać mikrokontoler znajdujący się w KA-Nucleo-F411CE, czyli układ STM32F411CEU6. Wybieramy serie STM32F4 (1) następnie linię STM32F411 (2) oraz obudowę UFQFPN48 (3), lista zawęziła się do dwóch układów (rysunek 6) wybieramy ten, który posiada 512 Mb pamieć Flash. Wybór akceptujemy przyciskiem OK w dolnej części okna.

Rysunek 6. Wybór odpowiedniego mikrokontrolera w programie CubeMX

 Szczegółowy opis narzędzia CubeMX znajduje się w artykule:

STM32Cube graficzny konfigurator STM32

Gdy już mamy utworzony projekt pierwszą czynnością, będzie ustawienie źródła taktowania rdzenia procesora i magistrali peryferiów. Najpierw na liście z lewej strony odnajdujemy element RCC i rozwijamy listę pojawi nam się lista (czerwona ramka – rysunek 7). Następnie dla przy ustawieniu High Speed Clock (HSE) wybieramy opcje Crystal/Ceramic Resonator. Po prawej przy pinach PH0 i PH1 powinny pojawić się napisy RCC_OSC_IN oraz RCC_OSC_OUT (czarna ramka na rysunku 7).

Rysunek 7. Ustawienie zewnętrznego oscylatora kwarcowego 

Następnie przechodzimy do zakładki clock configuration (w górnej części okna) w celu przeprowadzenia konfiguracji częstotliwości taktowania wewnątrz układu. Zaczynamy od ustawienia parametru Input frequency na 8 MHz (1) następnie wybieramy źródło sygnału zegarowego(PLL Source Mu) na HSE (2), i zmianę częstotliwości głównej magistrali (HCLK) (3) mikrokontrolera na maksymalną możliwą czyli 100 MHz (4). Po zmianie ostatniej wartości klikamy przycisk Enter, teraz program przeliczy wszystkie dane i ustawi dla poszczegolnych peryferiów odpowiednie częstotliwości pracy (rysunek 8).

Rysunek 8. Konfiguracja taktowania zegara i magistral STM32 w programie CubeMX

Następnie musimy ustawić role odpowiednich pinów mikrokontrolera, spójrzmy na tabele 1 w której mamy pokazane który pin shielda odpowiada jakiemu pinowi na KA-Nucleo oraz jaki należy ustawić w programie CubeMX:

Pin modułu Shieldu Pin KA-Nucleo Pin mikrokontrolera/CubeMX
E1(5) 5 PB4
M1(4) 4 PB5
E2(6) 6 PA10
M2(7) 7 PB8

Informacje które piny shieldu odpowiadają pinowi Ka-Nucelo/Arduino znajdziemy na samym shieldzie lub w dokumentacji modułu.

Piny M1 oraz M2 należy ustawić jako wyjścia cyfrowe (GPIO Output), będą one określały kierunek ruchu wału silnika, natomiast E1 i E2 muszą być ustawione w trybie generowania PWM, zmiana prędkości obrotu wału silnika.

Najpierw należy ustawić role pinów M1 (PB5) oraz M2 (PA8), w tym celu odnajdujemy jakie piny mikrokontolera odpowiadają tym pinów wybieramy te piny w programie CubeMX oraz wybieramy opcje GPIO_output (rysunek 9).

Rysunek 9. Ustawienie pinu PB5 jako wyjścia – GPIO_Output

Następnie przejdziemy do ustawienia pinów E1(PB4)i E2(PB10), muszą one generować sygnał PWM. Klikamy na wyprowadzanie PB4 i wybieramy opcje TIM3-CH1 (rysunek 10) oraz wyprowadzenie PB10 i wybieramy opcje TIM2 -CH3.

Rysunek 10. Ustawienia wyjścia PB4 jako TIM3-CH1

 

Następnie na liście z lewej strony odnajdujemy TIM2 oraz TIM3 oraz ustawiamy odpowiednio kanał 3 timera 2 (PB10) jako PWM Generation CH3 (rysunek 11) oraz dla kanału 1 timera 3 (PB4) jako PWM Generation CH1.

Rysunek 11. Ustawienie kanału 1 w timerze 3 jako wyjście sygnału PWM

Aby nasze piny generowały odpowiednio sygnał PWM, musimy ustawić odpowiednie wartości preskalara. W tym celu przechodzimy do zakładki configuration CubeMX (1 – rysunek 12). I wybieramy interesujący timer, np. TIM2 lub TIM3 (2 – rysunek 12).

Rysunek 12. Przejście do ustawień timera TIM2

W naszym przypadku sygnał PWM będzie generowany z częstotliwością 50 Hz, będziemy mieć możliwość sterowania wypełnieniem od 0 do 100 (gdzie 0 brak wypełnienia, a 100 maksymalne wypełnienie) aby to uzyskać należy ustawić parametry timer jak na rysunku 13:

Rysunek 13. Ustawienie timera 2 do pracy z częstotliwością 50 Hz 

Będąc w zakładce Configuration, warto otworzyć zakładkę GPIO która znajduje się w kategorii system. Możemy w niej przypisać własne nazwy (w polu User Label) dla wcześniej zadeklarowanych pinów, ja ustawie je zgodnie z opisem na shieldzie, czyli M1 dla pinu PB5 oraz M2 jako PA8 (Rysunek 14)

Rysunek 14. Ustawienie własnych nazw dla wyjść GPIO

Wracamy do zakładki Pinout powinniśmy zobaczyć następujący widok (rysunek 15):

Rysunek 15. Końcowa konfiguracja pinów mikrokontrolera w programie CubeMX

Teraz wygenerujemy kodu oraz plików projektu dla darmowego środowiska programowania STM32 – AC6. Aby to zrobić wybieramy z górnej belki Projekt > Generate Code. Pojawia nam się okno (rysunek 16) z ustawieniami projektu, ustawiamy nazwę projektu np.KA_Nucleo_Sterowanie_silnikami (1) wybieramy lokalizacje projektu, powinna być ona taka sama jak workspace programu AC6 (2). A następnie wybieramy środowisko na które ma zostać projekt, z rozwijanej listy wybieramy SW4STM32 (3), oraz naciskamy przycisk OK (4).

Rysunek 16. Generowanie plików projektu w programie CubeMX

Następnym krokiem będzie otworzenie wygenerowanego projektu w środowisku AC6. Uruchamiamy program AC6 a następnie klikamy File > Import, następnie z listy wybieramy General, a następie Existing Project into Workspace i przechodzimy dalej klikając na przycisk Next > (rysunek 17).

Rysunek 17. Importowanie plików do środowiska AC6

Najpierw wybieramy ścieżkę dostępu do naszego folderu roboczego (gdzie zapisaliśmy nasz projekt), klikając przycisk Browse (1), z liście wybieramy odpowiedni projekt (2). Ważne aby pole przy Copy project into workspace było NIE ZAZNACZONE (3). Aby skończyć importowanie projektu klikamy przycisk Finish.

Rysunek 18. Importowanie plików do środowiska AC6 – cd.

Od teraz nasz projekt powinien być widoczny w zakładce Project Explorer w lewej części okna programu.

Teraz napiszemy program, który będzie sterował silnikami podłączonymi do KA-Nucleo przy pomocy shielda. Jednak przed tym należy dowiedzieć się jakie sygnały należy podać na wyjścia E1, E2 oraz M1, M2.

Przykładowo dla silnia podłączonego do złącz M1+ oraz M1-, aby nasz silnik poruszał się do przodu na pinie M1 należy podać stan wysoki, na pin E1 sygnał PWM, aby silnik obracał się w przeciwnym kierunku na M1 musi pojawić się stan niski, a na wyjście E1 sygnał PWM.

Napiszemy program który będzie uruchamiał najpierw pierwszy silnik z wartością PWM od 0 do 100 (wartość będzie rosnąć od 0 do 100), następnie zatrzymywał silnik na 2 sekundy (2000 ms), oraz uruchamiał silnik w przeciwnym kierunku również z wartością od 0 do 100 wypełnienia PWM. Podobna sekwencja będzie wykonywana na silniku drugiem (podłączonym do wyjść M2- i M2+).

Kod programu będziemy tworzyć w pliku main.c znajdziemy go w katalogu Src w naszym projekcie, oraz otwieramy go klikając na niego dwukrotnie.

Rysunek 19. Lokalizacja pliku main.c w projekcie

Pierwszą czynnością będzie uruchomienie obu timerów i odpowiednich kanałów.

  /* USER CODE BEGIN 2 */

  HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
  HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3);

  /* USER CODE END 2 */

Kod musi znajdować się między komentarzami /* USER CODE BEGIN 2 */ a  /* USER CODE END 2 */.

Następnie w pętli głównej tworzymy pętle for, która będzie powtarzać się do momentu kiedy zmienna i nie osiągnie wartości 100. Wartość zmiennej i będzie przypisywana do rejestru (TIM3->CCR1 = i;) w którym znajduje się wartość PWM (w tym przypadku dla silnika pierwszego Timer 3 kanał 1) oraz ustawiana jest stan wysoki na pinie M1.

for(int i=0;i<=100;i++)
{
  TIM3->CCR1 = i;
  HAL_GPIO_WritePin(GPIOB,M1_Pin,GPIO_PIN_SET);
  HAL_Delay(200);
}

Następnie po wykonaniu tej pętli silnik jest zatrzymywany na 2 sekundy.

TIM3->CCR1 =0;
HAL_Delay(2000);

W kolejnej pętli wał silnika będzie obracał się w przeciwnym kierunku niż w ww. pętli, prędkość będzie się zwiększała co 200 milisekund aż do osiągnięcia wartości PWM równej 100 (zmienna i osiągnie wartość 100). Z tą różnica ze na pinie M1 jest w stanie niskim, co spowoduje obrót wału silnika w przeciwnym kierunku.

for(int i=0;i<=100;i++)
{

TIM3->CCR1 = i;
HAL_GPIO_WritePin(GPIOB,M1_Pin,GPIO_PIN_RESET);
HAL_Delay(200);

}

Następnie silnik zostanie zatrzymany na 2 sekundy.

TIM3->CCR1 =0;
HAL_Delay(2000);

Następnie podobna sekwencja zostanie wykonana dla silnika drugiego. Pełen kod programu znajduje się w sekcji do pobrania.

Autor: Patryk Mądry