Skocz do zawartości

PWM do silnika BLDC


mpkmateusz

Pomocna odpowiedź

Witam. Wytłumaczy mi ktoś w jaki sposób mogę sterować sygnałem PWM do zwiekszania/zmniejszania obrotów silnika? Kod jaki do tej pory napisałem rozpędza silnik do prędkości maksymalnej, a chciałbym płynnie sterować potencjometrem. Szukałem po internecie i niewiele znalazłem.

#define pierwszy 13  // czujnik halla 1
#define drugi 11     // czujnik halla 2
#define zerowy 12    // czujnik halla 3

void setup(){
 pinMode(3, OUTPUT);  // Faza 1 +
 pinMode(5, OUTPUT);  // Faza 2 +
 pinMode(6, OUTPUT);  // Faza 3 +
 pinMode(8, OUTPUT);  // Faza 1 -
 pinMode(9, OUTPUT);  // Faza 2 -
 pinMode(10, OUTPUT); // Faza 3 -


 pinMode(11, INPUT);
 pinMode(12, INPUT);   // czujniki
 pinMode(13, INPUT);


 pinMode(4,INPUT_PULLUP);

}

int obr(){
 while(1) {
if (digitalRead(drugi)==1){
   if (digitalRead(pierwszy)==0){
     if (digitalRead(zerowy)==1){
       digitalWrite(10,0);digitalWrite(9,0);digitalWrite(8,0);
       digitalWrite(6,1);digitalWrite(5,1);digitalWrite(3,0);}
     else {
       digitalWrite(10,1);digitalWrite(9,0);digitalWrite(8,0);
       digitalWrite(6,1);digitalWrite(5,0);digitalWrite(3,0);}}

    if (digitalRead(pierwszy)==1){
     if (digitalRead(zerowy)==0){
       digitalWrite(10,1);digitalWrite(9,0);digitalWrite(8,0);
       digitalWrite(6,0);digitalWrite(5,0);digitalWrite(3,1);}}}


if (digitalRead(drugi)==0){
   if (digitalRead(pierwszy)==1){
     if (digitalRead(zerowy)==0){
       digitalWrite(10,0);digitalWrite(9,0);digitalWrite(8,1);
       digitalWrite(6,0);digitalWrite(5,0);digitalWrite(3,1);}
     else {
       digitalWrite(10,0);digitalWrite(9,1);digitalWrite(8,1);
       digitalWrite(6,0);digitalWrite(5,0);digitalWrite(3,0);}}

    if (digitalRead(pierwszy)==0){
     if (digitalRead(zerowy)==1){
       digitalWrite(10,0);digitalWrite(9,1);digitalWrite(8,0);
       digitalWrite(6,0);digitalWrite(5,1);digitalWrite(3,0);}}}

}
}

void loop(){

 digitalWrite(10,0);digitalWrite(9,0);digitalWrite(8,0);
 digitalWrite(6,0);digitalWrite(5,0);digitalWrite(3,0);

 if (digitalRead(4)==0){

 obr();
 }
}
Link do komentarza
Share on other sites

Program wrzuciłeś niepotrzebnie, bo nikt nie będzie czytał takich wypocin z setką cyferek przypadkowo utkaną gdzieś w kodzie. Dopóki nie będziesz stosować nazw symbolicznych które tłumaczą czym są, Twoje programy będą nieczytelne. Wstyd.

A teraz o obrotach. Zaraz sam do tego dojdziesz bez pomocy internetu: odpowiedz na pytanie co sprawia, że w obecnej sytuacji silnik rozkręca się do obrotów maksymalnych tj. skąd bierze się przyrost energii kinetycznej wirnika i wzrost mocy oddawanej przez silnik na wale podczas pracy Twojego algorytmu?

Link do komentarza
Share on other sites

Dobra, może inaczej. Próbuję zrobić układ podobny jak na tej stronie

http://elabz.com/bldc-motor-with-arduino-circuit-and-software/

z tą różnicą, że sterowanie jest dwoma mosfetami na każdą z faz:

Nie mam zielonego pojęcia o co chodzi z tymi linijkami w kodzie ze strony wyżej.

void setup() {

 TCCR1B = TCCR1B & 0b11111000 | 0x01; // set PWM frequency @ 31250 Hz for Pins 9 and 10
 TCCR2B = TCCR2B & 0b11111000 | 0x01; // set PWM frequency @ 31250 Hz for Pins 11 and 3 (3 not used)
//  ICR1 = 255 ; // 8 bit resolution
 ICR1 = 1023 ; // 10 bit resolution

O co chodzi z "TCCR1B" itp? I główne pytanie jak mogę wstawić te funkcje do mojego skeczu, aby efekt był ten sam. Nie chce gotowej odpowiedzi, ale naprowadzenia albo najlepiej przykładu.

Link do komentarza
Share on other sites

To spróbujmy tak: rzucę Cię na głęboką wodę a Ty sam spróbujesz odkryć czy sięgasz palcami dna. Ściągnij ten dokument

http://www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdf

To jest pełny opis procesora na którym pracujesz. Masz tam opisane wszystkie peryferia za które zapłaciłeś a o nich nic nie wiesz. Na dzisiaj skup się na rozdziale o Timerze 1 - bo to on jest wykorzystywany do generacji PWM w przytoczonym przykładzie. Jutro powiedz czy coś z tego rozumiesz, czy wyjaśniła się sprawa rejestrów TCCR i czy PWM jest już bliżej niż dalej 🙂 Powodzenia.

EDIT: Dodam jeszcze, że układ który wymyśliłeś (ten na MOSFETach) potrzebuje dwóch bardzo sprytnie wygenerowanych przebiegów PWM na jedną fazę silnika. Prosty wniosek, że w sumie potrzebujesz aż 6 sygnałów PWM. To przekracza możliwości Twojego procesora i niestety driver będzie musiał być zmieniony. Właśnie dlatego ludzie używają scalonych driverów silników, bo tam sterowanie tranzystorami i rozsuwanie czasów martwych jest robione w środku a na wejście podajesz tylko jeden przebieg na fazę. Wtedy wystarczą tylko trzy PWMy a to już się da zrobić na Arduino. Tam w przykładzie gość użył obu wyjść Timera 1 i jednego wyjścia Timera 2.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

No wielkie dzięki.. A nie mógłbyś jakoś wytłumaczyć, opisać? Zanim do tego dotrę z tej strony to miną wieki, a mnie potrzebnych jest parę linijek kodu (tak myślę).

Głównie opierałem się na tej stronie przy robieniu części elektrycznej.

http://mikrokontrolery.blogspot.com/2011/03/silnik-bldc-podlaczamy-testujemy.html

Autor, użył sygnału PWM tylko na kluczach górnych. W moim przypadku piny 3,5,6, ale największy problem w tym, że zapisał kod w pliku dla AVR Studio, a ja robię w arduino.

Link do komentarza
Share on other sites

Zobacz: zrobiłeś coś bardzo prostego. Komutujesz kilka wyjść w zależności od stanu czujników kąta obrotu - to jest trywialne. Żeby zrobić coś więcej, musisz zrozumieć jak działają timery i jak generowany jest PWM ze wszystkimi niuansami szybkiego sterowania takimi półmostkami. Ponieważ nie jesteś w stanie wygenerować sprzętowo 6 sygnałów PWM, po prostu nie zrobisz tego na swoim sprzęcie. Koniec, kropka.

Dopiero gdy zmienisz driver na jakiś inny (lub dodasz jakiś lepszy sterownik bramek do istniejących tranzystorów), możesz wtedy myśleć o PWM i kontroli prądu/obrotów. Programikiem możesz machać pinami dowolnie, ale sprzętowe timery wymagają dołączenia się do dedykowanych wyjść a ich liczba jest ograniczona. Naprawdę dobrze Ci radzę: nie ma dróg na skróty a jeśli są, to przez bagna. Czytaj o timerach i zacznij myśleć o przebudowie układu mocy, bo utoniesz.

EDIT: No dobrze. Jeżeli robisz układ super oszczędnościowy i nie przejmujesz się sprawnościami, grzaniem itd a chcesz tylko by silnik się trochę pokręcił, możesz sterować tylko górne tranzystory. Rozwiązanie jest biedoszybowe, ale zadziała. To czego dokładnie nie rozumiesz? Dostęp do rejestrów timerów masz w Arduino taki sam jak w GCC. Wpisujesz

TCCR1A = cośtam;

i działa tak samo jak w czystym C.

Link do komentarza
Share on other sites

Ok.

Strona 153:

Czyli na początek wybieram sobie rejestr, powiedzmy TCCR2A. W tabeli wyżej pokazane są wyjścia PWM z pinów kontrolera, np. COM2A1 jako OC2A czyli pin 17 (w arduino pin 11). I dla tego rejestru mogę wybrać tylko OC2A i OC2B. Dopisanie COM2A0 i COM2B0 służy tylko do "regulacji" dla tabeli

18-2?

Dalej...

Wybrane WGM21 i WGM20 dają mi "mode 3" czyli " Fast PWM", tylko teraz czy jest różnica jakie "fast PWM" wybiore? Bo jest jeszcze na "mode 7" (ale brakuje WGM22 w tej pierwszej tabeli).

Dalej...

TCCR2B

Trzeba dopisać z tabeli 18-9 jaki jest preskaler. (czyli CS20, bo chcę preskaler 1)

zgodnie ze wzorem : F = 8Ghz / 2^8 (jakby ktoś wyjaśnił o co chodzi w tym wzorze byłoby miło).

F= 31250 Hz

Wychodzi na to, że aby uzyskać sygnał PWM dla pinów 5 i 17 (OC2A i OC2B) :

TCCR1A = (1<

i dodatkowo

TCCR2B = (1<

TCCR1A = (1<<COM2A0)  (1<<COM2B0)  (1<<WGM21)  (1<<WGM20);
TCCR2B = (1<<CS20);

i całość dajemy przed funkcją setup.

Dobry jest powyższy zapis?

Dla timera 2 jest OC2A i OC2B, dla timera 1 jest OC1A i OC1B i dla timera 0 jest OC0A i OC0B ?

Dobrze myślę? Takie to proste? 🤣

Link do komentarza
Share on other sites

Widzę, że szybko łapiesz. Trochę mieszasz jedynie numery od timerów i bitów. W nocie masz opisany np. timer TCCR2. Aby go używać musisz zmieniać bity w rejestrach TCCR2A oraz TCCR2B. Tak samo z timerem TCCR1, używasz tutaj TCCR1A i TCCR1B. Wynika to z tego, że mają one 10-bitową rozdzielczość. Jednak są również timery 8-bitowe, które posiadają tylko 1 rejestr.

W nocie jak zobaczysz to pod każdym rejestrem np TCCR1A znajdzie się TCCR1B i tam znajdziesz pozostałe bity (np. Ten WGM22, którego nie mogłeś znaleźć).

Co do wzoru:

F(częstotliwość PWM) =( F_CPU (częstotliwość uC) / preskaler ) / 256 (czyli 2^8)

256, bo z takiej wartości składa się "Cykl" PWM (tu można mnie pewnie poprawić)

I teraz co do twojego kodu

TCCR2A |= (1<

TCCR2B |= (1<

COMx - służy do obsługi pinów timera. Kombinacje bitów COM2A0 i COM2A1 masz w tej tabelce.

Link do komentarza
Share on other sites

No dobra, a jakie komendy mogę teraz użyć aby móc regulować wypełnienie? Patrzyłem na to:

http://www.robotyka.net.pl/mikrokontrolery-avr-czesc-7-tmier1/

i kod z przykłądu drugiego:

#define F_CPU 1000000 //ustawienie oscylatora na 1MHz

#include <avr/io.h> //dołączenie podstawowej biblioteki

int main()

{

    TCCR1A = (1<<COM1A1)|(1<<COM1B1)|(1<<WGM10)|(1<<WGM11);

    //konfiguracja trybu

    TCCR1B = (1<<CS10)|(1<<WGM12);

    //konfiguracja trybu i prescalera

    OCR1A = 500;

    //wartość określająca współczynnik wypełnienia

    while(1) //pusta pętla

    {



    }

}

Problem w tym że chciałem " OCR1A = 500; " to wpisać do arduino, ale wyskakuje błąd.

Dodałem tę bibliotekę, "#define F_CPU 1000000" też dodałem, ale to zapewne nie o to chodzi 😅 ???

Link do komentarza
Share on other sites

To mi właśnie wygląda na drogę na skróty. Nie rozumiem tego. W dziale o timerach jest specjalny rozdział poświęcony trybom pracy a tam specjalny kawał tekstu z rusunkami tylko o PWM. Naprawdę nie masz tej godziny żeby to przeczytać i zrozumieć? Brnąc dalej w ten sposób będziesz co chwila pytał o banały, bo jak już opanujesz wypełnienie to z chwilę będzie problem ze zmianą okresu. Myślisz, że skąd ja wiem jak używać timera. Właśnie z dokumentu, który dostałeś na talerzu - to opracowanie producenta procesora. Wszystko inne w internecie jest wtórne do tego. Jeśli cały rozdział jest dla Ciebie za długi, wystarczy tabelka opisująca wszystkie tryby pracy w pigułce. W zależności od tego który tryb pracy timera wybrałeś bitami WGM (a samych trybów PWM timer 1 ma kilka), różnie jest zdefiniowany okres, ale przy określaniu wypełnienia zawsze wyjście OC1A korzysta z rejestru OCR1A a OC1B z rejestru OCR1B.

Uwaga: w zależności od trybu pracy wyjścia (bity COM) wypełnienie rzeczywistego przebiegu PWM może się zwiększać lub zmniejszać przy wzroście liczby w OCR1x.

Środowisko Arduino IDE "wie" z jaką częstotliwością pracuje twój procesor bo ma to zdefiniowane w ustawieniach wybranej płytki. Definiowanie symbolu F_CPU jest zbędne tym bardziej, że nieprawdziwe. Naprawdę zmieniłeś taktowanie procesora na 1MHz? Po co? Myśl trochę.

Nic nikomu nie daje informacja, że "wyskakuje błąd". Mamy się domyślić jaki czy po prostu współczuć? I jaką bibliotekę dodałeś i po co? Jeżeli symbole TCCR1A i podobne są znane, to OCR1A także.

Link do komentarza
Share on other sites

Poczytam, ale szczerze? - potrzebuje to PWM zrobić szybko. Na wgłębianie się w "tajemnice" będę miał jeszcze czas później (najlepiej nie komentujcie tego).

Mam coś takiego:

void setup(){

 pinMode(3, OUTPUT);  // Faza 1 +
 pinMode(5, OUTPUT);  // Faza 2 +
 pinMode(6, OUTPUT);  // Faza 3 +

TCCR0A = (1<<COM0A0)|(1<<COM0B0)|(1<<WGM01)|(1<<WGM00);
TCCR0B = (1<<CS00);
TCCR2A = (1<<COM2B0)|(1<<WGM21)|(1<<WGM20);
TCCR2B = (1<<CS20);

 OCR0A = 10;
 OCR0B = 10;
 OCR2B = 10;

Ja to widze tak, że na pinach 3,5,6 w atmedze328p powinien być sygnał PWM (częstotliwość 31250Hz )o wypełnieniu 10/255 = 4%. Czyli powinny być niskie obroty silnika.

A jak jest? Tak jak wcześniej...

Link do komentarza
Share on other sites

Ja to widze tak, że na pinach 3,5,6 w atmedze328p powinien być sygnał PWM

W ATmedze328p na pinach 3, 6 nie ma PWM. W Arduino może tak, ale w atmedze na pewno nie.

... o wypełnieniu 10/255 = 4%. Czyli powinny być niskie obroty silnika.

Chyba nie wiele jeszcze wiesz o działaniu silników DC. Poczytaj to:Nieliniowa zależność obrotów w funkcji wypełnienia impulsu.

A tak w ogóle BLDC wymaga odpowiedniej komutacji faz i ustalania pozycji wirnika, a tego w kodzie u Ciebie wcale nie widać. OK już widzę - jest w 1. poście.

Link do komentarza
Share on other sites

Dałem fragment.

Cały:


#define pierwszy 13  // czujnik halla 1
#define drugi 11     // czujnik halla 2
#define zerowy 12    // czujnik halla 3



void setup(){

 pinMode(3, OUTPUT);  // Faza 1 +
 pinMode(5, OUTPUT);  // Faza 2 +
 pinMode(6, OUTPUT);  // Faza 3 +

TCCR0A = (1<<COM0A0)|(1<<COM0B0)|(1<<WGM01)|(1<<WGM00);
TCCR0B = (1<<CS00);
TCCR2A = (1<<COM2B0)|(1<<WGM21)|(1<<WGM20);
TCCR2B = (1<<CS20);

 OCR0A = 10;
 OCR0B = 10;
 OCR2B = 10;




 pinMode(8, OUTPUT);  // Faza 1 -
 pinMode(9, OUTPUT);  // Faza 2 -
 pinMode(10, OUTPUT); // Faza 3 -


 pinMode(11, INPUT);
 pinMode(12, INPUT);   // czujniki
 pinMode(13, INPUT);


 pinMode(4,INPUT_PULLUP); //załączenie

}

int obr(){
 while(1) {
if (digitalRead(drugi)==1){
   if (digitalRead(pierwszy)==0){
     if (digitalRead(zerowy)==1){
       digitalWrite(10,0);digitalWrite(9,0);digitalWrite(8,0);
       digitalWrite(6,1);digitalWrite(5,1);digitalWrite(3,0);}
     else {
       digitalWrite(10,1);digitalWrite(9,0);digitalWrite(8,0);
       digitalWrite(6,1);digitalWrite(5,0);digitalWrite(3,0);}}

    if (digitalRead(pierwszy)==1){
     if (digitalRead(zerowy)==0){
       digitalWrite(10,1);digitalWrite(9,0);digitalWrite(8,0);
       digitalWrite(6,0);digitalWrite(5,0);digitalWrite(3,1);}}}


if (digitalRead(drugi)==0){
   if (digitalRead(pierwszy)==1){
     if (digitalRead(zerowy)==0){
       digitalWrite(10,0);digitalWrite(9,0);digitalWrite(8,1);
       digitalWrite(6,0);digitalWrite(5,0);digitalWrite(3,1);}
     else {
       digitalWrite(10,0);digitalWrite(9,1);digitalWrite(8,1);
       digitalWrite(6,0);digitalWrite(5,0);digitalWrite(3,0);}}

    if (digitalRead(pierwszy)==0){
     if (digitalRead(zerowy)==1){
       digitalWrite(10,0);digitalWrite(9,1);digitalWrite(8,0);
       digitalWrite(6,0);digitalWrite(5,1);digitalWrite(3,0);}}}



}
}

void loop(){

 digitalWrite(10,0);digitalWrite(9,0);digitalWrite(8,0);
 digitalWrite(6,0);digitalWrite(5,0);digitalWrite(3,0);

 if (digitalRead(4)==0)
 {

 obr();


 }
}
Link do komentarza
Share on other sites

Weź schemat Arduino - dokładnie tego które masz (a które to jest?) i obejrzyj. Numeracja pinów procesora to jedno a numeracja pinów Arduino to drugie - jak słusznie zauważył Wojciech. Jeżeli doczytasz się na które piny wyprowadzone są wyjścia timera to prześledź gdzie idzie sygnał i na który pin płytki wychodzi. Programy w środowisku Arduino posługują się numeracją opisaną na PCB a opis procesora ATmega używa numeracji konkretnej obudowy - na początku dokumentu są rysunki różnych wersji obudów.

Jeżeli już odpalisz PWM to teraz musisz je jakoś komutować zgodnie algorytmem wymaganym przez silnik 3F. W sowim pierwszym kodzie miałeś łatwo, bo wystarczało wystawiać jedynki i zera na (w sumie dowolne) piny do których podłączyłeś tranzystory. Teraz będziesz musiał włączać i wyłączać PWM (dla górnych) i wysyłać jedynki i zera (dla dolnych kluczy). Kluczowanie PWM najłatwiej zrobić przez puszczenie timera cały czas a odłączanie jego wyjść od pinów przez modyfikacje bitów COM. Jeśli odłączysz timer od pinu to na wyjściu procesora pokazuje się stan tego co ostatnio wystawiłeś funkcję DigitalWrite. Jeśli gdzieś na początku ustawisz te piny na wyjścia i wystawisz tam zera, wystarczy że będziesz dołączał i dołączał pracujący timer bitami COM a dostaniesz modulowane PWM 🙂

Link do komentarza
Share on other sites

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ę »
×
×
  • 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.