Autor: Dondu
Artykuł z cyklu: Silnik BLDC: Spis treści
W poprzednim artykule omówiłem budowę prostego układu kluczy z wykorzystaniem tranzystorów MOSFET. Możemy więc zająć się skompletowaniem sterownika oraz przetestowaniem jego działania na diodach LED.
No to zabieramy się do budowy i testów.
Mikrokontroler sterujący (CPU)
Zaczniemy od przygotowania układu mikrokontrolera, który będzie sercem naszego sterownika. Skorzystamy z popularnego i często używanego na blogu mikrokontrolera ATmega8.
W kolejnych częściach cyklu dodawać będziemy różne funkcjonalności, dlatego też piny sterowania faz silnika oraz innych funkcjonalności wybieramy nieprzypadkowo.
Schemat serca sterownika będzie prosty na ile to tylko możliwe.
Kwarc
Na powyższym schemacie nie ma zaznaczonego kwarcu. Na tę chwilę nie jest nam potrzebny, a do czynności testujących opisanych w tym artykule wystarczy taktowanie mikrokontrolera z wewnętrznego generatora np. standardowego 1MHz. W późniejszym czasie kwarc będzie nam jednak potrzebny.
Dławik L1
Ze względu na to, iż mamy do czynienia ze sterownikiem silnika (czyli urządzeniem indukcyjnego) oraz wykorzystywać będziemy komparator analogowo cyfrowy i przetwornik analogowo-cyfrowy, stąd warto zadbać o poprawne zasilanie części analogowej mikrokontrolera. Dlatego też pin AVcc zasilany jest poprzez dławik L1.
Jeżeli nie posiadasz dławika, możesz ewentualnie zamiast niego dać rezystor np. 10Ω. W ostateczności możesz nie dawać nawet rezystora, ale musisz być świadomy, że może (nie musi) wpłynąć na poprawną pracę sterownika.
Więcej na ten temat znajdziesz tutaj: ADC - Dokładność vs podłączanie
Rezerwacja pinów
Ponieważ sterownik, będzie miał dodatkowe potrzeby w zakresie pinów, stąd niektóre z nich oznaczyłem etykietą REZERWA_x. Będziemy je sukcesywnie wykorzystywać, w następnych artykułach o silniku BLDC. Dlatego budując sterownik do testów, zostaw sobie trochę miejsca na dodatkowe elementy.
Złącze programatora
Na schemacie nie zaznaczyłem złącza programatora. Zwróć uwagę, że jeden z pinów wykorzystywanych do programowania mikrokontrolera (PB3 / MOSI / OC2) jest używany do sterowania tranzystora górnego fazy V. Piszę o tym w dalszej części niniejszego artykułu.
Klucze przełączające
Na początku artykułu wspomniałem, że najpierw przetestujemy sterownik na diodach LED. Dlaczego? Ponieważ tak proste rozwiązanie modułu kluczy ma jeden poważny problem:
Pisałem o tym w części dot. niezbędnych podstaw: Silnik BLDC: Niezbędne podstawy
Chodzi o to, że tylko i wyłącznie program decyduje o włączeniu lub wyłączeniu wybranych kluczy jednej fazy.
Dlatego w pierwszej kolejności musimy zadbać o to, by ewentualna pomyłka w programie, nie skutkowała dymem i dodatkowymi kosztami wymiany tranzystorów.
Jak to zrobimy?
Opracujemy odpowiedni bezpiecznik programowy.
Na razie jednak przygotuj trzy układy kluczy (po jednym dla każdej fazy), ale nie łącz tranzystorów kluczujących (MOSFET'ów). Zamiast tego podłącz do nich diody LED w następujący sposób:
Następnie wszystkie trzy moduły kluczy podłącz do mikrokontrolera zgodnie z etykietami na schemacie CPU. Po tej czynności powinieneś mieć kompletny sterownik, przygotowany do testów.
Programowanie vs pin PB3 (MOSI)
Zauważ, że do sterowania górnym tranzystorem fazy V (sygnał V_TR_G) na schemacie powyżej, używamy pinu PB3, który jest także używany do programowania mikrokontrolera. Pin ten połączony jest z rezystorem R4, przez który steruje bazą tranzystora Q3 (NPN), a ten steruje tranzystorem Q1 (MOSFET).
Takie rozwiązanie nie przeszkodzi nam w poprawnym zaprogramowaniu mikrokontrolera, ale należy być świadomym tego, że:
W czasie trwania programowania mikrokontrolera, tranzystor Q1 (górny) fazy V, może być otwierany i zamykany, co oznacza pojawianie się napięcia dodatniego na fazie V.
Dlatego sugeruję (bo nie jest to konieczne), programowanie mikrokontrolera, przy wyłączonym zasilaniu 12V.
Jeżeli zasilasz mikrokontroler z regulatora napięcia 5V, który podłączony jest pod 12V zasilające jednocześnie silniki, to sugeruję wstawienie na czas testów wyłącznika, który umożliwi Ci w czasie programowania mikrokontrolera odłączenie napięcia 12V tylko od tranzystorów sterownika .
Definicje
Dla potrzeb niniejszego cyklu artykułów stosować będziemy definicje, które ułatwią i uproszczą nam pokazywanie kolejnych fragmentów i wersji programów. Jednakże:
W kolejnych artykułach niektóre z definicji będą się zmieniały, dlatego uważnie sprawdzaj jakie definicje w danym artykule są zawarte.
Aby była jednolitość prawie wszystkie definicje będą nazywane według klucza:
X_TR_Y_...
gdzie:
- X - literka fazy (U, V lub W),
- TR - skrót słowa: tranzystor,
- Y - tranzystor górny (G) lub dolny (D)
- ... - dalsza część opisana w kodach
Przykład:
U_TR_D_DDRx - definicja DDR dla tranzystora dolnego fazy U.
Do testowania modułu kluczy użyjemy następujących definicji (zawarte w pliku: bldc.h):
//--- D E F I N I C J E D O T. B E Z P I E C Z N I K A ------ //LED bezpiecznika #define BEZP_LED_DDR DDRD #define BEZP_LED_PORT PORTD #define BEZP_LED_PIN PD3 //--- D E F I N I C J E D O T. S I L N I K A ------ //Faza U //tranzystor górny #define U_TR_G_PORTx PORTB #define U_TR_G_DDRx DDRB #define U_TR_G_PINx PINB #define U_TR_G_PIN PB1 #define U_TR_G_USTAW_DDR U_TR_G_DDRx |= (1<<U_TR_G_PIN); //ustaw port #define U_TR_G_PIN_L U_TR_G_PORTx &= ~(1<<U_TR_G_PIN); //ustaw niski #define U_TR_G_ON U_TR_G_PORTx |= (1<<U_TR_G_PIN); //włącz tranz. #define U_TR_G_OFF U_TR_G_PORTx &= ~(1<<U_TR_G_PIN); //wyłącz tranz. #define U_TR_G_SPRAW_STAN (U_TR_G_PINx & (1<<U_TR_G_PIN)) //warunek stanu //tranzystor dolny #define U_TR_D_PORTx PORTD #define U_TR_D_DDRx DDRD #define U_TR_D_PINx PIND #define U_TR_D_PIN PD4 #define U_TR_D_USTAW_DDR U_TR_D_DDRx |= (1<<U_TR_D_PIN); //ustaw port #define U_TR_D_PIN_L U_TR_D_PORTx &= ~(1<<U_TR_D_PIN); //ustaw niski #define U_TR_D_ON U_TR_D_PORTx |= (1<<U_TR_D_PIN); //włącz tranz. #define U_TR_D_OFF U_TR_D_PORTx &= ~(1<<U_TR_D_PIN); //wyłącz tranz. #define U_TR_D_SPRAW_STAN (U_TR_D_PINx & (1<<U_TR_D_PIN)) //warunek stanu //Faza V //tranzystor górny #define V_TR_G_PORTx PORTB #define V_TR_G_DDRx DDRB #define V_TR_G_PINx PINB #define V_TR_G_PIN PB3 #define V_TR_G_USTAW_DDR V_TR_G_DDRx |= (1<<V_TR_G_PIN); //ustaw port #define V_TR_G_PIN_L V_TR_G_PORTx &= ~(1<<V_TR_G_PIN); //ustaw niski #define V_TR_G_ON V_TR_G_PORTx |= (1<<V_TR_G_PIN); //włącz tranz. #define V_TR_G_OFF V_TR_G_PORTx &= ~(1<<V_TR_G_PIN); //wyłącz tranz. #define V_TR_G_SPRAW_STAN (V_TR_G_PINx & (1<<V_TR_G_PIN)) //warunek stanu //tranzystor dolny #define V_TR_D_PORTx PORTD #define V_TR_D_DDRx DDRD #define V_TR_D_PINx PIND #define V_TR_D_PIN PD5 #define V_TR_D_USTAW_DDR V_TR_D_DDRx |= (1<<V_TR_D_PIN); //ustaw port #define V_TR_D_PIN_L V_TR_D_PORTx &= ~(1<<V_TR_D_PIN); //ustaw niski #define V_TR_D_ON V_TR_D_PORTx |= (1<<V_TR_D_PIN); //włącz tranz. #define V_TR_D_OFF V_TR_D_PORTx &= ~(1<<V_TR_D_PIN); //wyłącz tranz. #define V_TR_D_SPRAW_STAN (V_TR_D_PINx & (1<<V_TR_D_PIN)) //warunek stanu //Faza W //tranzystor górny #define W_TR_G_PORTx PORTB #define W_TR_G_DDRx DDRB #define W_TR_G_PINx PINB #define W_TR_G_PIN PB2 #define W_TR_G_USTAW_DDR W_TR_G_DDRx |= (1<<W_TR_G_PIN); //ustaw port #define W_TR_G_PIN_L W_TR_G_PORTx &= ~(1<<W_TR_G_PIN); //ustaw niski #define W_TR_G_ON W_TR_G_PORTx |= (1<<W_TR_G_PIN); //włącz tranz. #define W_TR_G_OFF W_TR_G_PORTx &= ~(1<<W_TR_G_PIN); //wyłącz tranz. #define W_TR_G_SPRAW_STAN (W_TR_G_PINx & (1<<W_TR_G_PIN)) //warunek stanu //tranzystor dolny #define W_TR_D_PORTx PORTD #define W_TR_D_DDRx DDRD #define W_TR_D_PINx PIND #define W_TR_D_PIN PD7 #define W_TR_D_USTAW_DDR W_TR_D_DDRx |= (1<<W_TR_D_PIN); //ustaw port #define W_TR_D_PIN_L W_TR_D_PORTx &= ~(1<<W_TR_D_PIN); //ustaw niski #define W_TR_D_ON W_TR_D_PORTx |= (1<<W_TR_D_PIN); //włącz tranz. #define W_TR_D_OFF W_TR_D_PORTx &= ~(1<<W_TR_D_PIN); //wyłącz tranz. #define W_TR_D_SPRAW_STAN (W_TR_D_PINx & (1<<W_TR_D_PIN)) //warunek stanu //Wspólna definicja wyłączająca wszystkie tranzystory #define WYLACZ_TRANZYSTORY U_TR_G_OFF; U_TR_D_OFF; V_TR_G_OFF; V_TR_D_OFF; W_TR_G_OFF; W_TR_D_OFF;
Bezpiecznik
Jak wspomniałem wcześniej, sterownik nie posiada sprzętowej realizacji zabezpieczenia kluczy (tranzystorów MOSFET), przed ustawieniem stanu zabronionego w jednej fazie. Dlatego też powinniśmy się zabezpieczyć przed tym stanem za pomocą programu.
W celu zabezpieczenia kluczy (tranzystorów MOSFET) wykorzystamy funkcję bezpiecznika, która będzie wywoływana po każdej operacji zmiany stanu kluczy (komutacji silnika).
Innymi słowy, jeżeli w programie zmienisz stan kluczy, to natychmiast powinieneś wywołać funkcję bezpiecznika. Funkcja ta sprawdzi, czy program nie spowodował ustawienia kluczy w sposób, który prowadzi do powstania stanu zabronionego.
W tym celu zastosujemy dwie współdziałające funkcje:
- bezpiecznik()
- bezpiecznik_stop()
Jeżeli funkcja bezpiecznik() wykryje stan pinów sterujących kluczami, który jest stanem zabronionym, natychmiast wywoła funkcję bezpiecznik_stop(), która:
- wyłączy wszystkie tranzystory MOSFET,
- włączy diodę LED sygnalizacji stanu zabronionego,
- wejdzie w nieskończoną pętlę programową, w której będzie migać w/w LED'em.
Takie zabezpieczenie jest skuteczne pod warunkiem, że zawsze po każdej zmianie stanu kluczy, nie zapomnisz wywołać funkcji bezpiecznik().
Funkcje bezpiecznika (zamieszczone w pliku: bldc.c):
void bezpiecznik(void){ //Sprawdzamy, czy nie występuje konflikt sterowania, powodujący //jednoczene otwarcie tranzystora górnego i dolnego w tej samej fazie, //co oznacza wystąpienie zwarcia !!! if(U_TR_G_SPRAW_STAN && U_TR_D_SPRAW_STAN){ //Faza U - oba tranzystory są włączone - sytuacja niedopuszczalna!!! bezpiecznik_stop(); }else if(V_TR_G_SPRAW_STAN && V_TR_D_SPRAW_STAN){ //Faza V - oba tranzystory są włączone - sytuacja niedopuszczalna!!! bezpiecznik_stop(); }else if(W_TR_G_SPRAW_STAN && W_TR_D_SPRAW_STAN){ //Faza W - oba tranzystory są włączone - sytuacja niedopuszczalna!!! bezpiecznik_stop(); } } //------------------------------------------------------------------ void bezpiecznik_stop(void){ //Funkcja wyłącza wszelkie tranzystory oraz przechodzi w stan sygnalizacji //błędu komutacji. Funkcja ta razem z funkcją bezpiecznik() pełni rolę //zabezpieczenia przeciwzwarciowego dla błędnie działającego algorytmu // komutacji w czasie pisania i testów programu. //wyłącz przerwania cli(); //natychmiast wyłącz tranzystory WYLACZ_TRANZYSTORY //i ustaw stany niskie na pinach sterujących U_TR_G_USTAW_DDR V_TR_G_USTAW_DDR W_TR_G_USTAW_DDR U_TR_D_USTAW_DDR V_TR_D_USTAW_DDR W_TR_D_USTAW_DDR U_TR_G_PIN_L V_TR_G_PIN_L W_TR_G_PIN_L U_TR_D_PIN_L V_TR_D_PIN_L W_TR_D_PIN_L //ustaw pin LED jako wyjście BEZP_LED_DDR |= (1<<BEZP_LED_PIN); //zatrzymaj program w pętli nieskończonej sygnalizując błąd while(1){ //zmień stan LED na przeciwny BEZP_LED_PORT ^= (1<<BEZP_LED_PIN); //co 100ms _delay_ms(100); } }
Kompletne pliki bldc.h oraz bldc.c znajdziesz na końcu artykułu w pliku do pobrania.
Testujemy
Zanim zaczniesz testować gotowy układ pamiętaj, że tranzystory muszą być rozłączone i zaopatrzone w LED'y zgodnie ze schematem powyżej. Zamiast LED możesz używać multimetru, ale tranzystory muszą być rozłączone!
Ze względu na to, iż mamy tutaj do czynienia z napięciem 12V, to jeżeli:
- sprawdziłeś połączenia dwa razy,
- zrobiłeś przerwę na herbatę i następnie sprawdziłeś jeszcze raz,
- a na koniec multimetrem sprawdziłeś, czy nie ma zwarcia na liniach zasilających zarówno 12V jak i 5V,
W tym celu skorzystamy z poniższego programu oraz definicji i funkcji bezpiecznika, które omówiłem powyżej.
Program testowy:
/* Sterownik silnika BLDC. Test bezpiecznika na diodach LED Częstotliwość F_CPU: dowolna Szczegóły: http://mikrokontrolery.blogspot.com/2011/03/silnik-bldc-sterownik-bezpiecznik-test.html 2012 Dondu */ #include <avr/io.h> #include <util/delay.h> #include "bldc.h" //------------------------------------------------------------------ int main (void) { //ustaw i stan początkowy wyjść strujących tranzystorami U_TR_G_USTAW_DDR V_TR_G_USTAW_DDR W_TR_G_USTAW_DDR U_TR_D_USTAW_DDR V_TR_D_USTAW_DDR W_TR_D_USTAW_DDR U_TR_G_PIN_L V_TR_G_PIN_L W_TR_G_PIN_L U_TR_D_PIN_L V_TR_D_PIN_L W_TR_D_PIN_L //na wszelki wypadek WYLACZ_TRANZYSTORY //UWAGA!!! //Testuj program dowolnie sterując tranzystorami usuwając znak komentarza //w poniższych instrukcjach, obserwując diody LED poszczególnych //tranzystorów. Stan zabroniony powinien zostać złapany przez funkcję //bezpiecznik() i sygnalizowany jej diodą LED. //faza U tranzystor górny //U_TR_G_ON; //U_TR_G_OFF; //faza U tranzystor dolny //U_TR_D_ON; //U_TR_D_OFF; //faza V tranzystor górny //V_TR_G_ON; //V_TR_G_OFF; //faza V tranzystor dolny //V_TR_D_ON; //V_TR_D_OFF; //faza W tranzystor górny //W_TR_G_ON; //W_TR_G_OFF; //faza W tranzystor dolny //W_TR_D_ON; //W_TR_D_OFF; //sprawdzamy, czy nie ma stanu zabronionego na tranzystorach //ZAWSZE WYWOŁUJ TĘ FUNKCJĘ, GDY ZMIENIASZ STAN TRANZYSTORÓW!!! bezpiecznik(); //pętla główna while(1); }
Do pobrania: Kompletny projekt AVR Studio 4 (pliki: main.c, bldc.c, bldc.h): BLDC-01.zip
Pamiętaj, by w opcjach ustawić częstotliwość zegara Twojej ATmega8: F_CPU – gdzie definiować?
Teraz powinieneś testować, czy sterownik prawidłowo reaguje na ustawiane przez Ciebie stany tranzystorów oraz czy funkcja bezpiecznik() prawidłowo broni Ciebie, przed doprowadzeniem do włączenia obu tranzystorów w jednej fazie.
W następnym artykule podłączymy silnik do sterownika i zakręcimy nim po raz pierwszy. Jednakże musisz być pewien, że prawidłowo zbudowałeś sterownik oraz testowanie funkcji bezpiecznik przebiegło poprawnie. Jeżeli nie jesteś pewien, zapytaj poprzez system komentarzy do niniejszego artykułu.
Artykuł z cyklu: Silnik BLDC: Spis treści
Mam problem, bo na Atmedze8A nie działa funkcja bezpiecznika dla pierwszej pary tranzystorów. Dla pozostałych dwóch działa, lecz mogę włączyć dwa tranzystory fazy U i bezpiecznik się nie działa.
OdpowiedzUsuńCzy ATmega8A zasilana jest napięciem 5V?
UsuńZ jaką częstotliwością pracuje ATmega8A?
Atmega jest zasilana napięciem 5V i pracuje z częstotliwością 16 MHz. Rozwiązałem problem dodając opóźnienie 1ms przed funkcją bezpiecznika.
UsuńWstawienie dodatkowego opóźnienia to niewłaściwa droga. Należy ustalić przyczynę. Na pewno nie jest nią program w wersji oryginalnej pobranej wyżej. Testowałem go na ATmega8 i ATmega8A dla 16MHz i zasilania 5V.
UsuńMoże to jakiś problem z prockiem (wadliwy egzemplarz lub seria) sprawdź w Erratach
UsuńCo to jest za element Q1 i Q2 w schemacie kluczy przełączających?
OdpowiedzUsuńWitam.
OdpowiedzUsuńNiestety link http://dondu.elektroda.eu/mikrokontrolery_blog/autorzy/dondu/06_BLDC_TEST0/BLDC-01.zip jest nieaktywny. Proszę o aktualizację
Witam , używając podanego kodu programu otrzymuje błąd zwrotny
OdpowiedzUsuńBuilding target: 0001_BLDC_test.elf
Invoking: AVR C Linker
avr-gcc -Wl,-Map,0001_BLDC_test.map -mmcu=atmega32a -o "0001_BLDC_test.elf" ./bldc.o ./main.o
./main.o: In function `bezpiecznik':
main.c:(.text.bezpiecznik+0x0): multiple definition of `bezpiecznik'
./bldc.o:bldc.c:(.text.bezpiecznik+0x0): first defined here
./main.o: In function `bezpiecznik_stop':
main.c:(.text.bezpiecznik_stop+0x0): multiple definition of `bezpiecznik_stop'
./bldc.o:bldc.c:(.text.bezpiecznik_stop+0x0): first defined here
collect2.exe: error: ld returned 1 exit status
make: *** [0001_BLDC_test.elf] Błąd 1
czym to może być spowodowane?