Skocz do zawartości

PWM do silnika BLDC


Pomocna odpowiedź

Weź się w garść. Wciąż tylko nie wiem, nie wiem i nie wiem...

Wiedziałeś jak wysyłać jedynki i zera na piny? Chyba tak bo coś Ci przecież działało chyba, że ten program też skądś ściągnąłeś. A teraz wiesz już jak ustawić bity COM w rejestrze timera by pokazało się PWM na wyjściu? No to teraz sam algorytm komutacji i załączania dolnych driverów zostaje, ale zamiast wysyłać zero do dolnego drivera danej fazy zerujesz oba bity COM (co wyłącza PWM na danym pinie) a zamiast wystawiać jedynkę do tego drivera - ustawiasz bity COM tak by PWM sie pokazało. Jeśli tego nie rozumiesz, to widocznie na obecnym etapie silnik 3F z PWM jest dla Ciebie za trudny. Gotowca nie dostaniesz. Przynajmniej nie ode mnie.

mpkmateusz, Funkcji zapisu do rejestrów.

Daj wszystko proszę do osobnych linijek.

Najpierw komutację dolnych tranzystorów, potem ustawianie 3 PWM.

marek1707, faktycznie, nie zauważyłem.

No komutecję dolnych driwerów mam ustawioną - są sterowane 0 i 1 (są to piny 10,9,8 w arduino). Zostają 3,5,6 te od PWM, ale co ja mam wpisać?? To co zrobiłem post wyżej? Że zamiast stanu wysokiego na np. 3 wstawiłem (1<

Albo jakieś materiały do przejrzenia, bo nawet nie wiem co wpisać w google.

#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 = 1000;
 OCR0B = 1000;
 OCR2B = 1000;




 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(7,OUTPUT);    // led
 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);
       TCCR0A = (1<<COM0A0)|(1<<COM0B0);
       TCCR2A &= ~(1<<COM2B0);}

     else {
       digitalWrite(10,1);digitalWrite(9,0);digitalWrite(8,0);
       TCCR0A = (1<<COM0A0);
       TCCR0A &= ~(1<<COM0B0);
       TCCR2A &= ~(1<<COM2B0); }}

    if (digitalRead(pierwszy)==1){
     if (digitalRead(zerowy)==0){
       digitalWrite(10,1);digitalWrite(9,0);digitalWrite(8,0);
       TCCR0A &= ~(1<<COM0A0);
       TCCR0A &= ~(1<<COM0B0);
       TCCR2A = (1<<COM2B0);}}}

if (digitalRead(drugi)==0){
   if (digitalRead(pierwszy)==1){
     if (digitalRead(zerowy)==0){
       digitalWrite(10,0);digitalWrite(9,0);digitalWrite(8,1);
       TCCR0A &= ~(1<<COM0A0);
       TCCR0A &= ~(1<<COM0B0);
       TCCR2A = (1<<COM2B0);}

     else {
       digitalWrite(10,0);digitalWrite(9,1);digitalWrite(8,1);
       TCCR0A &= ~(1<<COM0A0);
       TCCR0A &= ~(1<<COM0B0);
       TCCR2A &= ~(1<<COM2B0);}}

    if (digitalRead(pierwszy)==0){
     if (digitalRead(zerowy)==1){
       digitalWrite(10,0);digitalWrite(9,1);digitalWrite(8,0);
       TCCR0A &= ~(1<<COM0A0);
       TCCR0A = (1<<COM0B0);
       TCCR2A &= ~(1<<COM2B0);}}}

}}

void loop(){

 digitalWrite(10,0);digitalWrite(9,0);digitalWrite(8,0);
       TCCR0A &= ~(1<<COM0A0);
       TCCR0A &= ~(1<<COM0B0);
       TCCR2A &= ~(1<<COM2B0);

 if (digitalRead(4)==0)
 {  
 obr();
}
}

Coś takiego? Wgrałem ten "program" i zachowuje się podobnie jak na digitalWrite.

Ale przecież nikt z nas nie będzie uruchamiał Twojego programu. Dobrze, że zamieniłeś załączanie górnych tranzystorów na manipulacje bitami COM i teraz czeka Cię zadanie zrobienia tego bezbłędnie. W takich pracach, przy uruchamianiu kodu tak ściśle współpracującego ze sprzętem przydaje się oscyloskop. W ciągu kilku sekund widzisz, że na wyjściu nie jest to czego się podziewałeś. Masz taki sprzęt? Może w szkole?

Ja mam kilka uwag, może Koledzy z czymś się jeszcze dorzucą:

W obu timerach użyłeś trybu 3, Fast PWM - i dobrze, tylko że jest to tryb 8-bitowy. Te timery nie umieją z resztą inaczej, ba sam licznik ma tylko 8 bitów. Rejestry OCR oczywiście także są tej samej długości, więc możesz do nich ładować liczby z zakresu 0-255. A Ty na początku wpisujesz do nich 1000?

Czy podczas inicjalizacji pinów I/O w poprzednim kodzie włączałeś od razu drivery górnych MOSFETów? Nie? To dlaczego teraz ustawiając tryby pracy timerów odpalasz PWM przez ustawianie bitów COM?

Używaj preprocesora C. To takie fajne coś wbudowane w kompilator (poczytaj o tym), dzięki czemu możesz robić różne fajne rzeczy z tekstem programu zanim zacznie się analiza składniowa. Np. zamiast wpisywać wiele razy w program tę samą nieczytelną linię:

TCCR0A &= ~(1<

możesz definiować sobie nowy symbol:

#define PHASE_2_PWM_OFF TCCR0A &= ~(1<

i od tej pory wszędzie kiedy musisz wyłączyć PWM na tej fazie możesz używać:

PHASE_2_PWM_OFF;

Preprocesor poszuka w znanych sobie łańcuchach tekstowych właśnie takiego i zmieni go na to, czego go nauczyłeś komendą #define.

Jeśli to samo zrobisz z każdą operacją na każdym tranzystorze każdej fazy, program nagle zacznie składać się z samych zrozumiałych linii. Przykładowo może to być:

PHASE_2_PWM_ON;

PHASE_1_LOW_ON;

PHASE_3_LOW_OFF;

Nie wiem czy akurat ta kombinacja ma sens, ale czytelność wzrosła na pewno 🙂 Dzięki takim zabiegom nie będziesz musiał zmieniać wciąż wielu linii kodu. Jeśli zechcesz np. inaczej włączać PWM, wystarczy zmiana jednej definicji.

Zastanów się nad potrzebnym stanem bitów COM. Każde wyjście timera ma je dwa. Stan 00 oznacza odłączenie timera od pinu. A jaka kombinacja jest potrzebna, by wyjściowy PWM był "prosty", tj. większy OCR dawał większe wypełnienie? Wszystko jest w tabelce opisującej znaczenie bitów w trybie Fast PWM. No i jeśli chcesz, zobaczyć wyraźną różnicę w działaniu silnika, to nie wpisuj 250 (do 8-bitowego OCR) bo to prawie niczego nie zmieni tylko może 50 lub 100?

I na koniec: to dobrze, że wkurza Cię Twoja nieporadność. Może będzie dobrą motywacją do dalszej pracy, czytania i nauki. Zwykle im więcej wiesz tym lepiej widzisz jak skromna jest Twoja wiedza. Moim zdaniem radzisz sobie całkiem nieźle 🙂

-------------------

EDIT: Mam nadzieję, że to już wiesz, ale nigdy, przenigdy nie dopuść do jednoczesnego włączenia obu tranzystorów jednej fazy. Zawsze najpierw wyłączaj jeden a dopiero potem na ten drugi podawaj stan 1 lub załączaj PWM. Przejrzyj cały kod bardzo dokładnie pod tym kątem, łącznie z inicjalizacją. Upewnij się, że wyjścia które potem będą wysyłały PWM ustawiłeś na początku w stanie 0. Po ustawieniu obu bitów COM w stan 00 timer się odłącza od pinu I/O (ale nie zatrzymuje generacji PWM) a na pinie pokazuje się stan taki jak ostatnio tam wysłałeś. Bez PWM to musi być 0.

Ja mam kilka uwag, może Koledzy z czymś się jeszcze dorzucą.

Bardzo chętnie.

mpkmateusz, fatalnie u Ciebie wygląda formatowanie kodu. Pozwól, że Ci trochę doradzę:

1. Instrukcje w obrębie tego samego bloku powinny mieć takie samo wcięcie. U Ciebie jest:

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 = 1000;
 OCR0B = 1000;
 OCR2B = 1000;

a powinno być:

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 = 1000;
 OCR0B = 1000;
 OCR2B = 1000;

2.Gdy wchodzimy do wnętrza nowego bloku zwiększamy wcięcie. U Ciebie jest:

int obr(){
 while(1) {
if (digitalRead(drugi)==1){
   if (digitalRead(pierwszy)==0){

a powinno być:

int obr(){
 while(1) {
   if (digitalRead(drugi)==1){
     if (digitalRead(pierwszy)==0){

3.Nie stawiamy zamykającej klamry w tej samej linii co ostatnia instrukcja. U Ciebie jest:

      if (digitalRead(zerowy)==1){
       digitalWrite(10,0);digitalWrite(9,0);digitalWrite(8,0);
       TCCR0A = (1<<COM0A0)|(1<<COM0B0);
       TCCR2A &= ~(1<<COM2B0);}

a powinno być:

      if (digitalRead(zerowy)==1){
       digitalWrite(10,0);digitalWrite(9,0);digitalWrite(8,0);
       TCCR0A = (1<<COM0A0)|(1<<COM0B0);
       TCCR2A &= ~(1<<COM2B0);
     }

4.Nie stawiamy w jednej linii więcej niż jednej zamykającej klamry. U Ciebie jest:

     if (digitalRead(pierwszy)==1){
     if (digitalRead(zerowy)==0){
       digitalWrite(10,1);digitalWrite(9,0);digitalWrite(8,0);
       TCCR0A &= ~(1<<COM0A0);
       TCCR0A &= ~(1<<COM0B0);
       TCCR2A = (1<<COM2B0);}}}

a powinno być:

     if (digitalRead(pierwszy)==1){
     if (digitalRead(zerowy)==0){
       digitalWrite(10,1);digitalWrite(9,0);digitalWrite(8,0);
       TCCR0A &= ~(1<<COM0A0);
       TCCR0A &= ~(1<<COM0B0);
       TCCR2A = (1<<COM2B0);
     }
    }
   }

No i trzeba się zdecydować jakich wcięć się używa: jedno czy dwu spacjowych, a nie raz takich, a raz takich.

No i trzeba się zdecydować jakich wcięć się używa: jedno czy dwu spacjowych, a nie raz takich, a raz takich.

Wcięcia najlepiej tabulatorem robić.

Jak dla mnie również klamra otwierająca nie powinna być w tej samej lini co warunek/pętla/etc.

if (digitalRead(pierwszy)==1)
{
    //while(1)
    while(digitalRead(niezerowy)==0) // bezproblemowe podmiany
    //if (digitalRead(zerowy)==0)
    {
         digitalWrite(10,1);digitalWrite(9,0);digitalWrite(8,0);
         TCCR0A &= ~(1<<COM0A0);
         TCCR0A &= ~(1<<COM0B0);
         TCCR2A = (1<<COM2B0);
    }
}

Dzięki temu można łatwo namierzyć wszelkie błędy - oraz np. zakomentować "poprawne-ale-jednak-błędne "if'y aby skorzystać z czegoś innego.

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...